| OLD | NEW |
| (Empty) |
| 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 "key.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, CERTCertExtensio
n **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_SequenceOfCertExtensionTempla
te)); | |
| 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 } | |
| OLD | NEW |