tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

certreq.c (10138B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "cert.h"
      6 #include "certt.h"
      7 #include "secder.h"
      8 #include "keyhi.h"
      9 #include "secitem.h"
     10 #include "secasn1.h"
     11 #include "secerr.h"
     12 
     13 SEC_ASN1_MKSUB(SEC_AnyTemplate)
     14 
     15 const SEC_ASN1Template CERT_AttributeTemplate[] = {
     16    { SEC_ASN1_SEQUENCE,
     17      0, NULL, sizeof(CERTAttribute) },
     18    { SEC_ASN1_OBJECT_ID, offsetof(CERTAttribute, attrType) },
     19    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(CERTAttribute, attrValue),
     20      SEC_ASN1_SUB(SEC_AnyTemplate) },
     21    { 0 }
     22 };
     23 
     24 const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = {
     25    { SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate },
     26 };
     27 
     28 const SEC_ASN1Template CERT_CertificateRequestTemplate[] = {
     29    { SEC_ASN1_SEQUENCE,
     30      0, NULL, sizeof(CERTCertificateRequest) },
     31    { SEC_ASN1_INTEGER,
     32      offsetof(CERTCertificateRequest, version) },
     33    { SEC_ASN1_INLINE,
     34      offsetof(CERTCertificateRequest, subject),
     35      CERT_NameTemplate },
     36    { SEC_ASN1_INLINE,
     37      offsetof(CERTCertificateRequest, subjectPublicKeyInfo),
     38      CERT_SubjectPublicKeyInfoTemplate },
     39    { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
     40      offsetof(CERTCertificateRequest, attributes),
     41      CERT_SetOfAttributeTemplate },
     42    { 0 }
     43 };
     44 
     45 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate)
     46 
     47 CERTCertificate *
     48 CERT_CreateCertificate(unsigned long serialNumber,
     49                       CERTName *issuer,
     50                       CERTValidity *validity,
     51                       CERTCertificateRequest *req)
     52 {
     53    CERTCertificate *c;
     54    int rv;
     55    PLArenaPool *arena;
     56 
     57    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     58 
     59    if (!arena) {
     60        return (0);
     61    }
     62 
     63    c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
     64 
     65    if (!c) {
     66        PORT_FreeArena(arena, PR_FALSE);
     67        return 0;
     68    }
     69 
     70    c->referenceCount = 1;
     71    c->arena = arena;
     72 
     73    /*
     74     * Default is a plain version 1.
     75     * If extensions are added, it will get changed as appropriate.
     76     */
     77    rv = DER_SetUInteger(arena, &c->version, SEC_CERTIFICATE_VERSION_1);
     78    if (rv)
     79        goto loser;
     80 
     81    rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber);
     82    if (rv)
     83        goto loser;
     84 
     85    rv = CERT_CopyName(arena, &c->issuer, issuer);
     86    if (rv)
     87        goto loser;
     88 
     89    rv = CERT_CopyValidity(arena, &c->validity, validity);
     90    if (rv)
     91        goto loser;
     92 
     93    rv = CERT_CopyName(arena, &c->subject, &req->subject);
     94    if (rv)
     95        goto loser;
     96    rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo,
     97                                         &req->subjectPublicKeyInfo);
     98    if (rv)
     99        goto loser;
    100 
    101    return c;
    102 
    103 loser:
    104    CERT_DestroyCertificate(c);
    105    return 0;
    106 }
    107 
    108 /************************************************************************/
    109 /* It's clear from the comments that the original author of this
    110 * function expected the template for certificate requests to treat
    111 * the attributes as a SET OF ANY.  This function expected to be
    112 * passed an array of SECItems each of which contained an already encoded
    113 * Attribute.  But the cert request template does not treat the
    114 * Attributes as a SET OF ANY, and AFAIK never has.  Instead the template
    115 * encodes attributes as a SET OF xxxxxxx.  That is, it expects to encode
    116 * each of the Attributes, not have them pre-encoded.  Consequently an
    117 * array of SECItems containing encoded Attributes is of no value to this
    118 * function.  But we cannot change the signature of this public function.
    119 * It must continue to take SECItems.
    120 *
    121 * I have recoded this function so that each SECItem contains an
    122 * encoded cert extension.  The encoded cert extensions form the list for the
    123 * single attribute of the cert request. In this implementation there is at most
    124 * one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST.
    125 */
    126 
    127 CERTCertificateRequest *
    128 CERT_CreateCertificateRequest(CERTName *subject,
    129                              CERTSubjectPublicKeyInfo *spki,
    130                              SECItem **attributes)
    131 {
    132    CERTCertificateRequest *certreq;
    133    PLArenaPool *arena;
    134    CERTAttribute *attribute;
    135    SECOidData *oidData;
    136    SECStatus rv;
    137    int i = 0;
    138 
    139    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    140    if (arena == NULL) {
    141        return NULL;
    142    }
    143 
    144    certreq = PORT_ArenaZNew(arena, CERTCertificateRequest);
    145    if (!certreq) {
    146        PORT_FreeArena(arena, PR_FALSE);
    147        return NULL;
    148    }
    149    /* below here it is safe to goto loser */
    150 
    151    certreq->arena = arena;
    152 
    153    rv = DER_SetUInteger(arena, &certreq->version,
    154                         SEC_CERTIFICATE_REQUEST_VERSION);
    155    if (rv != SECSuccess)
    156        goto loser;
    157 
    158    rv = CERT_CopyName(arena, &certreq->subject, subject);
    159    if (rv != SECSuccess)
    160        goto loser;
    161 
    162    rv = SECKEY_CopySubjectPublicKeyInfo(arena,
    163                                         &certreq->subjectPublicKeyInfo,
    164                                         spki);
    165    if (rv != SECSuccess)
    166        goto loser;
    167 
    168    certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute *, 2);
    169    if (!certreq->attributes)
    170        goto loser;
    171 
    172    /* Copy over attribute information */
    173    if (!attributes || !attributes[0]) {
    174        /*
    175         ** Invent empty attribute information. According to the
    176         ** pkcs#10 spec, attributes has this ASN.1 type:
    177         **
    178         ** attributes [0] IMPLICIT Attributes
    179         **
    180         ** Which means, we should create a NULL terminated list
    181         ** with the first entry being NULL;
    182         */
    183        certreq->attributes[0] = NULL;
    184        return certreq;
    185    }
    186 
    187    /* allocate space for attributes */
    188    attribute = PORT_ArenaZNew(arena, CERTAttribute);
    189    if (!attribute)
    190        goto loser;
    191 
    192    oidData = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
    193    PORT_Assert(oidData);
    194    if (!oidData)
    195        goto loser;
    196    rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid);
    197    if (rv != SECSuccess)
    198        goto loser;
    199 
    200    for (i = 0; attributes[i] != NULL; i++)
    201        ;
    202    attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i + 1);
    203    if (!attribute->attrValue)
    204        goto loser;
    205 
    206    /* copy attributes */
    207    for (i = 0; attributes[i]; i++) {
    208        /*
    209        ** Attributes are a SetOf Attribute which implies
    210        ** lexigraphical ordering.  It is assumes that the
    211        ** attributes are passed in sorted.  If we need to
    212        ** add functionality to sort them, there is an
    213        ** example in the PKCS 7 code.
    214        */
    215        attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]);
    216        if (!attribute->attrValue[i])
    217            goto loser;
    218    }
    219 
    220    certreq->attributes[0] = attribute;
    221 
    222    return certreq;
    223 
    224 loser:
    225    CERT_DestroyCertificateRequest(certreq);
    226    return NULL;
    227 }
    228 
    229 void
    230 CERT_DestroyCertificateRequest(CERTCertificateRequest *req)
    231 {
    232    if (req && req->arena) {
    233        PORT_FreeArena(req->arena, PR_FALSE);
    234    }
    235    return;
    236 }
    237 
    238 static void
    239 setCRExt(void *o, CERTCertExtension **exts)
    240 {
    241    ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts;
    242 }
    243 
    244 /*
    245 ** Set up to start gathering cert extensions for a cert request.
    246 ** The list is created as CertExtensions and converted to an
    247 ** attribute list by CERT_FinishCRAttributes().
    248 */
    249 extern void *cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
    250                                  void (*setExts)(void *object, CERTCertExtension **exts));
    251 void *
    252 CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req)
    253 {
    254    return (cert_StartExtensions((void *)req, req->arena, setCRExt));
    255 }
    256 
    257 /*
    258 ** At entry req->attributes actually contains an list of cert extensions--
    259 ** req-attributes is overloaded until the list is DER encoded (the first
    260 ** ...EncodeItem() below).
    261 ** We turn this into an attribute list by encapsulating it
    262 ** in a PKCS 10 Attribute structure
    263 */
    264 SECStatus
    265 CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req)
    266 {
    267    SECItem *extlist;
    268    SECOidData *oidrec;
    269    CERTAttribute *attribute;
    270 
    271    if (!req || !req->arena) {
    272        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    273        return SECFailure;
    274    }
    275    if (req->attributes == NULL || req->attributes[0] == NULL)
    276        return SECSuccess;
    277 
    278    extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes,
    279                                 SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate));
    280    if (extlist == NULL)
    281        return (SECFailure);
    282 
    283    oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
    284    if (oidrec == NULL)
    285        return SECFailure;
    286 
    287    /* now change the list of cert extensions into a list of attributes
    288     */
    289    req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute *, 2);
    290 
    291    attribute = PORT_ArenaZNew(req->arena, CERTAttribute);
    292 
    293    if (req->attributes == NULL || attribute == NULL ||
    294        SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) {
    295        PORT_SetError(SEC_ERROR_NO_MEMORY);
    296        return SECFailure;
    297    }
    298    attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem *, 2);
    299 
    300    if (attribute->attrValue == NULL)
    301        return SECFailure;
    302 
    303    attribute->attrValue[0] = extlist;
    304    attribute->attrValue[1] = NULL;
    305    req->attributes[0] = attribute;
    306    req->attributes[1] = NULL;
    307 
    308    return SECSuccess;
    309 }
    310 
    311 SECStatus
    312 CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
    313                                     CERTCertExtension ***exts)
    314 {
    315    if (req == NULL || exts == NULL) {
    316        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    317        return SECFailure;
    318    }
    319 
    320    if (req->attributes == NULL || *req->attributes == NULL)
    321        return SECSuccess;
    322 
    323    if ((*req->attributes)->attrValue == NULL) {
    324        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    325        return SECFailure;
    326    }
    327 
    328    return (SEC_ASN1DecodeItem(req->arena, exts,
    329                               SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate),
    330                               (*req->attributes)->attrValue[0]));
    331 }