| 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 PRArenaPool *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) goto loser; | |
| 79 | |
| 80 rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber); | |
| 81 if (rv) goto loser; | |
| 82 | |
| 83 rv = CERT_CopyName(arena, &c->issuer, issuer); | |
| 84 if (rv) goto loser; | |
| 85 | |
| 86 rv = CERT_CopyValidity(arena, &c->validity, validity); | |
| 87 if (rv) goto loser; | |
| 88 | |
| 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; | |
| 94 | |
| 95 return c; | |
| 96 | |
| 97 loser: | |
| 98 CERT_DestroyCertificate(c); | |
| 99 return 0; | |
| 100 } | |
| 101 | |
| 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 */ | |
| 120 | |
| 121 CERTCertificateRequest * | |
| 122 CERT_CreateCertificateRequest(CERTName *subject, | |
| 123 CERTSubjectPublicKeyInfo *spki, | |
| 124 SECItem **attributes) | |
| 125 { | |
| 126 CERTCertificateRequest *certreq; | |
| 127 PRArenaPool *arena; | |
| 128 CERTAttribute * attribute; | |
| 129 SECOidData * oidData; | |
| 130 SECStatus rv; | |
| 131 int i = 0; | |
| 132 | |
| 133 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
| 134 if ( arena == NULL ) { | |
| 135 return NULL; | |
| 136 } | |
| 137 | |
| 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 */ | |
| 144 | |
| 145 certreq->arena = arena; | |
| 146 | |
| 147 rv = DER_SetUInteger(arena, &certreq->version, | |
| 148 SEC_CERTIFICATE_REQUEST_VERSION); | |
| 149 if (rv != SECSuccess) | |
| 150 goto loser; | |
| 151 | |
| 152 rv = CERT_CopyName(arena, &certreq->subject, subject); | |
| 153 if (rv != SECSuccess) | |
| 154 goto loser; | |
| 155 | |
| 156 rv = SECKEY_CopySubjectPublicKeyInfo(arena, | |
| 157 &certreq->subjectPublicKeyInfo, | |
| 158 spki); | |
| 159 if (rv != SECSuccess) | |
| 160 goto loser; | |
| 161 | |
| 162 certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute*, 2); | |
| 163 if(!certreq->attributes) | |
| 164 goto loser; | |
| 165 | |
| 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 } | |
| 180 | |
| 181 /* allocate space for attributes */ | |
| 182 attribute = PORT_ArenaZNew(arena, CERTAttribute); | |
| 183 if (!attribute) | |
| 184 goto loser; | |
| 185 | |
| 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; | |
| 193 | |
| 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; | |
| 199 | |
| 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 } | |
| 213 | |
| 214 certreq->attributes[0] = attribute; | |
| 215 | |
| 216 return certreq; | |
| 217 | |
| 218 loser: | |
| 219 CERT_DestroyCertificateRequest(certreq); | |
| 220 return NULL; | |
| 221 } | |
| 222 | |
| 223 void | |
| 224 CERT_DestroyCertificateRequest(CERTCertificateRequest *req) | |
| 225 { | |
| 226 if (req && req->arena) { | |
| 227 PORT_FreeArena(req->arena, PR_FALSE); | |
| 228 } | |
| 229 return; | |
| 230 } | |
| 231 | |
| 232 static void | |
| 233 setCRExt(void *o, CERTCertExtension **exts) | |
| 234 { | |
| 235 ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts
; | |
| 236 } | |
| 237 | |
| 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, PRArenaPool *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 } | |
| 250 | |
| 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; | |
| 263 | |
| 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; | |
| 270 | |
| 271 extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes, | |
| 272 SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate)); | |
| 273 if (extlist == NULL) | |
| 274 return(SECFailure); | |
| 275 | |
| 276 oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST); | |
| 277 if (oidrec == NULL) | |
| 278 return SECFailure; | |
| 279 | |
| 280 /* now change the list of cert extensions into a list of attributes | |
| 281 */ | |
| 282 req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute*, 2); | |
| 283 | |
| 284 attribute = PORT_ArenaZNew(req->arena, CERTAttribute); | |
| 285 | |
| 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); | |
| 292 | |
| 293 if (attribute->attrValue == NULL) | |
| 294 return SECFailure; | |
| 295 | |
| 296 attribute->attrValue[0] = extlist; | |
| 297 attribute->attrValue[1] = NULL; | |
| 298 req->attributes[0] = attribute; | |
| 299 req->attributes[1] = NULL; | |
| 300 | |
| 301 return SECSuccess; | |
| 302 } | |
| 303 | |
| 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 } | |
| 312 | |
| 313 if (req->attributes == NULL || *req->attributes == NULL) | |
| 314 return SECSuccess; | |
| 315 | |
| 316 if ((*req->attributes)->attrValue == NULL) { | |
| 317 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 318 return SECFailure; | |
| 319 } | |
| 320 | |
| 321 return(SEC_ASN1DecodeItem(req->arena, exts, | |
| 322 SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), | |
| 323 (*req->attributes)->attrValue[0])); | |
| 324 } | |
| OLD | NEW |