123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664 |
- /* -*- Mode: C; tab-width: 8 -*-*/
- /* 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 "crmf.h"
- #include "crmfi.h"
- #include "keyhi.h"
- #include "secder.h"
- /*
- * Macro that returns PR_TRUE if the pointer is not NULL.
- * If the pointer is NULL, then the macro will return PR_FALSE.
- */
- #define IS_NOT_NULL(ptr) ((ptr) == NULL) ? PR_FALSE : PR_TRUE
- const unsigned char hexTrue = 0xff;
- const unsigned char hexFalse = 0x00;
- SECStatus
- crmf_encode_integer(PLArenaPool *poolp, SECItem *dest, long value)
- {
- SECItem *dummy;
- dummy = SEC_ASN1EncodeInteger(poolp, dest, value);
- PORT_Assert(dummy == dest);
- if (dummy == NULL) {
- return SECFailure;
- }
- return SECSuccess;
- }
- SECStatus
- crmf_encode_unsigned_integer(PLArenaPool *poolp, SECItem *dest,
- unsigned long value)
- {
- SECItem *dummy;
- dummy = SEC_ASN1EncodeUnsignedInteger(poolp, dest, value);
- PORT_Assert(dummy == dest);
- if (dummy != dest) {
- return SECFailure;
- }
- return SECSuccess;
- }
- static SECStatus
- crmf_copy_secitem(PLArenaPool *poolp, SECItem *dest, SECItem *src)
- {
- return SECITEM_CopyItem(poolp, dest, src);
- }
- PRBool
- CRMF_DoesRequestHaveField(CRMFCertRequest *inCertReq,
- CRMFCertTemplateField inField)
- {
- PORT_Assert(inCertReq != NULL);
- if (inCertReq == NULL) {
- return PR_FALSE;
- }
- switch (inField) {
- case crmfVersion:
- return inCertReq->certTemplate.version.data != NULL;
- case crmfSerialNumber:
- return inCertReq->certTemplate.serialNumber.data != NULL;
- case crmfSigningAlg:
- return inCertReq->certTemplate.signingAlg != NULL;
- case crmfIssuer:
- return inCertReq->certTemplate.issuer != NULL;
- case crmfValidity:
- return inCertReq->certTemplate.validity != NULL;
- case crmfSubject:
- return inCertReq->certTemplate.subject != NULL;
- case crmfPublicKey:
- return inCertReq->certTemplate.publicKey != NULL;
- case crmfIssuerUID:
- return inCertReq->certTemplate.issuerUID.data != NULL;
- case crmfSubjectUID:
- return inCertReq->certTemplate.subjectUID.data != NULL;
- case crmfExtension:
- return CRMF_CertRequestGetNumberOfExtensions(inCertReq) != 0;
- }
- return PR_FALSE;
- }
- CRMFCertRequest *
- CRMF_CreateCertRequest(PRUint32 inRequestID)
- {
- PLArenaPool *poolp;
- CRMFCertRequest *certReq;
- SECStatus rv;
- poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
- if (poolp == NULL) {
- goto loser;
- }
- certReq = PORT_ArenaZNew(poolp, CRMFCertRequest);
- if (certReq == NULL) {
- goto loser;
- }
- certReq->poolp = poolp;
- certReq->requestID = inRequestID;
- rv = crmf_encode_unsigned_integer(poolp, &(certReq->certReqId),
- inRequestID);
- if (rv != SECSuccess) {
- goto loser;
- }
- return certReq;
- loser:
- if (poolp) {
- PORT_FreeArena(poolp, PR_FALSE);
- }
- return NULL;
- }
- SECStatus
- CRMF_DestroyCertRequest(CRMFCertRequest *inCertReq)
- {
- PORT_Assert(inCertReq != NULL);
- if (inCertReq != NULL) {
- if (inCertReq->certTemplate.extensions) {
- PORT_Free(inCertReq->certTemplate.extensions);
- }
- if (inCertReq->controls) {
- /* Right now we don't support EnveloppedData option,
- * so we won't go through and delete each occurrence of
- * an EnveloppedData in the control.
- */
- PORT_Free(inCertReq->controls);
- }
- if (inCertReq->poolp) {
- PORT_FreeArena(inCertReq->poolp, PR_TRUE);
- }
- }
- return SECSuccess;
- }
- static SECStatus
- crmf_template_add_version(PLArenaPool *poolp, SECItem *dest, long version)
- {
- return (crmf_encode_integer(poolp, dest, version));
- }
- static SECStatus
- crmf_template_add_serialnumber(PLArenaPool *poolp, SECItem *dest, long serial)
- {
- return (crmf_encode_integer(poolp, dest, serial));
- }
- SECStatus
- crmf_template_copy_secalg(PLArenaPool *poolp, SECAlgorithmID **dest,
- SECAlgorithmID *src)
- {
- SECStatus rv;
- void *mark = NULL;
- SECAlgorithmID *mySecAlg;
- if (!poolp) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- mark = PORT_ArenaMark(poolp);
- *dest = mySecAlg = PORT_ArenaZNew(poolp, SECAlgorithmID);
- if (mySecAlg == NULL) {
- goto loser;
- }
- rv = SECOID_CopyAlgorithmID(poolp, mySecAlg, src);
- if (rv != SECSuccess) {
- goto loser;
- }
- if (mark) {
- PORT_ArenaUnmark(poolp, mark);
- }
- return SECSuccess;
- loser:
- *dest = NULL;
- if (mark) {
- PORT_ArenaRelease(poolp, mark);
- }
- return SECFailure;
- }
- SECStatus
- crmf_copy_cert_name(PLArenaPool *poolp, CERTName **dest,
- CERTName *src)
- {
- CERTName *newName;
- SECStatus rv;
- void *mark;
- mark = PORT_ArenaMark(poolp);
- *dest = newName = PORT_ArenaZNew(poolp, CERTName);
- if (newName == NULL) {
- goto loser;
- }
- rv = CERT_CopyName(poolp, newName, src);
- if (rv != SECSuccess) {
- goto loser;
- }
- PORT_ArenaUnmark(poolp, mark);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(poolp, mark);
- *dest = NULL;
- return SECFailure;
- }
- static SECStatus
- crmf_template_add_issuer(PLArenaPool *poolp, CERTName **dest,
- CERTName *issuerName)
- {
- return crmf_copy_cert_name(poolp, dest, issuerName);
- }
- static SECStatus
- crmf_template_add_validity(PLArenaPool *poolp, CRMFOptionalValidity **dest,
- CRMFValidityCreationInfo *info)
- {
- SECStatus rv;
- void *mark;
- CRMFOptionalValidity *myValidity;
- /*First off, let's make sure at least one of the two fields is present*/
- if (!info || (!info->notBefore && !info->notAfter)) {
- return SECFailure;
- }
- mark = PORT_ArenaMark(poolp);
- *dest = myValidity = PORT_ArenaZNew(poolp, CRMFOptionalValidity);
- if (myValidity == NULL) {
- goto loser;
- }
- if (info->notBefore) {
- rv = DER_EncodeTimeChoice(poolp, &myValidity->notBefore,
- *info->notBefore);
- if (rv != SECSuccess) {
- goto loser;
- }
- }
- if (info->notAfter) {
- rv = DER_EncodeTimeChoice(poolp, &myValidity->notAfter,
- *info->notAfter);
- if (rv != SECSuccess) {
- goto loser;
- }
- }
- PORT_ArenaUnmark(poolp, mark);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(poolp, mark);
- *dest = NULL;
- return SECFailure;
- }
- static SECStatus
- crmf_template_add_subject(PLArenaPool *poolp, CERTName **dest,
- CERTName *subject)
- {
- return crmf_copy_cert_name(poolp, dest, subject);
- }
- SECStatus
- crmf_template_add_public_key(PLArenaPool *poolp,
- CERTSubjectPublicKeyInfo **dest,
- CERTSubjectPublicKeyInfo *pubKey)
- {
- CERTSubjectPublicKeyInfo *spki;
- SECStatus rv;
- *dest = spki = (poolp == NULL) ? PORT_ZNew(CERTSubjectPublicKeyInfo) : PORT_ArenaZNew(poolp, CERTSubjectPublicKeyInfo);
- if (spki == NULL) {
- goto loser;
- }
- rv = SECKEY_CopySubjectPublicKeyInfo(poolp, spki, pubKey);
- if (rv != SECSuccess) {
- goto loser;
- }
- return SECSuccess;
- loser:
- if (poolp == NULL && spki != NULL) {
- SECKEY_DestroySubjectPublicKeyInfo(spki);
- }
- *dest = NULL;
- return SECFailure;
- }
- static SECStatus
- crmf_copy_bitstring(PLArenaPool *poolp, SECItem *dest, const SECItem *src)
- {
- SECStatus rv;
- SECItem byteSrc;
- byteSrc = *src;
- byteSrc.len = CRMF_BITS_TO_BYTES(byteSrc.len);
- rv = crmf_copy_secitem(poolp, dest, &byteSrc);
- dest->len = src->len;
- return rv;
- }
- static SECStatus
- crmf_template_add_issuer_uid(PLArenaPool *poolp, SECItem *dest,
- const SECItem *issuerUID)
- {
- return crmf_copy_bitstring(poolp, dest, issuerUID);
- }
- static SECStatus
- crmf_template_add_subject_uid(PLArenaPool *poolp, SECItem *dest,
- const SECItem *subjectUID)
- {
- return crmf_copy_bitstring(poolp, dest, subjectUID);
- }
- static void
- crmf_zeroize_new_extensions(CRMFCertExtension **extensions,
- int numToZeroize)
- {
- PORT_Memset((void *)extensions, 0, sizeof(CERTCertExtension *) * numToZeroize);
- }
- /*
- * The strategy for adding templates will differ from all the other
- * attributes in the template. First, we want to allow the client
- * of this API to set extensions more than just once. So we will
- * need the ability grow the array of extensions. Since arenas don't
- * give us the realloc function, we'll use the generic PORT_* functions
- * to allocate the array of pointers *ONLY*. Then we will allocate each
- * individual extension from the arena that comes along with the certReq
- * structure that owns this template.
- */
- static SECStatus
- crmf_template_add_extensions(PLArenaPool *poolp, CRMFCertTemplate *inTemplate,
- CRMFCertExtCreationInfo *extensions)
- {
- void *mark;
- int newSize, oldSize, i;
- SECStatus rv;
- CRMFCertExtension **extArray;
- CRMFCertExtension *newExt, *currExt;
- mark = PORT_ArenaMark(poolp);
- if (inTemplate->extensions == NULL) {
- newSize = extensions->numExtensions;
- extArray = PORT_ZNewArray(CRMFCertExtension *, newSize + 1);
- } else {
- newSize = inTemplate->numExtensions + extensions->numExtensions;
- extArray = PORT_Realloc(inTemplate->extensions,
- sizeof(CRMFCertExtension *) * (newSize + 1));
- }
- if (extArray == NULL) {
- goto loser;
- }
- oldSize = inTemplate->numExtensions;
- inTemplate->extensions = extArray;
- inTemplate->numExtensions = newSize;
- for (i = oldSize; i < newSize; i++) {
- newExt = PORT_ArenaZNew(poolp, CRMFCertExtension);
- if (newExt == NULL) {
- goto loser2;
- }
- currExt = extensions->extensions[i - oldSize];
- rv = crmf_copy_secitem(poolp, &(newExt->id), &(currExt->id));
- if (rv != SECSuccess) {
- goto loser2;
- }
- rv = crmf_copy_secitem(poolp, &(newExt->critical),
- &(currExt->critical));
- if (rv != SECSuccess) {
- goto loser2;
- }
- rv = crmf_copy_secitem(poolp, &(newExt->value), &(currExt->value));
- if (rv != SECSuccess) {
- goto loser2;
- }
- extArray[i] = newExt;
- }
- extArray[newSize] = NULL;
- PORT_ArenaUnmark(poolp, mark);
- return SECSuccess;
- loser2:
- crmf_zeroize_new_extensions(&(inTemplate->extensions[oldSize]),
- extensions->numExtensions);
- inTemplate->numExtensions = oldSize;
- loser:
- PORT_ArenaRelease(poolp, mark);
- return SECFailure;
- }
- SECStatus
- CRMF_CertRequestSetTemplateField(CRMFCertRequest *inCertReq,
- CRMFCertTemplateField inTemplateField,
- void *data)
- {
- CRMFCertTemplate *certTemplate;
- PLArenaPool *poolp;
- SECStatus rv = SECFailure;
- void *mark;
- if (inCertReq == NULL) {
- return SECFailure;
- }
- certTemplate = &(inCertReq->certTemplate);
- poolp = inCertReq->poolp;
- mark = PORT_ArenaMark(poolp);
- switch (inTemplateField) {
- case crmfVersion:
- rv = crmf_template_add_version(poolp, &(certTemplate->version),
- *(long *)data);
- break;
- case crmfSerialNumber:
- rv = crmf_template_add_serialnumber(poolp,
- &(certTemplate->serialNumber),
- *(long *)data);
- break;
- case crmfSigningAlg:
- rv = crmf_template_copy_secalg(poolp, &(certTemplate->signingAlg),
- (SECAlgorithmID *)data);
- break;
- case crmfIssuer:
- rv = crmf_template_add_issuer(poolp, &(certTemplate->issuer),
- (CERTName *)data);
- break;
- case crmfValidity:
- rv = crmf_template_add_validity(poolp, &(certTemplate->validity),
- (CRMFValidityCreationInfo *)data);
- break;
- case crmfSubject:
- rv = crmf_template_add_subject(poolp, &(certTemplate->subject),
- (CERTName *)data);
- break;
- case crmfPublicKey:
- rv = crmf_template_add_public_key(poolp, &(certTemplate->publicKey),
- (CERTSubjectPublicKeyInfo *)data);
- break;
- case crmfIssuerUID:
- rv = crmf_template_add_issuer_uid(poolp, &(certTemplate->issuerUID),
- (SECItem *)data);
- break;
- case crmfSubjectUID:
- rv = crmf_template_add_subject_uid(poolp, &(certTemplate->subjectUID),
- (SECItem *)data);
- break;
- case crmfExtension:
- rv = crmf_template_add_extensions(poolp, certTemplate,
- (CRMFCertExtCreationInfo *)data);
- break;
- }
- if (rv != SECSuccess) {
- PORT_ArenaRelease(poolp, mark);
- } else {
- PORT_ArenaUnmark(poolp, mark);
- }
- return rv;
- }
- SECStatus
- CRMF_CertReqMsgSetCertRequest(CRMFCertReqMsg *inCertReqMsg,
- CRMFCertRequest *inCertReq)
- {
- PORT_Assert(inCertReqMsg != NULL && inCertReq != NULL);
- if (inCertReqMsg == NULL || inCertReq == NULL) {
- return SECFailure;
- }
- inCertReqMsg->certReq = crmf_copy_cert_request(inCertReqMsg->poolp,
- inCertReq);
- return (inCertReqMsg->certReq == NULL) ? SECFailure : SECSuccess;
- }
- CRMFCertReqMsg *
- CRMF_CreateCertReqMsg(void)
- {
- PLArenaPool *poolp;
- CRMFCertReqMsg *reqMsg;
- poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
- if (poolp == NULL) {
- goto loser;
- }
- reqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg);
- if (reqMsg == NULL) {
- goto loser;
- }
- reqMsg->poolp = poolp;
- return reqMsg;
- loser:
- if (poolp) {
- PORT_FreeArena(poolp, PR_FALSE);
- }
- return NULL;
- }
- SECStatus
- CRMF_DestroyCertReqMsg(CRMFCertReqMsg *inCertReqMsg)
- {
- PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->poolp != NULL);
- if (!inCertReqMsg->isDecoded) {
- if (inCertReqMsg->certReq->certTemplate.extensions != NULL) {
- PORT_Free(inCertReqMsg->certReq->certTemplate.extensions);
- }
- if (inCertReqMsg->certReq->controls != NULL) {
- PORT_Free(inCertReqMsg->certReq->controls);
- }
- }
- PORT_FreeArena(inCertReqMsg->poolp, PR_TRUE);
- return SECSuccess;
- }
- CRMFCertExtension *
- crmf_create_cert_extension(PLArenaPool *poolp,
- SECOidTag id,
- PRBool isCritical,
- SECItem *data)
- {
- CRMFCertExtension *newExt;
- SECOidData *oidData;
- SECStatus rv;
- newExt = (poolp == NULL) ? PORT_ZNew(CRMFCertExtension) : PORT_ArenaZNew(poolp, CRMFCertExtension);
- if (newExt == NULL) {
- goto loser;
- }
- oidData = SECOID_FindOIDByTag(id);
- if (oidData == NULL ||
- oidData->supportedExtension != SUPPORTED_CERT_EXTENSION) {
- goto loser;
- }
- rv = SECITEM_CopyItem(poolp, &(newExt->id), &(oidData->oid));
- if (rv != SECSuccess) {
- goto loser;
- }
- rv = SECITEM_CopyItem(poolp, &(newExt->value), data);
- if (rv != SECSuccess) {
- goto loser;
- }
- if (isCritical) {
- newExt->critical.data = (poolp == NULL) ? PORT_New(unsigned char)
- : PORT_ArenaNew(poolp, unsigned char);
- if (newExt->critical.data == NULL) {
- goto loser;
- }
- newExt->critical.data[0] = hexTrue;
- newExt->critical.len = 1;
- }
- return newExt;
- loser:
- if (newExt != NULL && poolp == NULL) {
- CRMF_DestroyCertExtension(newExt);
- }
- return NULL;
- }
- CRMFCertExtension *
- CRMF_CreateCertExtension(SECOidTag id,
- PRBool isCritical,
- SECItem *data)
- {
- return crmf_create_cert_extension(NULL, id, isCritical, data);
- }
- static SECStatus
- crmf_destroy_cert_extension(CRMFCertExtension *inExtension, PRBool freeit)
- {
- if (inExtension != NULL) {
- SECITEM_FreeItem(&(inExtension->id), PR_FALSE);
- SECITEM_FreeItem(&(inExtension->value), PR_FALSE);
- SECITEM_FreeItem(&(inExtension->critical), PR_FALSE);
- if (freeit) {
- PORT_Free(inExtension);
- }
- }
- return SECSuccess;
- }
- SECStatus
- CRMF_DestroyCertExtension(CRMFCertExtension *inExtension)
- {
- return crmf_destroy_cert_extension(inExtension, PR_TRUE);
- }
- SECStatus
- CRMF_DestroyCertReqMessages(CRMFCertReqMessages *inCertReqMsgs)
- {
- PORT_Assert(inCertReqMsgs != NULL);
- if (inCertReqMsgs != NULL) {
- PORT_FreeArena(inCertReqMsgs->poolp, PR_TRUE);
- }
- return SECSuccess;
- }
- static PRBool
- crmf_item_has_data(SECItem *item)
- {
- if (item != NULL && item->data != NULL) {
- return PR_TRUE;
- }
- return PR_FALSE;
- }
- PRBool
- CRMF_CertRequestIsFieldPresent(CRMFCertRequest *inCertReq,
- CRMFCertTemplateField inTemplateField)
- {
- PRBool retVal;
- CRMFCertTemplate *certTemplate;
- PORT_Assert(inCertReq != NULL);
- if (inCertReq == NULL) {
- /* This is probably some kind of error, but this is
- * the safest return value for this function.
- */
- return PR_FALSE;
- }
- certTemplate = &inCertReq->certTemplate;
- switch (inTemplateField) {
- case crmfVersion:
- retVal = crmf_item_has_data(&certTemplate->version);
- break;
- case crmfSerialNumber:
- retVal = crmf_item_has_data(&certTemplate->serialNumber);
- break;
- case crmfSigningAlg:
- retVal = IS_NOT_NULL(certTemplate->signingAlg);
- break;
- case crmfIssuer:
- retVal = IS_NOT_NULL(certTemplate->issuer);
- break;
- case crmfValidity:
- retVal = IS_NOT_NULL(certTemplate->validity);
- break;
- case crmfSubject:
- retVal = IS_NOT_NULL(certTemplate->subject);
- break;
- case crmfPublicKey:
- retVal = IS_NOT_NULL(certTemplate->publicKey);
- break;
- case crmfIssuerUID:
- retVal = crmf_item_has_data(&certTemplate->issuerUID);
- break;
- case crmfSubjectUID:
- retVal = crmf_item_has_data(&certTemplate->subjectUID);
- break;
- case crmfExtension:
- retVal = IS_NOT_NULL(certTemplate->extensions);
- break;
- default:
- retVal = PR_FALSE;
- }
- return retVal;
- }
|