summaryrefslogtreecommitdiff
path: root/security/nss/lib/crmf/crmfreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/crmf/crmfreq.c')
-rw-r--r--security/nss/lib/crmf/crmfreq.c702
1 files changed, 702 insertions, 0 deletions
diff --git a/security/nss/lib/crmf/crmfreq.c b/security/nss/lib/crmf/crmfreq.c
new file mode 100644
index 000000000..6e30a0af2
--- /dev/null
+++ b/security/nss/lib/crmf/crmfreq.c
@@ -0,0 +1,702 @@
+/* -*- Mode: C; tab-width: 8 -*-*/
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#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(PRArenaPool *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(PRArenaPool *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 (PRArenaPool *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)
+{
+ PRArenaPool *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(PRArenaPool *poolp, SECItem *dest, long version)
+{
+ return (crmf_encode_integer(poolp, dest, version));
+}
+
+static SECStatus
+crmf_template_add_serialnumber(PRArenaPool *poolp, SECItem *dest, long serial)
+{
+ return (crmf_encode_integer(poolp, dest, serial));
+}
+
+SECStatus
+crmf_template_copy_secalg (PRArenaPool *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(PRArenaPool *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 (PRArenaPool *poolp, CERTName **dest,
+ CERTName* issuerName)
+{
+ return crmf_copy_cert_name(poolp, dest, issuerName);
+}
+
+
+static SECStatus
+crmf_template_add_validity (PRArenaPool *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 (PRArenaPool *poolp, CERTName **dest,
+ CERTName *subject)
+{
+ return crmf_copy_cert_name(poolp, dest, subject);
+}
+
+SECStatus
+crmf_template_add_public_key(PRArenaPool *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 (PRArenaPool *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(PRArenaPool *poolp, SECItem *dest,
+ const SECItem *issuerUID)
+{
+ return crmf_copy_bitstring (poolp, dest, issuerUID);
+}
+
+static SECStatus
+crmf_template_add_subject_uid(PRArenaPool *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(PRArenaPool *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;
+ PRArenaPool *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)
+{
+ PRArenaPool *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(PRArenaPool *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;
+}