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

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

mercurial