123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "cert.h"
- #include "certt.h"
- #include "secder.h"
- #include "keyhi.h"
- #include "secitem.h"
- #include "secasn1.h"
- #include "secerr.h"
- SEC_ASN1_MKSUB(SEC_AnyTemplate)
- const SEC_ASN1Template CERT_AttributeTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(CERTAttribute) },
- { SEC_ASN1_OBJECT_ID, offsetof(CERTAttribute, attrType) },
- { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(CERTAttribute, attrValue),
- SEC_ASN1_SUB(SEC_AnyTemplate) },
- { 0 }
- };
- const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = {
- { SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate },
- };
- const SEC_ASN1Template CERT_CertificateRequestTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(CERTCertificateRequest) },
- { SEC_ASN1_INTEGER,
- offsetof(CERTCertificateRequest, version) },
- { SEC_ASN1_INLINE,
- offsetof(CERTCertificateRequest, subject),
- CERT_NameTemplate },
- { SEC_ASN1_INLINE,
- offsetof(CERTCertificateRequest, subjectPublicKeyInfo),
- CERT_SubjectPublicKeyInfoTemplate },
- { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(CERTCertificateRequest, attributes),
- CERT_SetOfAttributeTemplate },
- { 0 }
- };
- SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate)
- CERTCertificate *
- CERT_CreateCertificate(unsigned long serialNumber,
- CERTName *issuer,
- CERTValidity *validity,
- CERTCertificateRequest *req)
- {
- CERTCertificate *c;
- int rv;
- PLArenaPool *arena;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (!arena) {
- return (0);
- }
- c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
- if (!c) {
- PORT_FreeArena(arena, PR_FALSE);
- return 0;
- }
- c->referenceCount = 1;
- c->arena = arena;
- /*
- * Default is a plain version 1.
- * If extensions are added, it will get changed as appropriate.
- */
- rv = DER_SetUInteger(arena, &c->version, SEC_CERTIFICATE_VERSION_1);
- if (rv)
- goto loser;
- rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber);
- if (rv)
- goto loser;
- rv = CERT_CopyName(arena, &c->issuer, issuer);
- if (rv)
- goto loser;
- rv = CERT_CopyValidity(arena, &c->validity, validity);
- if (rv)
- goto loser;
- rv = CERT_CopyName(arena, &c->subject, &req->subject);
- if (rv)
- goto loser;
- rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo,
- &req->subjectPublicKeyInfo);
- if (rv)
- goto loser;
- return c;
- loser:
- CERT_DestroyCertificate(c);
- return 0;
- }
- /************************************************************************/
- /* It's clear from the comments that the original author of this
- * function expected the template for certificate requests to treat
- * the attributes as a SET OF ANY. This function expected to be
- * passed an array of SECItems each of which contained an already encoded
- * Attribute. But the cert request template does not treat the
- * Attributes as a SET OF ANY, and AFAIK never has. Instead the template
- * encodes attributes as a SET OF xxxxxxx. That is, it expects to encode
- * each of the Attributes, not have them pre-encoded. Consequently an
- * array of SECItems containing encoded Attributes is of no value to this
- * function. But we cannot change the signature of this public function.
- * It must continue to take SECItems.
- *
- * I have recoded this function so that each SECItem contains an
- * encoded cert extension. The encoded cert extensions form the list for the
- * single attribute of the cert request. In this implementation there is at most
- * one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST.
- */
- CERTCertificateRequest *
- CERT_CreateCertificateRequest(CERTName *subject,
- CERTSubjectPublicKeyInfo *spki,
- SECItem **attributes)
- {
- CERTCertificateRequest *certreq;
- PLArenaPool *arena;
- CERTAttribute *attribute;
- SECOidData *oidData;
- SECStatus rv;
- int i = 0;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (arena == NULL) {
- return NULL;
- }
- certreq = PORT_ArenaZNew(arena, CERTCertificateRequest);
- if (!certreq) {
- PORT_FreeArena(arena, PR_FALSE);
- return NULL;
- }
- /* below here it is safe to goto loser */
- certreq->arena = arena;
- rv = DER_SetUInteger(arena, &certreq->version,
- SEC_CERTIFICATE_REQUEST_VERSION);
- if (rv != SECSuccess)
- goto loser;
- rv = CERT_CopyName(arena, &certreq->subject, subject);
- if (rv != SECSuccess)
- goto loser;
- rv = SECKEY_CopySubjectPublicKeyInfo(arena,
- &certreq->subjectPublicKeyInfo,
- spki);
- if (rv != SECSuccess)
- goto loser;
- certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute *, 2);
- if (!certreq->attributes)
- goto loser;
- /* Copy over attribute information */
- if (!attributes || !attributes[0]) {
- /*
- ** Invent empty attribute information. According to the
- ** pkcs#10 spec, attributes has this ASN.1 type:
- **
- ** attributes [0] IMPLICIT Attributes
- **
- ** Which means, we should create a NULL terminated list
- ** with the first entry being NULL;
- */
- certreq->attributes[0] = NULL;
- return certreq;
- }
- /* allocate space for attributes */
- attribute = PORT_ArenaZNew(arena, CERTAttribute);
- if (!attribute)
- goto loser;
- oidData = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
- PORT_Assert(oidData);
- if (!oidData)
- goto loser;
- rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid);
- if (rv != SECSuccess)
- goto loser;
- for (i = 0; attributes[i] != NULL; i++)
- ;
- attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i + 1);
- if (!attribute->attrValue)
- goto loser;
- /* copy attributes */
- for (i = 0; attributes[i]; i++) {
- /*
- ** Attributes are a SetOf Attribute which implies
- ** lexigraphical ordering. It is assumes that the
- ** attributes are passed in sorted. If we need to
- ** add functionality to sort them, there is an
- ** example in the PKCS 7 code.
- */
- attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]);
- if (!attribute->attrValue[i])
- goto loser;
- }
- certreq->attributes[0] = attribute;
- return certreq;
- loser:
- CERT_DestroyCertificateRequest(certreq);
- return NULL;
- }
- void
- CERT_DestroyCertificateRequest(CERTCertificateRequest *req)
- {
- if (req && req->arena) {
- PORT_FreeArena(req->arena, PR_FALSE);
- }
- return;
- }
- static void
- setCRExt(void *o, CERTCertExtension **exts)
- {
- ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts;
- }
- /*
- ** Set up to start gathering cert extensions for a cert request.
- ** The list is created as CertExtensions and converted to an
- ** attribute list by CERT_FinishCRAttributes().
- */
- extern void *cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
- void (*setExts)(void *object, CERTCertExtension **exts));
- void *
- CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req)
- {
- return (cert_StartExtensions((void *)req, req->arena, setCRExt));
- }
- /*
- ** At entry req->attributes actually contains an list of cert extensions--
- ** req-attributes is overloaded until the list is DER encoded (the first
- ** ...EncodeItem() below).
- ** We turn this into an attribute list by encapsulating it
- ** in a PKCS 10 Attribute structure
- */
- SECStatus
- CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req)
- {
- SECItem *extlist;
- SECOidData *oidrec;
- CERTAttribute *attribute;
- if (!req || !req->arena) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- if (req->attributes == NULL || req->attributes[0] == NULL)
- return SECSuccess;
- extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes,
- SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate));
- if (extlist == NULL)
- return (SECFailure);
- oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
- if (oidrec == NULL)
- return SECFailure;
- /* now change the list of cert extensions into a list of attributes
- */
- req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute *, 2);
- attribute = PORT_ArenaZNew(req->arena, CERTAttribute);
- if (req->attributes == NULL || attribute == NULL ||
- SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem *, 2);
- if (attribute->attrValue == NULL)
- return SECFailure;
- attribute->attrValue[0] = extlist;
- attribute->attrValue[1] = NULL;
- req->attributes[0] = attribute;
- req->attributes[1] = NULL;
- return SECSuccess;
- }
- SECStatus
- CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
- CERTCertExtension ***exts)
- {
- if (req == NULL || exts == NULL) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- if (req->attributes == NULL || *req->attributes == NULL)
- return SECSuccess;
- if ((*req->attributes)->attrValue == NULL) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- return (SEC_ASN1DecodeItem(req->arena, exts,
- SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate),
- (*req->attributes)->attrValue[0]));
- }
|