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 }