security/nss/lib/certhigh/certreq.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     5 #include "cert.h"
     6 #include "certt.h"
     7 #include "secder.h"
     8 #include "key.h"
     9 #include "secitem.h"
    10 #include "secasn1.h"
    11 #include "secerr.h"
    13 SEC_ASN1_MKSUB(SEC_AnyTemplate)
    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 };
    24 const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = {
    25     { SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate },
    26 };
    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 };
    45 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate)
    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;
    57     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    59     if ( !arena ) {
    60 	return(0);
    61     }
    63     c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
    65     if (!c) {
    66 	PORT_FreeArena(arena, PR_FALSE);
    67 	return 0;
    68     }
    70     c->referenceCount = 1;
    71     c->arena = arena;
    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) goto loser;
    80     rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber);
    81     if (rv) goto loser;
    83     rv = CERT_CopyName(arena, &c->issuer, issuer);
    84     if (rv) goto loser;
    86     rv = CERT_CopyValidity(arena, &c->validity, validity);
    87     if (rv) goto loser;
    89     rv = CERT_CopyName(arena, &c->subject, &req->subject);
    90     if (rv) goto loser;
    91     rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo,
    92 					 &req->subjectPublicKeyInfo);
    93     if (rv) goto loser;
    95     return c;
    97  loser:
    98     CERT_DestroyCertificate(c);
    99     return 0;
   100 }
   102 /************************************************************************/
   103 /* It's clear from the comments that the original author of this 
   104  * function expected the template for certificate requests to treat
   105  * the attributes as a SET OF ANY.  This function expected to be 
   106  * passed an array of SECItems each of which contained an already encoded
   107  * Attribute.  But the cert request template does not treat the 
   108  * Attributes as a SET OF ANY, and AFAIK never has.  Instead the template
   109  * encodes attributes as a SET OF xxxxxxx.  That is, it expects to encode
   110  * each of the Attributes, not have them pre-encoded.  Consequently an 
   111  * array of SECItems containing encoded Attributes is of no value to this 
   112  * function.  But we cannot change the signature of this public function.
   113  * It must continue to take SECItems.
   114  *
   115  * I have recoded this function so that each SECItem contains an 
   116  * encoded cert extension.  The encoded cert extensions form the list for the
   117  * single attribute of the cert request. In this implementation there is at most
   118  * one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST.
   119  */
   121 CERTCertificateRequest *
   122 CERT_CreateCertificateRequest(CERTName *subject,
   123 			     CERTSubjectPublicKeyInfo *spki,
   124 			     SECItem **attributes)
   125 {
   126     CERTCertificateRequest *certreq;
   127     PLArenaPool *arena;
   128     CERTAttribute * attribute;
   129     SECOidData * oidData;
   130     SECStatus rv;
   131     int i = 0;
   133     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   134     if ( arena == NULL ) {
   135 	return NULL;
   136     }
   138     certreq = PORT_ArenaZNew(arena, CERTCertificateRequest);
   139     if (!certreq) {
   140 	PORT_FreeArena(arena, PR_FALSE);
   141 	return NULL;
   142     }
   143     /* below here it is safe to goto loser */
   145     certreq->arena = arena;
   147     rv = DER_SetUInteger(arena, &certreq->version,
   148 			 SEC_CERTIFICATE_REQUEST_VERSION);
   149     if (rv != SECSuccess)
   150 	goto loser;
   152     rv = CERT_CopyName(arena, &certreq->subject, subject);
   153     if (rv != SECSuccess)
   154 	goto loser;
   156     rv = SECKEY_CopySubjectPublicKeyInfo(arena,
   157 				      &certreq->subjectPublicKeyInfo,
   158 				      spki);
   159     if (rv != SECSuccess)
   160 	goto loser;
   162     certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute*, 2);
   163     if(!certreq->attributes) 
   164 	goto loser;
   166     /* Copy over attribute information */
   167     if (!attributes || !attributes[0]) {
   168 	/*
   169 	 ** Invent empty attribute information. According to the
   170 	 ** pkcs#10 spec, attributes has this ASN.1 type:
   171 	 **
   172 	 ** attributes [0] IMPLICIT Attributes
   173 	 ** 
   174 	 ** Which means, we should create a NULL terminated list
   175 	 ** with the first entry being NULL;
   176 	 */
   177 	certreq->attributes[0] = NULL;
   178 	return certreq;
   179     }	
   181     /* allocate space for attributes */
   182     attribute = PORT_ArenaZNew(arena, CERTAttribute);
   183     if (!attribute) 
   184 	goto loser;
   186     oidData = SECOID_FindOIDByTag( SEC_OID_PKCS9_EXTENSION_REQUEST );
   187     PORT_Assert(oidData);
   188     if (!oidData)
   189 	goto loser;
   190     rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid);
   191     if (rv != SECSuccess)
   192 	goto loser;
   194     for (i = 0; attributes[i] != NULL ; i++) 
   195 	;
   196     attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i+1);
   197     if (!attribute->attrValue) 
   198 	goto loser;
   200     /* copy attributes */
   201     for (i = 0; attributes[i]; i++) {
   202 	/*
   203 	** Attributes are a SetOf Attribute which implies
   204 	** lexigraphical ordering.  It is assumes that the
   205 	** attributes are passed in sorted.  If we need to
   206 	** add functionality to sort them, there is an
   207 	** example in the PKCS 7 code.
   208 	*/
   209 	attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]);
   210 	if(!attribute->attrValue[i]) 
   211 	    goto loser;
   212     }
   214     certreq->attributes[0] = attribute;
   216     return certreq;
   218 loser:
   219     CERT_DestroyCertificateRequest(certreq);
   220     return NULL;
   221 }
   223 void
   224 CERT_DestroyCertificateRequest(CERTCertificateRequest *req)
   225 {
   226     if (req && req->arena) {
   227 	PORT_FreeArena(req->arena, PR_FALSE);
   228     }
   229     return;
   230 }
   232 static void
   233 setCRExt(void *o, CERTCertExtension **exts)
   234 {
   235     ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts;
   236 }
   238 /*
   239 ** Set up to start gathering cert extensions for a cert request.
   240 ** The list is created as CertExtensions and converted to an
   241 ** attribute list by CERT_FinishCRAttributes().
   242  */
   243 extern void *cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
   244                        void (*setExts)(void *object, CERTCertExtension **exts));
   245 void *
   246 CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req)
   247 {
   248     return (cert_StartExtensions ((void *)req, req->arena, setCRExt));
   249 }
   251 /*
   252 ** At entry req->attributes actually contains an list of cert extensions--
   253 ** req-attributes is overloaded until the list is DER encoded (the first
   254 ** ...EncodeItem() below).
   255 ** We turn this into an attribute list by encapsulating it
   256 ** in a PKCS 10 Attribute structure
   257  */
   258 SECStatus
   259 CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req)
   260 {   SECItem *extlist;
   261     SECOidData *oidrec;
   262     CERTAttribute *attribute;
   264     if (!req || !req->arena) {
   265 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   266         return SECFailure;
   267     }
   268     if (req->attributes == NULL || req->attributes[0] == NULL)
   269         return SECSuccess;
   271     extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes,
   272                             SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate));
   273     if (extlist == NULL)
   274         return(SECFailure);
   276     oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
   277     if (oidrec == NULL)
   278 	return SECFailure;
   280     /* now change the list of cert extensions into a list of attributes
   281      */
   282     req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute*, 2);
   284     attribute = PORT_ArenaZNew(req->arena, CERTAttribute);
   286     if (req->attributes == NULL || attribute == NULL ||
   287         SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) {
   288         PORT_SetError(SEC_ERROR_NO_MEMORY);
   289 	return SECFailure;
   290     }
   291     attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem*, 2);
   293     if (attribute->attrValue == NULL)
   294         return SECFailure;
   296     attribute->attrValue[0] = extlist;
   297     attribute->attrValue[1] = NULL;
   298     req->attributes[0] = attribute;
   299     req->attributes[1] = NULL;
   301     return SECSuccess;
   302 }
   304 SECStatus
   305 CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
   306                                         CERTCertExtension ***exts)
   307 {
   308     if (req == NULL || exts == NULL) {
   309 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   310         return SECFailure;
   311     }
   313     if (req->attributes == NULL || *req->attributes == NULL)
   314         return SECSuccess;
   316     if ((*req->attributes)->attrValue == NULL) {
   317 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   318         return SECFailure;
   319     }
   321     return(SEC_ASN1DecodeItem(req->arena, exts, 
   322             SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate),
   323             (*req->attributes)->attrValue[0]));
   324 }

mercurial