summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/crmf
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/crmf')
-rw-r--r--security/nss/lib/crmf/Makefile49
-rw-r--r--security/nss/lib/crmf/asn1cmn.c216
-rw-r--r--security/nss/lib/crmf/challcli.c238
-rw-r--r--security/nss/lib/crmf/cmmf.h1082
-rw-r--r--security/nss/lib/crmf/cmmfasn1.c131
-rw-r--r--security/nss/lib/crmf/cmmfchal.c289
-rw-r--r--security/nss/lib/crmf/cmmfi.h92
-rw-r--r--security/nss/lib/crmf/cmmfit.h115
-rw-r--r--security/nss/lib/crmf/cmmfrec.c316
-rw-r--r--security/nss/lib/crmf/cmmfresp.c280
-rw-r--r--security/nss/lib/crmf/cmmft.h73
-rw-r--r--security/nss/lib/crmf/config.mk16
-rw-r--r--security/nss/lib/crmf/crmf.gyp43
-rw-r--r--security/nss/lib/crmf/crmf.h1741
-rw-r--r--security/nss/lib/crmf/crmfcont.c1161
-rw-r--r--security/nss/lib/crmf/crmfdec.c360
-rw-r--r--security/nss/lib/crmf/crmfenc.c48
-rw-r--r--security/nss/lib/crmf/crmffut.h357
-rw-r--r--security/nss/lib/crmf/crmfget.c443
-rw-r--r--security/nss/lib/crmf/crmfi.h185
-rw-r--r--security/nss/lib/crmf/crmfit.h185
-rw-r--r--security/nss/lib/crmf/crmfpop.c598
-rw-r--r--security/nss/lib/crmf/crmfreq.c663
-rw-r--r--security/nss/lib/crmf/crmft.h186
-rw-r--r--security/nss/lib/crmf/crmftmpl.c240
-rw-r--r--security/nss/lib/crmf/encutil.c33
-rw-r--r--security/nss/lib/crmf/exports.gyp37
-rw-r--r--security/nss/lib/crmf/manifest.mn46
-rw-r--r--security/nss/lib/crmf/respcli.c136
-rw-r--r--security/nss/lib/crmf/respcmn.c399
-rw-r--r--security/nss/lib/crmf/servget.c974
31 files changed, 10732 insertions, 0 deletions
diff --git a/security/nss/lib/crmf/Makefile b/security/nss/lib/crmf/Makefile
new file mode 100644
index 000000000..a774a9566
--- /dev/null
+++ b/security/nss/lib/crmf/Makefile
@@ -0,0 +1,49 @@
+#! gmake
+#
+# 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/.
+
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+
+export:: private_export
diff --git a/security/nss/lib/crmf/asn1cmn.c b/security/nss/lib/crmf/asn1cmn.c
new file mode 100644
index 000000000..6cf469fb4
--- /dev/null
+++ b/security/nss/lib/crmf/asn1cmn.c
@@ -0,0 +1,216 @@
+/* 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 "cmmf.h"
+#include "cmmfi.h"
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+SEC_ASN1_MKSUB(SEC_IntegerTemplate)
+SEC_ASN1_MKSUB(SEC_SignedCertificateTemplate)
+
+static const SEC_ASN1Template CMMFCertResponseTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFCertResponse) },
+ { SEC_ASN1_INTEGER, offsetof(CMMFCertResponse, certReqId) },
+ { SEC_ASN1_INLINE, offsetof(CMMFCertResponse, status),
+ CMMFPKIStatusInfoTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_POINTER,
+ offsetof(CMMFCertResponse, certifiedKeyPair),
+ CMMFCertifiedKeyPairTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template CMMFCertOrEncCertTemplate[] = {
+ { SEC_ASN1_ANY, offsetof(CMMFCertOrEncCert, derValue), NULL,
+ sizeof(CMMFCertOrEncCert) },
+ { 0 }
+};
+
+const SEC_ASN1Template CMMFCertifiedKeyPairTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFCertifiedKeyPair) },
+ { SEC_ASN1_INLINE, offsetof(CMMFCertifiedKeyPair, certOrEncCert),
+ CMMFCertOrEncCertTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER | 0,
+ offsetof(CMMFCertifiedKeyPair, privateKey),
+ CRMFEncryptedValueTemplate },
+ { SEC_ASN1_NO_STREAM | SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_XTRN | 1,
+ offsetof(CMMFCertifiedKeyPair, derPublicationInfo),
+ SEC_ASN1_SUB(SEC_AnyTemplate) },
+ { 0 }
+};
+
+const SEC_ASN1Template CMMFPKIStatusInfoTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFPKIStatusInfo) },
+ { SEC_ASN1_INTEGER, offsetof(CMMFPKIStatusInfo, status) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_UTF8_STRING,
+ offsetof(CMMFPKIStatusInfo, statusString) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_BIT_STRING,
+ offsetof(CMMFPKIStatusInfo, failInfo) },
+ { 0 }
+};
+
+const SEC_ASN1Template CMMFSequenceOfCertsTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0,
+ SEC_ASN1_SUB(SEC_SignedCertificateTemplate) }
+};
+
+const SEC_ASN1Template CMMFRandTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFRand) },
+ { SEC_ASN1_INTEGER, offsetof(CMMFRand, integer) },
+ { SEC_ASN1_OCTET_STRING, offsetof(CMMFRand, senderHash) },
+ { 0 }
+};
+
+const SEC_ASN1Template CMMFPOPODecKeyRespContentTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN,
+ offsetof(CMMFPOPODecKeyRespContent, responses),
+ SEC_ASN1_SUB(SEC_IntegerTemplate),
+ sizeof(CMMFPOPODecKeyRespContent) },
+ { 0 }
+};
+
+const SEC_ASN1Template CMMFCertOrEncCertEncryptedCertTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ 0,
+ CRMFEncryptedValueTemplate },
+ { 0 }
+};
+
+const SEC_ASN1Template CMMFCertOrEncCertCertificateTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+ 0,
+ SEC_ASN1_SUB(SEC_SignedCertificateTemplate) },
+ { 0 }
+};
+
+const SEC_ASN1Template CMMFCertRepContentTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFCertRepContent) },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_OPTIONAL |
+ SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ offsetof(CMMFCertRepContent, caPubs),
+ CMMFSequenceOfCertsTemplate },
+ { SEC_ASN1_SEQUENCE_OF, offsetof(CMMFCertRepContent, response),
+ CMMFCertResponseTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template CMMFChallengeTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFChallenge) },
+ { SEC_ASN1_POINTER | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
+ offsetof(CMMFChallenge, owf),
+ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+ { SEC_ASN1_OCTET_STRING, offsetof(CMMFChallenge, witness) },
+ { SEC_ASN1_ANY, offsetof(CMMFChallenge, senderDER) },
+ { SEC_ASN1_OCTET_STRING, offsetof(CMMFChallenge, key) },
+ { SEC_ASN1_OCTET_STRING, offsetof(CMMFChallenge, challenge) },
+ { 0 }
+};
+
+const SEC_ASN1Template CMMFPOPODecKeyChallContentTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, offsetof(CMMFPOPODecKeyChallContent, challenges),
+ CMMFChallengeTemplate, sizeof(CMMFPOPODecKeyChallContent) },
+ { 0 }
+};
+
+SECStatus
+cmmf_decode_process_cert_response(PLArenaPool *poolp,
+ CERTCertDBHandle *db,
+ CMMFCertResponse *inCertResp)
+{
+ SECStatus rv = SECSuccess;
+
+ if (inCertResp->certifiedKeyPair != NULL) {
+ rv = cmmf_decode_process_certified_key_pair(poolp,
+ db,
+ inCertResp->certifiedKeyPair);
+ }
+ return rv;
+}
+
+static CERTCertificate *
+cmmf_DecodeDERCertificate(CERTCertDBHandle *db, SECItem *derCert)
+{
+ CERTCertificate *newCert;
+
+ newCert = CERT_NewTempCertificate(db, derCert, NULL, PR_FALSE, PR_TRUE);
+ return newCert;
+}
+
+static CMMFCertOrEncCertChoice
+cmmf_get_certorenccertchoice_from_der(SECItem *der)
+{
+ CMMFCertOrEncCertChoice retChoice;
+
+ switch (der->data[0] & 0x0f) {
+ case 0:
+ retChoice = cmmfCertificate;
+ break;
+ case 1:
+ retChoice = cmmfEncryptedCert;
+ break;
+ default:
+ retChoice = cmmfNoCertOrEncCert;
+ break;
+ }
+ return retChoice;
+}
+
+static SECStatus
+cmmf_decode_process_certorenccert(PLArenaPool *poolp,
+ CERTCertDBHandle *db,
+ CMMFCertOrEncCert *inCertOrEncCert)
+{
+ SECStatus rv = SECSuccess;
+
+ inCertOrEncCert->choice =
+ cmmf_get_certorenccertchoice_from_der(&inCertOrEncCert->derValue);
+
+ switch (inCertOrEncCert->choice) {
+ case cmmfCertificate: {
+ /* The DER has implicit tagging, so we gotta switch it to
+ * un-tagged in order for the ASN1 parser to understand it.
+ * Saving the bits that were changed.
+ */
+ inCertOrEncCert->derValue.data[0] = 0x30;
+ inCertOrEncCert->cert.certificate =
+ cmmf_DecodeDERCertificate(db, &inCertOrEncCert->derValue);
+ if (inCertOrEncCert->cert.certificate == NULL) {
+ rv = SECFailure;
+ }
+
+ } break;
+ case cmmfEncryptedCert:
+ PORT_Assert(poolp);
+ if (!poolp) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ break;
+ }
+ inCertOrEncCert->cert.encryptedCert =
+ PORT_ArenaZNew(poolp, CRMFEncryptedValue);
+ if (inCertOrEncCert->cert.encryptedCert == NULL) {
+ rv = SECFailure;
+ break;
+ }
+ rv = SEC_ASN1Decode(poolp, inCertOrEncCert->cert.encryptedCert,
+ CMMFCertOrEncCertEncryptedCertTemplate,
+ (const char *)inCertOrEncCert->derValue.data,
+ inCertOrEncCert->derValue.len);
+ break;
+ default:
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+SECStatus
+cmmf_decode_process_certified_key_pair(PLArenaPool *poolp,
+ CERTCertDBHandle *db,
+ CMMFCertifiedKeyPair *inCertKeyPair)
+{
+ return cmmf_decode_process_certorenccert(poolp,
+ db,
+ &inCertKeyPair->certOrEncCert);
+}
diff --git a/security/nss/lib/crmf/challcli.c b/security/nss/lib/crmf/challcli.c
new file mode 100644
index 000000000..a92843894
--- /dev/null
+++ b/security/nss/lib/crmf/challcli.c
@@ -0,0 +1,238 @@
+/* -*- 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 "cmmf.h"
+#include "cmmfi.h"
+#include "secitem.h"
+#include "pk11func.h"
+#include "secder.h"
+#include "sechash.h"
+
+CMMFPOPODecKeyChallContent *
+CMMF_CreatePOPODecKeyChallContentFromDER(const char *buf, long len)
+{
+ PLArenaPool *poolp;
+ CMMFPOPODecKeyChallContent *challContent;
+ SECStatus rv;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ return NULL;
+ }
+ challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent);
+ if (challContent == NULL) {
+ goto loser;
+ }
+ challContent->poolp = poolp;
+ rv = SEC_ASN1Decode(poolp, challContent,
+ CMMFPOPODecKeyChallContentTemplate, buf, len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (challContent->challenges) {
+ while (challContent->challenges[challContent->numChallenges] != NULL) {
+ challContent->numChallenges++;
+ }
+ challContent->numAllocated = challContent->numChallenges;
+ }
+ return challContent;
+loser:
+ if (poolp != NULL) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ }
+ return NULL;
+}
+
+int
+CMMF_POPODecKeyChallContentGetNumChallenges(CMMFPOPODecKeyChallContent *inKeyChallCont)
+{
+ PORT_Assert(inKeyChallCont != NULL);
+ if (inKeyChallCont == NULL) {
+ return 0;
+ }
+ return inKeyChallCont->numChallenges;
+}
+
+SECItem *
+CMMF_POPODecKeyChallContentGetPublicValue(CMMFPOPODecKeyChallContent *inKeyChallCont,
+ int inIndex)
+{
+ PORT_Assert(inKeyChallCont != NULL);
+ if (inKeyChallCont == NULL || (inIndex > inKeyChallCont->numChallenges - 1) ||
+ inIndex < 0) {
+ return NULL;
+ }
+ return SECITEM_DupItem(&inKeyChallCont->challenges[inIndex]->key);
+}
+
+static SECAlgorithmID *
+cmmf_get_owf(CMMFPOPODecKeyChallContent *inChalCont,
+ int inIndex)
+{
+ int i;
+
+ for (i = inIndex; i >= 0; i--) {
+ if (inChalCont->challenges[i]->owf != NULL) {
+ return inChalCont->challenges[i]->owf;
+ }
+ }
+ return NULL;
+}
+
+SECStatus
+CMMF_POPODecKeyChallContDecryptChallenge(CMMFPOPODecKeyChallContent *inChalCont,
+ int inIndex,
+ SECKEYPrivateKey *inPrivKey)
+{
+ CMMFChallenge *challenge;
+ SECItem *decryptedRand = NULL;
+ PLArenaPool *poolp = NULL;
+ SECAlgorithmID *owf;
+ SECStatus rv = SECFailure;
+ SECOidTag tag;
+ CMMFRand randStr;
+ SECItem hashItem;
+ unsigned char hash[HASH_LENGTH_MAX];
+
+ PORT_Assert(inChalCont != NULL && inPrivKey != NULL);
+ if (inChalCont == NULL || inIndex < 0 || inIndex > inChalCont->numChallenges ||
+ inPrivKey == NULL) {
+ return SECFailure;
+ }
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ goto loser;
+ }
+
+ challenge = inChalCont->challenges[inIndex];
+ decryptedRand = SECITEM_AllocItem(poolp, NULL, challenge->challenge.len);
+ if (decryptedRand == NULL) {
+ goto loser;
+ }
+ rv = PK11_PrivDecryptPKCS1(inPrivKey, decryptedRand->data,
+ &decryptedRand->len, decryptedRand->len,
+ challenge->challenge.data, challenge->challenge.len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = SEC_ASN1DecodeItem(poolp, &randStr, CMMFRandTemplate,
+ decryptedRand);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECFailure; /* Just so that when we do go to loser,
+ * I won't have to set it again.
+ */
+ owf = cmmf_get_owf(inChalCont, inIndex);
+ if (owf == NULL) {
+ /* No hashing algorithm came with the challenges. Can't verify */
+ goto loser;
+ }
+ /* Verify the hashes in the challenge */
+ tag = SECOID_FindOIDTag(&owf->algorithm);
+ hashItem.len = HASH_ResultLenByOidTag(tag);
+ if (!hashItem.len)
+ goto loser; /* error code has been set */
+
+ rv = PK11_HashBuf(tag, hash, randStr.integer.data, randStr.integer.len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ hashItem.data = hash;
+ if (SECITEM_CompareItem(&hashItem, &challenge->witness) != SECEqual) {
+ /* The hash for the data we decrypted doesn't match the hash provided
+ * in the challenge. Bail out.
+ */
+ PORT_SetError(SEC_ERROR_BAD_DATA);
+ rv = SECFailure;
+ goto loser;
+ }
+ rv = PK11_HashBuf(tag, hash, challenge->senderDER.data,
+ challenge->senderDER.len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (SECITEM_CompareItem(&hashItem, &randStr.senderHash) != SECEqual) {
+ /* The hash for the data we decrypted doesn't match the hash provided
+ * in the challenge. Bail out.
+ */
+ PORT_SetError(SEC_ERROR_BAD_DATA);
+ rv = SECFailure;
+ goto loser;
+ }
+ /* All of the hashes have verified, so we can now store the integer away.*/
+ rv = SECITEM_CopyItem(inChalCont->poolp, &challenge->randomNumber,
+ &randStr.integer);
+loser:
+ if (poolp) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ }
+ return rv;
+}
+
+SECStatus
+CMMF_POPODecKeyChallContentGetRandomNumber(CMMFPOPODecKeyChallContent *inKeyChallCont,
+ int inIndex,
+ long *inDest)
+{
+ CMMFChallenge *challenge;
+
+ PORT_Assert(inKeyChallCont != NULL);
+ if (inKeyChallCont == NULL || inIndex > 0 || inIndex >= inKeyChallCont->numChallenges) {
+ return SECFailure;
+ }
+ challenge = inKeyChallCont->challenges[inIndex];
+ if (challenge->randomNumber.data == NULL) {
+ /* There is no random number here, nothing to see. */
+ return SECFailure;
+ }
+ *inDest = DER_GetInteger(&challenge->randomNumber);
+ return (*inDest == -1) ? SECFailure : SECSuccess;
+}
+
+SECStatus
+CMMF_EncodePOPODecKeyRespContent(long *inDecodedRand,
+ int inNumRand,
+ CRMFEncoderOutputCallback inCallback,
+ void *inArg)
+{
+ PLArenaPool *poolp;
+ CMMFPOPODecKeyRespContent *response;
+ SECItem *currItem;
+ SECStatus rv = SECFailure;
+ int i;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ return SECFailure;
+ }
+ response = PORT_ArenaZNew(poolp, CMMFPOPODecKeyRespContent);
+ if (response == NULL) {
+ goto loser;
+ }
+ response->responses = PORT_ArenaZNewArray(poolp, SECItem *, inNumRand + 1);
+ if (response->responses == NULL) {
+ goto loser;
+ }
+ for (i = 0; i < inNumRand; i++) {
+ currItem = response->responses[i] = PORT_ArenaZNew(poolp, SECItem);
+ if (currItem == NULL) {
+ goto loser;
+ }
+ currItem = SEC_ASN1EncodeInteger(poolp, currItem, inDecodedRand[i]);
+ if (currItem == NULL) {
+ goto loser;
+ }
+ }
+ rv = cmmf_user_encode(response, inCallback, inArg,
+ CMMFPOPODecKeyRespContentTemplate);
+loser:
+ if (poolp != NULL) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ }
+ return rv;
+}
diff --git a/security/nss/lib/crmf/cmmf.h b/security/nss/lib/crmf/cmmf.h
new file mode 100644
index 000000000..1e39a8d2d
--- /dev/null
+++ b/security/nss/lib/crmf/cmmf.h
@@ -0,0 +1,1082 @@
+/* -*- 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/. */
+
+#ifndef _CMMF_H_
+#define _CMMF_H_
+/*
+ * These are the functions exported by the security library for
+ * implementing Certificate Management Message Formats (CMMF).
+ *
+ * This API is designed against July 1998 CMMF draft. Please read this
+ * draft before trying to use this API in an application that use CMMF.
+ */
+#include "seccomon.h"
+#include "cmmft.h"
+#include "crmf.h"
+
+SEC_BEGIN_PROTOS
+
+/******************* Creation Functions *************************/
+
+/*
+ * FUNCTION: CMMF_CreateCertRepContent
+ * INPUTS:
+ * NONE
+ * NOTES:
+ * This function will create an empty CMMFCertRepContent Structure.
+ * The client of the library must set the CMMFCertResponses.
+ * Call CMMF_CertRepContentSetCertResponse to accomplish this task.
+ * If the client of the library also wants to include the chain of
+ * CA certs required to make the certificates in CMMFCertResponse valid,
+ * then the user must also set the caPubs field of CMMFCertRepContent.
+ * Call CMMF_CertRepContentSetCAPubs to accomplish this. After setting
+ * the desired fields, the user can then call CMMF_EncodeCertRepContent
+ * to DER-encode the CertRepContent.
+ * RETURN:
+ * A pointer to the CMMFCertRepContent. A NULL return value indicates
+ * an error in allocating memory or failure to initialize the structure.
+ */
+extern CMMFCertRepContent *CMMF_CreateCertRepContent(void);
+
+/*
+ * FUNCTION: CMMF_CreateCertRepContentFromDER
+ * INPUTS
+ * db
+ * The certificate database where the certificates will be placed.
+ * The certificates will be placed in the temporary database associated
+ * with the handle.
+ * buf
+ * A buffer to the DER-encoded CMMFCertRepContent
+ * len
+ * The length in bytes of the buffer 'buf'
+ * NOTES:
+ * This function passes the buffer to the ASN1 decoder and creates a
+ * CMMFCertRepContent structure. The user must call
+ * CMMF_DestroyCertRepContent after the return value is no longer needed.
+ *
+ * RETURN:
+ * A pointer to the CMMFCertRepContent structure. A NULL return
+ * value indicates the library was unable to parse the DER.
+ */
+extern CMMFCertRepContent *
+CMMF_CreateCertRepContentFromDER(CERTCertDBHandle *db,
+ const char *buf,
+ long len);
+
+/*
+ * FUNCTION: CMMF_CreateCertResponse
+ * INPUTS:
+ * inCertReqId
+ * The Certificate Request Id this response is for.
+ * NOTES:
+ * This creates a CMMFCertResponse. This response should correspond
+ * to a request that was received via CRMF. From the CRMF message you
+ * can get the Request Id to pass in as inCertReqId, in essence binding
+ * a CMRFCertRequest message to the CMMFCertResponse created by this
+ * function. If no requuest id is associated with the response to create
+ * then the user should pass in -1 for 'inCertReqId'.
+ *
+ * RETURN:
+ * A pointer to the new CMMFCertResponse corresponding to the request id
+ * passed in. A NULL return value indicates an error while trying to
+ * create the CMMFCertResponse.
+ */
+extern CMMFCertResponse *CMMF_CreateCertResponse(long inCertReqId);
+
+/*
+ * FUNCTION: CMMF_CreateKeyRecRepContent
+ * INPUTS:
+ * NONE
+ * NOTES:
+ * This function creates a new empty CMMFKeyRecRepContent structure.
+ * At the very minimum, the user must call
+ * CMMF_KeyRecRepContentSetPKIStatusInfoStatus field to have an
+ * encodable structure. Depending on what the response is, the user may
+ * have to set other fields as well to properly build up the structure so
+ * that it can be encoded. Refer to the CMMF draft for how to properly
+ * set up a CMMFKeyRecRepContent. This is the structure that an RA returns
+ * to an end entity when doing key recovery.
+
+ * The user must call CMMF_DestroyKeyRecRepContent when the return value
+ * is no longer needed.
+ * RETURN:
+ * A pointer to the empty CMMFKeyRecRepContent. A return value of NULL
+ * indicates an error in allocating memory or initializing the structure.
+ */
+extern CMMFKeyRecRepContent *CMMF_CreateKeyRecRepContent(void);
+
+/*
+ * FUNCTION: CMMF_CreateKeyRecRepContentFromDER
+ * INPUTS:
+ * db
+ * The handle for the certificate database where the decoded
+ * certificates will be placed. The decoded certificates will
+ * be placed in the temporary database associated with the
+ * handle.
+ * buf
+ * A buffer contatining the DER-encoded CMMFKeyRecRepContent
+ * len
+ * The length in bytes of the buffer 'buf'
+ * NOTES
+ * This function passes the buffer to the ASN1 decoder and creates a
+ * CMMFKeyRecRepContent structure.
+ *
+ * RETURN:
+ * A pointer to the CMMFKeyRecRepContent structure. A NULL return
+ * value indicates the library was unable to parse the DER.
+ */
+extern CMMFKeyRecRepContent *
+CMMF_CreateKeyRecRepContentFromDER(CERTCertDBHandle *db,
+ const char *buf,
+ long len);
+
+/*
+ * FUNCTION: CMMF_CreatePOPODecKeyChallContent
+ * INPUTS:
+ * NONE
+ * NOTES:
+ * This function creates an empty CMMFPOPODecKeyChallContent. The user
+ * must add the challenges individually specifying the random number to
+ * be used and the public key to be used when creating each individual
+ * challenge. User can accomplish this by calling the function
+ * CMMF_POPODecKeyChallContentSetNextChallenge.
+ * RETURN:
+ * A pointer to a CMMFPOPODecKeyChallContent structure. Ther user can
+ * then call CMMF_EncodePOPODecKeyChallContent passing in the return
+ * value from this function after setting all of the challenges. A
+ * return value of NULL indicates an error while creating the
+ * CMMFPOPODecKeyChallContent structure.
+ */
+extern CMMFPOPODecKeyChallContent *
+CMMF_CreatePOPODecKeyChallContent(void);
+
+/*
+ * FUNCTION: CMMF_CreatePOPODecKeyChallContentFromDER
+ * INPUTS
+ * buf
+ * A buffer containing the DER-encoded CMMFPOPODecKeyChallContent
+ * len
+ * The length in bytes of the buffer 'buf'
+ * NOTES:
+ * This function passes the buffer to the ASN1 decoder and creates a
+ * CMMFPOPODecKeyChallContent structure.
+ *
+ * RETURN:
+ * A pointer to the CMMFPOPODecKeyChallContent structure. A NULL return
+ * value indicates the library was unable to parse the DER.
+ */
+extern CMMFPOPODecKeyChallContent *
+CMMF_CreatePOPODecKeyChallContentFromDER(const char *buf, long len);
+
+/*
+ * FUNCTION: CMMF_CreatePOPODecKeyRespContentFromDER
+ * INPUTS:
+ * buf
+ * A buffer contatining the DER-encoded CMMFPOPODecKeyRespContent
+ * len
+ * The length in bytes of the buffer 'buf'
+ * NOTES
+ * This function passes the buffer to the ASN1 decoder and creates a
+ * CMMFPOPODecKeyRespContent structure.
+ *
+ * RETURN:
+ * A pointer to the CMMFPOPODecKeyRespContent structure. A NULL return
+ * value indicates the library was unable to parse the DER.
+ */
+extern CMMFPOPODecKeyRespContent *
+CMMF_CreatePOPODecKeyRespContentFromDER(const char *buf, long len);
+
+/************************** Set Functions *************************/
+
+/*
+ * FUNCTION: CMMF_CertRepContentSetCertResponses
+ * INPUTS:
+ * inCertRepContent
+ * The CMMFCertRepContent to operate on.
+ * inCertResponses
+ * An array of pointers to CMMFCertResponse structures to
+ * add to the CMMFCertRepContent structure.
+ * inNumResponses
+ * The length of the array 'inCertResponses'
+ * NOTES:
+ * This function will add the CMMFCertResponse structure to the
+ * CMMFCertRepContent passed in. The CMMFCertResponse field of
+ * CMMFCertRepContent is required, so the client must call this function
+ * before calling CMMF_EncodeCertRepContent. If the user calls
+ * CMMF_EncodeCertRepContent before calling this function,
+ * CMMF_EncodeCertRepContent will fail.
+ *
+ * RETURN:
+ * SECSuccess if adding the CMMFCertResponses to the CMMFCertRepContent
+ * structure was successful. Any other return value indicates an error
+ * while trying to add the CMMFCertResponses.
+ */
+extern SECStatus
+CMMF_CertRepContentSetCertResponses(CMMFCertRepContent *inCertRepContent,
+ CMMFCertResponse **inCertResponses,
+ int inNumResponses);
+
+/*
+ * FUNCTION: CMMF_CertRepContentSetCAPubs
+ * INPUTS:
+ * inCertRepContent
+ * The CMMFCertRepContent to operate on.
+ * inCAPubs
+ * The certificate list which makes up the chain of CA certificates
+ * required to make the issued cert valid.
+ * NOTES:
+ * This function will set the the certificates in the CA chain as part
+ * of the CMMFCertRepContent. This field is an optional member of the
+ * CMMFCertRepContent structure, so the client is not required to call
+ * this function before calling CMMF_EncodeCertRepContent.
+ *
+ * RETURN:
+ * SECSuccess if adding the 'inCAPubs' to the CERTRepContent was successful.
+ * Any other return value indicates an error while adding 'inCAPubs' to the
+ * CMMFCertRepContent structure.
+ *
+ */
+extern SECStatus
+CMMF_CertRepContentSetCAPubs(CMMFCertRepContent *inCertRepContent,
+ CERTCertList *inCAPubs);
+
+/*
+ * FUNCTION: CMMF_CertResponseSetPKIStatusInfoStatus
+ * INPUTS:
+ * inCertResp
+ * The CMMFCertResponse to operate on.
+ * inPKIStatus
+ * The value to set for the PKIStatusInfo.status field.
+ * NOTES:
+ * This function will set the CertResponse.status.status field of
+ * the CMMFCertResponse structure. (View the definition of CertResponse
+ * in the CMMF draft to see exactly which value this talks about.) This
+ * field is a required member of the structure, so the user must call this
+ * function in order to have a CMMFCertResponse that can be encoded.
+ *
+ * RETURN:
+ * SECSuccess if setting the field with the passed in value was successful.
+ * Any other return value indicates an error while trying to set the field.
+ */
+extern SECStatus
+CMMF_CertResponseSetPKIStatusInfoStatus(CMMFCertResponse *inCertResp,
+ CMMFPKIStatus inPKIStatus);
+
+/*
+ * FUNCTION: CMMF_CertResponseSetCertificate
+ * INPUTS:
+ * inCertResp
+ * The CMMFCertResponse to operate on.
+ * inCertificate
+ * The certificate to add to the
+ * CertResponse.CertifiedKeyPair.certOrEncCert.certificate field.
+ * NOTES:
+ * This function will take the certificate and make it a member of the
+ * CMMFCertResponse. The certificate should be the actual certificate
+ * being issued via the response.
+ *
+ * RETURN:
+ * SECSuccess if adding the certificate to the response was successful.
+ * Any other return value indicates an error in adding the certificate to
+ * the CertResponse.
+ */
+extern SECStatus
+CMMF_CertResponseSetCertificate(CMMFCertResponse *inCertResp,
+ CERTCertificate *inCertificate);
+
+/*
+ * FUNCTION: CMMF_KeyRecRepContentSetPKIStatusInfoStatus
+ * INPUTS:
+ * inKeyRecRep
+ * The CMMFKeyRecRepContent to operate on.
+ * inPKIStatus
+ * The value to set the PKIStatusInfo.status field to.
+ * NOTES:
+ * This function sets the only required field for the KeyRecRepContent.
+ * In most cases, the user will set this field and other fields of the
+ * structure to properly create the CMMFKeyRecRepContent structure.
+ * Refer to the CMMF draft to see which fields need to be set in order
+ * to create the desired CMMFKeyRecRepContent.
+ *
+ * RETURN:
+ * SECSuccess if setting the PKIStatusInfo.status field was successful.
+ * Any other return value indicates an error in setting the field.
+ */
+extern SECStatus
+CMMF_KeyRecRepContentSetPKIStatusInfoStatus(CMMFKeyRecRepContent *inKeyRecRep,
+ CMMFPKIStatus inPKIStatus);
+
+/*
+ * FUNCTION: CMMF_KeyRecRepContentSetNewSignCert
+ * INPUTS:
+ * inKeyRecRep
+ * The CMMFKeyRecRepContent to operate on.
+ * inNewSignCert
+ * The new signing cert to add to the CMMFKeyRecRepContent structure.
+ * NOTES:
+ * This function sets the new signeing cert in the CMMFKeyRecRepContent
+ * structure.
+ *
+ * RETURN:
+ * SECSuccess if setting the new signing cert was successful. Any other
+ * return value indicates an error occurred while trying to add the
+ * new signing certificate.
+ */
+extern SECStatus
+CMMF_KeyRecRepContentSetNewSignCert(CMMFKeyRecRepContent *inKeyRecRep,
+ CERTCertificate *inNewSignCert);
+
+/*
+ * FUNCTION: CMMF_KeyRecRepContentSetCACerts
+ * INPUTS:
+ * inKeyRecRep
+ * The CMMFKeyRecRepContent to operate on.
+ * inCACerts
+ * The list of CA certificates required to construct a valid
+ * certificate chain with the certificates that will be returned
+ * to the end user via this KeyRecRepContent.
+ * NOTES:
+ * This function sets the caCerts that are required to form a chain with the
+ * end entity certificates that are being re-issued in this
+ * CMMFKeyRecRepContent structure.
+ *
+ * RETURN:
+ * SECSuccess if adding the caCerts was successful. Any other return value
+ * indicates an error while tring to add the caCerts.
+ */
+extern SECStatus
+CMMF_KeyRecRepContentSetCACerts(CMMFKeyRecRepContent *inKeyRecRep,
+ CERTCertList *inCACerts);
+
+/*
+ * FUNCTION: CMMF_KeyRecRepContentSetCertifiedKeyPair
+ * INPUTS:
+ * inKeyRecRep
+ * The CMMFKeyRecRepContent to operate on.
+ * inCert
+ * The certificate to add to the CMMFKeyRecRepContent structure.
+ * inPrivKey
+ * The private key associated with the certificate above passed in.
+ * inPubKey
+ * The public key to use for wrapping the private key.
+ * NOTES:
+ * This function adds another certificate-key pair to the
+ * CMMFKeyRecRepcontent structure. There may be more than one
+ * certificate-key pair in the structure, so the user must call this
+ * function multiple times to add more than one cert-key pair.
+ *
+ * RETURN:
+ * SECSuccess if adding the certified key pair was successful. Any other
+ * return value indicates an error in adding certified key pair to
+ * CMMFKeyRecRepContent structure.
+ */
+extern SECStatus
+CMMF_KeyRecRepContentSetCertifiedKeyPair(CMMFKeyRecRepContent *inKeyRecRep,
+ CERTCertificate *inCert,
+ SECKEYPrivateKey *inPrivKey,
+ SECKEYPublicKey *inPubKey);
+
+/*
+ * FUNCTION: CMMF_POPODecKeyChallContentSetNextChallenge
+ * INPUTS:
+ * inDecKeyChall
+ * The CMMFPOPODecKeyChallContent to operate on.
+ * inRandom
+ * The random number to use when generating the challenge,
+ * inSender
+ * The GeneralName representation of the sender of the challenge.
+ * inPubKey
+ * The public key to use when encrypting the challenge.
+ * passwdArg
+ * This value will be passed to the function used for getting a
+ * password. The password for getting a password should be registered
+ * by calling PK11_SetPasswordFunc before this function is called.
+ * If no password callback is registered and the library needs to
+ * authenticate to the slot for any reason, this function will fail.
+ * NOTES:
+ * This function adds a challenge to the end of the list of challenges
+ * contained by 'inDecKeyChall'. Refer to the CMMF draft on how the
+ * the random number passed in and the sender's GeneralName are used
+ * to generate the challenge and witness fields of the challenge. This
+ * library will use SHA1 as the one-way function for generating the
+ * witess field of the challenge.
+ *
+ * RETURN:
+ * SECSuccess if generating the challenge and adding to the end of list
+ * of challenges was successful. Any other return value indicates an error
+ * while trying to generate the challenge.
+ */
+extern SECStatus
+CMMF_POPODecKeyChallContentSetNextChallenge(CMMFPOPODecKeyChallContent *inDecKeyChall,
+ long inRandom,
+ CERTGeneralName *inSender,
+ SECKEYPublicKey *inPubKey,
+ void *passwdArg);
+
+/************************** Encoding Functions *************************/
+
+/*
+ * FUNCTION: CMMF_EncodeCertRepContent
+ * INPUTS:
+ * inCertRepContent
+ * The CMMFCertRepContent to DER-encode.
+ * inCallback
+ * A callback function that the ASN1 encoder will call whenever it
+ * wants to write out DER-encoded bytes. Look at the defintion of
+ * CRMFEncoderOutputCallback in crmft.h for a description of the
+ * parameters to the function.
+ * inArg
+ * An opaque pointer to a user-supplied argument that will be passed
+ * to the callback funtion whenever the function is called.
+ * NOTES:
+ * The CMMF library will use the same DER-encoding scheme as the CRMF
+ * library. In other words, when reading CRMF comments that pertain to
+ * encoding, those comments apply to the CMMF libray as well.
+ * The callback function will be called multiple times, each time supplying
+ * the next chunk of DER-encoded bytes. The user must concatenate the
+ * output of each successive call to the callback in order to get the
+ * entire DER-encoded CMMFCertRepContent structure.
+ *
+ * RETURN:
+ * SECSuccess if encoding the CMMFCertRepContent was successful. Any
+ * other return value indicates an error while decoding the structure.
+ */
+extern SECStatus
+CMMF_EncodeCertRepContent(CMMFCertRepContent *inCertRepContent,
+ CRMFEncoderOutputCallback inCallback,
+ void *inArg);
+
+/*
+ * FUNCTION: CMMF_EncodeKeyRecRepContent
+ * INPUTS:
+ * inKeyRecRep
+ * The CMMFKeyRepContent to DER-encode.
+ * inCallback
+ * A callback function that the ASN1 encoder will call whenever it
+ * wants to write out DER-encoded bytes. Look at the defintion of
+ * CRMFEncoderOutputCallback in crmft.h for a description of the
+ * parameters to the function.
+ * inArg
+ * An opaque pointer to a user-supplied argument that will be passed
+ * to the callback funtion whenever the function is called.
+ * NOTES:
+ * The CMMF library will use the same DER-encoding scheme as the CRMF
+ * library. In other words, when reading CRMF comments that pertain to
+ * encoding, those comments apply to the CMMF libray as well.
+ * The callback function will be called multiple times, each time supplying
+ * the next chunk of DER-encoded bytes. The user must concatenate the
+ * output of each successive call to the callback in order to get the
+ * entire DER-encoded CMMFCertRepContent structure.
+ *
+ * RETURN:
+ * SECSuccess if encoding the CMMFKeyRecRepContent was successful. Any
+ * other return value indicates an error while decoding the structure.
+ */
+extern SECStatus
+CMMF_EncodeKeyRecRepContent(CMMFKeyRecRepContent *inKeyRecRep,
+ CRMFEncoderOutputCallback inCallback,
+ void *inArg);
+
+/*
+ * FUNCTION: CMMF_EncodePOPODecKeyChallContent
+ * INPUTS:
+ * inDecKeyChall
+ * The CMMFDecKeyChallContent to operate on.
+ * inCallback
+ * A callback function that the ASN1 encoder will call whenever it
+ * wants to write out DER-encoded bytes. Look at the defintion of
+ * CRMFEncoderOutputCallback in crmft.h for a description of the
+ * parameters to the function.
+ * inArg
+ * An opaque pointer to a user-supplied argument that will be passed
+ * to the callback function whenever the function is called.
+ * NOTES:
+ * The CMMF library will use the same DER-encoding scheme as the CRMF
+ * library. In other words, when reading CRMF comments that pertain to
+ * encoding, those comments apply to the CMMF libray as well.
+ * The callback function will be called multiple times, each time supplying
+ * the next chunk of DER-encoded bytes. The user must concatenate the
+ * output of each successive call to the callback in order to get the
+ * entire DER-encoded CMMFCertRepContent structure.
+ * The DER will be an encoding of the type POPODecKeyChallContents, which
+ * is just a sequence of challenges.
+ *
+ * RETURN:
+ * SECSuccess if encoding was successful. Any other return value indicates
+ * an error in trying to encode the Challenges.
+ */
+extern SECStatus
+CMMF_EncodePOPODecKeyChallContent(CMMFPOPODecKeyChallContent *inDecKeyChall,
+ CRMFEncoderOutputCallback inCallback,
+ void *inArg);
+
+/*
+ * FUNCTION: CMMF_EncodePOPODecKeyRespContent
+ * INPUTS:
+ * inDecodedRand
+ * An array of integers to encode as the responses to
+ * CMMFPOPODecKeyChallContent. The integers must be in the same order
+ * as the challenges extracted from CMMFPOPODecKeyChallContent.
+ * inNumRand
+ * The number of random integers contained in the array 'inDecodedRand'
+ * inCallback
+ * A callback function that the ASN1 encoder will call whenever it
+ * wants to write out DER-encoded bytes. Look at the defintion of
+ * CRMFEncoderOutputCallback in crmft.h for a description of the
+ * parameters to the function.
+ * inArg
+ * An opaque pointer to a user-supplied argument that will be passed
+ * to the callback funtion whenever the function is called.
+ * NOTES:
+ * The CMMF library will use the same DER-encoding scheme as the CRMF
+ * library. In other words, when reading CRMF comments that pertain to
+ * encoding, those comments apply to the CMMF libray as well.
+ * The callback function will be called multiple times, each time supplying
+ * the next chunk of DER-encoded bytes. The user must concatenate the
+ * output of each successive call to the callback in order to get the
+ * entire DER-encoded POPODecKeyRespContent.
+ *
+ * RETURN:
+ * SECSuccess if encoding was successful. Any other return value indicates
+ * an error in trying to encode the Challenges.
+ */
+extern SECStatus
+CMMF_EncodePOPODecKeyRespContent(long *inDecodedRand,
+ int inNumRand,
+ CRMFEncoderOutputCallback inCallback,
+ void *inArg);
+
+/*************** Accessor function ***********************************/
+
+/*
+ * FUNCTION: CMMF_CertRepContentGetCAPubs
+ * INPUTS:
+ * inCertRepContent
+ * The CMMFCertRepContent to extract the caPubs from.
+ * NOTES:
+ * This function will return a copy of the list of certificates that
+ * make up the chain of CA's required to make the cert issued valid.
+ * The user must call CERT_DestroyCertList on the return value when
+ * done using the return value.
+ *
+ * Only call this function on a CertRepContent that has been decoded.
+ * The client must call CERT_DestroyCertList when the certificate list
+ * is no longer needed.
+ *
+ * The certs in the list will not be in the temporary database. In order
+ * to make these certificates a part of the permanent CA internal database,
+ * the user must collect the der for all of these certs and call
+ * CERT_ImportCAChain. Afterwards the certs will be part of the permanent
+ * database.
+ *
+ * RETURN:
+ * A pointer to the CERTCertList representing the CA chain associated
+ * with the issued cert. A NULL return value indicates that no CA Pubs
+ * were available in the CMMFCertRepContent structure.
+ */
+extern CERTCertList *
+CMMF_CertRepContentGetCAPubs(CMMFCertRepContent *inCertRepContent);
+
+/*
+ * FUNCTION: CMMF_CertRepContentGetNumResponses
+ * INPUTS:
+ * inCertRepContent
+ * The CMMFCertRepContent to operate on.
+ * NOTES:
+ * This function will return the number of CertResponses that are contained
+ * by the CMMFCertRepContent passed in.
+ *
+ * RETURN:
+ * The number of CMMFCertResponses contained in the structure passed in.
+ */
+extern int
+CMMF_CertRepContentGetNumResponses(CMMFCertRepContent *inCertRepContent);
+
+/*
+ * FUNCTION: CMMF_CertRepContentGetResponseAtIndex
+ * INPUTS:
+ * inCertRepContent
+ * The CMMFCertRepContent to operate on.
+ * inIndex
+ * The index of the CMMFCertResponse the user wants a copy of.
+ * NOTES:
+ * This function creates a copy of the CMMFCertResponse at the index
+ * corresponding to the parameter 'inIndex'. Indexing is done like a
+ * traditional C array, ie the valid indexes are (0...numResponses-1).
+ * The user must call CMMF_DestroyCertResponse after the return value is
+ * no longer needed.
+ *
+ * RETURN:
+ * A pointer to the CMMFCertResponse at the index corresponding to
+ * 'inIndex'. A return value of NULL indicates an error in copying
+ * the CMMFCertResponse.
+ */
+extern CMMFCertResponse *
+CMMF_CertRepContentGetResponseAtIndex(CMMFCertRepContent *inCertRepContent,
+ int inIndex);
+
+/*
+ * FUNCTION: CMMF_CertResponseGetCertReqId
+ * INPUTS:
+ * inCertResp
+ * The CMMFCertResponse to operate on.
+ * NOTES:
+ * This function returns the CertResponse.certReqId from the
+ * CMMFCertResponse structure passed in. If the return value is -1, that
+ * means there is no associated certificate request with the CertResponse.
+ * RETURN:
+ * A long representing the id of the certificate request this
+ * CMMFCertResponse corresponds to. A return value of -1 indicates an
+ * error in extracting the value of the integer.
+ */
+extern long CMMF_CertResponseGetCertReqId(CMMFCertResponse *inCertResp);
+
+/*
+ * FUNCTION: CMMF_CertResponseGetPKIStatusInfoStatus
+ * INPUTS:
+ * inCertResp
+ * The CMMFCertResponse to operate on.
+ * NOTES:
+ * This function returns the CertResponse.status.status field of the
+ * CMMFCertResponse structure.
+ *
+ * RETURN:
+ * The enumerated value corresponding to the PKIStatus defined in the CMMF
+ * draft. See the CMMF draft for the definition of PKIStatus. See crmft.h
+ * for the definition of CMMFPKIStatus.
+ */
+extern CMMFPKIStatus
+CMMF_CertResponseGetPKIStatusInfoStatus(CMMFCertResponse *inCertResp);
+
+/*
+ * FUNCTION: CMMF_CertResponseGetCertificate
+ * INPUTS:
+ * inCertResp
+ * The Certificate Response to operate on.
+ * inCertdb
+ * This is the certificate database where the function will place the
+ * newly issued certificate.
+ * NOTES:
+ * This function retrieves the CertResponse.certifiedKeyPair.certificate
+ * from the CMMFCertResponse. The user will get a copy of that certificate
+ * so the user must call CERT_DestroyCertificate when the return value is
+ * no longer needed. The certificate returned will be in the temporary
+ * certificate database.
+ *
+ * RETURN:
+ * A pointer to a copy of the certificate contained within the
+ * CMMFCertResponse. A return value of NULL indicates an error while trying
+ * to make a copy of the certificate.
+ */
+extern CERTCertificate *
+CMMF_CertResponseGetCertificate(CMMFCertResponse *inCertResp,
+ CERTCertDBHandle *inCertdb);
+
+/*
+ * FUNCTION: CMMF_KeyRecRepContentGetPKIStatusInfoStatus
+ * INPUTS:
+ * inKeyRecRep
+ * The CMMFKeyRecRepContent structure to operate on.
+ * NOTES:
+ * This function retrieves the KeyRecRepContent.status.status field of
+ * the CMMFKeyRecRepContent structure.
+ * RETURN:
+ * The CMMFPKIStatus corresponding to the value held in the
+ * CMMFKeyRecRepContent structure.
+ */
+extern CMMFPKIStatus
+CMMF_KeyRecRepContentGetPKIStatusInfoStatus(CMMFKeyRecRepContent *inKeyRecRep);
+
+/*
+ * FUNCTION: CMMF_KeyRecRepContentGetNewSignCert
+ * INPUTS:
+ * inKeyRecRep
+ * The CMMFKeyRecRepContent to operate on.
+ * NOTES:
+ * This function retrieves the KeyRecRepContent.newSignCert field of the
+ * CMMFKeyRecRepContent structure. The user must call
+ * CERT_DestroyCertificate when the return value is no longer needed. The
+ * returned certificate will be in the temporary database. The user
+ * must then place the certificate permanently in whatever token the
+ * user determines is the proper destination. A return value of NULL
+ * indicates the newSigCert field was not present.
+ */
+extern CERTCertificate *
+CMMF_KeyRecRepContentGetNewSignCert(CMMFKeyRecRepContent *inKeyRecRep);
+
+/*
+ * FUNCTION: CMMF_KeyRecRepContentGetCACerts
+ * INPUTS:
+ * inKeyRecRep
+ * The CMMFKeyRecRepContent to operate on.
+ * NOTES:
+ * This function returns a CERTCertList which contains all of the
+ * certficates that are in the sequence KeyRecRepContent.caCerts
+ * User must call CERT_DestroyCertList when the return value is no longer
+ * needed. All of these certificates will be placed in the tempoaray
+ * database.
+ *
+ * RETURN:
+ * A pointer to the list of caCerts contained in the CMMFKeyRecRepContent
+ * structure. A return value of NULL indicates the library was not able to
+ * make a copy of the certifcates. This may be because there are no caCerts
+ * included in the CMMFKeyRecRepContent strucure or an internal error. Call
+ * CMMF_KeyRecRepContentHasCACerts to find out if there are any caCerts
+ * included in 'inKeyRecRep'.
+ */
+extern CERTCertList *
+CMMF_KeyRecRepContentGetCACerts(CMMFKeyRecRepContent *inKeyRecRep);
+
+/*
+ * FUNCTION: CMMF_KeyRecRepContentGetNumKeyPairs
+ * INPUTS:
+ * inKeyRecRep
+ * The CMMFKeyRecRepContent to operate on.
+ * RETURN:
+ * This function returns the number of CMMFCertifiedKeyPair structures that
+ * that are stored in the KeyRecRepContent structure.
+ */
+extern int
+CMMF_KeyRecRepContentGetNumKeyPairs(CMMFKeyRecRepContent *inKeyRecRep);
+
+/*
+ * FUNCTION: CMMF_KeyRecRepContentGetCertKeyAtIndex
+ * INPUTS:
+ * inKeyRecRepContent
+ * The CMMFKeyRecRepContent to operate on.
+ * inIndex
+ * The index of the desired CMMFCertifiedKeyPair
+ * NOTES:
+ * This function retrieves the CMMFCertifiedKeyPair structure at the index
+ * 'inIndex'. Valid indexes are 0...(numKeyPairs-1) The user must call
+ * CMMF_DestroyCertifiedKeyPair when the return value is no longer needed.
+ *
+ * RETURN:
+ * A pointer to the Certified Key Pair at the desired index. A return value
+ * of NULL indicates an error in extracting the Certified Key Pair at the
+ * desired index.
+ */
+extern CMMFCertifiedKeyPair *
+CMMF_KeyRecRepContentGetCertKeyAtIndex(CMMFKeyRecRepContent *inKeyRecRep,
+ int inIndex);
+
+/*
+ * FUNCTION: CMMF_CertifiedKeyPairGetCertificate
+ * INPUTS:
+ * inCertKeyPair
+ * The CMMFCertifiedKeyPair to operate on.
+ * inCertdb
+ * The database handle for the database you want this certificate
+ * to wind up in.
+ * NOTES:
+ * This function retrieves the certificate at
+ * CertifiedKeyPair.certOrEncCert.certificate
+ * The user must call CERT_DestroyCertificate when the return value is no
+ * longer needed. The user must import this certificate as a token object
+ * onto PKCS#11 slot in order to make it a permanent object. The returned
+ * certificate will be in the temporary database.
+ *
+ * RETURN:
+ * A pointer to the certificate contained within the certified key pair.
+ * A return value of NULL indicates an error in creating the copy of the
+ * certificate.
+ */
+extern CERTCertificate *
+CMMF_CertifiedKeyPairGetCertificate(CMMFCertifiedKeyPair *inCertKeyPair,
+ CERTCertDBHandle *inCertdb);
+
+/*
+ * FUNCTION: CMMF_POPODecKeyChallContentGetNumChallenges
+ * INPUTS:
+ * inKeyChallCont
+ * The CMMFPOPODecKeyChallContent to operate on.
+ * RETURN:
+ * This function returns the number of CMMFChallenges are contained in
+ * the CMMFPOPODecKeyChallContent structure.
+ */
+extern int CMMF_POPODecKeyChallContentGetNumChallenges(CMMFPOPODecKeyChallContent *inKeyChallCont);
+
+/*
+ * FUNCTION: CMMF_POPODecKeyChallContentGetPublicValue
+ * ---------------------------------------------------
+ * INPUTS:
+ * inKeyChallCont
+ * The CMMFPOPODecKeyChallContent to operate on.
+ * inIndex
+ * The index of the Challenge within inKeyChallCont to operate on.
+ * Indexes start from 0, ie the Nth Challenge corresponds to index
+ * N-1.
+ * NOTES:
+ * This function retrieves the public value stored away in the Challenge at
+ * index inIndex of inKeyChallCont.
+ * RETURN:
+ * A pointer to a SECItem containing the public value. User must call
+ * SECITEM_FreeItem on the return value when the value is no longer necessary.
+ * A return value of NULL indicates an error while retrieving the public value.
+ */
+extern SECItem *CMMF_POPODecKeyChallContentGetPublicValue(CMMFPOPODecKeyChallContent *inKeyChallCont,
+ int inIndex);
+
+/*
+ * FUNCTION: CMMF_POPODecKeyChallContentGetRandomNumber
+ * INPUTS:
+ * inChallContent
+ * The CMMFPOPODecKeyChallContent to operate on.
+ * inIndex
+ * The index of the challenge to look at. Valid indexes are 0 through
+ * (CMMF_POPODecKeyChallContentGetNumChallenges(inChallContent) - 1).
+ * inDest
+ * A pointer to a user supplied buffer where the library
+ * can place a copy of the random integer contatained in the
+ * challenge.
+ * NOTES:
+ * This function returns the value held in the decrypted Rand structure
+ * corresponding to the random integer. The user must call
+ * CMMF_POPODecKeyChallContentDecryptChallenge before calling this function. Call
+ * CMMF_ChallengeIsDecrypted to find out if the challenge has been
+ * decrypted.
+ *
+ * RETURN:
+ * SECSuccess indicates the witness field has been previously decrypted
+ * and the value for the random integer was successfully placed at *inDest.
+ * Any other return value indicates an error and that the value at *inDest
+ * is not a valid value.
+ */
+extern SECStatus CMMF_POPODecKeyChallContentGetRandomNumber(CMMFPOPODecKeyChallContent *inKeyChallCont,
+ int inIndex,
+ long *inDest);
+
+/*
+ * FUNCTION: CMMF_POPODecKeyRespContentGetNumResponses
+ * INPUTS:
+ * inRespCont
+ * The POPODecKeyRespContent to operate on.
+ * RETURN:
+ * This function returns the number of responses contained in inRespContent.
+ */
+extern int
+CMMF_POPODecKeyRespContentGetNumResponses(CMMFPOPODecKeyRespContent *inRespCont);
+
+/*
+ * FUNCTION: CMMF_POPODecKeyRespContentGetResponse
+ * INPUTS:
+ * inRespCont
+ * The POPODecKeyRespContent to operate on.
+ * inIndex
+ * The index of the response to retrieve.
+ * The Nth response is at index N-1, ie the 1st response is at index 0,
+ * the 2nd response is at index 1, and so on.
+ * inDest
+ * A pointer to a pre-allocated buffer where the library can put the
+ * value of the response located at inIndex.
+ * NOTES:
+ * The function returns the response contained at index inIndex.
+ * CMMFPOPODecKeyRespContent is a structure that the server will generally
+ * get in response to a CMMFPOPODecKeyChallContent. The server will expect
+ * to see the responses in the same order as it constructed them in
+ * the CMMFPOPODecKeyChallContent structure.
+ * RETURN:
+ * SECSuccess if getting the response at the desired index was successful. Any
+ * other return value indicates an errror.
+ */
+extern SECStatus
+CMMF_POPODecKeyRespContentGetResponse(CMMFPOPODecKeyRespContent *inRespCont,
+ int inIndex,
+ long *inDest);
+
+/************************* Destructor Functions ******************************/
+
+/*
+ * FUNCTION: CMMF_DestroyCertResponse
+ * INPUTS:
+ * inCertResp
+ * The CMMFCertResponse to destroy.
+ * NOTES:
+ * This function frees all the memory associated with the CMMFCertResponse
+ * passed in.
+ * RETURN:
+ * SECSuccess if freeing the memory was successful. Any other return value
+ * indicates an error while freeing the memory.
+ */
+extern SECStatus CMMF_DestroyCertResponse(CMMFCertResponse *inCertResp);
+
+/*
+ * FUNCTION: CMMF_DestroyCertRepContent
+ * INPUTS:
+ * inCertRepContent
+ * The CMMFCertRepContent to destroy
+ * NOTES:
+ * This function frees the memory associated with the CMMFCertRepContent
+ * passed in.
+ * RETURN:
+ * SECSuccess if freeing all the memory associated with the
+ * CMMFCertRepContent passed in is successful. Any other return value
+ * indicates an error while freeing the memory.
+ */
+extern SECStatus
+CMMF_DestroyCertRepContent(CMMFCertRepContent *inCertRepContent);
+
+/*
+ * FUNCTION: CMMF_DestroyKeyRecRepContent
+ * INPUTS:
+ * inKeyRecRep
+ * The CMMFKeyRecRepContent to destroy.
+ * NOTES:
+ * This function destroys all the memory associated with the
+ * CMMFKeyRecRepContent passed in.
+ *
+ * RETURN:
+ * SECSuccess if freeing all the memory is successful. Any other return
+ * value indicates an error in freeing the memory.
+ */
+extern SECStatus
+CMMF_DestroyKeyRecRepContent(CMMFKeyRecRepContent *inKeyRecRep);
+
+/*
+ * FUNCTION: CMMF_DestroyCertifiedKeyPair
+ * INPUTS:
+ * inCertKeyPair
+ * The CMMFCertifiedKeyPair to operate on.
+ * NOTES:
+ * This function frees up all the memory associated with 'inCertKeyPair'
+ *
+ * RETURN:
+ * SECSuccess if freeing all the memory associated with 'inCertKeyPair'
+ * is successful. Any other return value indicates an error while trying
+ * to free the memory.
+ */
+extern SECStatus
+CMMF_DestroyCertifiedKeyPair(CMMFCertifiedKeyPair *inCertKeyPair);
+
+/*
+ * FUNCTION: CMMF_DestroyPOPODecKeyRespContent
+ * INPUTS:
+ * inDecKeyResp
+ * The CMMFPOPODecKeyRespContent structure to free.
+ * NOTES:
+ * This function frees up all the memory associate with the
+ * CMMFPOPODecKeyRespContent.
+ *
+ * RETURN:
+ * SECSuccess if freeing up all the memory associated with the
+ * CMMFPOPODecKeyRespContent structure is successful. Any other
+ * return value indicates an error while freeing the memory.
+ */
+extern SECStatus
+CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent *inDecKeyResp);
+
+/************************** Miscellaneous Functions *************************/
+
+/*
+ * FUNCTION: CMMF_CertifiedKeyPairUnwrapPrivKey
+ * INPUTS:
+ * inCertKeyPair
+ * The CMMFCertifiedKeyPair to operate on.
+ * inPrivKey
+ * The private key to use to un-wrap the private key
+ * inNickName
+ * This is the nickname that will be associated with the private key
+ * to be unwrapped.
+ * inSlot
+ * The PKCS11 slot where the unwrapped private key should end up.
+ * inCertdb
+ * The Certificate database with which the new key will be associated.
+ * destPrivKey
+ * A pointer to memory where the library can place a pointer to the
+ * private key after importing the key onto the specified slot.
+ * wincx
+ * An opaque pointer that the library will use in a callback function
+ * to get the password if necessary.
+ *
+ * NOTES:
+ * This function uses the private key passed in to unwrap the private key
+ * contained within the CMMFCertifiedKeyPair structure. After this
+ * function successfully returns, the private key has been unwrapped and
+ * placed in the specified slot.
+ *
+ * RETURN:
+ * SECSuccess if unwrapping the private key was successful. Any other
+ * return value indicates an error while trying to un-wrap the private key.
+ */
+extern SECStatus
+CMMF_CertifiedKeyPairUnwrapPrivKey(CMMFCertifiedKeyPair *inKeyPair,
+ SECKEYPrivateKey *inPrivKey,
+ SECItem *inNickName,
+ PK11SlotInfo *inSlot,
+ CERTCertDBHandle *inCertdb,
+ SECKEYPrivateKey **destPrivKey,
+ void *wincx);
+
+/*
+ * FUNCTION: CMMF_KeyRecRepContentHasCACerts
+ * INPUTS:
+ * inKeyRecRecp
+ * The CMMFKeyRecRepContent to operate on.
+ * RETURN:
+ * This function returns PR_TRUE if there are one or more certificates in
+ * the sequence KeyRecRepContent.caCerts within the CMMFKeyRecRepContent
+ * structure. The function will return PR_FALSE if there are 0 certificate
+ * in the above mentioned sequence.
+ */
+extern PRBool
+CMMF_KeyRecRepContentHasCACerts(CMMFKeyRecRepContent *inKeyRecRep);
+
+/*
+ * FUNCTION: CMMF_POPODecKeyChallContDecryptChallenge
+ * INPUTS:
+ * inChalCont
+ * The CMMFPOPODecKeyChallContent to operate on.
+ * inIndex
+ * The index of the Challenge to operate on. The 1st Challenge is
+ * at index 0, the second at index 1 and so forth.
+ * inPrivKey
+ * The private key to use to decrypt the witness field.
+ * NOTES:
+ * This function uses the private key to decrypt the challenge field
+ * contained in the appropriate challenge. Make sure the private key matches
+ * the public key that was used to encrypt the witness. Use
+ * CMMF_POPODecKeyChallContentGetPublicValue to get the public value of
+ * the key used to encrypt the witness and then use that to determine the
+ * appropriate private key. This can be done by calling PK11_MakeIDFromPubKey
+ * and then passing that return value to PK11_FindKeyByKeyID. The creator of
+ * the challenge will most likely be an RA that has the public key
+ * from a Cert request. So the private key should be the private key
+ * associated with public key in that request. This function will also
+ * verify the witness field of the challenge. This function also verifies
+ * that the sender and witness hashes match within the challenge.
+ *
+ * RETURN:
+ * SECSuccess if decrypting the witness field was successful. This does
+ * not indicate that the decrypted data is valid, since the private key
+ * passed in may not be the actual key needed to properly decrypt the
+ * witness field. Meaning that there is a decrypted structure now, but
+ * may be garbage because the private key was incorrect.
+ * Any other return value indicates the function could not complete the
+ * decryption process.
+ */
+extern SECStatus
+CMMF_POPODecKeyChallContDecryptChallenge(CMMFPOPODecKeyChallContent *inChalCont,
+ int inIndex,
+ SECKEYPrivateKey *inPrivKey);
+
+/*
+ * FUNCTION: CMMF_DestroyPOPODecKeyChallContent
+ * INPUTS:
+ * inDecKeyCont
+ * The CMMFPOPODecKeyChallContent to free
+ * NOTES:
+ * This function frees up all the memory associated with the
+ * CMMFPOPODecKeyChallContent
+ * RETURN:
+ * SECSuccess if freeing up all the memory associatd with the
+ * CMMFPOPODecKeyChallContent is successful. Any other return value
+ * indicates an error while freeing the memory.
+ *
+ */
+extern SECStatus
+CMMF_DestroyPOPODecKeyChallContent(CMMFPOPODecKeyChallContent *inDecKeyCont);
+
+SEC_END_PROTOS
+#endif /* _CMMF_H_ */
diff --git a/security/nss/lib/crmf/cmmfasn1.c b/security/nss/lib/crmf/cmmfasn1.c
new file mode 100644
index 000000000..64915b339
--- /dev/null
+++ b/security/nss/lib/crmf/cmmfasn1.c
@@ -0,0 +1,131 @@
+/* -*- 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 "cmmf.h"
+#include "cmmfi.h"
+#include "secasn1.h"
+#include "secitem.h"
+
+SEC_ASN1_MKSUB(SEC_SignedCertificateTemplate)
+
+static const SEC_ASN1Template CMMFSequenceOfCertifiedKeyPairsTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, CMMFCertifiedKeyPairTemplate }
+};
+
+static const SEC_ASN1Template CMMFKeyRecRepContentTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFKeyRecRepContent) },
+ { SEC_ASN1_INLINE, offsetof(CMMFKeyRecRepContent, status),
+ CMMFPKIStatusInfoTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER |
+ SEC_ASN1_XTRN | 0,
+ offsetof(CMMFKeyRecRepContent, newSigCert),
+ SEC_ASN1_SUB(SEC_SignedCertificateTemplate) },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ offsetof(CMMFKeyRecRepContent, caCerts),
+ CMMFSequenceOfCertsTemplate },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 2,
+ offsetof(CMMFKeyRecRepContent, keyPairHist),
+ CMMFSequenceOfCertifiedKeyPairsTemplate },
+ { 0 }
+};
+
+SECStatus
+CMMF_EncodeCertRepContent(CMMFCertRepContent *inCertRepContent,
+ CRMFEncoderOutputCallback inCallback,
+ void *inArg)
+{
+ return cmmf_user_encode(inCertRepContent, inCallback, inArg,
+ CMMFCertRepContentTemplate);
+}
+
+SECStatus
+CMMF_EncodePOPODecKeyChallContent(CMMFPOPODecKeyChallContent *inDecKeyChall,
+ CRMFEncoderOutputCallback inCallback,
+ void *inArg)
+{
+ return cmmf_user_encode(inDecKeyChall, inCallback, inArg,
+ CMMFPOPODecKeyChallContentTemplate);
+}
+
+CMMFPOPODecKeyRespContent *
+CMMF_CreatePOPODecKeyRespContentFromDER(const char *buf, long len)
+{
+ PLArenaPool *poolp;
+ CMMFPOPODecKeyRespContent *decKeyResp;
+ SECStatus rv;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ return NULL;
+ }
+ decKeyResp = PORT_ArenaZNew(poolp, CMMFPOPODecKeyRespContent);
+ if (decKeyResp == NULL) {
+ goto loser;
+ }
+ decKeyResp->poolp = poolp;
+ rv = SEC_ASN1Decode(poolp, decKeyResp, CMMFPOPODecKeyRespContentTemplate,
+ buf, len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return decKeyResp;
+
+loser:
+ if (poolp != NULL) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ }
+ return NULL;
+}
+
+SECStatus
+CMMF_EncodeKeyRecRepContent(CMMFKeyRecRepContent *inKeyRecRep,
+ CRMFEncoderOutputCallback inCallback,
+ void *inArg)
+{
+ return cmmf_user_encode(inKeyRecRep, inCallback, inArg,
+ CMMFKeyRecRepContentTemplate);
+}
+
+CMMFKeyRecRepContent *
+CMMF_CreateKeyRecRepContentFromDER(CERTCertDBHandle *db, const char *buf,
+ long len)
+{
+ PLArenaPool *poolp;
+ CMMFKeyRecRepContent *keyRecContent;
+ SECStatus rv;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ return NULL;
+ }
+ keyRecContent = PORT_ArenaZNew(poolp, CMMFKeyRecRepContent);
+ if (keyRecContent == NULL) {
+ goto loser;
+ }
+ keyRecContent->poolp = poolp;
+ rv = SEC_ASN1Decode(poolp, keyRecContent, CMMFKeyRecRepContentTemplate,
+ buf, len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (keyRecContent->keyPairHist != NULL) {
+ while (keyRecContent->keyPairHist[keyRecContent->numKeyPairs] != NULL) {
+ rv = cmmf_decode_process_certified_key_pair(poolp, db,
+ keyRecContent->keyPairHist[keyRecContent->numKeyPairs]);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ keyRecContent->numKeyPairs++;
+ }
+ keyRecContent->allocKeyPairs = keyRecContent->numKeyPairs;
+ }
+ keyRecContent->isDecoded = PR_TRUE;
+ return keyRecContent;
+loser:
+ if (poolp != NULL) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ }
+ return NULL;
+}
diff --git a/security/nss/lib/crmf/cmmfchal.c b/security/nss/lib/crmf/cmmfchal.c
new file mode 100644
index 000000000..2fee983c9
--- /dev/null
+++ b/security/nss/lib/crmf/cmmfchal.c
@@ -0,0 +1,289 @@
+/* -*- 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 "cmmf.h"
+#include "cmmfi.h"
+#include "sechash.h"
+#include "genname.h"
+#include "pk11func.h"
+#include "cert.h"
+#include "secitem.h"
+#include "secmod.h"
+#include "keyhi.h"
+
+static int
+cmmf_create_witness_and_challenge(PLArenaPool *poolp,
+ CMMFChallenge *challenge,
+ long inRandom,
+ SECItem *senderDER,
+ SECKEYPublicKey *inPubKey,
+ void *passwdArg)
+{
+ SECItem *encodedRandNum;
+ SECItem encodedRandStr = { siBuffer, NULL, 0 };
+ SECItem *dummy;
+ unsigned char *randHash, *senderHash, *encChal = NULL;
+ unsigned modulusLen = 0;
+ SECStatus rv = SECFailure;
+ CMMFRand randStr = { { siBuffer, NULL, 0 }, { siBuffer, NULL, 0 } };
+ PK11SlotInfo *slot;
+ PK11SymKey *symKey = NULL;
+ CERTSubjectPublicKeyInfo *spki = NULL;
+
+ encodedRandNum = SEC_ASN1EncodeInteger(poolp, &challenge->randomNumber,
+ inRandom);
+ if (!encodedRandNum) {
+ goto loser;
+ }
+ randHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH);
+ senderHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH);
+ if (randHash == NULL) {
+ goto loser;
+ }
+ rv = PK11_HashBuf(SEC_OID_SHA1, randHash, encodedRandNum->data,
+ (PRUint32)encodedRandNum->len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = PK11_HashBuf(SEC_OID_SHA1, senderHash, senderDER->data,
+ (PRUint32)senderDER->len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ challenge->witness.data = randHash;
+ challenge->witness.len = SHA1_LENGTH;
+
+ randStr.integer = *encodedRandNum;
+ randStr.senderHash.data = senderHash;
+ randStr.senderHash.len = SHA1_LENGTH;
+ dummy = SEC_ASN1EncodeItem(NULL, &encodedRandStr, &randStr,
+ CMMFRandTemplate);
+ if (dummy != &encodedRandStr) {
+ rv = SECFailure;
+ goto loser;
+ }
+ /* XXXX Now I have to encrypt encodedRandStr and stash it away. */
+ modulusLen = SECKEY_PublicKeyStrength(inPubKey);
+ encChal = PORT_ArenaNewArray(poolp, unsigned char, modulusLen);
+ if (encChal == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ slot = PK11_GetBestSlotWithAttributes(CKM_RSA_PKCS, CKF_WRAP, 0, passwdArg);
+ if (slot == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ (void)PK11_ImportPublicKey(slot, inPubKey, PR_FALSE);
+ /* In order to properly encrypt the data, we import as a symmetric
+ * key, and then wrap that key. That in essence encrypts the data.
+ * This is the method recommended in the PK11 world in order
+ * to prevent threading issues as well as breaking any other semantics
+ * the PK11 libraries depend on.
+ */
+ symKey = PK11_ImportSymKey(slot, CKM_RSA_PKCS, PK11_OriginGenerated,
+ CKA_VALUE, &encodedRandStr, passwdArg);
+ if (symKey == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ challenge->challenge.data = encChal;
+ challenge->challenge.len = modulusLen;
+ rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, inPubKey, symKey,
+ &challenge->challenge);
+ PK11_FreeSlot(slot);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(poolp, &challenge->senderDER, senderDER);
+ crmf_get_public_value(inPubKey, &challenge->key);
+/* Fall through */
+loser:
+ if (spki != NULL) {
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ }
+ if (encodedRandStr.data != NULL) {
+ PORT_Free(encodedRandStr.data);
+ }
+ if (encodedRandNum != NULL) {
+ SECITEM_FreeItem(encodedRandNum, PR_TRUE);
+ }
+ if (symKey != NULL) {
+ PK11_FreeSymKey(symKey);
+ }
+ return rv;
+}
+
+static SECStatus
+cmmf_create_first_challenge(CMMFPOPODecKeyChallContent *challContent,
+ long inRandom,
+ SECItem *senderDER,
+ SECKEYPublicKey *inPubKey,
+ void *passwdArg)
+{
+ SECOidData *oidData;
+ CMMFChallenge *challenge;
+ SECAlgorithmID *algId;
+ PLArenaPool *poolp;
+ SECStatus rv;
+
+ oidData = SECOID_FindOIDByTag(SEC_OID_SHA1);
+ if (oidData == NULL) {
+ return SECFailure;
+ }
+ poolp = challContent->poolp;
+ challenge = PORT_ArenaZNew(poolp, CMMFChallenge);
+ if (challenge == NULL) {
+ return SECFailure;
+ }
+ algId = challenge->owf = PORT_ArenaZNew(poolp, SECAlgorithmID);
+ if (algId == NULL) {
+ return SECFailure;
+ }
+ rv = SECITEM_CopyItem(poolp, &algId->algorithm, &oidData->oid);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ rv = cmmf_create_witness_and_challenge(poolp, challenge, inRandom,
+ senderDER, inPubKey, passwdArg);
+ challContent->challenges[0] = (rv == SECSuccess) ? challenge : NULL;
+ challContent->numChallenges++;
+ return rv;
+}
+
+CMMFPOPODecKeyChallContent *
+CMMF_CreatePOPODecKeyChallContent(void)
+{
+ PLArenaPool *poolp;
+ CMMFPOPODecKeyChallContent *challContent;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ return NULL;
+ }
+ challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent);
+ if (challContent == NULL) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ return NULL;
+ }
+ challContent->poolp = poolp;
+ return challContent;
+}
+
+SECStatus
+CMMF_POPODecKeyChallContentSetNextChallenge(CMMFPOPODecKeyChallContent *inDecKeyChall,
+ long inRandom,
+ CERTGeneralName *inSender,
+ SECKEYPublicKey *inPubKey,
+ void *passwdArg)
+{
+ CMMFChallenge *curChallenge;
+ PLArenaPool *genNamePool = NULL, *poolp;
+ SECStatus rv;
+ SECItem *genNameDER;
+ void *mark;
+
+ PORT_Assert(inDecKeyChall != NULL &&
+ inSender != NULL &&
+ inPubKey != NULL);
+
+ if (inDecKeyChall == NULL ||
+ inSender == NULL || inPubKey == NULL) {
+ return SECFailure;
+ }
+ poolp = inDecKeyChall->poolp;
+ mark = PORT_ArenaMark(poolp);
+
+ genNamePool = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ genNameDER = CERT_EncodeGeneralName(inSender, NULL, genNamePool);
+ if (genNameDER == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ if (inDecKeyChall->challenges == NULL) {
+ inDecKeyChall->challenges =
+ PORT_ArenaZNewArray(poolp, CMMFChallenge *, (CMMF_MAX_CHALLENGES + 1));
+ inDecKeyChall->numAllocated = CMMF_MAX_CHALLENGES;
+ }
+
+ if (inDecKeyChall->numChallenges >= inDecKeyChall->numAllocated) {
+ rv = SECFailure;
+ goto loser;
+ }
+
+ if (inDecKeyChall->numChallenges == 0) {
+ rv = cmmf_create_first_challenge(inDecKeyChall, inRandom,
+ genNameDER, inPubKey, passwdArg);
+ } else {
+ curChallenge = PORT_ArenaZNew(poolp, CMMFChallenge);
+ if (curChallenge == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ rv = cmmf_create_witness_and_challenge(poolp, curChallenge, inRandom,
+ genNameDER, inPubKey,
+ passwdArg);
+ if (rv == SECSuccess) {
+ inDecKeyChall->challenges[inDecKeyChall->numChallenges] =
+ curChallenge;
+ inDecKeyChall->numChallenges++;
+ }
+ }
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_ArenaUnmark(poolp, mark);
+ PORT_FreeArena(genNamePool, PR_FALSE);
+ return SECSuccess;
+
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ if (genNamePool != NULL) {
+ PORT_FreeArena(genNamePool, PR_FALSE);
+ }
+ PORT_Assert(rv != SECSuccess);
+ return rv;
+}
+
+SECStatus
+CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent *inDecKeyResp)
+{
+ PORT_Assert(inDecKeyResp != NULL);
+ if (inDecKeyResp != NULL && inDecKeyResp->poolp != NULL) {
+ PORT_FreeArena(inDecKeyResp->poolp, PR_FALSE);
+ }
+ return SECSuccess;
+}
+
+int
+CMMF_POPODecKeyRespContentGetNumResponses(CMMFPOPODecKeyRespContent *inRespCont)
+{
+ int numResponses = 0;
+
+ PORT_Assert(inRespCont != NULL);
+ if (inRespCont == NULL) {
+ return 0;
+ }
+
+ while (inRespCont->responses[numResponses] != NULL) {
+ numResponses++;
+ }
+ return numResponses;
+}
+
+SECStatus
+CMMF_POPODecKeyRespContentGetResponse(CMMFPOPODecKeyRespContent *inRespCont,
+ int inIndex,
+ long *inDest)
+{
+ PORT_Assert(inRespCont != NULL);
+
+ if (inRespCont == NULL || inIndex < 0 ||
+ inIndex >= CMMF_POPODecKeyRespContentGetNumResponses(inRespCont)) {
+ return SECFailure;
+ }
+ *inDest = DER_GetInteger(inRespCont->responses[inIndex]);
+ return (*inDest == -1) ? SECFailure : SECSuccess;
+}
diff --git a/security/nss/lib/crmf/cmmfi.h b/security/nss/lib/crmf/cmmfi.h
new file mode 100644
index 000000000..9336ccfc2
--- /dev/null
+++ b/security/nss/lib/crmf/cmmfi.h
@@ -0,0 +1,92 @@
+/* -*- 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/. */
+
+/*
+ * These are the definitions needed by the library internally to implement
+ * CMMF. Most of these will be helper utilities for manipulating internal
+ * data strucures.
+ */
+#ifndef _CMMFI_H_
+#define _CMMFI_H_
+#include "cmmfit.h"
+#include "crmfi.h"
+
+#define CMMF_MAX_CHALLENGES 10
+#define CMMF_MAX_KEY_PAIRS 50
+
+/*
+ * Some templates that the code will need to implement CMMF.
+ */
+extern const SEC_ASN1Template CMMFCertOrEncCertCertificateTemplate[];
+extern const SEC_ASN1Template CMMFCertOrEncCertEncryptedCertTemplate[];
+extern const SEC_ASN1Template CMMFPOPODecKeyRespContentTemplate[];
+extern const SEC_ASN1Template CMMFRandTemplate[];
+extern const SEC_ASN1Template CMMFSequenceOfCertsTemplate[];
+extern const SEC_ASN1Template CMMFPKIStatusInfoTemplate[];
+extern const SEC_ASN1Template CMMFCertifiedKeyPairTemplate[];
+
+/*
+ * Some utility functions that are shared by multiple files in this
+ * implementation.
+ */
+
+extern SECStatus cmmf_CopyCertResponse(PLArenaPool *poolp,
+ CMMFCertResponse *dest,
+ CMMFCertResponse *src);
+
+extern SECStatus cmmf_CopyPKIStatusInfo(PLArenaPool *poolp,
+ CMMFPKIStatusInfo *dest,
+ CMMFPKIStatusInfo *src);
+
+extern SECStatus cmmf_CopyCertifiedKeyPair(PLArenaPool *poolp,
+ CMMFCertifiedKeyPair *dest,
+ CMMFCertifiedKeyPair *src);
+
+extern SECStatus cmmf_DestroyPKIStatusInfo(CMMFPKIStatusInfo *info,
+ PRBool freeit);
+
+extern SECStatus cmmf_DestroyCertOrEncCert(CMMFCertOrEncCert *certOrEncCert,
+ PRBool freeit);
+
+extern SECStatus cmmf_PKIStatusInfoSetStatus(CMMFPKIStatusInfo *statusInfo,
+ PLArenaPool *poolp,
+ CMMFPKIStatus inStatus);
+
+extern SECStatus cmmf_ExtractCertsFromList(CERTCertList *inCertList,
+ PLArenaPool *poolp,
+ CERTCertificate ***certArray);
+
+extern SECStatus
+cmmf_CertOrEncCertSetCertificate(CMMFCertOrEncCert *certOrEncCert,
+ PLArenaPool *poolp,
+ CERTCertificate *inCert);
+
+extern CMMFPKIStatus
+cmmf_PKIStatusInfoGetStatus(CMMFPKIStatusInfo *inStatus);
+
+extern CERTCertList *
+cmmf_MakeCertList(CERTCertificate **inCerts);
+
+extern CERTCertificate *
+cmmf_CertOrEncCertGetCertificate(CMMFCertOrEncCert *certOrEncCert,
+ CERTCertDBHandle *certdb);
+
+extern SECStatus
+cmmf_decode_process_cert_response(PLArenaPool *poolp,
+ CERTCertDBHandle *db,
+ CMMFCertResponse *inCertResp);
+
+extern SECStatus
+cmmf_decode_process_certified_key_pair(PLArenaPool *poolp,
+ CERTCertDBHandle *db,
+ CMMFCertifiedKeyPair *inCertKeyPair);
+
+extern SECStatus
+cmmf_user_encode(void *src, CRMFEncoderOutputCallback inCallback, void *inArg,
+ const SEC_ASN1Template *inTemplate);
+
+extern SECStatus
+cmmf_copy_secitem(PLArenaPool *poolp, SECItem *dest, SECItem *src);
+#endif /*_CMMFI_H_*/
diff --git a/security/nss/lib/crmf/cmmfit.h b/security/nss/lib/crmf/cmmfit.h
new file mode 100644
index 000000000..014413f07
--- /dev/null
+++ b/security/nss/lib/crmf/cmmfit.h
@@ -0,0 +1,115 @@
+/* -*- 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/. */
+
+#ifndef _CMMFIT_H_
+#define _CMMFIT_H_
+
+/*
+ * All fields marked by a PKIStausInfo in comments is an integer
+ * with the following possible values.
+ *
+ * Integer Value Meaning
+ * ------------- -------
+ * 0 granted- got exactly what you asked for.
+ *
+ * 1 grantedWithMods-got something like what you asked
+ * for;requester is responsible for ascertainging the
+ * differences.
+ *
+ * 2 rejection-you don't get what you asked for; more
+ * information elsewhere in the message
+ *
+ * 3 waiting-the request body part has not yet been
+ * processed, expect to hear more later.
+ *
+ * 4 revocationWarning-this message contains a warning
+ * that a revocation is imminent.
+ *
+ * 5 revocationNotification-notification that a
+ * revocation has occurred.
+ *
+ * 6 keyUpdateWarning-update already done for the
+ * oldCertId specified in FullCertTemplate.
+ */
+
+struct CMMFPKIStatusInfoStr {
+ SECItem status;
+ SECItem statusString;
+ SECItem failInfo;
+};
+
+struct CMMFCertOrEncCertStr {
+ union {
+ CERTCertificate *certificate;
+ CRMFEncryptedValue *encryptedCert;
+ } cert;
+ CMMFCertOrEncCertChoice choice;
+ SECItem derValue;
+};
+
+struct CMMFCertifiedKeyPairStr {
+ CMMFCertOrEncCert certOrEncCert;
+ CRMFEncryptedValue *privateKey;
+ SECItem derPublicationInfo; /* We aren't creating
+ * PKIPublicationInfo's, so
+ * we'll store away the der
+ * here if we decode one that
+ * does have pubInfo.
+ */
+ SECItem unwrappedPrivKey;
+};
+
+struct CMMFCertResponseStr {
+ SECItem certReqId;
+ CMMFPKIStatusInfo status; /*PKIStatusInfo*/
+ CMMFCertifiedKeyPair *certifiedKeyPair;
+};
+
+struct CMMFCertRepContentStr {
+ CERTCertificate **caPubs;
+ CMMFCertResponse **response;
+ PLArenaPool *poolp;
+ PRBool isDecoded;
+};
+
+struct CMMFChallengeStr {
+ SECAlgorithmID *owf;
+ SECItem witness;
+ SECItem senderDER;
+ SECItem key;
+ SECItem challenge;
+ SECItem randomNumber;
+};
+
+struct CMMFRandStr {
+ SECItem integer;
+ SECItem senderHash;
+ CERTGeneralName *sender;
+};
+
+struct CMMFPOPODecKeyChallContentStr {
+ CMMFChallenge **challenges;
+ PLArenaPool *poolp;
+ int numChallenges;
+ int numAllocated;
+};
+
+struct CMMFPOPODecKeyRespContentStr {
+ SECItem **responses;
+ PLArenaPool *poolp;
+};
+
+struct CMMFKeyRecRepContentStr {
+ CMMFPKIStatusInfo status; /* PKIStatusInfo */
+ CERTCertificate *newSigCert;
+ CERTCertificate **caCerts;
+ CMMFCertifiedKeyPair **keyPairHist;
+ PLArenaPool *poolp;
+ int numKeyPairs;
+ int allocKeyPairs;
+ PRBool isDecoded;
+};
+
+#endif /* _CMMFIT_H_ */
diff --git a/security/nss/lib/crmf/cmmfrec.c b/security/nss/lib/crmf/cmmfrec.c
new file mode 100644
index 000000000..5dfe1fcca
--- /dev/null
+++ b/security/nss/lib/crmf/cmmfrec.c
@@ -0,0 +1,316 @@
+/* -*- 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/. */
+
+/*
+ * This file will implement the functions related to key recovery in
+ * CMMF
+ */
+
+#include "cmmf.h"
+#include "cmmfi.h"
+#include "secitem.h"
+#include "keyhi.h"
+
+CMMFKeyRecRepContent *
+CMMF_CreateKeyRecRepContent(void)
+{
+ PLArenaPool *poolp;
+ CMMFKeyRecRepContent *keyRecContent;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ return NULL;
+ }
+ keyRecContent = PORT_ArenaZNew(poolp, CMMFKeyRecRepContent);
+ if (keyRecContent == NULL) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ return NULL;
+ }
+ keyRecContent->poolp = poolp;
+ return keyRecContent;
+}
+
+SECStatus
+CMMF_DestroyKeyRecRepContent(CMMFKeyRecRepContent *inKeyRecRep)
+{
+ PORT_Assert(inKeyRecRep != NULL);
+ if (inKeyRecRep != NULL && inKeyRecRep->poolp != NULL) {
+ int i;
+
+ if (!inKeyRecRep->isDecoded && inKeyRecRep->newSigCert != NULL) {
+ CERT_DestroyCertificate(inKeyRecRep->newSigCert);
+ }
+ if (inKeyRecRep->caCerts != NULL) {
+ for (i = 0; inKeyRecRep->caCerts[i] != NULL; i++) {
+ CERT_DestroyCertificate(inKeyRecRep->caCerts[i]);
+ }
+ }
+ if (inKeyRecRep->keyPairHist != NULL) {
+ for (i = 0; inKeyRecRep->keyPairHist[i] != NULL; i++) {
+ if (inKeyRecRep->keyPairHist[i]->certOrEncCert.choice ==
+ cmmfCertificate) {
+ CERT_DestroyCertificate(inKeyRecRep->keyPairHist[i]->certOrEncCert.cert.certificate);
+ }
+ }
+ }
+ PORT_FreeArena(inKeyRecRep->poolp, PR_TRUE);
+ }
+ return SECSuccess;
+}
+
+SECStatus
+CMMF_KeyRecRepContentSetPKIStatusInfoStatus(CMMFKeyRecRepContent *inKeyRecRep,
+ CMMFPKIStatus inPKIStatus)
+{
+ PORT_Assert(inKeyRecRep != NULL && inPKIStatus >= cmmfGranted &&
+ inPKIStatus < cmmfNumPKIStatus);
+ if (inKeyRecRep == NULL) {
+ return SECFailure;
+ }
+
+ return cmmf_PKIStatusInfoSetStatus(&inKeyRecRep->status,
+ inKeyRecRep->poolp,
+ inPKIStatus);
+}
+
+SECStatus
+CMMF_KeyRecRepContentSetNewSignCert(CMMFKeyRecRepContent *inKeyRecRep,
+ CERTCertificate *inNewSignCert)
+{
+ PORT_Assert(inKeyRecRep != NULL && inNewSignCert != NULL);
+ if (inKeyRecRep == NULL || inNewSignCert == NULL) {
+ return SECFailure;
+ }
+ if (!inKeyRecRep->isDecoded && inKeyRecRep->newSigCert) {
+ CERT_DestroyCertificate(inKeyRecRep->newSigCert);
+ }
+ inKeyRecRep->isDecoded = PR_FALSE;
+ inKeyRecRep->newSigCert = CERT_DupCertificate(inNewSignCert);
+ return (inKeyRecRep->newSigCert == NULL) ? SECFailure : SECSuccess;
+}
+
+SECStatus
+CMMF_KeyRecRepContentSetCACerts(CMMFKeyRecRepContent *inKeyRecRep,
+ CERTCertList *inCACerts)
+{
+ SECStatus rv;
+ void *mark;
+
+ PORT_Assert(inKeyRecRep != NULL && inCACerts != NULL);
+ if (inKeyRecRep == NULL || inCACerts == NULL) {
+ return SECFailure;
+ }
+ mark = PORT_ArenaMark(inKeyRecRep->poolp);
+ rv = cmmf_ExtractCertsFromList(inCACerts, inKeyRecRep->poolp,
+ &inKeyRecRep->caCerts);
+ if (rv != SECSuccess) {
+ PORT_ArenaRelease(inKeyRecRep->poolp, mark);
+ } else {
+ PORT_ArenaUnmark(inKeyRecRep->poolp, mark);
+ }
+ return rv;
+}
+
+SECStatus
+CMMF_KeyRecRepContentSetCertifiedKeyPair(CMMFKeyRecRepContent *inKeyRecRep,
+ CERTCertificate *inCert,
+ SECKEYPrivateKey *inPrivKey,
+ SECKEYPublicKey *inPubKey)
+{
+ CMMFCertifiedKeyPair *keyPair;
+ CRMFEncryptedValue *dummy;
+ PLArenaPool *poolp;
+ void *mark;
+ SECStatus rv;
+
+ PORT_Assert(inKeyRecRep != NULL &&
+ inCert != NULL &&
+ inPrivKey != NULL &&
+ inPubKey != NULL);
+ if (inKeyRecRep == NULL ||
+ inCert == NULL ||
+ inPrivKey == NULL ||
+ inPubKey == NULL) {
+ return SECFailure;
+ }
+ poolp = inKeyRecRep->poolp;
+ mark = PORT_ArenaMark(poolp);
+ if (inKeyRecRep->keyPairHist == NULL) {
+ inKeyRecRep->keyPairHist = PORT_ArenaNewArray(poolp,
+ CMMFCertifiedKeyPair *,
+ (CMMF_MAX_KEY_PAIRS + 1));
+ if (inKeyRecRep->keyPairHist == NULL) {
+ goto loser;
+ }
+ inKeyRecRep->allocKeyPairs = CMMF_MAX_KEY_PAIRS;
+ inKeyRecRep->numKeyPairs = 0;
+ }
+
+ if (inKeyRecRep->allocKeyPairs == inKeyRecRep->numKeyPairs) {
+ goto loser;
+ }
+
+ keyPair = PORT_ArenaZNew(poolp, CMMFCertifiedKeyPair);
+ if (keyPair == NULL) {
+ goto loser;
+ }
+ rv = cmmf_CertOrEncCertSetCertificate(&keyPair->certOrEncCert,
+ poolp, inCert);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ keyPair->privateKey = PORT_ArenaZNew(poolp, CRMFEncryptedValue);
+ if (keyPair->privateKey == NULL) {
+ goto loser;
+ }
+ dummy = crmf_create_encrypted_value_wrapped_privkey(inPrivKey, inPubKey,
+ keyPair->privateKey);
+ PORT_Assert(dummy == keyPair->privateKey);
+ if (dummy != keyPair->privateKey) {
+ crmf_destroy_encrypted_value(dummy, PR_TRUE);
+ goto loser;
+ }
+ inKeyRecRep->keyPairHist[inKeyRecRep->numKeyPairs] = keyPair;
+ inKeyRecRep->numKeyPairs++;
+ inKeyRecRep->keyPairHist[inKeyRecRep->numKeyPairs] = NULL;
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ return SECFailure;
+}
+
+CMMFPKIStatus
+CMMF_KeyRecRepContentGetPKIStatusInfoStatus(CMMFKeyRecRepContent *inKeyRecRep)
+{
+ PORT_Assert(inKeyRecRep != NULL);
+ if (inKeyRecRep == NULL) {
+ return cmmfNoPKIStatus;
+ }
+ return cmmf_PKIStatusInfoGetStatus(&inKeyRecRep->status);
+}
+
+CERTCertificate *
+CMMF_KeyRecRepContentGetNewSignCert(CMMFKeyRecRepContent *inKeyRecRep)
+{
+ PORT_Assert(inKeyRecRep != NULL);
+ if (inKeyRecRep == NULL ||
+ inKeyRecRep->newSigCert == NULL) {
+ return NULL;
+ }
+ /* newSigCert may not be a real certificate, it may be a hand decoded
+ * cert structure. This code makes sure we hand off a real, fully formed
+ * CERTCertificate to the caller. TODO: This should move into the decode
+ * portion so that we never wind up with a half formed CERTCertificate
+ * here. In this case the call would be to CERT_DupCertificate.
+ */
+ return CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
+ &inKeyRecRep->newSigCert->signatureWrap.data,
+ NULL, PR_FALSE, PR_TRUE);
+}
+
+CERTCertList *
+CMMF_KeyRecRepContentGetCACerts(CMMFKeyRecRepContent *inKeyRecRep)
+{
+ PORT_Assert(inKeyRecRep != NULL);
+ if (inKeyRecRep == NULL || inKeyRecRep->caCerts == NULL) {
+ return NULL;
+ }
+ return cmmf_MakeCertList(inKeyRecRep->caCerts);
+}
+
+int
+CMMF_KeyRecRepContentGetNumKeyPairs(CMMFKeyRecRepContent *inKeyRecRep)
+{
+ PORT_Assert(inKeyRecRep != NULL);
+ return (inKeyRecRep == NULL) ? 0 : inKeyRecRep->numKeyPairs;
+}
+
+PRBool
+cmmf_KeyRecRepContentIsValidIndex(CMMFKeyRecRepContent *inKeyRecRep,
+ int inIndex)
+{
+ int numKeyPairs = CMMF_KeyRecRepContentGetNumKeyPairs(inKeyRecRep);
+
+ return (PRBool)(inIndex >= 0 && inIndex < numKeyPairs);
+}
+
+CMMFCertifiedKeyPair *
+CMMF_KeyRecRepContentGetCertKeyAtIndex(CMMFKeyRecRepContent *inKeyRecRep,
+ int inIndex)
+{
+ CMMFCertifiedKeyPair *newKeyPair;
+ SECStatus rv;
+
+ PORT_Assert(inKeyRecRep != NULL &&
+ cmmf_KeyRecRepContentIsValidIndex(inKeyRecRep, inIndex));
+ if (inKeyRecRep == NULL ||
+ !cmmf_KeyRecRepContentIsValidIndex(inKeyRecRep, inIndex)) {
+ return NULL;
+ }
+ newKeyPair = PORT_ZNew(CMMFCertifiedKeyPair);
+ if (newKeyPair == NULL) {
+ return NULL;
+ }
+ rv = cmmf_CopyCertifiedKeyPair(NULL, newKeyPair,
+ inKeyRecRep->keyPairHist[inIndex]);
+ if (rv != SECSuccess) {
+ CMMF_DestroyCertifiedKeyPair(newKeyPair);
+ newKeyPair = NULL;
+ }
+ return newKeyPair;
+}
+
+SECStatus
+CMMF_CertifiedKeyPairUnwrapPrivKey(CMMFCertifiedKeyPair *inKeyPair,
+ SECKEYPrivateKey *inPrivKey,
+ SECItem *inNickName,
+ PK11SlotInfo *inSlot,
+ CERTCertDBHandle *inCertdb,
+ SECKEYPrivateKey **destPrivKey,
+ void *wincx)
+{
+ CERTCertificate *cert;
+ SECItem keyUsageValue = { siBuffer, NULL, 0 };
+ unsigned char keyUsage = 0x0;
+ SECKEYPublicKey *pubKey;
+ SECStatus rv;
+
+ PORT_Assert(inKeyPair != NULL &&
+ inPrivKey != NULL && inCertdb != NULL);
+ if (inKeyPair == NULL ||
+ inPrivKey == NULL ||
+ inKeyPair->privateKey == NULL ||
+ inCertdb == NULL) {
+ return SECFailure;
+ }
+
+ cert = CMMF_CertifiedKeyPairGetCertificate(inKeyPair, inCertdb);
+ CERT_FindKeyUsageExtension(cert, &keyUsageValue);
+ if (keyUsageValue.data != NULL) {
+ keyUsage = keyUsageValue.data[3];
+ PORT_Free(keyUsageValue.data);
+ }
+ pubKey = CERT_ExtractPublicKey(cert);
+ rv = crmf_encrypted_value_unwrap_priv_key(NULL, inKeyPair->privateKey,
+ inPrivKey, pubKey,
+ inNickName, inSlot, keyUsage,
+ destPrivKey, wincx);
+ SECKEY_DestroyPublicKey(pubKey);
+ CERT_DestroyCertificate(cert);
+ return rv;
+}
+
+PRBool
+CMMF_KeyRecRepContentHasCACerts(CMMFKeyRecRepContent *inKeyRecRep)
+{
+ PORT_Assert(inKeyRecRep != NULL);
+ if (inKeyRecRep == NULL) {
+ return PR_FALSE;
+ }
+ return (PRBool)(inKeyRecRep->caCerts != NULL &&
+ inKeyRecRep->caCerts[0] != NULL);
+}
diff --git a/security/nss/lib/crmf/cmmfresp.c b/security/nss/lib/crmf/cmmfresp.c
new file mode 100644
index 000000000..c4b59b8e9
--- /dev/null
+++ b/security/nss/lib/crmf/cmmfresp.c
@@ -0,0 +1,280 @@
+/* -*- 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/. */
+
+/*
+ * This file will contain all routines dealing with creating a
+ * CMMFCertRepContent structure through Create/Set functions.
+ */
+
+#include "cmmf.h"
+#include "cmmfi.h"
+#include "crmf.h"
+#include "crmfi.h"
+#include "secitem.h"
+#include "secder.h"
+
+CMMFCertRepContent *
+CMMF_CreateCertRepContent(void)
+{
+ CMMFCertRepContent *retCertRep;
+ PLArenaPool *poolp;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ goto loser;
+ }
+ retCertRep = PORT_ArenaZNew(poolp, CMMFCertRepContent);
+ if (retCertRep == NULL) {
+ goto loser;
+ }
+ retCertRep->poolp = poolp;
+ return retCertRep;
+loser:
+ if (poolp != NULL) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ }
+ return NULL;
+}
+
+SECStatus
+cmmf_CertOrEncCertSetCertificate(CMMFCertOrEncCert *certOrEncCert,
+ PLArenaPool *poolp,
+ CERTCertificate *inCert)
+{
+ SECItem *derDest = NULL;
+ SECStatus rv = SECFailure;
+
+ if (inCert->derCert.data == NULL) {
+ derDest = SEC_ASN1EncodeItem(NULL, NULL, inCert,
+ CMMFCertOrEncCertCertificateTemplate);
+ if (derDest == NULL) {
+ goto loser;
+ }
+ } else {
+ derDest = SECITEM_DupItem(&inCert->derCert);
+ if (derDest == NULL) {
+ goto loser;
+ }
+ }
+ PORT_Assert(certOrEncCert->cert.certificate == NULL);
+ certOrEncCert->cert.certificate = CERT_DupCertificate(inCert);
+ certOrEncCert->choice = cmmfCertificate;
+ if (poolp != NULL) {
+ rv = SECITEM_CopyItem(poolp, &certOrEncCert->derValue, derDest);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ } else {
+ certOrEncCert->derValue = *derDest;
+ }
+ PORT_Free(derDest);
+ return SECSuccess;
+loser:
+ if (derDest != NULL) {
+ SECITEM_FreeItem(derDest, PR_TRUE);
+ }
+ return rv;
+}
+
+SECStatus
+cmmf_ExtractCertsFromList(CERTCertList *inCertList,
+ PLArenaPool *poolp,
+ CERTCertificate ***certArray)
+{
+ CERTCertificate **arrayLocalCopy;
+ CERTCertListNode *node;
+ int numNodes = 0, i;
+
+ for (node = CERT_LIST_HEAD(inCertList); !CERT_LIST_END(node, inCertList);
+ node = CERT_LIST_NEXT(node)) {
+ numNodes++;
+ }
+
+ arrayLocalCopy = *certArray = (poolp == NULL) ? PORT_NewArray(CERTCertificate *, (numNodes + 1)) : PORT_ArenaNewArray(poolp, CERTCertificate *, (numNodes + 1));
+ if (arrayLocalCopy == NULL) {
+ return SECFailure;
+ }
+ for (node = CERT_LIST_HEAD(inCertList), i = 0;
+ !CERT_LIST_END(node, inCertList);
+ node = CERT_LIST_NEXT(node), i++) {
+ arrayLocalCopy[i] = CERT_DupCertificate(node->cert);
+ if (arrayLocalCopy[i] == NULL) {
+ int j;
+
+ for (j = 0; j < i; j++) {
+ CERT_DestroyCertificate(arrayLocalCopy[j]);
+ }
+ if (poolp == NULL) {
+ PORT_Free(arrayLocalCopy);
+ }
+ *certArray = NULL;
+ return SECFailure;
+ }
+ }
+ arrayLocalCopy[numNodes] = NULL;
+ return SECSuccess;
+}
+
+SECStatus
+CMMF_CertRepContentSetCertResponses(CMMFCertRepContent *inCertRepContent,
+ CMMFCertResponse **inCertResponses,
+ int inNumResponses)
+{
+ PLArenaPool *poolp;
+ CMMFCertResponse **respArr, *newResp;
+ void *mark;
+ SECStatus rv;
+ int i;
+
+ PORT_Assert(inCertRepContent != NULL &&
+ inCertResponses != NULL &&
+ inNumResponses > 0);
+ if (inCertRepContent == NULL ||
+ inCertResponses == NULL ||
+ inCertRepContent->response != NULL) {
+ return SECFailure;
+ }
+ poolp = inCertRepContent->poolp;
+ mark = PORT_ArenaMark(poolp);
+ respArr = inCertRepContent->response =
+ PORT_ArenaZNewArray(poolp, CMMFCertResponse *, (inNumResponses + 1));
+ if (respArr == NULL) {
+ goto loser;
+ }
+ for (i = 0; i < inNumResponses; i++) {
+ newResp = PORT_ArenaZNew(poolp, CMMFCertResponse);
+ if (newResp == NULL) {
+ goto loser;
+ }
+ rv = cmmf_CopyCertResponse(poolp, newResp, inCertResponses[i]);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ respArr[i] = newResp;
+ }
+ respArr[inNumResponses] = NULL;
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ return SECFailure;
+}
+
+CMMFCertResponse *
+CMMF_CreateCertResponse(long inCertReqId)
+{
+ SECItem *dummy;
+ CMMFCertResponse *newResp;
+
+ newResp = PORT_ZNew(CMMFCertResponse);
+ if (newResp == NULL) {
+ goto loser;
+ }
+ dummy = SEC_ASN1EncodeInteger(NULL, &newResp->certReqId, inCertReqId);
+ if (dummy != &newResp->certReqId) {
+ goto loser;
+ }
+ return newResp;
+
+loser:
+ if (newResp != NULL) {
+ CMMF_DestroyCertResponse(newResp);
+ }
+ return NULL;
+}
+
+SECStatus
+CMMF_CertResponseSetPKIStatusInfoStatus(CMMFCertResponse *inCertResp,
+ CMMFPKIStatus inPKIStatus)
+{
+ PORT_Assert(inCertResp != NULL && inPKIStatus >= cmmfGranted &&
+ inPKIStatus < cmmfNumPKIStatus);
+
+ if (inCertResp == NULL) {
+ return SECFailure;
+ }
+ return cmmf_PKIStatusInfoSetStatus(&inCertResp->status, NULL,
+ inPKIStatus);
+}
+
+SECStatus
+CMMF_CertResponseSetCertificate(CMMFCertResponse *inCertResp,
+ CERTCertificate *inCertificate)
+{
+ CMMFCertifiedKeyPair *keyPair = NULL;
+ SECStatus rv = SECFailure;
+
+ PORT_Assert(inCertResp != NULL && inCertificate != NULL);
+ if (inCertResp == NULL || inCertificate == NULL) {
+ return SECFailure;
+ }
+ if (inCertResp->certifiedKeyPair == NULL) {
+ keyPair = inCertResp->certifiedKeyPair =
+ PORT_ZNew(CMMFCertifiedKeyPair);
+ } else {
+ keyPair = inCertResp->certifiedKeyPair;
+ }
+ if (keyPair == NULL) {
+ goto loser;
+ }
+ rv = cmmf_CertOrEncCertSetCertificate(&keyPair->certOrEncCert, NULL,
+ inCertificate);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return SECSuccess;
+loser:
+ if (keyPair) {
+ if (keyPair->certOrEncCert.derValue.data) {
+ PORT_Free(keyPair->certOrEncCert.derValue.data);
+ }
+ PORT_Free(keyPair);
+ }
+ return rv;
+}
+
+SECStatus
+CMMF_CertRepContentSetCAPubs(CMMFCertRepContent *inCertRepContent,
+ CERTCertList *inCAPubs)
+{
+ PLArenaPool *poolp;
+ void *mark;
+ SECStatus rv;
+
+ PORT_Assert(inCertRepContent != NULL &&
+ inCAPubs != NULL &&
+ inCertRepContent->caPubs == NULL);
+
+ if (inCertRepContent == NULL ||
+ inCAPubs == NULL || inCertRepContent == NULL) {
+ return SECFailure;
+ }
+
+ poolp = inCertRepContent->poolp;
+ mark = PORT_ArenaMark(poolp);
+
+ rv = cmmf_ExtractCertsFromList(inCAPubs, poolp,
+ &inCertRepContent->caPubs);
+
+ if (rv != SECSuccess) {
+ PORT_ArenaRelease(poolp, mark);
+ } else {
+ PORT_ArenaUnmark(poolp, mark);
+ }
+ return rv;
+}
+
+CERTCertificate *
+CMMF_CertifiedKeyPairGetCertificate(CMMFCertifiedKeyPair *inCertKeyPair,
+ CERTCertDBHandle *inCertdb)
+{
+ PORT_Assert(inCertKeyPair != NULL);
+ if (inCertKeyPair == NULL) {
+ return NULL;
+ }
+ return cmmf_CertOrEncCertGetCertificate(&inCertKeyPair->certOrEncCert,
+ inCertdb);
+}
diff --git a/security/nss/lib/crmf/cmmft.h b/security/nss/lib/crmf/cmmft.h
new file mode 100644
index 000000000..e39f19ed3
--- /dev/null
+++ b/security/nss/lib/crmf/cmmft.h
@@ -0,0 +1,73 @@
+/* -*- 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/. */
+
+#ifndef _CMMFT_H_
+#define _CMMFT_H_
+
+#include "secasn1.h"
+
+/*
+ * These are the enumerations used to distinguish between the different
+ * choices available for the CMMFCertOrEncCert structure.
+ */
+typedef enum {
+ cmmfNoCertOrEncCert = 0,
+ cmmfCertificate = 1,
+ cmmfEncryptedCert = 2
+} CMMFCertOrEncCertChoice;
+
+/*
+ * This is the enumeration and the corresponding values used to
+ * represent the CMMF type PKIStatus
+ */
+typedef enum {
+ cmmfNoPKIStatus = -1,
+ cmmfGranted = 0,
+ cmmfGrantedWithMods = 1,
+ cmmfRejection = 2,
+ cmmfWaiting = 3,
+ cmmfRevocationWarning = 4,
+ cmmfRevocationNotification = 5,
+ cmmfKeyUpdateWarning = 6,
+ cmmfNumPKIStatus
+} CMMFPKIStatus;
+
+/*
+ * These enumerations are used to represent the corresponding values
+ * in PKIFailureInfo defined in CMMF.
+ */
+typedef enum {
+ cmmfBadAlg = 0,
+ cmmfBadMessageCheck = 1,
+ cmmfBadRequest = 2,
+ cmmfBadTime = 3,
+ cmmfBadCertId = 4,
+ cmmfBadDataFormat = 5,
+ cmmfWrongAuthority = 6,
+ cmmfIncorrectData = 7,
+ cmmfMissingTimeStamp = 8,
+ cmmfNoFailureInfo = 9
+} CMMFPKIFailureInfo;
+
+typedef struct CMMFPKIStatusInfoStr CMMFPKIStatusInfo;
+typedef struct CMMFCertOrEncCertStr CMMFCertOrEncCert;
+typedef struct CMMFCertifiedKeyPairStr CMMFCertifiedKeyPair;
+typedef struct CMMFCertResponseStr CMMFCertResponse;
+typedef struct CMMFCertResponseSeqStr CMMFCertResponseSeq;
+typedef struct CMMFPOPODecKeyChallContentStr CMMFPOPODecKeyChallContent;
+typedef struct CMMFChallengeStr CMMFChallenge;
+typedef struct CMMFRandStr CMMFRand;
+typedef struct CMMFPOPODecKeyRespContentStr CMMFPOPODecKeyRespContent;
+typedef struct CMMFKeyRecRepContentStr CMMFKeyRecRepContent;
+typedef struct CMMFCertRepContentStr CMMFCertRepContent;
+
+/* Export this so people can call SEC_ASN1EncodeItem instead of having to
+ * write callbacks that are passed in to the high level encode function
+ * for CMMFCertRepContent.
+ */
+extern const SEC_ASN1Template CMMFCertRepContentTemplate[];
+extern const SEC_ASN1Template CMMFPOPODecKeyChallContentTemplate[];
+
+#endif /*_CMMFT_H_*/
diff --git a/security/nss/lib/crmf/config.mk b/security/nss/lib/crmf/config.mk
new file mode 100644
index 000000000..dc39ee4d6
--- /dev/null
+++ b/security/nss/lib/crmf/config.mk
@@ -0,0 +1,16 @@
+#
+# 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/.
+
+
+#
+# Override TARGETS variable so that only static libraries
+# are specifed as dependencies within rules.mk.
+#
+
+TARGETS = $(LIBRARY)
+SHARED_LIBRARY =
+IMPORT_LIBRARY =
+PROGRAM =
+
diff --git a/security/nss/lib/crmf/crmf.gyp b/security/nss/lib/crmf/crmf.gyp
new file mode 100644
index 000000000..f8fa8a48d
--- /dev/null
+++ b/security/nss/lib/crmf/crmf.gyp
@@ -0,0 +1,43 @@
+# 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/.
+{
+ 'includes': [
+ '../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'crmf',
+ 'type': 'static_library',
+ 'sources': [
+ 'asn1cmn.c',
+ 'challcli.c',
+ 'cmmfasn1.c',
+ 'cmmfchal.c',
+ 'cmmfrec.c',
+ 'cmmfresp.c',
+ 'crmfcont.c',
+ 'crmfdec.c',
+ 'crmfenc.c',
+ 'crmfget.c',
+ 'crmfpop.c',
+ 'crmfreq.c',
+ 'crmftmpl.c',
+ 'encutil.c',
+ 'respcli.c',
+ 'respcmn.c',
+ 'servget.c'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ],
+ 'variables': {
+ # This is purely for the use of the Mozilla build system.
+ 'no_expand_libs': 1,
+ },
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/security/nss/lib/crmf/crmf.h b/security/nss/lib/crmf/crmf.h
new file mode 100644
index 000000000..c56e28913
--- /dev/null
+++ b/security/nss/lib/crmf/crmf.h
@@ -0,0 +1,1741 @@
+/* -*- 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/. */
+
+#ifndef _CRMF_H_
+#define _CRMF_H_
+
+#include "seccomon.h"
+#include "cert.h"
+#include "crmft.h"
+#include "secoid.h"
+#include "secpkcs7.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+ * FUNCTION: CRMF_EncodeCertReqMsg
+ * INPUTS:
+ * inCertReqMsg
+ * The Certificate Request Message to be encoded.
+ * fn
+ * A Callback function that the ASN1 encoder calls whenever
+ * the encoder wants to write out some DER encoded bytes.
+ * arg
+ * An opaque pointer that gets passed to the function fn
+ * OUTPUT:
+ * The function fn will be called multiple times. Look at the
+ * comments in crmft.h where the CRMFEncoderOutputCallback type is
+ * defined for information on proper behavior of the function fn.
+ * RETURN:
+ * SECSuccess if encoding was successful. Any other return value
+ * indicates an error occurred during encoding.
+ */
+extern SECStatus
+CRMF_EncodeCertReqMsg(CRMFCertReqMsg *inCertReqMsg,
+ CRMFEncoderOutputCallback fn,
+ void *arg);
+
+/*
+ * FUNCTION: CRMF_EncoderCertRequest
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to be encoded.
+ * fn
+ * A Callback function that the ASN1 encoder calls whenever
+ * the encoder wants to write out some DER encoded bytes.
+ * arg
+ * An opaque pointer that gets passed to the function fn.
+ * OUTPUT:
+ * The function fn will be called, probably multiple times whenever
+ * the ASN1 encoder wants to write out DER-encoded bytes. Look at the
+ * comments in crmft.h where the CRMFEncoderOutputCallback type is
+ * defined for information on proper behavior of the function fn.
+ * RETURN:
+ * SECSuccess if encoding was successful. Any other return value
+ * indicates an error occurred during encoding.
+ */
+extern SECStatus CRMF_EncodeCertRequest(CRMFCertRequest *inCertReq,
+ CRMFEncoderOutputCallback fn,
+ void *arg);
+/*
+ * FUNCTION: CRMF_EncodeCertReqMessages
+ * INPUTS:
+ * inCertReqMsgs
+ * An array of pointers to the Certificate Request Messages
+ * to encode. The user must place a NULL pointer in the index
+ * after the last message to be encoded. When the library runs
+ * into the NULL pointer, the library assumes there are no more
+ * messages to encode.
+ * fn
+ * A Callback function that the ASN1 encoder calls whenever
+ * the encoder wants to write out some DER encoded byts.
+ * arg
+ * An opaque pointer that gets passed to the function fn.
+ *
+ * NOTES:
+ * The parameter inCertReqMsgs needs to be an array with a NULL pointer
+ * to signal the end of messages. An array in the form of
+ * {m1, m2, m3, NULL, m4, ...} will only encode the messages m1, m2, and
+ * m3. All messages from m4 on will not be looked at by the library.
+ *
+ * OUTPUT:
+ * The function fn will be called, probably multiple times. Look at the
+ * comments in crmft.h where the CRMFEncoderOutputCallback type is
+ * defined for information on proper behavior of the function fn.
+ *
+ * RETURN:
+ * SECSuccess if encoding the Certificate Request Messages was successful.
+ * Any other return value indicates an error occurred while encoding the
+ * certificate request messages.
+ */
+extern SECStatus
+CRMF_EncodeCertReqMessages(CRMFCertReqMsg **inCertReqMsgs,
+ CRMFEncoderOutputCallback fn,
+ void *arg);
+
+/*
+ * FUNCTION: CRMF_CreateCertReqMsg
+ * INPUTS:
+ * NONE
+ * OUTPUT:
+ * An empty CRMF Certificate Request Message.
+ * Before encoding this message, the user must set
+ * the ProofOfPossession field and the certificate
+ * request which are necessary for the full message.
+ * After the user no longer needs this CertReqMsg,
+ * the user must call CRMF_DestroyCertReqMsg to free
+ * all memory associated with the Certificate Request
+ * Message.
+ * RETURN:
+ * A pointer to a Certificate Request Message. The user
+ * must pass the return value of this function to
+ * CRMF_DestroyCertReqMsg after the Certificate Request
+ * Message is no longer necessary.
+ */
+extern CRMFCertReqMsg *CRMF_CreateCertReqMsg(void);
+
+/*
+ * FUNCTION: CRMF_DestroyCertReqMsg
+ * INPUTS:
+ * inCertReqMsg
+ * The Certificate Request Message to destroy.
+ * NOTES:
+ * This function frees all the memory used for the Certificate
+ * Request Message and all the memory used in making copies of
+ * fields of elelments of the message, eg. the Proof Of Possession
+ * filed and the Cetificate Request.
+ * RETURN:
+ * SECSuccess if destruction was successful. Any other return value
+ * indicates an error while trying to free the memory associated
+ * with inCertReqMsg.
+ *
+ */
+extern SECStatus CRMF_DestroyCertReqMsg(CRMFCertReqMsg *inCertReqMsg);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgSetCertRequest
+ * INPUTS:
+ * inCertReqMsg
+ * The Certificate Request Message that the function will set
+ * the certificate request for.
+ * inCertReq
+ * The Certificate Request that will be added to the Certificate
+ * Request Message.
+ * NOTES:
+ * This function will make a copy of the Certificate Request passed in
+ * and store it as part of the Certificate Request Message. Therefore,
+ * the user must not call this function until the Certificate Request
+ * has been fully built and is ready to be encoded.
+ * RETURN:
+ * SECSuccess
+ * If copying the Certificate as a member of the Certificate
+ * request message was successful.
+ * Any other return value indicates a failure to copy the Certificate
+ * Request and make it a part of the Certificate Request Message.
+ */
+extern SECStatus CRMF_CertReqMsgSetCertRequest(CRMFCertReqMsg *inCertReqMsg,
+ CRMFCertRequest *inCertReq);
+
+/*
+ * FUNCTION: CRMF_CreateCertRequest
+ * INPUTS:
+ * inRequestID
+ * The ID that will be associated with this certificate request.
+ * OUTPUTS:
+ * A certificate request which only has the requestID set.
+ * NOTES:
+ * The user must call the function CRMF_DestroyCertRequest when
+ * the returned value is no longer needed. This is usually the
+ * case after fully constructing the Certificate Request and then
+ * calling the function CRMF_CertReqMsgSetCertRequest.
+ * RETURN:
+ * A pointer to the new Certificate Request. A NULL return value
+ * indicates an error in creating the Certificate Request.
+ */
+extern CRMFCertRequest *CRMF_CreateCertRequest(PRUint32 inRequestID);
+
+/*
+ * FUNCTION: CRMF_DestroyCertRequest
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request that will be destroyed.
+ * RETURN:
+ * SECSuccess
+ * If freeing the memory associated with the certificate request
+ * was successful.
+ * Any other return value indicates an error while trying to free the
+ * memory.
+ */
+extern SECStatus CRMF_DestroyCertRequest(CRMFCertRequest *inCertReq);
+
+/*
+ * FUNCTION: CRMF_CreateCertExtension
+ * INPUTS:
+ * id
+ * The SECOidTag to associate with this CertExtension. This must
+ * correspond to a valid Certificate Extension, if not the function
+ * will fail.
+ * isCritical
+ * A boolean value stating if the extension value is crtical. PR_TRUE
+ * means the value is crtical. PR_FALSE indicates the value is not
+ * critical.
+ * data
+ * This is the data associated with the extension. The user of the
+ * library is responsible for making sure the value passed in is a
+ * valid interpretation of the certificate extension.
+ * NOTES:
+ * Use this function to create CRMFCertExtension Structures which will
+ * then be passed to CRMF_AddFieldToCertTemplate as part of the
+ * CRMFCertCreationInfo.extensions The user must call
+ * CRMF_DestroyCertExtension after the extension has been added to a certifcate
+ * and the extension is no longer needed.
+ *
+ * RETURN:
+ * A pointer to a newly created CertExtension. A return value of NULL
+ * indicates the id passed in was an invalid certificate extension.
+ */
+extern CRMFCertExtension *CRMF_CreateCertExtension(SECOidTag id,
+ PRBool isCritical,
+ SECItem *data);
+
+/*
+ * FUNCTION: CMRF_DestroyCertExtension
+ * INPUTS:
+ * inExtension
+ * The Cert Extension to destroy
+ * NOTES:
+ * Destroy a structure allocated by CRMF_CreateCertExtension.
+ *
+ * RETURN:
+ * SECSuccess if freeing the memory associated with the certificate extension
+ * was successful. Any other error indicates an error while freeing the
+ * memory.
+ */
+extern SECStatus CRMF_DestroyCertExtension(CRMFCertExtension *inExtension);
+
+/*
+ * FUNCTION: CRMF_CertRequestSetTemplateField
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to operate on.
+ * inTemplateField
+ * An enumeration that indicates which field of the Certificate
+ * template to add.
+ * data
+ * A generic pointer that will be type cast according to the
+ * table under NOTES and used as the key for adding to the
+ * certificate template;
+ * NOTES:
+ *
+ * Below is a table that tells what type to pass in as data
+ * depending on the template field one wants to set.
+ *
+ * Look in crmft.h for the definition of CRMFCertTemplateField.
+ *
+ * In all cases, the library makes copies of the data passed in.
+ *
+ * CRMFCertTemplateField Type of data What data means
+ * --------------------- ------------ ---------------
+ * crmfVersion long * The version of
+ * the certificate
+ * to be created.
+ *
+ * crmfSerialNumber long * The serial number
+ * for the cert to be
+ * created.
+ *
+ * crmfSigningAlg SECAlgorithm * The ASN.1 object ID for
+ * the algorithm used in encoding
+ * the certificate.
+ *
+ * crmfIssuer CERTName * Certificate Library
+ * representation of the ASN1 type
+ * Name from X.509
+ *
+ * crmfValidity CRMFValidityCreationInfo * At least one of the two
+ * fields in the structure must
+ * be present. A NULL pointer
+ * in the structure indicates
+ * that member should not be
+ * added.
+ *
+ * crmfSubject CERTName * Certificate Library
+ * representation of the ASN1 type
+ * Name from X.509
+ *
+ * crmfPublicKey CERTSubjectPublicKeyInfo * The public key info for the
+ * certificate being requested.
+ *
+ * crmfIssuerUID SECItem * A bit string representation
+ * of the issuer UID. NOTE: The
+ * length is the number of bits
+ * and not the number of bytes.
+ *
+ * crmfSubjectUID SECItem* A bit string representation
+ * of the subject UID. NOTE: The
+ * length is the number of bits
+ * and not the number of bytes.
+ *
+ * crmfExtension CRMFCertExtCreationInfo * A pointer to the structure
+ * populated with an array of
+ * of certificate extensions
+ * and an integer that tells
+ * how many elements are in the
+ * array. Look in crmft.h for
+ * the definition of
+ * CRMFCertExtCreationInfo
+ * RETURN:
+ * SECSuccess if adding the desired field to the template was successful.
+ * Any other return value indicates failure when trying to add the field
+ * to the template.
+ *
+ */
+extern SECStatus
+CRMF_CertRequestSetTemplateField(CRMFCertRequest *inCertReq,
+ CRMFCertTemplateField inTemplateField,
+ void *data);
+
+/*
+ * FUNCTION: CRMF_CertRequestIsFieldPresent
+ * INPUTS:
+ * inCertReq
+ * The certificate request to operate on.
+ * inTemplateField
+ * The enumeration for the template field the user wants to query
+ * about.
+ * NOTES:
+ * This function checks to see if the the field associated with inTemplateField
+ * enumeration is already present in the certificate request passed in.
+ *
+ * RETURN:
+ * The function returns PR_TRUE if the field associated with inTemplateField
+ * is already present in the certificate request. If the field is not present
+ * the function returns PR_FALSE.
+ */
+extern PRBool
+CRMF_CertRequestIsFieldPresent(CRMFCertRequest *inCertReq,
+ CRMFCertTemplateField inTemplateField);
+
+/*
+ * FUNCTION: CRMF_CertRequestIsControlPresent
+ * INPUTS:
+ * inCertReq
+ * The certificate request to operate on.
+ * inControlType
+ * The type of control to look for.
+ * NOTES:
+ * This function looks at the control present in the certificate request
+ * and returns PR_TRUE iff a control of type inControlType already exists.
+ * The CRMF draft does not explicitly state that two controls of the same
+ * type can not exist within the same request. So the library will not
+ * cause an error if you try to add a control and one of the same type
+ * already exists. It is up to the application to ensure that multiple
+ * controls of the same type do not exist, if that is the desired behavior
+ * by the application.
+ *
+ * RETURN:
+ * The function returns PR_TRUE if a control of type inControlType already
+ * exists in the certificate request. If a control of type inControlType
+ * does not exist, the function will return PR_FALSE.
+ */
+extern PRBool
+CRMF_CertRequestIsControlPresent(CRMFCertRequest *inCertReq,
+ CRMFControlType inControlType);
+
+/*
+ * FUNCTION: CRMF_CertRequestSetRegTokenControl
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to operate on.
+ * value
+ * The UTF8 value which will be the Registration Token Control
+ * for this Certificate Request.
+ * NOTES:
+ * The library does no verification that the value passed in is
+ * a valid UTF8 value. The caller must make sure of this in order
+ * to get an encoding that is valid. The library will ultimately
+ * encode this value as it was passed in.
+ * RETURN:
+ * SECSucces on successful addition of the Registration Token Control.
+ * Any other return value indicates an unsuccessful attempt to add the
+ * control.
+ *
+ */
+extern SECStatus CRMF_CertRequestSetRegTokenControl(CRMFCertRequest *inCertReq,
+ SECItem *value);
+
+/*
+ * FUNCTION: CRMF_CertRequestSetAuthenticatorControl
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to operate on.
+ * value
+ * The UTF8 value that will become the Authenticator Control
+ * for the passed in Certificate Request.
+ * NOTES:
+ * The library does no verification that the value passed in is
+ * a valid UTF8 value. The caller must make sure of this in order
+ * to get an encoding that is valid. The library will ultimately
+ * encode this value as it was passed in.
+ * RETURN:
+ * SECSucces on successful addition of the Authenticator Control.
+ * Any other return value indicates an unsuccessful attempt to add the
+ * control.
+ */
+extern SECStatus
+CRMF_CertRequestSetAuthenticatorControl(CRMFCertRequest *inCertReq,
+ SECItem *value);
+
+/*
+ * FUNCTION: CRMF_CreateEncryptedKeyWithencryptedValue
+ * INPUTS:
+ * inPrivKey
+ * This is the private key associated with a certificate that is
+ * being requested. This structure will eventually wind up as
+ * a part of the PKIArchiveOptions Control.
+ * inCACert
+ * This is the certificate for the CA that will be receiving the
+ * certificate request for the private key passed in.
+ * OUTPUT:
+ * A CRMFEncryptedKey that can ultimately be used as part of the
+ * PKIArchiveOptions Control.
+ *
+ * RETURN:
+ * A pointer to a CRMFEncyptedKey. A NULL return value indicates an erro
+ * during the creation of the encrypted key.
+ */
+extern CRMFEncryptedKey *
+CRMF_CreateEncryptedKeyWithEncryptedValue(SECKEYPrivateKey *inPrivKey,
+ CERTCertificate *inCACert);
+
+/*
+ * FUNCTION: CRMF_DestroyEncryptedKey
+ * INPUTS:
+ * inEncrKey
+ * The CRMFEncryptedKey to be destroyed.
+ * NOTES:
+ * Frees all memory associated with the CRMFEncryptedKey passed in.
+ * RETURN:
+ * SECSuccess if freeing the memory was successful. Any other return
+ * value indicates an error while freeig the memroy.
+ */
+extern SECStatus CRMF_DestroyEncryptedKey(CRMFEncryptedKey *inEncrKey);
+
+/*
+ * FUNCTION: CRMF_CreatePKIArchiveOptions
+ * INPUTS:
+ * inType
+ * An enumeration value indicating which option for
+ * PKIArchiveOptions to use.
+ * data
+ * A pointer that will be type-cast and de-referenced according
+ * to the table under NOTES.
+ * NOTES:
+ * A table listing what should be passed in as data
+ * ------------------------------------------------
+ *
+ * inType data
+ * ------ ----
+ * crmfEncryptedPrivateKey CRMFEncryptedKey*
+ * crmfKeyGenParameters SECItem*(This needs to be an octet string)
+ * crmfArchiveRemGenPrivKey PRBool*
+ *
+ * RETURN:
+ * A pointer the a CRMFPKIArchiveOptions that can be added to a Certificate
+ * Request. A NULL pointer indicates an error occurred while creating
+ * the CRMFPKIArchiveOptions Structure.
+ */
+extern CRMFPKIArchiveOptions *
+CRMF_CreatePKIArchiveOptions(CRMFPKIArchiveOptionsType inType,
+ void *data);
+/*
+ * FUNCTION: CRMF_DestroyPKIArchiveOptions
+ * INPUTS:
+ * inArchOpt
+ * A pointer to the CRMFPKIArchiveOptions structure to free.
+ * NOTES:
+ * Will free all memory associated with 'inArchOpt'.
+ * RETURN:
+ * SECSuccess if successful in freeing the memory used by 'inArchOpt'
+ * Any other return value indicates an error while freeing the memory.
+ */
+extern SECStatus
+CRMF_DestroyPKIArchiveOptions(CRMFPKIArchiveOptions *inArchOpt);
+
+/*
+ * FUNCTION: CRMF_CertRequestSetPKIArchiveOptions
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to add the the options to.
+ * inOptions
+ * The Archive Options to add to the Certificate Request.
+ * NOTES:
+ * Adds the PKIArchiveOption to the Certificate Request. This is what
+ * enables Key Escrow to take place through CRMF. The library makes
+ * its own copy of the information.
+ * RETURN:
+ * SECSuccess if successful in adding the ArchiveOptions to the Certificate
+ * request. Any other return value indicates an error when trying to add
+ * the Archive Options to the Certificate Request.
+ */
+extern SECStatus
+CRMF_CertRequestSetPKIArchiveOptions(CRMFCertRequest *inCertReq,
+ CRMFPKIArchiveOptions *inOptions);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgGetPOPType
+ * INPUTS:
+ * inCertReqMsg
+ * The Certificate Request Message to operate on.
+ * NOTES:
+ * Returns an enumeration value indicating the method of Proof
+ * of Possession that was used for the passed in Certificate Request
+ * Message.
+ * RETURN:
+ * An enumeration indicating what method for Proof Of Possession is
+ * being used in this Certificate Request Message. Look in the file
+ * crmft.h for the definition of CRMFPOPChoice for the possible return
+ * values.
+ */
+extern CRMFPOPChoice CRMF_CertReqMsgGetPOPType(CRMFCertReqMsg *inCertReqMsg);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgSetRAVerifiedPOP
+ * INPUT:
+ * InCertReqMsg
+ * The Certificate Request Message to operate on.
+ * NOTES:
+ * This function will set the method of Proof Of Possession to
+ * crmfRAVerified which means the RA has already verified the
+ * requester does possess the private key.
+ * RETURN:
+ * SECSuccess if adding RAVerified to the message is successful.
+ * Any other message indicates an error while trying to add RAVerified
+ * as the Proof of Possession.
+ */
+extern SECStatus CRMF_CertReqMsgSetRAVerifiedPOP(CRMFCertReqMsg *inCertReqMsg);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgSetSignaturePOP
+ * INPUT:
+ * inCertReqMsg
+ * The Certificate Request Message to add the SignaturePOP to.
+ * inPrivKey
+ * The Private Key which corresponds to the the Certificate Request
+ * Message.
+ * inPubKey
+ * The Public Key which corresponds to the Private Key passed in.
+ * inCertForInput
+ * A Certificate that in the future may be used to create
+ * POPOSigningKeyInput.
+ * fn
+ * A callback for retrieving a password which may be used in the
+ * future to generate POPOSigningKeyInput.
+ * arg
+ * An opaque pointer that would be passed to fn whenever it is
+ * called.
+ * NOTES:
+ * Adds Proof Of Possession to the CertRequest using the signature field
+ * of the ProofOfPossession field. NOTE: In order to use this option,
+ * the certificate template must contain the publicKey at the very minimum.
+ *
+ * If you don't want the function to generate POPOSigningKeyInput, then
+ * make sure the cert template already contains the subject and public key
+ * values. Currently creating POPOSigningKeyInput is not supported, so
+ * a Message passed to this function must have the publicKey and the subject
+ * as part of the template
+ *
+ * This will take care of creating the entire POPOSigningKey structure
+ * that will become part of the message.
+ *
+ * inPrivKey is the key to be used in the signing operation when creating
+ * POPOSigningKey structure. This should be the key corresponding to
+ * the certificate being requested.
+ *
+ * inCertForInput will be used if POPOSigningKeyInput needs to be generated.
+ * It will be used in generating the authInfo.sender field. If the parameter
+ * is not passed in then authInfo.publicKeyMAC will be generated instead.
+ * If passed in, this certificate needs to be a valid certificate.
+ *
+ * The last 3 arguments are for future compatibility in case we ever want to
+ * support generating POPOSigningKeyInput. Pass in NULL for all 3 if you
+ * definitely don't want the function to even try to generate
+ * POPOSigningKeyInput. If you try to use POPOSigningKeyInput, the function
+ * will fail.
+ *
+ * RETURN:
+ * SECSuccess if adding the Signature Proof Of Possession worked.
+ * Any other return value indicates an error in trying to add
+ * the Signature Proof Of Possession.
+ */
+extern SECStatus
+CRMF_CertReqMsgSetSignaturePOP(CRMFCertReqMsg *inCertReqMsg,
+ SECKEYPrivateKey *inPrivKey,
+ SECKEYPublicKey *inPubKey,
+ CERTCertificate *inCertForInput,
+ CRMFMACPasswordCallback fn,
+ void *arg);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgSetKeyEnciphermentPOP
+ * INPUTS:
+ * inCertReqMsg
+ * The Certificate Request Message to operate on.
+ * inKeyChoice
+ * An enumeration indicating which POPOPrivKey Choice to use
+ * in constructing the KeyEnciphermentPOP.
+ * subseqMess
+ * This parameter must be provided iff inKeyChoice is
+ * crmfSubsequentMessage. This details how the RA is to respond
+ * in order to perform Proof Of Possession. Look in crmft.h under
+ * the definition of CRMFSubseqMessOptions for possible values.
+ * encPrivKey
+ * This parameter only needs to be provided if inKeyChoice is
+ * crmfThisMessage. The item should contain the encrypted private
+ * key.
+ *
+ * NOTES:
+ * Adds Proof Of Possession using the keyEncipherment field of
+ * ProofOfPossession.
+ *
+ * The function looks at the the inKeyChoice parameter and interprets it in
+ * in the following manner.
+ *
+ * If a parameter is not mentioned under interpretation, the function will not
+ * look at its value when implementing that case.
+ *
+ * inKeyChoice Interpretation
+ * ----------- --------------
+ * crmfThisMessage This options requires that the encrypted private key
+ * be included in the thisMessage field of POPOPrivKey.
+ * We don't support this yet, so any clients who want
+ * to use this feature have to implement a wrapping
+ * function and agree with the server on how to properly
+ * wrap the key. That encrypted key must be passed in
+ * as the encPrivKey parameter.
+ *
+ * crmfSubequentMessage Must pass in a value for subseqMess. The value must
+ * be either CRMFEncrCert or CRMFChallengeResp. The
+ * parameter encPrivKey will not be looked at in this
+ * case.
+ *
+ * crmfDHMAC This is not a valid option for this function. Passing
+ * in this value will result in the function returning
+ * SECFailure.
+ * RETURN:
+ * SECSuccess if adding KeyEnciphermentPOP was successful. Any other return
+ * value indicates an error in adding KeyEnciphermentPOP.
+ */
+extern SECStatus
+CRMF_CertReqMsgSetKeyEnciphermentPOP(CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOPrivKeyChoice inKeyChoice,
+ CRMFSubseqMessOptions subseqMess,
+ SECItem *encPrivKey);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgSetKeyAgreementPOP
+ * INPUTS:
+ * inCertReqMsg
+ * The Certificate Request Message to operate on.
+ * inKeyChoice
+ * An enumeration indicating which POPOPrivKey Choice to use
+ * in constructing the KeyAgreementPOP.
+ * subseqMess
+ * This parameter must be provided iff inKeyChoice is
+ * crmfSubsequentMessage. This details how the RA is to respond
+ * in order to perform Proof Of Possession. Look in crmft.h under
+ * the definition of CRMFSubseqMessOptions for possible values.
+ * encPrivKey
+ * This parameter only needs to be provided if inKeyChoice is
+ * crmfThisMessage. The item should contain the encrypted private
+ * key.
+ * Adds Proof Of Possession using the keyAgreement field of
+ * ProofOfPossession.
+ *
+ * The function looks at the the inKeyChoice parameter and interprets it in
+ * in the following manner.
+ *
+ * If a parameter is not mentioned under interpretation, the function will not
+ * look at its value when implementing that case.
+ *
+ * inKeyChoice Interpretation
+ * ----------- --------------
+ * crmfThisMessage This options requires that the encrypted private key
+ * be included in the thisMessage field of POPOPrivKey.
+ * We don't support this yet, so any clients who want
+ * to use this feature have to implement a wrapping
+ * function and agree with the server on how to properly
+ * wrap the key. That encrypted key must be passed in
+ * as the encPrivKey parameter.
+ *
+ * crmfSubequentMessage Must pass in a value for subseqMess. The value must
+ * be either crmfEncrCert or crmfChallengeResp. The
+ * parameter encPrivKey will not be looked at in this
+ * case.
+ *
+ * crmfDHMAC This option is not supported.
+ */
+extern SECStatus
+CRMF_CertReqMsgSetKeyAgreementPOP(CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOPrivKeyChoice inKeyChoice,
+ CRMFSubseqMessOptions subseqMess,
+ SECItem *encPrivKey);
+
+/*
+ * FUNCTION: CRMF_CreateCertReqMsgFromDER
+ * INPUTS:
+ * buf
+ * A buffer to the DER-encoded Certificate Request Message.
+ * len
+ * The length in bytes of the buffer 'buf'
+ * NOTES:
+ * This function passes the buffer to the ASN1 decoder and creates a
+ * CRMFCertReqMsg structure. Do not try adding any fields to a message
+ * returned from this function. Specifically adding more Controls or
+ * Extensions may cause your program to crash.
+ *
+ * RETURN:
+ * A pointer to the Certificate Request Message structure. A NULL return
+ * value indicates the library was unable to parse the DER.
+ */
+extern CRMFCertReqMsg *CRMF_CreateCertReqMsgFromDER(const char *buf, long len);
+
+/*
+ * FUNCTION: CRMF_CreateCertReqMessagesFromDER
+ * INPUTS:
+ * buf
+ * A buffer to the DER-encoded Certificate Request Messages.
+ * len
+ * The length in bytes of buf
+ * NOTES:
+ * This function passes the buffer to the ASN1 decoder and creates a
+ * CRMFCertReqMessages structure. Do not try adding any fields to a message
+ * derived from this function. Specifically adding more Controls or
+ * Extensions may cause your program to crash.
+ * The user must call CRMF_DestroyCertReqMessages after the return value is
+ * no longer needed, ie when all individual messages have been extracted.
+ *
+ * RETURN:
+ * A pointer to the Certificate Request Messages structure. A NULL return
+ * value indicates the library was unable to parse the DER.
+ */
+extern CRMFCertReqMessages *
+CRMF_CreateCertReqMessagesFromDER(const char *buf, long len);
+
+/*
+ * FUNCTION: CRMF_DestroyCertReqMessages
+ * INPUTS
+ * inCertReqMsgs
+ * The Messages to destroy.
+ * RETURN:
+ * SECSuccess if freeing the memory was done successfully. Any other
+ * return value indicates an error in freeing up memory.
+ */
+extern SECStatus
+CRMF_DestroyCertReqMessages(CRMFCertReqMessages *inCertReqMsgs);
+
+/*
+ * FUNCTION: CRMF_CertReqMessagesGetNumMessages
+ * INPUTS:
+ * inCertReqMsgs
+ * The Request Messages to operate on.
+ * RETURN:
+ * The number of messages contained in the in the Request Messages
+ * strucure.
+ */
+extern int
+CRMF_CertReqMessagesGetNumMessages(CRMFCertReqMessages *inCertReqMsgs);
+
+/*
+ * FUNCTION: CRMF_CertReqMessagesGetCertReqMsgAtIndex
+ * INPUTS:
+ * inReqMsgs
+ * The Certificate Request Messages to operate on.
+ * index
+ * The index of the single message the user wants a copy of.
+ * NOTES:
+ * This function returns a copy of the request messages stored at the
+ * index corresponding to the parameter 'index'. Indexing of the messages
+ * is done in the same manner as a C array. Meaning the valid index are
+ * 0...numMessages-1. User must call CRMF_DestroyCertReqMsg when done using
+ * the return value of this function.
+ *
+ * RETURN:
+ * SECSuccess if copying the message at the requested index was successful.
+ * Any other return value indicates an invalid index or error while copying
+ * the single request message.
+ */
+extern CRMFCertReqMsg *
+CRMF_CertReqMessagesGetCertReqMsgAtIndex(CRMFCertReqMessages *inReqMsgs,
+ int index);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgGetID
+ * INPUTS:
+ * inCertReqMsg
+ * The Certificate Request Message to get the ID from.
+ * destID
+ * A pointer to where the library can place the ID of the Message.
+ * RETURN:
+ * SECSuccess if the function was able to retrieve the ID and place it
+ * at *destID. Any other return value indicates an error meaning the value
+ * in *destId is un-reliable and should not be used by the caller of this
+ * function.
+ *
+ */
+extern SECStatus CRMF_CertReqMsgGetID(CRMFCertReqMsg *inCertReqMsg,
+ long *destID);
+
+/*
+ * FUNCTION: CRMF_DoesRequestHaveField
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to operate on.
+ * inField
+ * An enumeration indicating which filed of the certificate template
+ * to look for.
+ * NOTES:
+ * All the fields in a certificate template are optional. This function
+ * checks to see if the requested field is present. Look in crmft.h at the
+ * definition of CRMFCertTemplateField for possible values for possible
+ * querying.
+ *
+ * RETURN:
+ * PR_TRUE iff the field corresponding to 'inField' has been specified as part
+ * of 'inCertReq'
+ * PR_FALSE iff the field corresponding to 'inField' has not been speicified
+ * as part of 'inCertReq'
+ *
+ */
+extern PRBool CRMF_DoesRequestHaveField(CRMFCertRequest *inCertReq,
+ CRMFCertTemplateField inField);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgGetCertRequest
+ * INPUTS:
+ * inCertReqMsg
+ * The Certificate Request Message to operate on.
+ * NOTES:
+ * This function returns a copy of the Certificate Request to the user.
+ * The user can keep adding to this request and then making it a part
+ * of another message. After the user no longer wants to use the
+ * returned request, the user must call CRMF_DestroyCertRequest and
+ * pass it the request returned by this function.
+ * RETURN:
+ * A pointer to a copy of the certificate request contained by the message.
+ * A NULL return value indicates an error occurred while copying the
+ * certificate request.
+ */
+extern CRMFCertRequest *
+CRMF_CertReqMsgGetCertRequest(CRMFCertReqMsg *inCertReqMsg);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetCertTemplateVersion
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to operate on.
+ * version
+ * A pointer to where the library can store the version contatined
+ * in the certificate template within the certifcate request.
+ * RETURN:
+ * SECSuccess if the Certificate template contains the version field. In
+ * this case, *version will hold the value of the certificate template
+ * version.
+ * SECFailure indicates that version field was not present as part of
+ * of the certificate template.
+ */
+extern SECStatus
+CRMF_CertRequestGetCertTemplateVersion(CRMFCertRequest *inCertReq,
+ long *version);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetCertTemplateSerialNumber
+ * INPUTS:
+ * inCertReq
+ * The certificate request to operate on.
+ * serialNumber
+ * A pointer where the library can put the serial number contained
+ * in the certificate request's certificate template.
+ * RETURN:
+ * If a serial number exists in the CertTemplate of the request, the function
+ * returns SECSuccess and the value at *serialNumber contains the serial
+ * number.
+ * If no serial number is present, then the function returns SECFailure and
+ * the value at *serialNumber is un-changed.
+ */
+extern SECStatus
+CRMF_CertRequestGetCertTemplateSerialNumber(CRMFCertRequest *inCertReq,
+ long *serialNumber);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetCertTemplateSigningAlg
+ * INPUT:
+ * inCertReq
+ * The Certificate Request to operate on.
+ * destAlg
+ * A Pointer to where the library can place a copy of the signing alg
+ * used in the cert request's cert template.
+ * RETURN:
+ * If the signingAlg is present in the CertRequest's CertTemplate, then
+ * the function returns SECSuccess and places a copy of sigingAlg in
+ * *destAlg.
+ * If no signingAlg is present, then the function returns SECFailure and
+ * the value at *destAlg is un-changed
+ */
+extern SECStatus
+CRMF_CertRequestGetCertTemplateSigningAlg(CRMFCertRequest *inCertReq,
+ SECAlgorithmID *destAlg);
+/*
+ * FUNCTION: CRMF_CertRequestGetCertTemplateIssuer
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to operate on.
+ * destIssuer
+ * A pointer to where the library can place a copy of the cert
+ * request's cert template issuer field.
+ * RETURN:
+ * If the issuer is present in the cert request cert template, the function
+ * returns SECSuccess and places a copy of the issuer in *destIssuer.
+ * If there is no issuer present, the function returns SECFailure and the
+ * value at *destIssuer is unchanged.
+ */
+extern SECStatus
+CRMF_CertRequestGetCertTemplateIssuer(CRMFCertRequest *inCertReq,
+ CERTName *destIssuer);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetCertTemplateValidity
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to operate on.
+ * destValdity
+ * A pointer to where the library can place a copy of the validity
+ * info in the cert request cert template.
+ * NOTES:
+ * Pass the pointer to
+ * RETURN:
+ * If there is an OptionalValidity field, the function will return SECSuccess
+ * and place the appropriate values in *destValidity->notBefore and
+ * *destValidity->notAfter. (Each field is optional, but at least one will
+ * be present if the function returns SECSuccess)
+ *
+ * If there is no OptionalValidity field, the function will return SECFailure
+ * and the values at *destValidity will be un-changed.
+ */
+extern SECStatus
+CRMF_CertRequestGetCertTemplateValidity(CRMFCertRequest *inCertReq,
+ CRMFGetValidity *destValidity);
+/*
+ * FUNCTION: CRMF_DestroyGetValidity
+ * INPUTS:
+ * inValidity
+ * A pointer to the memroy to be freed.
+ * NOTES:
+ * The function will free the memory allocated by the function
+ * CRMF_CertRequestGetCertTemplateValidity. That means only memory pointed
+ * to within the CRMFGetValidity structure. Since
+ * CRMF_CertRequestGetCertTemplateValidity does not allocate memory for the
+ * structure passed into it, it will not free it. Meaning this function will
+ * free the memory at inValidity->notBefore and inValidity->notAfter, but not
+ * the memory directly at inValdity.
+ *
+ * RETURN:
+ * SECSuccess if freeing the memory was successful. Any other return value
+ * indicates an error while freeing the memory.
+ */
+extern SECStatus
+CRMF_DestroyGetValidity(CRMFGetValidity *inValidity);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetCertTemplateSubject
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to operate on.
+ * destSubject
+ * A pointer to where the library can place a copy of the subject
+ * contained in the request's cert template.
+ * RETURN:
+ * If there is a subject in the CertTemplate, then the function returns
+ * SECSuccess and a copy of the subject is placed in *destSubject.
+ *
+ * If there is no subject, the function returns SECFailure and the values at
+ * *destSubject is unchanged.
+ */
+extern SECStatus
+CRMF_CertRequestGetCertTemplateSubject(CRMFCertRequest *inCertReq,
+ CERTName *destSubject);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetCertTemplatePublicKey
+ * INPUTS:
+ * inCertReq
+ * The Cert request to operate on.
+ * destPublicKey
+ * A pointer to where the library can place a copy of the request's
+ * cert template public key.
+ * RETURN:
+ * If there is a publicKey parameter in the CertRequest, the function returns
+ * SECSuccess, and places a copy of the publicKey in *destPublicKey.
+ *
+ * If there is no publicKey, the function returns SECFailure and the value
+ * at *destPublicKey is un-changed.
+ */
+extern SECStatus
+CRMF_CertRequestGetCertTemplatePublicKey(CRMFCertRequest *inCertReq,
+ CERTSubjectPublicKeyInfo *destPublicKey);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetCertTemplateIssuerUID
+ * INPUTS:
+ * inCertReq
+ * The Cert request to operate on.
+ * destIssuerUID
+ * A pointer to where the library can store a copy of the request's
+ * cert template destIssuerUID.
+ *
+ * NOTES:
+ * destIssuerUID is a bit string and will be returned in a SECItem as
+ * a bit string. Meaning the len field contains the number of valid bits as
+ * opposed to the number of bytes allocated.
+ *
+ * RETURN:
+ * If the CertTemplate has an issuerUID, the function returns SECSuccess and
+ * places a copy of the issuerUID in *destIssuerUID.
+ *
+ * If there is no issuerUID, the function returns SECFailure and the value
+ * *destIssuerUID is unchanged.
+ */
+extern SECStatus
+CRMF_CertRequestGetCertTemplateIssuerUID(CRMFCertRequest *inCertReq,
+ SECItem *destIssuerUID);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetCertTemplateSubjectUID
+ * inCertReq
+ * The Cert request to operate on.
+ * destSubjectUID
+ * A pointer to where the library can store a copy of the request's
+ * cert template destIssuerUID.
+ *
+ * NOTES:
+ * destSubjectUID is a bit string and will be returned in a SECItem as
+ * a bit string. Meaning the len field contains the number of valid bits as
+ * opposed to the number of bytes allocated.
+ *
+ * RETURN:
+ * If the CertTemplate has an issuerUID, the function returns SECSuccess and
+ * places a copy of the issuerUID in *destIssuerUID.
+ *
+ * If there is no issuerUID, the function returns SECSuccess and the value
+ * *destIssuerUID is unchanged.
+ */
+extern SECStatus CRMF_GetCertTemplateSubjectUID(CRMFCertRequest *inCertReq,
+ SECItem *destSubjectUID);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetNumberOfExtensions
+ * INPUTS:
+ * inCertReq
+ * The cert request to operate on.
+ * RETURN:
+ * Returns the number of extensions contained by the Cert Request.
+ */
+extern int CRMF_CertRequestGetNumberOfExtensions(CRMFCertRequest *inCertReq);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetExtensionAtIndex
+ * INPUTS:
+ * inCertReq
+ * The Certificate request to operate on.
+ * index
+ * The index of the extension array whihc the user wants to access.
+ * NOTES:
+ * This function retrieves the extension at the index corresponding to the
+ * parameter "index" indicates. Indexing is done like a C array.
+ * (0 ... numElements-1)
+ *
+ * Call CRMF_DestroyCertExtension when done using the return value.
+ *
+ * RETURN:
+ * A pointer to a copy of the extension at the desired index. A NULL
+ * return value indicates an invalid index or an error while copying
+ * the extension.
+ */
+extern CRMFCertExtension *
+CRMF_CertRequestGetExtensionAtIndex(CRMFCertRequest *inCertReq,
+ int index);
+/*
+ * FUNCTION: CRMF_CertExtensionGetOidTag
+ * INPUTS:
+ * inExtension
+
+ * The extension to operate on.
+ * RETURN:
+ * Returns the SECOidTag associated with the cert extension passed in.
+ */
+extern SECOidTag CRMF_CertExtensionGetOidTag(CRMFCertExtension *inExtension);
+
+/*
+ * FUNCTION: CRMF_CertExtensionGetIsCritical
+ * INPUT:
+ * inExt
+ * The cert extension to operate on.
+ *
+ * RETURN:
+ * PR_TRUE if the extension is critical.
+ * PR_FALSE if the extension is not critical.
+ */
+extern PRBool CRMF_CertExtensionGetIsCritical(CRMFCertExtension *inExt);
+
+/*
+ * FUNCTION: CRMF_CertExtensionGetValue
+ * INPUT:
+ * inExtension
+ * The extension to operate on.
+ * NOTES:
+ * Caller is responsible for freeing the memory associated with the return
+ * value. Call SECITEM_FreeItem(retVal, PR_TRUE) when done using the return
+ * value.
+ *
+ * RETURN:
+ * A pointer to an item containig the value for the certificate extension.
+ * A NULL return value indicates an error in copying the information.
+ */
+extern SECItem *CRMF_CertExtensionGetValue(CRMFCertExtension *inExtension);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgGetPOPOSigningKey
+ * INPUTS:
+ * inCertReqMsg
+ * The certificate request message to operate on.
+ * destKey
+ * A pointer to where the library can place a pointer to
+ * a copy of the Proof Of Possession Signing Key used
+ * by the message.
+ *
+ * RETURN:
+ * Get the POPOSigningKey associated with this CRMFCertReqMsg.
+ * If the CertReqMsg does not have a pop, the function returns
+ * SECFailure and the value at *destKey is un-changed..
+ *
+ * If the CertReqMsg does have a pop, then the CertReqMsg's
+ * POPOSigningKey will be placed at *destKey.
+ */
+extern SECStatus
+CRMF_CertReqMsgGetPOPOSigningKey(CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOSigningKey **destKey);
+
+/*
+ * FUNCTION: CRMF_DestroyPOPOSigningKey
+ * INPUTS:
+ * inKey
+ * The signing key to free.
+ *
+ * RETURN:
+ * SECSuccess if freeing the memory was successful. Any other return value
+ * indicates an error while freeing memory.
+ */
+extern SECStatus CRMF_DestroyPOPOSigningKey(CRMFPOPOSigningKey *inKey);
+
+/*
+ * FUNCTION: CRMF_POPOSigningKeyGetAlgID
+ * INPUTS:
+ * inSignKey
+ * The Signing Key to operate on.
+ * RETURN:
+ * Return the algorithmID used by the CRMFPOPOSigningKey. User must
+ * call SECOID_DestroyAlgorithmID(destID, PR_TRUE) when done using the
+ * return value.
+ */
+extern SECAlgorithmID *
+CRMF_POPOSigningKeyGetAlgID(CRMFPOPOSigningKey *inSignKey);
+
+/*
+ * FUNCTION: CRMF_POPOSigningKeyGetSignature
+ * INPUTS:
+ * inSignKey
+ * The Signing Key to operate on.
+ *
+ * RETURN:
+ * Get the actual signature stored away in the CRMFPOPOSigningKey. SECItem
+ * returned is a BIT STRING, so the len field is the number of bits as opposed
+ * to the total number of bytes allocatd. User must call
+ * SECITEM_FreeItem(retVal,PR_TRUE) when done using the return value.
+ */
+extern SECItem *CRMF_POPOSigningKeyGetSignature(CRMFPOPOSigningKey *inSignKey);
+
+/*
+ * FUNCTION: CRMF_POPOSigningKeyGetInput
+ * INPUTS:
+ * inSignKey
+ * The Signing Key to operate on.
+ * NOTES:
+ * This function will return the der encoded input that was read in while
+ * decoding. The API does not support this option when creating, so you
+ * cannot add this field.
+ *
+ * RETURN:
+ * Get the poposkInput that is part of the of the POPOSigningKey. If the
+ * optional field is not part of the POPOSigningKey, the function returns
+ * NULL.
+ *
+ * If the optional field is part of the POPOSingingKey, the function will
+ * return a copy of the der encoded poposkInput.
+ */
+extern SECItem *CRMF_POPOSigningKeyGetInput(CRMFPOPOSigningKey *inSignKey);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgGetPOPKeyEncipherment
+ * INPUTS:
+ * inCertReqMsg
+ * The certificate request message to operate on.
+ * destKey
+ * A pointer to where the library can place a pointer to a
+ * copy of the POPOPrivKey representing Key Encipherment
+ * Proof of Possession.
+ *NOTES:
+ * This function gets the POPOPrivKey associated with this CRMFCertReqMsg
+ * for Key Encipherment.
+ *
+ * RETURN:
+ * If the CertReqMsg did not use Key Encipherment for Proof Of Possession, the
+ * function returns SECFailure and the value at *destKey is un-changed.
+ *
+ * If the CertReqMsg did use Key Encipherment for ProofOfPossession, the
+ * function returns SECSuccess and places the POPOPrivKey representing the
+ * Key Encipherment Proof Of Possessin at *destKey.
+ */
+extern SECStatus
+CRMF_CertReqMsgGetPOPKeyEncipherment(CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOPrivKey **destKey);
+
+/*
+ * FUNCTION: CRMF_CertReqMsgGetPOPKeyAgreement
+ * INPUTS:
+ * inCertReqMsg
+ * The certificate request message to operate on.
+ * destKey
+ * A pointer to where the library can place a pointer to a
+ * copy of the POPOPrivKey representing Key Agreement
+ * Proof of Possession.
+ * NOTES:
+ * This function gets the POPOPrivKey associated with this CRMFCertReqMsg for
+ * Key Agreement.
+ *
+ * RETURN:
+ * If the CertReqMsg used Key Agreement for Proof Of Possession, the
+ * function returns SECSuccess and the POPOPrivKey for Key Agreement
+ * is placed at *destKey.
+ *
+ * If the CertReqMsg did not use Key Agreement for Proof Of Possession, the
+ * function return SECFailure and the value at *destKey is unchanged.
+ */
+extern SECStatus
+CRMF_CertReqMsgGetPOPKeyAgreement(CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOPrivKey **destKey);
+
+/*
+ * FUNCTION: CRMF_DestroyPOPOPrivKey
+ * INPUTS:
+ * inPrivKey
+ * The POPOPrivKey to destroy.
+ * NOTES:
+ * Destroy a structure allocated by CRMF_GetPOPKeyEncipherment or
+ * CRMF_GetPOPKeyAgreement.
+ *
+ * RETURN:
+ * SECSuccess on successful destruction of the POPOPrivKey.
+ * Any other return value indicates an error in freeing the
+ * memory.
+ */
+extern SECStatus CRMF_DestroyPOPOPrivKey(CRMFPOPOPrivKey *inPrivKey);
+
+/*
+ * FUNCTION: CRMF_POPOPrivKeyGetChoice
+ * INPUT:
+ * inKey
+ * The POPOPrivKey to operate on.
+ * RETURN:
+ * Returns which choice was used in constructing the POPPOPrivKey. Look at
+ * the definition of CRMFPOPOPrivKeyChoice in crmft.h for the possible return
+ * values.
+ */
+extern CRMFPOPOPrivKeyChoice CRMF_POPOPrivKeyGetChoice(CRMFPOPOPrivKey *inKey);
+
+/*
+ * FUNCTION: CRMF_POPOPrivKeyGetThisMessage
+ * INPUTS:
+ * inKey
+ * The POPOPrivKey to operate on.
+ * destString
+ * A pointer to where the library can place a copy of the This Message
+ * field stored in the POPOPrivKey
+ *
+ * RETURN:
+ * Returns the field thisMessage from the POPOPrivKey.
+ * If the POPOPrivKey did not use the field thisMessage, the function
+ * returns SECFailure and the value at *destString is unchanged.
+ *
+ * If the POPOPrivKey did use the field thisMessage, the function returns
+ * SECSuccess and the BIT STRING representing thisMessage is placed
+ * at *destString. BIT STRING representation means the len field is the
+ * number of valid bits as opposed to the total number of bytes.
+ */
+extern SECStatus CRMF_POPOPrivKeyGetThisMessage(CRMFPOPOPrivKey *inKey,
+ SECItem *destString);
+
+/*
+ * FUNCTION: CRMF_POPOPrivKeyGetSubseqMess
+ * INPUTS:
+ * inKey
+ * The POPOPrivKey to operate on.
+ * destOpt
+ * A pointer to where the library can place the value of the
+ * Subsequent Message option used by POPOPrivKey.
+ *
+ * RETURN:
+ * Retrieves the field subsequentMessage from the POPOPrivKey.
+ * If the POPOPrivKey used the subsequentMessage option, the function
+ * returns SECSuccess and places the appropriate enumerated value at
+ * *destMessageOption.
+ *
+ * If the POPOPrivKey did not use the subsequenMessage option, the function
+ * returns SECFailure and the value at *destOpt is un-changed.
+ */
+extern SECStatus CRMF_POPOPrivKeyGetSubseqMess(CRMFPOPOPrivKey *inKey,
+ CRMFSubseqMessOptions *destOpt);
+
+/*
+ * FUNCTION: CRMF_POPOPrivKeyGetDHMAC
+ * INPUTS:
+ * inKey
+ * The POPOPrivKey to operate on.
+ * destMAC
+ * A pointer to where the library can place a copy of the dhMAC
+ * field of the POPOPrivKey.
+ *
+ * NOTES:
+ * Returns the field dhMAC from the POPOPrivKey. The populated SECItem
+ * is in BIT STRING format.
+ *
+ * RETURN:
+ * If the POPOPrivKey used the dhMAC option, the function returns SECSuccess
+ * and the BIT STRING for dhMAC will be placed at *destMAC. The len field in
+ * destMAC (ie destMAC->len) will be the valid number of bits as opposed to
+ * the number of allocated bytes.
+ *
+ * If the POPOPrivKey did not use the dhMAC option, the function returns
+ * SECFailure and the value at *destMAC is unchanged.
+ *
+ */
+extern SECStatus CRMF_POPOPrivKeyGetDHMAC(CRMFPOPOPrivKey *inKey,
+ SECItem *destMAC);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetNumControls
+ * INPUTS:
+ * inCertReq
+ * The Certificate Request to operate on.
+ * RETURN:
+ * Returns the number of Controls registered with this CertRequest.
+ */
+extern int CRMF_CertRequestGetNumControls(CRMFCertRequest *inCertReq);
+
+/*
+ * FUNCTION: CRMF_CertRequestGetControlAtIndex
+ * INPUTS:
+ * inCertReq
+ * The certificate request to operate on.
+ * index
+ * The index of the control the user wants a copy of.
+ * NOTES:
+ * Function retrieves the Control at located at index. The Controls
+ * are numbered like a traditional C array (0 ... numElements-1)
+ *
+ * RETURN:
+ * Returns a copy of the control at the index specified. This is a copy
+ * so the user must call CRMF_DestroyControl after the return value is no
+ * longer needed. A return value of NULL indicates an error while copying
+ * the control or that the index was invalid.
+ */
+extern CRMFControl *
+CRMF_CertRequestGetControlAtIndex(CRMFCertRequest *inCertReq,
+ int index);
+
+/*
+ * FUNCTION: CRMF_DestroyControl
+ * INPUTS:
+ * inControl
+ * The Control to destroy.
+ * NOTES:
+ * Destroy a CRMFControl allocated by CRMF_GetControlAtIndex.
+ *
+ * RETURN:
+ * SECSuccess if freeing the memory was successful. Any other return
+ * value indicates an error while freeing the memory.
+ */
+extern SECStatus CRMF_DestroyControl(CRMFControl *inControl);
+
+/*
+ * FUNCTION: CRMF_ControlGetControlType
+ * INPUTS:
+ * inControl
+ * The control to operate on.
+ * NOTES:
+ * The function returns an enumertion which indicates the type of control
+ * 'inControl'.
+ *
+ * RETURN:
+ * Look in crmft.h at the definition of the enumerated type CRMFControlType
+ * for the possible return values.
+ */
+extern CRMFControlType CRMF_ControlGetControlType(CRMFControl *inControl);
+
+/*
+ * FUNCTION: CRMF_ControlGetRegTokenControlValue
+ * INPUTS:
+ * inControl
+ * The Control to operate on.
+ * NOTES:
+ * The user must call SECITEM_FreeItem passing in the return value
+ * after the returnvalue is no longer needed.
+
+ * RETURN:
+ * Return the value for a Registration Token Control.
+ * The SECItem returned should be in UTF8 format. A NULL
+ * return value indicates there was no Registration Control associated
+ * with the Control.
+ * (This library will not verify format. It assumes the client properly
+ * formatted the strings when adding it or the message decoded was properly
+ * formatted. The library will just give back the bytes it was given.)
+ */
+extern SECItem *CRMF_ControlGetRegTokenControlValue(CRMFControl *inControl);
+
+/*
+ * FUNCTION: CRMF_ControlGetAuthenticatorControlValue
+ * INPUTS:
+ * inControl
+ * The Control to operate on.
+ * NOTES:
+ * The user must call SECITEM_FreeItem passing in the return value
+ * after the returnvalue is no longer needed.
+ *
+ * RETURN:
+ * Return the value for the Authenticator Control.
+ * The SECItem returned should be in UTF8 format. A NULL
+ * return value indicates there was no Authenticator Control associated
+ * with the CRMFControl..
+ * (This library will not verify format. It assumes the client properly
+ * formatted the strings when adding it or the message decoded was properly
+ * formatted. The library will just give back the bytes it was given.)
+ */
+extern SECItem *CRMF_ControlGetAuthicatorControlValue(CRMFControl *inControl);
+
+/*
+ * FUNCTION: CRMF_ControlGetPKIArchiveOptions
+ * INPUTS:inControl
+ * The Control tooperate on.
+ * NOTES:
+ * This function returns a copy of the PKIArchiveOptions. The user must call
+ * the function CRMF_DestroyPKIArchiveOptions when the return value is no
+ * longer needed.
+ *
+ * RETURN:
+ * Get the PKIArchiveOptions associated with the Control. A return
+ * value of NULL indicates the Control was not a PKIArchiveOptions
+ * Control.
+ */
+extern CRMFPKIArchiveOptions *
+CRMF_ControlGetPKIArchiveOptions(CRMFControl *inControl);
+
+/*
+ * FUNCTION: CMRF_DestroyPKIArchiveOptions
+ * INPUTS:
+ * inOptions
+ * The ArchiveOptions to destroy.
+ * NOTE:
+ * Destroy the CRMFPKIArchiveOptions structure.
+ *
+ * RETURN:
+ * SECSuccess if successful in freeing all the memory associated with
+ * the PKIArchiveOptions. Any other return value indicates an error while
+ * freeing the PKIArchiveOptions.
+ */
+extern SECStatus
+CRMF_DestroyPKIArchiveOptions(CRMFPKIArchiveOptions *inOptions);
+
+/*
+ * FUNCTION: CRMF_PKIArchiveOptionsGetOptionType
+ * INPUTS:
+ * inOptions
+ * The PKIArchiveOptions to operate on.
+ * RETURN:
+ * Returns the choice used for the PKIArchiveOptions. Look at the definition
+ * of CRMFPKIArchiveOptionsType in crmft.h for possible return values.
+ */
+extern CRMFPKIArchiveOptionsType
+CRMF_PKIArchiveOptionsGetOptionType(CRMFPKIArchiveOptions *inOptions);
+
+/*
+ * FUNCTION: CRMF_PKIArchiveOptionsGetEncryptedPrivKey
+ * INPUTS:
+ * inOpts
+ * The PKIArchiveOptions to operate on.
+ *
+ * NOTES:
+ * The user must call CRMF_DestroyEncryptedKey when done using this return
+ * value.
+ *
+ * RETURN:
+ * Get the encryptedPrivKey field of the PKIArchiveOptions structure.
+ * A return value of NULL indicates that encryptedPrivKey was not used as
+ * the choice for this PKIArchiveOptions.
+ */
+extern CRMFEncryptedKey *
+CRMF_PKIArchiveOptionsGetEncryptedPrivKey(CRMFPKIArchiveOptions *inOpts);
+
+/*
+ * FUNCTION: CRMF_EncryptedKeyGetChoice
+ * INPUTS:
+ * inEncrKey
+ * The EncryptedKey to operate on.
+ *
+ * NOTES:
+ * Get the choice used for representing the EncryptedKey.
+ *
+ * RETURN:
+ * Returns the Choice used in representing the EncryptedKey. Look in
+ * crmft.h at the definition of CRMFEncryptedKeyChoice for possible return
+ * values.
+ */
+extern CRMFEncryptedKeyChoice
+CRMF_EncryptedKeyGetChoice(CRMFEncryptedKey *inEncrKey);
+
+/*
+ * FUNCTION: CRMF_EncryptedKeyGetEncryptedValue
+ * INPUTS:
+ * inKey
+ * The EncryptedKey to operate on.
+ *
+ * NOTES:
+ * The user must call CRMF_DestroyEncryptedValue passing in
+ * CRMF_GetEncryptedValue's return value.
+ *
+ * RETURN:
+ * A pointer to a copy of the EncryptedValue contained as a member of
+ * the EncryptedKey.
+ */
+extern CRMFEncryptedValue *
+CRMF_EncryptedKeyGetEncryptedValue(CRMFEncryptedKey *inKey);
+
+/*
+ * FUNCTION: CRMF_DestroyEncryptedValue
+ * INPUTS:
+ * inEncrValue
+ * The EncryptedValue to destroy.
+ *
+ * NOTES:
+ * Free up all memory associated with 'inEncrValue'.
+ *
+ * RETURN:
+ * SECSuccess if freeing up the memory associated with the EncryptedValue
+ * is successful. Any other return value indicates an error while freeing the
+ * memory.
+ */
+extern SECStatus CRMF_DestroyEncryptedValue(CRMFEncryptedValue *inEncrValue);
+
+/*
+ * FUNCTION: CRMF_EncryptedValueGetEncValue
+ * INPUTS:
+ * inEncValue
+ * The EncryptedValue to operate on.
+ * NOTES:
+ * Function retrieves the encValue from an EncryptedValue structure.
+ *
+ * RETURN:
+ * A poiner to a SECItem containing the encValue of the EncryptedValue
+ * structure. The return value is in BIT STRING format, meaning the
+ * len field of the return structure represents the number of valid bits
+ * as opposed to the allocated number of bytes.
+ * ANULL return value indicates an error in copying the encValue field.
+ */
+extern SECItem *CRMF_EncryptedValueGetEncValue(CRMFEncryptedValue *inEncValue);
+
+/*
+ * FUNCTION: CRMF_EncryptedValueGetIntendedAlg
+ * INPUTS
+ * inEncValue
+ * The EncryptedValue to operate on.
+ * NOTES:
+ * Retrieve the IntendedAlg field from the EncryptedValue structure.
+ * Call SECOID_DestroyAlgorithmID (destAlgID, PR_TRUE) after done using
+ * the return value. When present, this alogorithm is the alogrithm for
+ * which the private key will be used.
+ *
+ * RETURN:
+ * A Copy of the intendedAlg field. A NULL return value indicates the
+ * optional field was not present in the structure.
+ */
+extern SECAlgorithmID *
+CRMF_EncryptedValueGetIntendedAlg(CRMFEncryptedValue *inEncValue);
+
+/*
+ * FUNCTION: CRMF_EncryptedValueGetSymmAlg
+ * INPUTS
+ * inEncValue
+ * The EncryptedValue to operate on.
+ * NOTES:
+ * Retrieve the symmAlg field from the EncryptedValue structure.
+ * Call SECOID_DestroyAlgorithmID (destAlgID, PR_TRUE) after done using
+ * the return value. When present, this is algorithm used to
+ * encrypt the encValue of the EncryptedValue.
+ *
+ * RETURN:
+ * A Copy of the symmAlg field. A NULL return value indicates the
+ * optional field was not present in the structure.
+ */
+extern SECAlgorithmID *
+CRMF_EncryptedValueGetSymmAlg(CRMFEncryptedValue *inEncValue);
+
+/*
+ * FUNCTION: CRMF_EncryptedValueGetKeyAlg
+ * INPUTS
+ * inEncValue
+ * The EncryptedValue to operate on.
+ * NOTES:
+ * Retrieve the keyAlg field from the EncryptedValue structure.
+ * Call SECOID_DestroyAlgorithmID (destAlgID, PR_TRUE) after done using
+ * the return value. When present, this is the algorithm used to encrypt
+ * the symmetric key in the encSymmKey field of the EncryptedValue structure.
+ *
+ * RETURN:
+ * A Copy of the keyAlg field. A NULL return value indicates the
+ * optional field was not present in the structure.
+ */
+extern SECAlgorithmID *
+CRMF_EncryptedValueGetKeyAlg(CRMFEncryptedValue *inEncValue);
+
+/*
+ * FUNCTION: CRMF_EncryptedValueGetValueHint
+ * INPUTS:
+ * inEncValue
+ * The EncryptedValue to operate on.
+ *
+ * NOTES:
+ * Return a copy of the der-encoded value hint.
+ * User must call SECITEM_FreeItem(retVal, PR_TRUE) when done using the
+ * return value. When, present, this is a value that the client which
+ * originally issued a certificate request can use to reproduce any data
+ * it wants. The RA does not know how to interpret this data.
+ *
+ * RETURN:
+ * A copy of the valueHint field of the EncryptedValue. A NULL return
+ * value indicates the optional valueHint field is not present in the
+ * EncryptedValue.
+ */
+extern SECItem *
+CRMF_EncryptedValueGetValueHint(CRMFEncryptedValue *inEncValue);
+
+/*
+ * FUNCTION: CRMF_EncrypteValueGetEncSymmKey
+ * INPUTS:
+ * inEncValue
+ * The EncryptedValue to operate on.
+ *
+ * NOTES:
+ * Return a copy of the encSymmKey field. This field is the encrypted
+ * symmetric key that the client uses in doing Public Key wrap of a private
+ * key. When present, this is the symmetric key that was used to wrap the
+ * private key. (The encrypted private key will be stored in encValue
+ * of the same EncryptedValue structure.) The user must call
+ * SECITEM_FreeItem(retVal, PR_TRUE) when the return value is no longer
+ * needed.
+ *
+ * RETURN:
+ * A copy of the optional encSymmKey field of the EncryptedValue structure.
+ * The return value will be in BIT STRING format, meaning the len field will
+ * be the number of valid bits as opposed to the number of bytes. A return
+ * value of NULL means the optional encSymmKey field was not present in
+ * the EncryptedValue structure.
+ */
+extern SECItem *
+CRMF_EncryptedValueGetEncSymmKey(CRMFEncryptedValue *inEncValue);
+
+/*
+ * FUNCTION: CRMF_PKIArchiveOptionsGetKeyGenParameters
+ * INPUTS:
+ * inOptions
+ * The PKiArchiveOptions to operate on.
+ *
+ * NOTES:
+ * User must call SECITEM_FreeItem(retVal, PR_TRUE) after the return
+ * value is no longer needed.
+ *
+ * RETURN:
+ * Get the keyGenParameters field of the PKIArchiveOptions.
+ * A NULL return value indicates that keyGenParameters was not
+ * used as the choice for this PKIArchiveOptions.
+ *
+ * The SECItem returned is in BIT STRING format (ie, the len field indicates
+ * number of valid bits as opposed to allocated number of bytes.)
+ */
+extern SECItem *
+CRMF_PKIArchiveOptionsGetKeyGenParameters(CRMFPKIArchiveOptions *inOptions);
+
+/*
+ * FUNCTION: CRMF_PKIArchiveOptionsGetArchiveRemGenPrivKey
+ * INPUTS:
+ * inOpt
+ * The PKIArchiveOptions to operate on.
+ * destVal
+ * A pointer to where the library can place the value for
+ * arciveRemGenPrivKey
+ * RETURN:
+ * If the PKIArchiveOptions used the archiveRemGenPrivKey field, the
+ * function returns SECSuccess and fills the value at *destValue with either
+ * PR_TRUE or PR_FALSE, depending on what the PKIArchiveOptions has as a
+ * value.
+ *
+ * If the PKIArchiveOptions does not use the archiveRemGenPrivKey field, the
+ * function returns SECFailure and the value at *destValue is unchanged.
+ */
+extern SECStatus
+CRMF_PKIArchiveOptionsGetArchiveRemGenPrivKey(CRMFPKIArchiveOptions *inOpt,
+ PRBool *destVal);
+
+/* Helper functions that can be used by other libraries. */
+/*
+ * A quick helper function to get the best wrap mechanism.
+ */
+extern CK_MECHANISM_TYPE CRMF_GetBestWrapPadMechanism(PK11SlotInfo *slot);
+
+/*
+ * A helper function to get a randomly generated IV from a mechanism
+ * type.
+ */
+extern SECItem *CRMF_GetIVFromMechanism(CK_MECHANISM_TYPE mechType);
+
+SEC_END_PROTOS
+#endif /*_CRMF_H_*/
diff --git a/security/nss/lib/crmf/crmfcont.c b/security/nss/lib/crmf/crmfcont.c
new file mode 100644
index 000000000..5df2bd828
--- /dev/null
+++ b/security/nss/lib/crmf/crmfcont.c
@@ -0,0 +1,1161 @@
+/* -*- 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 "pk11func.h"
+#include "keyhi.h"
+#include "secoid.h"
+
+static SECStatus
+crmf_modify_control_array(CRMFCertRequest *inCertReq, int count)
+{
+ if (count > 0) {
+ void *dummy = PORT_Realloc(inCertReq->controls,
+ sizeof(CRMFControl *) * (count + 2));
+ if (dummy == NULL) {
+ return SECFailure;
+ }
+ inCertReq->controls = dummy;
+ } else {
+ inCertReq->controls = PORT_ZNewArray(CRMFControl *, 2);
+ }
+ return (inCertReq->controls == NULL) ? SECFailure : SECSuccess;
+}
+
+static SECStatus
+crmf_add_new_control(CRMFCertRequest *inCertReq, SECOidTag inTag,
+ CRMFControl **destControl)
+{
+ SECOidData *oidData;
+ SECStatus rv;
+ PLArenaPool *poolp;
+ int numControls = 0;
+ CRMFControl *newControl;
+ CRMFControl **controls;
+ void *mark;
+
+ poolp = inCertReq->poolp;
+ if (poolp == NULL) {
+ return SECFailure;
+ }
+ mark = PORT_ArenaMark(poolp);
+ if (inCertReq->controls != NULL) {
+ while (inCertReq->controls[numControls] != NULL)
+ numControls++;
+ }
+ rv = crmf_modify_control_array(inCertReq, numControls);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ controls = inCertReq->controls;
+ oidData = SECOID_FindOIDByTag(inTag);
+ newControl = *destControl = PORT_ArenaZNew(poolp, CRMFControl);
+ if (newControl == NULL) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(poolp, &newControl->derTag, &oidData->oid);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ newControl->tag = inTag;
+ controls[numControls] = newControl;
+ controls[numControls + 1] = NULL;
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ *destControl = NULL;
+ return SECFailure;
+}
+
+static SECStatus
+crmf_add_secitem_control(CRMFCertRequest *inCertReq, SECItem *value,
+ SECOidTag inTag)
+{
+ SECStatus rv;
+ CRMFControl *newControl;
+ void *mark;
+
+ rv = crmf_add_new_control(inCertReq, inTag, &newControl);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ mark = PORT_ArenaMark(inCertReq->poolp);
+ rv = SECITEM_CopyItem(inCertReq->poolp, &newControl->derValue, value);
+ if (rv != SECSuccess) {
+ PORT_ArenaRelease(inCertReq->poolp, mark);
+ return rv;
+ }
+ PORT_ArenaUnmark(inCertReq->poolp, mark);
+ return SECSuccess;
+}
+
+SECStatus
+CRMF_CertRequestSetRegTokenControl(CRMFCertRequest *inCertReq, SECItem *value)
+{
+ return crmf_add_secitem_control(inCertReq, value,
+ SEC_OID_PKIX_REGCTRL_REGTOKEN);
+}
+
+SECStatus
+CRMF_CertRequestSetAuthenticatorControl(CRMFCertRequest *inCertReq,
+ SECItem *value)
+{
+ return crmf_add_secitem_control(inCertReq, value,
+ SEC_OID_PKIX_REGCTRL_AUTHENTICATOR);
+}
+
+SECStatus
+crmf_destroy_encrypted_value(CRMFEncryptedValue *inEncrValue, PRBool freeit)
+{
+ if (inEncrValue != NULL) {
+ if (inEncrValue->intendedAlg) {
+ SECOID_DestroyAlgorithmID(inEncrValue->intendedAlg, PR_TRUE);
+ inEncrValue->intendedAlg = NULL;
+ }
+ if (inEncrValue->symmAlg) {
+ SECOID_DestroyAlgorithmID(inEncrValue->symmAlg, PR_TRUE);
+ inEncrValue->symmAlg = NULL;
+ }
+ if (inEncrValue->encSymmKey.data) {
+ PORT_Free(inEncrValue->encSymmKey.data);
+ inEncrValue->encSymmKey.data = NULL;
+ }
+ if (inEncrValue->keyAlg) {
+ SECOID_DestroyAlgorithmID(inEncrValue->keyAlg, PR_TRUE);
+ inEncrValue->keyAlg = NULL;
+ }
+ if (inEncrValue->valueHint.data) {
+ PORT_Free(inEncrValue->valueHint.data);
+ inEncrValue->valueHint.data = NULL;
+ }
+ if (inEncrValue->encValue.data) {
+ PORT_Free(inEncrValue->encValue.data);
+ inEncrValue->encValue.data = NULL;
+ }
+ if (freeit) {
+ PORT_Free(inEncrValue);
+ }
+ }
+ return SECSuccess;
+}
+
+SECStatus
+CRMF_DestroyEncryptedValue(CRMFEncryptedValue *inEncrValue)
+{
+ return crmf_destroy_encrypted_value(inEncrValue, PR_TRUE);
+}
+
+SECStatus
+crmf_copy_encryptedvalue_secalg(PLArenaPool *poolp,
+ SECAlgorithmID *srcAlgId,
+ SECAlgorithmID **destAlgId)
+{
+ SECAlgorithmID *newAlgId;
+ SECStatus rv;
+
+ newAlgId = (poolp != NULL) ? PORT_ArenaZNew(poolp, SECAlgorithmID) : PORT_ZNew(SECAlgorithmID);
+ if (newAlgId == NULL) {
+ return SECFailure;
+ }
+
+ rv = SECOID_CopyAlgorithmID(poolp, newAlgId, srcAlgId);
+ if (rv != SECSuccess) {
+ if (!poolp) {
+ SECOID_DestroyAlgorithmID(newAlgId, PR_TRUE);
+ }
+ return rv;
+ }
+ *destAlgId = newAlgId;
+
+ return rv;
+}
+
+SECStatus
+crmf_copy_encryptedvalue(PLArenaPool *poolp,
+ CRMFEncryptedValue *srcValue,
+ CRMFEncryptedValue *destValue)
+{
+ SECStatus rv;
+
+ if (srcValue->intendedAlg != NULL) {
+ rv = crmf_copy_encryptedvalue_secalg(poolp,
+ srcValue->intendedAlg,
+ &destValue->intendedAlg);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcValue->symmAlg != NULL) {
+ rv = crmf_copy_encryptedvalue_secalg(poolp,
+ srcValue->symmAlg,
+ &destValue->symmAlg);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcValue->encSymmKey.data != NULL) {
+ rv = crmf_make_bitstring_copy(poolp,
+ &destValue->encSymmKey,
+ &srcValue->encSymmKey);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcValue->keyAlg != NULL) {
+ rv = crmf_copy_encryptedvalue_secalg(poolp,
+ srcValue->keyAlg,
+ &destValue->keyAlg);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcValue->valueHint.data != NULL) {
+ rv = SECITEM_CopyItem(poolp,
+ &destValue->valueHint,
+ &srcValue->valueHint);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcValue->encValue.data != NULL) {
+ rv = crmf_make_bitstring_copy(poolp,
+ &destValue->encValue,
+ &srcValue->encValue);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ return SECSuccess;
+loser:
+ if (poolp == NULL && destValue != NULL) {
+ crmf_destroy_encrypted_value(destValue, PR_FALSE);
+ }
+ return SECFailure;
+}
+
+SECStatus
+crmf_copy_encryptedkey(PLArenaPool *poolp,
+ CRMFEncryptedKey *srcEncrKey,
+ CRMFEncryptedKey *destEncrKey)
+{
+ SECStatus rv;
+ void *mark = NULL;
+
+ if (poolp != NULL) {
+ mark = PORT_ArenaMark(poolp);
+ }
+
+ switch (srcEncrKey->encKeyChoice) {
+ case crmfEncryptedValueChoice:
+ rv = crmf_copy_encryptedvalue(poolp,
+ &srcEncrKey->value.encryptedValue,
+ &destEncrKey->value.encryptedValue);
+ break;
+ case crmfEnvelopedDataChoice:
+ destEncrKey->value.envelopedData =
+ SEC_PKCS7CopyContentInfo(srcEncrKey->value.envelopedData);
+ rv = (destEncrKey->value.envelopedData != NULL) ? SECSuccess : SECFailure;
+ break;
+ default:
+ rv = SECFailure;
+ }
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ destEncrKey->encKeyChoice = srcEncrKey->encKeyChoice;
+ if (mark) {
+ PORT_ArenaUnmark(poolp, mark);
+ }
+ return SECSuccess;
+
+loser:
+ if (mark) {
+ PORT_ArenaRelease(poolp, mark);
+ }
+ return SECFailure;
+}
+
+static CRMFPKIArchiveOptions *
+crmf_create_encr_pivkey_option(CRMFEncryptedKey *inEncryptedKey)
+{
+ CRMFPKIArchiveOptions *newArchOpt;
+ SECStatus rv;
+
+ newArchOpt = PORT_ZNew(CRMFPKIArchiveOptions);
+ if (newArchOpt == NULL) {
+ goto loser;
+ }
+
+ rv = crmf_copy_encryptedkey(NULL, inEncryptedKey,
+ &newArchOpt->option.encryptedKey);
+
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ newArchOpt->archOption = crmfEncryptedPrivateKey;
+ return newArchOpt;
+loser:
+ if (newArchOpt != NULL) {
+ CRMF_DestroyPKIArchiveOptions(newArchOpt);
+ }
+ return NULL;
+}
+
+static CRMFPKIArchiveOptions *
+crmf_create_keygen_param_option(SECItem *inKeyGenParams)
+{
+ CRMFPKIArchiveOptions *newArchOptions;
+ SECStatus rv;
+
+ newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions);
+ if (newArchOptions == NULL) {
+ goto loser;
+ }
+ newArchOptions->archOption = crmfKeyGenParameters;
+ rv = SECITEM_CopyItem(NULL, &newArchOptions->option.keyGenParameters,
+ inKeyGenParams);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return newArchOptions;
+loser:
+ if (newArchOptions != NULL) {
+ CRMF_DestroyPKIArchiveOptions(newArchOptions);
+ }
+ return NULL;
+}
+
+static CRMFPKIArchiveOptions *
+crmf_create_arch_rem_gen_privkey(PRBool archiveRemGenPrivKey)
+{
+ unsigned char value;
+ SECItem *dummy;
+ CRMFPKIArchiveOptions *newArchOptions;
+
+ value = (archiveRemGenPrivKey) ? hexTrue : hexFalse;
+ newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions);
+ if (newArchOptions == NULL) {
+ goto loser;
+ }
+ dummy = SEC_ASN1EncodeItem(NULL,
+ &newArchOptions->option.archiveRemGenPrivKey,
+ &value, SEC_ASN1_GET(SEC_BooleanTemplate));
+ PORT_Assert(dummy == &newArchOptions->option.archiveRemGenPrivKey);
+ if (dummy != &newArchOptions->option.archiveRemGenPrivKey) {
+ SECITEM_FreeItem(dummy, PR_TRUE);
+ goto loser;
+ }
+ newArchOptions->archOption = crmfArchiveRemGenPrivKey;
+ return newArchOptions;
+loser:
+ if (newArchOptions != NULL) {
+ CRMF_DestroyPKIArchiveOptions(newArchOptions);
+ }
+ return NULL;
+}
+
+CRMFPKIArchiveOptions *
+CRMF_CreatePKIArchiveOptions(CRMFPKIArchiveOptionsType inType, void *data)
+{
+ CRMFPKIArchiveOptions *retOptions;
+
+ PORT_Assert(data != NULL);
+ if (data == NULL) {
+ return NULL;
+ }
+ switch (inType) {
+ case crmfEncryptedPrivateKey:
+ retOptions = crmf_create_encr_pivkey_option((CRMFEncryptedKey *)data);
+ break;
+ case crmfKeyGenParameters:
+ retOptions = crmf_create_keygen_param_option((SECItem *)data);
+ break;
+ case crmfArchiveRemGenPrivKey:
+ retOptions = crmf_create_arch_rem_gen_privkey(*(PRBool *)data);
+ break;
+ default:
+ retOptions = NULL;
+ }
+ return retOptions;
+}
+
+static SECStatus
+crmf_destroy_encrypted_key(CRMFEncryptedKey *inEncrKey, PRBool freeit)
+{
+ PORT_Assert(inEncrKey != NULL);
+ if (inEncrKey != NULL) {
+ switch (inEncrKey->encKeyChoice) {
+ case crmfEncryptedValueChoice:
+ crmf_destroy_encrypted_value(&inEncrKey->value.encryptedValue,
+ PR_FALSE);
+ break;
+ case crmfEnvelopedDataChoice:
+ SEC_PKCS7DestroyContentInfo(inEncrKey->value.envelopedData);
+ break;
+ default:
+ break;
+ }
+ if (freeit) {
+ PORT_Free(inEncrKey);
+ }
+ }
+ return SECSuccess;
+}
+
+SECStatus
+crmf_destroy_pkiarchiveoptions(CRMFPKIArchiveOptions *inArchOptions,
+ PRBool freeit)
+{
+ PORT_Assert(inArchOptions != NULL);
+ if (inArchOptions != NULL) {
+ switch (inArchOptions->archOption) {
+ case crmfEncryptedPrivateKey:
+ crmf_destroy_encrypted_key(&inArchOptions->option.encryptedKey,
+ PR_FALSE);
+ break;
+ case crmfKeyGenParameters:
+ case crmfArchiveRemGenPrivKey:
+ /* This is a union, so having a pointer to one is like
+ * having a pointer to both.
+ */
+ SECITEM_FreeItem(&inArchOptions->option.keyGenParameters,
+ PR_FALSE);
+ break;
+ case crmfNoArchiveOptions:
+ break;
+ }
+ if (freeit) {
+ PORT_Free(inArchOptions);
+ }
+ }
+ return SECSuccess;
+}
+
+SECStatus
+CRMF_DestroyPKIArchiveOptions(CRMFPKIArchiveOptions *inArchOptions)
+{
+ return crmf_destroy_pkiarchiveoptions(inArchOptions, PR_TRUE);
+}
+
+static CK_MECHANISM_TYPE
+crmf_get_non_pad_mechanism(CK_MECHANISM_TYPE type)
+{
+ switch (type) {
+ case CKM_DES3_CBC_PAD:
+ return CKM_DES3_CBC;
+ case CKM_CAST5_CBC_PAD:
+ return CKM_CAST5_CBC;
+ case CKM_DES_CBC_PAD:
+ return CKM_DES_CBC;
+ case CKM_IDEA_CBC_PAD:
+ return CKM_IDEA_CBC;
+ case CKM_CAST3_CBC_PAD:
+ return CKM_CAST3_CBC;
+ case CKM_CAST_CBC_PAD:
+ return CKM_CAST_CBC;
+ case CKM_RC5_CBC_PAD:
+ return CKM_RC5_CBC;
+ case CKM_RC2_CBC_PAD:
+ return CKM_RC2_CBC;
+ case CKM_CDMF_CBC_PAD:
+ return CKM_CDMF_CBC;
+ }
+ return type;
+}
+
+static CK_MECHANISM_TYPE
+crmf_get_pad_mech_from_tag(SECOidTag oidTag)
+{
+ CK_MECHANISM_TYPE mechType;
+ SECOidData *oidData;
+
+ oidData = SECOID_FindOIDByTag(oidTag);
+ mechType = (CK_MECHANISM_TYPE)oidData->mechanism;
+ return PK11_GetPadMechanism(mechType);
+}
+
+static CK_MECHANISM_TYPE
+crmf_get_best_privkey_wrap_mechanism(PK11SlotInfo *slot)
+{
+ CK_MECHANISM_TYPE privKeyPadMechs[] = { CKM_DES3_CBC_PAD,
+ CKM_CAST5_CBC_PAD,
+ CKM_DES_CBC_PAD,
+ CKM_IDEA_CBC_PAD,
+ CKM_CAST3_CBC_PAD,
+ CKM_CAST_CBC_PAD,
+ CKM_RC5_CBC_PAD,
+ CKM_RC2_CBC_PAD,
+ CKM_CDMF_CBC_PAD };
+ int mechCount = sizeof(privKeyPadMechs) / sizeof(privKeyPadMechs[0]);
+ int i;
+
+ for (i = 0; i < mechCount; i++) {
+ if (PK11_DoesMechanism(slot, privKeyPadMechs[i])) {
+ return privKeyPadMechs[i];
+ }
+ }
+ return CKM_INVALID_MECHANISM;
+}
+
+CK_MECHANISM_TYPE
+CRMF_GetBestWrapPadMechanism(PK11SlotInfo *slot)
+{
+ return crmf_get_best_privkey_wrap_mechanism(slot);
+}
+
+static SECItem *
+crmf_get_iv(CK_MECHANISM_TYPE mechType)
+{
+ int iv_size = PK11_GetIVLength(mechType);
+ SECItem *iv;
+ SECStatus rv;
+
+ iv = PORT_ZNew(SECItem);
+ if (iv == NULL) {
+ return NULL;
+ }
+ if (iv_size == 0) {
+ iv->data = NULL;
+ iv->len = 0;
+ return iv;
+ }
+ iv->data = PORT_NewArray(unsigned char, iv_size);
+ if (iv->data == NULL) {
+ iv->len = 0;
+ return iv;
+ }
+ iv->len = iv_size;
+ rv = PK11_GenerateRandom(iv->data, iv->len);
+ if (rv != SECSuccess) {
+ PORT_Free(iv->data);
+ iv->data = NULL;
+ iv->len = 0;
+ }
+ return iv;
+}
+
+SECItem *
+CRMF_GetIVFromMechanism(CK_MECHANISM_TYPE mechType)
+{
+ return crmf_get_iv(mechType);
+}
+
+CK_MECHANISM_TYPE
+crmf_get_mechanism_from_public_key(SECKEYPublicKey *inPubKey)
+{
+ CERTSubjectPublicKeyInfo *spki = NULL;
+ SECOidTag tag;
+
+ spki = SECKEY_CreateSubjectPublicKeyInfo(inPubKey);
+ if (spki == NULL) {
+ return CKM_INVALID_MECHANISM;
+ }
+ tag = SECOID_FindOIDTag(&spki->algorithm.algorithm);
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ spki = NULL;
+ return PK11_AlgtagToMechanism(tag);
+}
+
+SECItem *
+crmf_get_public_value(SECKEYPublicKey *pubKey, SECItem *dest)
+{
+ SECItem *src;
+
+ switch (pubKey->keyType) {
+ case dsaKey:
+ src = &pubKey->u.dsa.publicValue;
+ break;
+ case rsaKey:
+ src = &pubKey->u.rsa.modulus;
+ break;
+ case dhKey:
+ src = &pubKey->u.dh.publicValue;
+ break;
+ default:
+ src = NULL;
+ break;
+ }
+ if (!src) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ if (dest != NULL) {
+ SECStatus rv = SECITEM_CopyItem(NULL, dest, src);
+ if (rv != SECSuccess) {
+ dest = NULL;
+ }
+ } else {
+ dest = SECITEM_ArenaDupItem(NULL, src);
+ }
+ return dest;
+}
+
+static SECItem *
+crmf_decode_params(SECItem *inParams)
+{
+ SECItem *params;
+ SECStatus rv = SECFailure;
+ PLArenaPool *poolp;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ return NULL;
+ }
+
+ params = PORT_ArenaZNew(poolp, SECItem);
+ if (params) {
+ rv = SEC_ASN1DecodeItem(poolp, params,
+ SEC_ASN1_GET(SEC_OctetStringTemplate),
+ inParams);
+ }
+ params = (rv == SECSuccess) ? SECITEM_ArenaDupItem(NULL, params) : NULL;
+ PORT_FreeArena(poolp, PR_FALSE);
+ return params;
+}
+
+static int
+crmf_get_key_size_from_mech(CK_MECHANISM_TYPE mechType)
+{
+ CK_MECHANISM_TYPE keyGen = PK11_GetKeyGen(mechType);
+
+ switch (keyGen) {
+ case CKM_CDMF_KEY_GEN:
+ case CKM_DES_KEY_GEN:
+ return 8;
+ case CKM_DES2_KEY_GEN:
+ return 16;
+ case CKM_DES3_KEY_GEN:
+ return 24;
+ }
+ return 0;
+}
+
+SECStatus
+crmf_encrypted_value_unwrap_priv_key(PLArenaPool *poolp,
+ CRMFEncryptedValue *encValue,
+ SECKEYPrivateKey *privKey,
+ SECKEYPublicKey *newPubKey,
+ SECItem *nickname,
+ PK11SlotInfo *slot,
+ unsigned char keyUsage,
+ SECKEYPrivateKey **unWrappedKey,
+ void *wincx)
+{
+ PK11SymKey *wrappingKey = NULL;
+ CK_MECHANISM_TYPE wrapMechType;
+ SECOidTag oidTag;
+ SECItem *params = NULL, *publicValue = NULL;
+ int keySize, origLen;
+ CK_KEY_TYPE keyType;
+ CK_ATTRIBUTE_TYPE *usage = NULL;
+ CK_ATTRIBUTE_TYPE rsaUsage[] = {
+ CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER
+ };
+ CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN };
+ CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE };
+ int usageCount = 0;
+
+ oidTag = SECOID_GetAlgorithmTag(encValue->symmAlg);
+ wrapMechType = crmf_get_pad_mech_from_tag(oidTag);
+ keySize = crmf_get_key_size_from_mech(wrapMechType);
+ wrappingKey = PK11_PubUnwrapSymKey(privKey, &encValue->encSymmKey,
+ wrapMechType, CKA_UNWRAP, keySize);
+ if (wrappingKey == NULL) {
+ goto loser;
+ } /* Make the length a byte length instead of bit length*/
+ params = (encValue->symmAlg != NULL) ? crmf_decode_params(&encValue->symmAlg->parameters)
+ : NULL;
+ origLen = encValue->encValue.len;
+ encValue->encValue.len = CRMF_BITS_TO_BYTES(origLen);
+ publicValue = crmf_get_public_value(newPubKey, NULL);
+ switch (newPubKey->keyType) {
+ default:
+ case rsaKey:
+ keyType = CKK_RSA;
+ switch (keyUsage & (KU_KEY_ENCIPHERMENT | KU_DIGITAL_SIGNATURE)) {
+ case KU_KEY_ENCIPHERMENT:
+ usage = rsaUsage;
+ usageCount = 2;
+ break;
+ case KU_DIGITAL_SIGNATURE:
+ usage = &rsaUsage[2];
+ usageCount = 2;
+ break;
+ case KU_KEY_ENCIPHERMENT |
+ KU_DIGITAL_SIGNATURE:
+ case 0: /* default to everything */
+ usage = rsaUsage;
+ usageCount = 4;
+ break;
+ }
+ break;
+ case dhKey:
+ keyType = CKK_DH;
+ usage = dhUsage;
+ usageCount = sizeof(dhUsage) / sizeof(dhUsage[0]);
+ break;
+ case dsaKey:
+ keyType = CKK_DSA;
+ usage = dsaUsage;
+ usageCount = sizeof(dsaUsage) / sizeof(dsaUsage[0]);
+ break;
+ }
+ PORT_Assert(usage != NULL);
+ PORT_Assert(usageCount != 0);
+ *unWrappedKey = PK11_UnwrapPrivKey(slot, wrappingKey, wrapMechType, params,
+ &encValue->encValue, nickname,
+ publicValue, PR_TRUE, PR_TRUE,
+ keyType, usage, usageCount, wincx);
+ encValue->encValue.len = origLen;
+ if (*unWrappedKey == NULL) {
+ goto loser;
+ }
+ SECITEM_FreeItem(publicValue, PR_TRUE);
+ if (params != NULL) {
+ SECITEM_FreeItem(params, PR_TRUE);
+ }
+ PK11_FreeSymKey(wrappingKey);
+ return SECSuccess;
+loser:
+ *unWrappedKey = NULL;
+ return SECFailure;
+}
+
+CRMFEncryptedValue *
+crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey *inPrivKey,
+ SECKEYPublicKey *inCAKey,
+ CRMFEncryptedValue *destValue)
+{
+ SECItem wrappedPrivKey, wrappedSymKey;
+ SECItem encodedParam, *dummy;
+ SECStatus rv;
+ CK_MECHANISM_TYPE pubMechType, symKeyType;
+ unsigned char *wrappedSymKeyBits;
+ unsigned char *wrappedPrivKeyBits;
+ SECItem *iv = NULL;
+ SECOidTag tag;
+ PK11SymKey *symKey;
+ PK11SlotInfo *slot;
+ SECAlgorithmID *symmAlg;
+ CRMFEncryptedValue *myEncrValue = NULL;
+
+ encodedParam.data = NULL;
+ wrappedSymKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
+ wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
+ if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) {
+ goto loser;
+ }
+ if (destValue == NULL) {
+ myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue);
+ if (destValue == NULL) {
+ goto loser;
+ }
+ }
+
+ pubMechType = crmf_get_mechanism_from_public_key(inCAKey);
+ if (pubMechType == CKM_INVALID_MECHANISM) {
+ /* XXX I should probably do something here for non-RSA
+ * keys that are in certs. (ie DSA)
+ * XXX or at least SET AN ERROR CODE.
+ */
+ goto loser;
+ }
+ slot = inPrivKey->pkcs11Slot;
+ PORT_Assert(slot != NULL);
+ symKeyType = crmf_get_best_privkey_wrap_mechanism(slot);
+ symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL);
+ if (symKey == NULL) {
+ goto loser;
+ }
+
+ wrappedSymKey.data = wrappedSymKeyBits;
+ wrappedSymKey.len = MAX_WRAPPED_KEY_LEN;
+ rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ /* Make the length of the result a Bit String length. */
+ wrappedSymKey.len <<= 3;
+
+ wrappedPrivKey.data = wrappedPrivKeyBits;
+ wrappedPrivKey.len = MAX_WRAPPED_KEY_LEN;
+ iv = crmf_get_iv(symKeyType);
+ rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv,
+ &wrappedPrivKey, NULL);
+ PK11_FreeSymKey(symKey);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ /* Make the length of the result a Bit String length. */
+ wrappedPrivKey.len <<= 3;
+ rv = crmf_make_bitstring_copy(NULL,
+ &destValue->encValue,
+ &wrappedPrivKey);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = crmf_make_bitstring_copy(NULL,
+ &destValue->encSymmKey,
+ &wrappedSymKey);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID);
+ if (symmAlg == NULL) {
+ goto loser;
+ }
+
+ dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv,
+ SEC_ASN1_GET(SEC_OctetStringTemplate));
+ if (dummy != &encodedParam) {
+ SECITEM_FreeItem(dummy, PR_TRUE);
+ goto loser;
+ }
+
+ symKeyType = crmf_get_non_pad_mechanism(symKeyType);
+ tag = PK11_MechanismToAlgtag(symKeyType);
+ rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ SECITEM_FreeItem(&encodedParam, PR_FALSE);
+ PORT_Free(wrappedPrivKeyBits);
+ PORT_Free(wrappedSymKeyBits);
+ SECITEM_FreeItem(iv, PR_TRUE);
+ return destValue;
+loser:
+ if (iv != NULL) {
+ SECITEM_FreeItem(iv, PR_TRUE);
+ }
+ if (myEncrValue != NULL) {
+ crmf_destroy_encrypted_value(myEncrValue, PR_TRUE);
+ }
+ if (wrappedSymKeyBits != NULL) {
+ PORT_Free(wrappedSymKeyBits);
+ }
+ if (wrappedPrivKeyBits != NULL) {
+ PORT_Free(wrappedPrivKeyBits);
+ }
+ if (encodedParam.data != NULL) {
+ SECITEM_FreeItem(&encodedParam, PR_FALSE);
+ }
+ return NULL;
+}
+
+CRMFEncryptedKey *
+CRMF_CreateEncryptedKeyWithEncryptedValue(SECKEYPrivateKey *inPrivKey,
+ CERTCertificate *inCACert)
+{
+ SECKEYPublicKey *caPubKey = NULL;
+ CRMFEncryptedKey *encKey = NULL;
+
+ PORT_Assert(inPrivKey != NULL && inCACert != NULL);
+ if (inPrivKey == NULL || inCACert == NULL) {
+ return NULL;
+ }
+
+ caPubKey = CERT_ExtractPublicKey(inCACert);
+ if (caPubKey == NULL) {
+ goto loser;
+ }
+
+ encKey = PORT_ZNew(CRMFEncryptedKey);
+ if (encKey == NULL) {
+ goto loser;
+ }
+#ifdef DEBUG
+ {
+ CRMFEncryptedValue *dummy =
+ crmf_create_encrypted_value_wrapped_privkey(
+ inPrivKey, caPubKey, &encKey->value.encryptedValue);
+ PORT_Assert(dummy == &encKey->value.encryptedValue);
+ }
+#else
+ crmf_create_encrypted_value_wrapped_privkey(
+ inPrivKey, caPubKey, &encKey->value.encryptedValue);
+#endif
+ /* We won't add the der value here, but rather when it
+ * becomes part of a certificate request.
+ */
+ SECKEY_DestroyPublicKey(caPubKey);
+ encKey->encKeyChoice = crmfEncryptedValueChoice;
+ return encKey;
+loser:
+ if (encKey != NULL) {
+ CRMF_DestroyEncryptedKey(encKey);
+ }
+ if (caPubKey != NULL) {
+ SECKEY_DestroyPublicKey(caPubKey);
+ }
+ return NULL;
+}
+
+SECStatus
+CRMF_DestroyEncryptedKey(CRMFEncryptedKey *inEncrKey)
+{
+ return crmf_destroy_encrypted_key(inEncrKey, PR_TRUE);
+}
+
+SECStatus
+crmf_copy_pkiarchiveoptions(PLArenaPool *poolp,
+ CRMFPKIArchiveOptions *destOpt,
+ CRMFPKIArchiveOptions *srcOpt)
+{
+ SECStatus rv;
+ destOpt->archOption = srcOpt->archOption;
+ switch (srcOpt->archOption) {
+ case crmfEncryptedPrivateKey:
+ rv = crmf_copy_encryptedkey(poolp,
+ &srcOpt->option.encryptedKey,
+ &destOpt->option.encryptedKey);
+ break;
+ case crmfKeyGenParameters:
+ case crmfArchiveRemGenPrivKey:
+ /* We've got a union, so having a pointer to one is just
+ * like having a pointer to the other one.
+ */
+ rv = SECITEM_CopyItem(poolp,
+ &destOpt->option.keyGenParameters,
+ &srcOpt->option.keyGenParameters);
+ break;
+ default:
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+static SECStatus
+crmf_check_and_adjust_archoption(CRMFControl *inControl)
+{
+ CRMFPKIArchiveOptions *options;
+
+ options = &inControl->value.archiveOptions;
+ if (options->archOption == crmfNoArchiveOptions) {
+ /* It hasn't been set, so figure it out from the
+ * der.
+ */
+ switch (inControl->derValue.data[0] & 0x0f) {
+ case 0:
+ options->archOption = crmfEncryptedPrivateKey;
+ break;
+ case 1:
+ options->archOption = crmfKeyGenParameters;
+ break;
+ case 2:
+ options->archOption = crmfArchiveRemGenPrivKey;
+ break;
+ default:
+ /* We've got bad DER. Return an error. */
+ return SECFailure;
+ }
+ }
+ return SECSuccess;
+}
+
+static const SEC_ASN1Template *
+crmf_get_pkiarchive_subtemplate(CRMFControl *inControl)
+{
+ const SEC_ASN1Template *retTemplate;
+ SECStatus rv;
+ /*
+ * We could be in the process of decoding, in which case the
+ * archOption field will not be set. Let's check it and set
+ * it accordingly.
+ */
+
+ rv = crmf_check_and_adjust_archoption(inControl);
+ if (rv != SECSuccess) {
+ return NULL;
+ }
+
+ switch (inControl->value.archiveOptions.archOption) {
+ case crmfEncryptedPrivateKey:
+ retTemplate = CRMFEncryptedKeyWithEncryptedValueTemplate;
+ inControl->value.archiveOptions.option.encryptedKey.encKeyChoice =
+ crmfEncryptedValueChoice;
+ break;
+ default:
+ retTemplate = NULL;
+ }
+ return retTemplate;
+}
+
+const SEC_ASN1Template *
+crmf_get_pkiarchiveoptions_subtemplate(CRMFControl *inControl)
+{
+ const SEC_ASN1Template *retTemplate;
+
+ switch (inControl->tag) {
+ case SEC_OID_PKIX_REGCTRL_REGTOKEN:
+ case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
+ retTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate);
+ break;
+ case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
+ retTemplate = crmf_get_pkiarchive_subtemplate(inControl);
+ break;
+ case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
+ case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
+ case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
+ /* We don't support these controls, so we fail for now.*/
+ retTemplate = NULL;
+ break;
+ default:
+ retTemplate = NULL;
+ }
+ return retTemplate;
+}
+
+static SECStatus
+crmf_encode_pkiarchiveoptions(PLArenaPool *poolp, CRMFControl *inControl)
+{
+ const SEC_ASN1Template *asn1Template;
+
+ asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
+ /* We've got a union, so passing a pointer to one element of the
+ * union, is the same as passing a pointer to any of the other
+ * members of the union.
+ */
+ SEC_ASN1EncodeItem(poolp, &inControl->derValue,
+ &inControl->value.archiveOptions, asn1Template);
+
+ if (inControl->derValue.data == NULL) {
+ goto loser;
+ }
+ return SECSuccess;
+loser:
+ return SECFailure;
+}
+
+SECStatus
+CRMF_CertRequestSetPKIArchiveOptions(CRMFCertRequest *inCertReq,
+ CRMFPKIArchiveOptions *inOptions)
+{
+ CRMFControl *newControl;
+ PLArenaPool *poolp;
+ SECStatus rv;
+ void *mark;
+
+ PORT_Assert(inCertReq != NULL && inOptions != NULL);
+ if (inCertReq == NULL || inOptions == NULL) {
+ return SECFailure;
+ }
+ poolp = inCertReq->poolp;
+ mark = PORT_ArenaMark(poolp);
+ rv = crmf_add_new_control(inCertReq,
+ SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS,
+ &newControl);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = crmf_copy_pkiarchiveoptions(poolp,
+ &newControl->value.archiveOptions,
+ inOptions);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = crmf_encode_pkiarchiveoptions(poolp, newControl);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ return SECFailure;
+}
+
+static SECStatus
+crmf_destroy_control(CRMFControl *inControl, PRBool freeit)
+{
+ PORT_Assert(inControl != NULL);
+ if (inControl != NULL) {
+ SECITEM_FreeItem(&inControl->derTag, PR_FALSE);
+ SECITEM_FreeItem(&inControl->derValue, PR_FALSE);
+ /* None of the other tags require special processing at
+ * the moment when freeing because they are not supported,
+ * but if/when they are, add the necessary routines here.
+ * If all controls are supported, then every member of the
+ * union inControl->value will have a case that deals with
+ * it in the following switch statement.
+ */
+ switch (inControl->tag) {
+ case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
+ crmf_destroy_pkiarchiveoptions(&inControl->value.archiveOptions,
+ PR_FALSE);
+ break;
+ default:
+ /* Put this here to get rid of all those annoying warnings.*/
+ break;
+ }
+ if (freeit) {
+ PORT_Free(inControl);
+ }
+ }
+ return SECSuccess;
+}
+
+SECStatus
+CRMF_DestroyControl(CRMFControl *inControl)
+{
+ return crmf_destroy_control(inControl, PR_TRUE);
+}
+
+static SECOidTag
+crmf_controltype_to_tag(CRMFControlType inControlType)
+{
+ SECOidTag retVal;
+
+ switch (inControlType) {
+ case crmfRegTokenControl:
+ retVal = SEC_OID_PKIX_REGCTRL_REGTOKEN;
+ break;
+ case crmfAuthenticatorControl:
+ retVal = SEC_OID_PKIX_REGCTRL_AUTHENTICATOR;
+ break;
+ case crmfPKIPublicationInfoControl:
+ retVal = SEC_OID_PKIX_REGCTRL_PKIPUBINFO;
+ break;
+ case crmfPKIArchiveOptionsControl:
+ retVal = SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS;
+ break;
+ case crmfOldCertIDControl:
+ retVal = SEC_OID_PKIX_REGCTRL_OLD_CERT_ID;
+ break;
+ case crmfProtocolEncrKeyControl:
+ retVal = SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY;
+ break;
+ default:
+ retVal = SEC_OID_UNKNOWN;
+ break;
+ }
+ return retVal;
+}
+
+PRBool
+CRMF_CertRequestIsControlPresent(CRMFCertRequest *inCertReq,
+ CRMFControlType inControlType)
+{
+ SECOidTag controlTag;
+ int i;
+
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL || inCertReq->controls == NULL) {
+ return PR_FALSE;
+ }
+ controlTag = crmf_controltype_to_tag(inControlType);
+ for (i = 0; inCertReq->controls[i] != NULL; i++) {
+ if (inCertReq->controls[i]->tag == controlTag) {
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE;
+}
diff --git a/security/nss/lib/crmf/crmfdec.c b/security/nss/lib/crmf/crmfdec.c
new file mode 100644
index 000000000..ac6e87268
--- /dev/null
+++ b/security/nss/lib/crmf/crmfdec.c
@@ -0,0 +1,360 @@
+/* -*- 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 "secitem.h"
+
+static CRMFPOPChoice
+crmf_get_popchoice_from_der(SECItem *derPOP)
+{
+ CRMFPOPChoice retChoice;
+
+ switch (derPOP->data[0] & 0x0f) {
+ case 0:
+ retChoice = crmfRAVerified;
+ break;
+ case 1:
+ retChoice = crmfSignature;
+ break;
+ case 2:
+ retChoice = crmfKeyEncipherment;
+ break;
+ case 3:
+ retChoice = crmfKeyAgreement;
+ break;
+ default:
+ retChoice = crmfNoPOPChoice;
+ break;
+ }
+ return retChoice;
+}
+
+static SECStatus
+crmf_decode_process_raverified(CRMFCertReqMsg *inCertReqMsg)
+{
+ CRMFProofOfPossession *pop;
+ /* Just set up the structure so that the message structure
+ * looks like one that was created using the API
+ */
+ pop = inCertReqMsg->pop;
+ pop->popChoice.raVerified.data = NULL;
+ pop->popChoice.raVerified.len = 0;
+ return SECSuccess;
+}
+
+static SECStatus
+crmf_decode_process_signature(CRMFCertReqMsg *inCertReqMsg)
+{
+ PORT_Assert(inCertReqMsg->poolp);
+ if (!inCertReqMsg->poolp) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ return SEC_ASN1Decode(inCertReqMsg->poolp,
+ &inCertReqMsg->pop->popChoice.signature,
+ CRMFPOPOSigningKeyTemplate,
+ (const char *)inCertReqMsg->derPOP.data,
+ inCertReqMsg->derPOP.len);
+}
+
+static CRMFPOPOPrivKeyChoice
+crmf_get_messagechoice_from_der(SECItem *derPOP)
+{
+ CRMFPOPOPrivKeyChoice retChoice;
+
+ switch (derPOP->data[2] & 0x0f) {
+ case 0:
+ retChoice = crmfThisMessage;
+ break;
+ case 1:
+ retChoice = crmfSubsequentMessage;
+ break;
+ case 2:
+ retChoice = crmfDHMAC;
+ break;
+ default:
+ retChoice = crmfNoMessage;
+ }
+ return retChoice;
+}
+
+static SECStatus
+crmf_decode_process_popoprivkey(CRMFCertReqMsg *inCertReqMsg)
+{
+ /* We've got a union, so a pointer to one POPOPrivKey
+ * struct is the same as having a pointer to the other
+ * one.
+ */
+ CRMFPOPOPrivKey *popoPrivKey =
+ &inCertReqMsg->pop->popChoice.keyEncipherment;
+ SECItem *derPOP, privKeyDer;
+ SECStatus rv;
+
+ derPOP = &inCertReqMsg->derPOP;
+ popoPrivKey->messageChoice = crmf_get_messagechoice_from_der(derPOP);
+ if (popoPrivKey->messageChoice == crmfNoMessage) {
+ return SECFailure;
+ }
+ /* If we ever encounter BER encodings of this, we'll get in trouble*/
+ switch (popoPrivKey->messageChoice) {
+ case crmfThisMessage:
+ case crmfDHMAC:
+ privKeyDer.type = derPOP->type;
+ privKeyDer.data = &derPOP->data[5];
+ privKeyDer.len = derPOP->len - 5;
+ break;
+ case crmfSubsequentMessage:
+ privKeyDer.type = derPOP->type;
+ privKeyDer.data = &derPOP->data[4];
+ privKeyDer.len = derPOP->len - 4;
+ break;
+ default:
+ return SECFailure;
+ }
+
+ rv = SECITEM_CopyItem(inCertReqMsg->poolp,
+ &popoPrivKey->message.subsequentMessage,
+ &privKeyDer);
+
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ if (popoPrivKey->messageChoice == crmfThisMessage ||
+ popoPrivKey->messageChoice == crmfDHMAC) {
+
+ popoPrivKey->message.thisMessage.len =
+ CRMF_BYTES_TO_BITS(privKeyDer.len) - (int)derPOP->data[4];
+ }
+ return SECSuccess;
+}
+
+static SECStatus
+crmf_decode_process_keyagreement(CRMFCertReqMsg *inCertReqMsg)
+{
+ return crmf_decode_process_popoprivkey(inCertReqMsg);
+}
+
+static SECStatus
+crmf_decode_process_keyencipherment(CRMFCertReqMsg *inCertReqMsg)
+{
+ SECStatus rv;
+
+ rv = crmf_decode_process_popoprivkey(inCertReqMsg);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ if (inCertReqMsg->pop->popChoice.keyEncipherment.messageChoice ==
+ crmfDHMAC) {
+ /* Key Encipherment can not use the dhMAC option for
+ * POPOPrivKey.
+ */
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+static SECStatus
+crmf_decode_process_pop(CRMFCertReqMsg *inCertReqMsg)
+{
+ SECItem *derPOP;
+ PLArenaPool *poolp;
+ CRMFProofOfPossession *pop;
+ void *mark;
+ SECStatus rv;
+
+ derPOP = &inCertReqMsg->derPOP;
+ poolp = inCertReqMsg->poolp;
+ if (derPOP->data == NULL) {
+ /* There is no Proof of Possession field in this message. */
+ return SECSuccess;
+ }
+ mark = PORT_ArenaMark(poolp);
+ pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
+ if (pop == NULL) {
+ goto loser;
+ }
+ pop->popUsed = crmf_get_popchoice_from_der(derPOP);
+ if (pop->popUsed == crmfNoPOPChoice) {
+ /* A bad encoding of CRMF. Not a valid tag was given to the
+ * Proof Of Possession field.
+ */
+ goto loser;
+ }
+ inCertReqMsg->pop = pop;
+ switch (pop->popUsed) {
+ case crmfRAVerified:
+ rv = crmf_decode_process_raverified(inCertReqMsg);
+ break;
+ case crmfSignature:
+ rv = crmf_decode_process_signature(inCertReqMsg);
+ break;
+ case crmfKeyEncipherment:
+ rv = crmf_decode_process_keyencipherment(inCertReqMsg);
+ break;
+ case crmfKeyAgreement:
+ rv = crmf_decode_process_keyagreement(inCertReqMsg);
+ break;
+ default:
+ rv = SECFailure;
+ }
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ inCertReqMsg->pop = NULL;
+ return SECFailure;
+}
+
+static SECStatus
+crmf_decode_process_single_control(PLArenaPool *poolp,
+ CRMFControl *inControl)
+{
+ const SEC_ASN1Template *asn1Template = NULL;
+
+ inControl->tag = SECOID_FindOIDTag(&inControl->derTag);
+ asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl);
+
+ PORT_Assert(asn1Template != NULL);
+ PORT_Assert(poolp != NULL);
+ if (!asn1Template || !poolp) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ /* We've got a union, so passing a pointer to one element of the
+ * union is the same as passing a pointer to any of the other
+ * members of the union.
+ */
+ return SEC_ASN1Decode(poolp, &inControl->value.archiveOptions,
+ asn1Template, (const char *)inControl->derValue.data,
+ inControl->derValue.len);
+}
+
+static SECStatus
+crmf_decode_process_controls(CRMFCertReqMsg *inCertReqMsg)
+{
+ int i, numControls;
+ SECStatus rv;
+ PLArenaPool *poolp;
+ CRMFControl **controls;
+
+ numControls = CRMF_CertRequestGetNumControls(inCertReqMsg->certReq);
+ controls = inCertReqMsg->certReq->controls;
+ poolp = inCertReqMsg->poolp;
+ for (i = 0; i < numControls; i++) {
+ rv = crmf_decode_process_single_control(poolp, controls[i]);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+ return SECSuccess;
+}
+
+static SECStatus
+crmf_decode_process_single_reqmsg(CRMFCertReqMsg *inCertReqMsg)
+{
+ SECStatus rv;
+
+ rv = crmf_decode_process_pop(inCertReqMsg);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = crmf_decode_process_controls(inCertReqMsg);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ inCertReqMsg->certReq->certTemplate.numExtensions =
+ CRMF_CertRequestGetNumberOfExtensions(inCertReqMsg->certReq);
+ inCertReqMsg->isDecoded = PR_TRUE;
+ rv = SECSuccess;
+loser:
+ return rv;
+}
+
+CRMFCertReqMsg *
+CRMF_CreateCertReqMsgFromDER(const char *buf, long len)
+{
+ PLArenaPool *poolp;
+ CRMFCertReqMsg *certReqMsg;
+ SECStatus rv;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ goto loser;
+ }
+ certReqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg);
+ if (certReqMsg == NULL) {
+ goto loser;
+ }
+ certReqMsg->poolp = poolp;
+ rv = SEC_ASN1Decode(poolp, certReqMsg, CRMFCertReqMsgTemplate, buf, len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = crmf_decode_process_single_reqmsg(certReqMsg);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ return certReqMsg;
+loser:
+ if (poolp != NULL) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ }
+ return NULL;
+}
+
+CRMFCertReqMessages *
+CRMF_CreateCertReqMessagesFromDER(const char *buf, long len)
+{
+ long arenaSize;
+ int i;
+ SECStatus rv;
+ PLArenaPool *poolp;
+ CRMFCertReqMessages *certReqMsgs;
+
+ PORT_Assert(buf != NULL);
+ /* Wanna make sure the arena is big enough to store all of the requests
+ * coming in. We'll guestimate according to the length of the buffer.
+ */
+ arenaSize = len + len / 2;
+ poolp = PORT_NewArena(arenaSize);
+ if (poolp == NULL) {
+ return NULL;
+ }
+ certReqMsgs = PORT_ArenaZNew(poolp, CRMFCertReqMessages);
+ if (certReqMsgs == NULL) {
+ goto loser;
+ }
+ certReqMsgs->poolp = poolp;
+ rv = SEC_ASN1Decode(poolp, certReqMsgs, CRMFCertReqMessagesTemplate,
+ buf, len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ for (i = 0; certReqMsgs->messages[i] != NULL; i++) {
+ /* The sub-routines expect the individual messages to have
+ * an arena. We'll give them one temporarily.
+ */
+ certReqMsgs->messages[i]->poolp = poolp;
+ rv = crmf_decode_process_single_reqmsg(certReqMsgs->messages[i]);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ certReqMsgs->messages[i]->poolp = NULL;
+ }
+ return certReqMsgs;
+
+loser:
+ PORT_FreeArena(poolp, PR_FALSE);
+ return NULL;
+}
diff --git a/security/nss/lib/crmf/crmfenc.c b/security/nss/lib/crmf/crmfenc.c
new file mode 100644
index 000000000..6d01a45ce
--- /dev/null
+++ b/security/nss/lib/crmf/crmfenc.c
@@ -0,0 +1,48 @@
+/* -*- 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"
+
+SECStatus
+CRMF_EncodeCertReqMsg(CRMFCertReqMsg *inCertReqMsg,
+ CRMFEncoderOutputCallback fn,
+ void *arg)
+{
+ struct crmfEncoderOutput output;
+
+ output.fn = fn;
+ output.outputArg = arg;
+ return SEC_ASN1Encode(inCertReqMsg, CRMFCertReqMsgTemplate,
+ crmf_encoder_out, &output);
+}
+
+SECStatus
+CRMF_EncodeCertRequest(CRMFCertRequest *inCertReq,
+ CRMFEncoderOutputCallback fn,
+ void *arg)
+{
+ struct crmfEncoderOutput output;
+
+ output.fn = fn;
+ output.outputArg = arg;
+ return SEC_ASN1Encode(inCertReq, CRMFCertRequestTemplate,
+ crmf_encoder_out, &output);
+}
+
+SECStatus
+CRMF_EncodeCertReqMessages(CRMFCertReqMsg **inCertReqMsgs,
+ CRMFEncoderOutputCallback fn,
+ void *arg)
+{
+ struct crmfEncoderOutput output;
+ CRMFCertReqMessages msgs;
+
+ output.fn = fn;
+ output.outputArg = arg;
+ msgs.messages = inCertReqMsgs;
+ return SEC_ASN1Encode(&msgs, CRMFCertReqMessagesTemplate,
+ crmf_encoder_out, &output);
+}
diff --git a/security/nss/lib/crmf/crmffut.h b/security/nss/lib/crmf/crmffut.h
new file mode 100644
index 000000000..d6f937438
--- /dev/null
+++ b/security/nss/lib/crmf/crmffut.h
@@ -0,0 +1,357 @@
+/* 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/. */
+
+/*
+ * These functions to be implemented in the future if the features
+ * which these functions would implement wind up being needed.
+ */
+
+/*
+ * Use this function to create the CRMFSinglePubInfo* variables that will
+ * populate the inPubInfoArray parameter for the function
+ * CRMF_CreatePKIPublicationInfo.
+ *
+ * "inPubMethod" specifies which publication method will be used
+ * "pubLocation" is a representation of the location where
+ */
+extern CRMFSinglePubInfo *
+CRMF_CreateSinglePubInfo(CRMFPublicationMethod inPubMethod,
+ CRMFGeneralName *pubLocation);
+
+/*
+ * Create a PKIPublicationInfo that can later be passed to the function
+ * CRMFAddPubInfoControl.
+ */
+extern CRMFPKIPublicationInfo *
+CRMF_CreatePKIPublicationInfo(CRMFPublicationAction inAction,
+ CRMFSinglePubInfo **inPubInfoArray,
+ int numPubInfo);
+
+/*
+ * Only call this function on a CRMFPublicationInfo that was created by
+ * CRMF_CreatePKIPublicationInfo that was passed in NULL for arena.
+ */
+
+extern SECStatus
+CRMF_DestroyPKIPublicationInfo(CRMFPKIPublicationInfo *inPubInfo);
+
+extern SECStatus CRMF_AddPubInfoControl(CRMFCertRequest *inCertReq,
+ CRMFPKIPublicationInfo *inPubInfo);
+
+/*
+ * This is to create a Cert ID Control which can later be added to
+ * a certificate request.
+ */
+extern CRMFCertID *CRMF_CreateCertID(CRMFGeneralName *issuer,
+ long serialNumber);
+
+extern SECStatus CRMF_DestroyCertID(CRMFCertID *certID);
+
+extern SECStatus CRMF_AddCertIDControl(CRMFCertRequest *inCertReq,
+ CRMFCertID *certID);
+
+extern SECStatus
+CRMF_AddProtocolEncryptioKeyControl(CRMFCertRequest *inCertReq,
+ CERTSubjectPublicKeyInfo *spki);
+
+/*
+ * Add the ASCII Pairs Registration Info to the Certificate Request.
+ * The SECItem must be an OCTET string representation.
+ */
+extern SECStatus
+CRMF_AddUTF8PairsRegInfo(CRMFCertRequest *inCertReq,
+ SECItem *asciiPairs);
+
+/*
+ * This takes a CertRequest and adds it to another CertRequest.
+ */
+extern SECStatus
+CRMF_AddCertReqToRegInfo(CRMFCertRequest *certReqToAddTo,
+ CRMFCertRequest *certReqBeingAdded);
+
+/*
+ * Returns which option was used for the authInfo field of POPOSigningKeyInput
+ */
+extern CRMFPOPOSkiInputAuthChoice
+CRMF_GetSignKeyInputAuthChoice(CRMFPOPOSigningKeyInput *inKeyInput);
+
+/*
+ * Gets the PKMACValue associated with the POPOSigningKeyInput.
+ * If the POPOSigningKeyInput did not use authInfo.publicKeyMAC
+ * the function returns SECFailure and the value at *destValue is unchanged.
+ *
+ * If the POPOSigningKeyInput did use authInfo.publicKeyMAC, the function
+ * returns SECSuccess and places the PKMACValue at *destValue.
+ */
+extern SECStatus
+CRMF_GetSignKeyInputPKMACValue(CRMFPOPOSigningKeyInput *inKeyInput,
+ CRMFPKMACValue **destValue);
+/*
+ * Gets the SubjectPublicKeyInfo from the POPOSigningKeyInput
+ */
+extern CERTSubjectPublicKeyInfo *
+CRMF_GetSignKeyInputPublicKey(CRMFPOPOSigningKeyInput *inKeyInput);
+
+/*
+ * Return the value for the PKIPublicationInfo Control.
+ * A return value of NULL indicates that the Control was
+ * not a PKIPublicationInfo Control. Call
+ * CRMF_DestroyPKIPublicationInfo on the return value when done
+ * using the pointer.
+ */
+extern CRMFPKIPublicationInfo *CRMF_GetPKIPubInfo(CRMFControl *inControl);
+
+/*
+ * Free up a CRMFPKIPublicationInfo structure.
+ */
+extern SECStatus
+CRMF_DestroyPKIPublicationInfo(CRMFPKIPublicationInfo *inPubInfo);
+
+/*
+ * Get the choice used for action in this PKIPublicationInfo.
+ */
+extern CRMFPublicationAction
+CRMF_GetPublicationAction(CRMFPKIPublicationInfo *inPubInfo);
+
+/*
+ * Get the number of pubInfos are stored in the PKIPubicationInfo.
+ */
+extern int CRMF_GetNumPubInfos(CRMFPKIPublicationInfo *inPubInfo);
+
+/*
+ * Get the pubInfo at index for the given PKIPubicationInfo.
+ * Indexing is done like a traditional C Array. (0 .. numElements-1)
+ */
+extern CRMFSinglePubInfo *
+CRMF_GetPubInfoAtIndex(CRMFPKIPublicationInfo *inPubInfo,
+ int index);
+
+/*
+ * Destroy the CRMFSinglePubInfo.
+ */
+extern SECStatus CRMF_DestroySinglePubInfo(CRMFSinglePubInfo *inPubInfo);
+
+/*
+ * Get the pubMethod used by the SinglePubInfo.
+ */
+extern CRMFPublicationMethod
+CRMF_GetPublicationMethod(CRMFSinglePubInfo *inPubInfo);
+
+/*
+ * Get the pubLocation associated with the SinglePubInfo.
+ * A NULL return value indicates there was no pubLocation associated
+ * with the SinglePuInfo.
+ */
+extern CRMFGeneralName *CRMF_GetPubLocation(CRMFSinglePubInfo *inPubInfo);
+
+/*
+ * Get the authInfo.sender field out of the POPOSigningKeyInput.
+ * If the POPOSigningKeyInput did not use the authInfo the function
+ * returns SECFailure and the value at *destName is unchanged.
+ *
+ * If the POPOSigningKeyInput did use authInfo.sender, the function returns
+ * SECSuccess and puts the authInfo.sender at *destName/
+ */
+extern SECStatus CRMF_GetSignKeyInputSender(CRMFPOPOSigningKeyInput *keyInput,
+ CRMFGeneralName **destName);
+
+/**************** CMMF Functions that need to be added. **********************/
+
+/*
+ * FUNCTION: CMMF_POPODecKeyChallContentSetNextChallenge
+ * INPUTS:
+ * inDecKeyChall
+ * The CMMFPOPODecKeyChallContent to operate on.
+ * inRandom
+ * The random number to use when generating the challenge,
+ * inSender
+ * The GeneralName representation of the sender of the challenge.
+ * inPubKey
+ * The public key to use when encrypting the challenge.
+ * NOTES:
+ * This function adds a challenge to the end of the list of challenges
+ * contained by 'inDecKeyChall'. Refer to the CMMF draft on how the
+ * the random number passed in and the sender's GeneralName are used
+ * to generate the challenge and witness fields of the challenge. This
+ * library will use SHA1 as the one-way function for generating the
+ * witess field of the challenge.
+ *
+ * RETURN:
+ * SECSuccess if generating the challenge and adding to the end of list
+ * of challenges was successful. Any other return value indicates an error
+ * while trying to generate the challenge.
+ */
+extern SECStatus
+CMMF_POPODecKeyChallContentSetNextChallenge(CMMFPOPODecKeyChallContent *inDecKeyChall,
+ long inRandom,
+ CERTGeneralName *inSender,
+ SECKEYPublicKey *inPubKey);
+
+/*
+ * FUNCTION: CMMF_POPODecKeyChallContentGetNumChallenges
+ * INPUTS:
+ * inKeyChallCont
+ * The CMMFPOPODecKeyChallContent to operate on.
+ * RETURN:
+ * This function returns the number of CMMFChallenges are contained in
+ * the CMMFPOPODecKeyChallContent structure.
+ */
+extern int CMMF_POPODecKeyChallContentGetNumChallenges(CMMFPOPODecKeyChallContent *inKeyChallCont);
+
+/*
+ * FUNCTION: CMMF_ChallengeGetRandomNumber
+ * INPUTS:
+ * inChallenge
+ * The CMMFChallenge to operate on.
+ * inDest
+ * A pointer to a user supplied buffer where the library
+ * can place a copy of the random integer contatained in the
+ * challenge.
+ * NOTES:
+ * This function returns the value held in the decrypted Rand structure
+ * corresponding to the random integer. The user must call
+ * CMMF_ChallengeDecryptWitness before calling this function. Call
+ * CMMF_ChallengeIsDecrypted to find out if the challenge has been
+ * decrypted.
+ *
+ * RETURN:
+ * SECSuccess indicates the witness field has been previously decrypted
+ * and the value for the random integer was successfully placed at *inDest.
+ * Any other return value indicates an error and that the value at *inDest
+ * is not a valid value.
+ */
+extern SECStatus CMMF_ChallengeGetRandomNumber(CMMFChallenge *inChallenge,
+ long *inDest);
+
+/*
+ * FUNCTION: CMMF_ChallengeGetSender
+ * INPUTS:
+ * inChallenge
+ * the CMMFChallenge to operate on.
+ * NOTES:
+ * This function returns the value held in the decrypted Rand structure
+ * corresponding to the sender. The user must call
+ * CMMF_ChallengeDecryptWitness before calling this function. Call
+ * CMMF_ChallengeIsDecrypted to find out if the witness field has been
+ * decrypted. The user must call CERT_DestroyGeneralName after the return
+ * value is no longer needed.
+ *
+ * RETURN:
+ * A pointer to a copy of the sender CERTGeneralName. A return value of
+ * NULL indicates an error in trying to copy the information or that the
+ * witness field has not been decrypted.
+ */
+extern CERTGeneralName *CMMF_ChallengeGetSender(CMMFChallenge *inChallenge);
+
+/*
+ * FUNCTION: CMMF_ChallengeGetAlgId
+ * INPUTS:
+ * inChallenge
+ * The CMMFChallenge to operate on.
+ * inDestAlgId
+ * A pointer to memory where a pointer to a copy of the algorithm
+ * id can be placed.
+ * NOTES:
+ * This function retrieves the one way function algorithm identifier
+ * contained within the CMMFChallenge if the optional field is present.
+ *
+ * RETURN:
+ * SECSucces indicates the function was able to place a pointer to a copy of
+ * the alogrithm id at *inAlgId. If the value at *inDestAlgId is NULL,
+ * that means there was no algorithm identifier present in the
+ * CMMFChallenge. Any other return value indicates the function was not
+ * able to make a copy of the algorithm identifier. In this case the value
+ * at *inDestAlgId is not valid.
+ */
+extern SECStatus CMMF_ChallengeGetAlgId(CMMFChallenge *inChallenge,
+ SECAlgorithmID *inAlgId);
+
+/*
+ * FUNCTION: CMMF_DestroyChallenge
+ * INPUTS:
+ * inChallenge
+ * The CMMFChallenge to free up.
+ * NOTES:
+ * This function frees up all the memory associated with the CMMFChallenge
+ * passed in.
+ * RETURN:
+ * SECSuccess if freeing all the memory associated with the CMMFChallenge
+ * passed in is successful. Any other return value indicates an error
+ * while freeing the memory.
+ */
+extern SECStatus CMMF_DestroyChallenge(CMMFChallenge *inChallenge);
+
+/*
+ * FUNCTION: CMMF_DestroyPOPODecKeyRespContent
+ * INPUTS:
+ * inDecKeyResp
+ * The CMMFPOPODecKeyRespContent structure to free.
+ * NOTES:
+ * This function frees up all the memory associate with the
+ * CMMFPOPODecKeyRespContent.
+ *
+ * RETURN:
+ * SECSuccess if freeint up all the memory associated with the
+ * CMMFPOPODecKeyRespContent structure is successful. Any other
+ * return value indicates an error while freeing the memory.
+ */
+extern SECStatus
+CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent *inDecKeyResp);
+
+/*
+ * FUNCTION: CMMF_ChallengeDecryptWitness
+ * INPUTS:
+ * inChallenge
+ * The CMMFChallenge to operate on.
+ * inPrivKey
+ * The private key to use to decrypt the witness field.
+ * NOTES:
+ * This function uses the private key to decrypt the challenge field
+ * contained in the CMMFChallenge. Make sure the private key matches the
+ * public key that was used to encrypt the witness. The creator of
+ * the challenge will most likely be an RA that has the public key
+ * from a Cert request. So the private key should be the private key
+ * associated with public key in that request. This function will also
+ * verify the witness field of the challenge.
+ *
+ * RETURN:
+ * SECSuccess if decrypting the witness field was successful. This does
+ * not indicate that the decrypted data is valid, since the private key
+ * passed in may not be the actual key needed to properly decrypt the
+ * witness field. Meaning that there is a decrypted structure now, but
+ * may be garbage because the private key was incorrect.
+ * Any other return value indicates the function could not complete the
+ * decryption process.
+ */
+extern SECStatus CMMF_ChallengeDecryptWitness(CMMFChallenge *inChallenge,
+ SECKEYPrivateKey *inPrivKey);
+
+/*
+ * FUNCTION: CMMF_ChallengeIsDecrypted
+ * INPUTS:
+ * inChallenge
+ * The CMMFChallenge to operate on.
+ * RETURN:
+ * This is a predicate function that returns PR_TRUE if the decryption
+ * process has already been performed. The function return PR_FALSE if
+ * the decryption process has not been performed yet.
+ */
+extern PRBool CMMF_ChallengeIsDecrypted(CMMFChallenge *inChallenge);
+
+/*
+ * FUNCTION: CMMF_DestroyPOPODecKeyChallContent
+ * INPUTS:
+ * inDecKeyCont
+ * The CMMFPOPODecKeyChallContent to free
+ * NOTES:
+ * This function frees up all the memory associated with the
+ * CMMFPOPODecKeyChallContent
+ * RETURN:
+ * SECSuccess if freeing up all the memory associatd with the
+ * CMMFPOPODecKeyChallContent is successful. Any other return value
+ * indicates an error while freeing the memory.
+ *
+ */
+extern SECStatus
+CMMF_DestroyPOPODecKeyChallContent(CMMFPOPODecKeyChallContent *inDecKeyCont);
diff --git a/security/nss/lib/crmf/crmfget.c b/security/nss/lib/crmf/crmfget.c
new file mode 100644
index 000000000..5c1d2aa19
--- /dev/null
+++ b/security/nss/lib/crmf/crmfget.c
@@ -0,0 +1,443 @@
+/* -*- 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"
+
+CRMFPOPChoice
+CRMF_CertReqMsgGetPOPType(CRMFCertReqMsg *inCertReqMsg)
+{
+ PORT_Assert(inCertReqMsg != NULL);
+ if (inCertReqMsg != NULL && inCertReqMsg->pop != NULL) {
+ return inCertReqMsg->pop->popUsed;
+ }
+ return crmfNoPOPChoice;
+}
+
+static SECStatus
+crmf_destroy_validity(CRMFOptionalValidity *inValidity, PRBool freeit)
+{
+ if (inValidity != NULL) {
+ if (inValidity->notBefore.data != NULL) {
+ PORT_Free(inValidity->notBefore.data);
+ }
+ if (inValidity->notAfter.data != NULL) {
+ PORT_Free(inValidity->notAfter.data);
+ }
+ if (freeit) {
+ PORT_Free(inValidity);
+ }
+ }
+ return SECSuccess;
+}
+
+static SECStatus
+crmf_copy_cert_request_validity(PLArenaPool *poolp,
+ CRMFOptionalValidity **destValidity,
+ CRMFOptionalValidity *srcValidity)
+{
+ CRMFOptionalValidity *myValidity = NULL;
+ SECStatus rv;
+
+ *destValidity = myValidity = (poolp == NULL) ? PORT_ZNew(CRMFOptionalValidity)
+ : PORT_ArenaZNew(poolp, CRMFOptionalValidity);
+ if (myValidity == NULL) {
+ goto loser;
+ }
+ if (srcValidity->notBefore.data != NULL) {
+ rv = SECITEM_CopyItem(poolp, &myValidity->notBefore,
+ &srcValidity->notBefore);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcValidity->notAfter.data != NULL) {
+ rv = SECITEM_CopyItem(poolp, &myValidity->notAfter,
+ &srcValidity->notAfter);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ return SECSuccess;
+loser:
+ if (myValidity != NULL && poolp == NULL) {
+ crmf_destroy_validity(myValidity, PR_TRUE);
+ }
+ return SECFailure;
+}
+
+static SECStatus
+crmf_copy_extensions(PLArenaPool *poolp,
+ CRMFCertTemplate *destTemplate,
+ CRMFCertExtension **srcExt)
+{
+ int numExt = 0, i;
+ CRMFCertExtension **myExtArray = NULL;
+
+ while (srcExt[numExt] != NULL) {
+ numExt++;
+ }
+ if (numExt == 0) {
+ /*No extensions to copy.*/
+ destTemplate->extensions = NULL;
+ destTemplate->numExtensions = 0;
+ return SECSuccess;
+ }
+ destTemplate->extensions = myExtArray =
+ PORT_NewArray(CRMFCertExtension *, numExt + 1);
+ if (myExtArray == NULL) {
+ goto loser;
+ }
+
+ for (i = 0; i < numExt; i++) {
+ myExtArray[i] = crmf_copy_cert_extension(poolp, srcExt[i]);
+ if (myExtArray[i] == NULL) {
+ goto loser;
+ }
+ }
+ destTemplate->numExtensions = numExt;
+ myExtArray[numExt] = NULL;
+ return SECSuccess;
+loser:
+ if (myExtArray != NULL) {
+ if (poolp == NULL) {
+ for (i = 0; myExtArray[i] != NULL; i++) {
+ CRMF_DestroyCertExtension(myExtArray[i]);
+ }
+ }
+ PORT_Free(myExtArray);
+ }
+ destTemplate->extensions = NULL;
+ destTemplate->numExtensions = 0;
+ return SECFailure;
+}
+
+static SECStatus
+crmf_copy_cert_request_template(PLArenaPool *poolp,
+ CRMFCertTemplate *destTemplate,
+ CRMFCertTemplate *srcTemplate)
+{
+ SECStatus rv;
+
+ if (srcTemplate->version.data != NULL) {
+ rv = SECITEM_CopyItem(poolp, &destTemplate->version,
+ &srcTemplate->version);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcTemplate->serialNumber.data != NULL) {
+ rv = SECITEM_CopyItem(poolp, &destTemplate->serialNumber,
+ &srcTemplate->serialNumber);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcTemplate->signingAlg != NULL) {
+ rv = crmf_template_copy_secalg(poolp, &destTemplate->signingAlg,
+ srcTemplate->signingAlg);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcTemplate->issuer != NULL) {
+ rv = crmf_copy_cert_name(poolp, &destTemplate->issuer,
+ srcTemplate->issuer);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcTemplate->validity != NULL) {
+ rv = crmf_copy_cert_request_validity(poolp, &destTemplate->validity,
+ srcTemplate->validity);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcTemplate->subject != NULL) {
+ rv = crmf_copy_cert_name(poolp, &destTemplate->subject,
+ srcTemplate->subject);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcTemplate->publicKey != NULL) {
+ rv = crmf_template_add_public_key(poolp, &destTemplate->publicKey,
+ srcTemplate->publicKey);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcTemplate->issuerUID.data != NULL) {
+ rv = crmf_make_bitstring_copy(poolp, &destTemplate->issuerUID,
+ &srcTemplate->issuerUID);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcTemplate->subjectUID.data != NULL) {
+ rv = crmf_make_bitstring_copy(poolp, &destTemplate->subjectUID,
+ &srcTemplate->subjectUID);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ if (srcTemplate->extensions != NULL) {
+ rv = crmf_copy_extensions(poolp, destTemplate,
+ srcTemplate->extensions);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ return SECSuccess;
+loser:
+ return SECFailure;
+}
+
+static CRMFControl *
+crmf_copy_control(PLArenaPool *poolp, CRMFControl *srcControl)
+{
+ CRMFControl *newControl;
+ SECStatus rv;
+
+ newControl = (poolp == NULL) ? PORT_ZNew(CRMFControl) : PORT_ArenaZNew(poolp, CRMFControl);
+ if (newControl == NULL) {
+ goto loser;
+ }
+ newControl->tag = srcControl->tag;
+ rv = SECITEM_CopyItem(poolp, &newControl->derTag, &srcControl->derTag);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(poolp, &newControl->derValue, &srcControl->derValue);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ /* We only handle PKIArchiveOptions Control right now. But if in
+ * the future, more controls that are part of the union are added,
+ * then they need to be handled here as well.
+ */
+ switch (newControl->tag) {
+ case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
+ rv = crmf_copy_pkiarchiveoptions(poolp,
+ &newControl->value.archiveOptions,
+ &srcControl->value.archiveOptions);
+ break;
+ default:
+ rv = SECSuccess;
+ }
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return newControl;
+
+loser:
+ if (poolp == NULL && newControl != NULL) {
+ CRMF_DestroyControl(newControl);
+ }
+ return NULL;
+}
+
+static SECStatus
+crmf_copy_cert_request_controls(PLArenaPool *poolp,
+ CRMFCertRequest *destReq,
+ CRMFCertRequest *srcReq)
+{
+ int numControls, i;
+ CRMFControl **myControls = NULL;
+
+ numControls = CRMF_CertRequestGetNumControls(srcReq);
+ if (numControls == 0) {
+ /* No Controls To Copy*/
+ return SECSuccess;
+ }
+ myControls = destReq->controls = PORT_NewArray(CRMFControl *,
+ numControls + 1);
+ if (myControls == NULL) {
+ goto loser;
+ }
+ for (i = 0; i < numControls; i++) {
+ myControls[i] = crmf_copy_control(poolp, srcReq->controls[i]);
+ if (myControls[i] == NULL) {
+ goto loser;
+ }
+ }
+ myControls[numControls] = NULL;
+ return SECSuccess;
+loser:
+ if (myControls != NULL) {
+ if (poolp == NULL) {
+ for (i = 0; myControls[i] != NULL; i++) {
+ CRMF_DestroyControl(myControls[i]);
+ }
+ }
+ PORT_Free(myControls);
+ }
+ return SECFailure;
+}
+
+CRMFCertRequest *
+crmf_copy_cert_request(PLArenaPool *poolp, CRMFCertRequest *srcReq)
+{
+ CRMFCertRequest *newReq = NULL;
+ SECStatus rv;
+
+ if (srcReq == NULL) {
+ return NULL;
+ }
+ newReq = (poolp == NULL) ? PORT_ZNew(CRMFCertRequest) : PORT_ArenaZNew(poolp, CRMFCertRequest);
+ if (newReq == NULL) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(poolp, &newReq->certReqId, &srcReq->certReqId);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = crmf_copy_cert_request_template(poolp, &newReq->certTemplate,
+ &srcReq->certTemplate);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = crmf_copy_cert_request_controls(poolp, newReq, srcReq);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return newReq;
+loser:
+ if (newReq != NULL && poolp == NULL) {
+ CRMF_DestroyCertRequest(newReq);
+ PORT_Free(newReq);
+ }
+ return NULL;
+}
+
+SECStatus
+CRMF_DestroyGetValidity(CRMFGetValidity *inValidity)
+{
+ PORT_Assert(inValidity != NULL);
+ if (inValidity != NULL) {
+ if (inValidity->notAfter) {
+ PORT_Free(inValidity->notAfter);
+ inValidity->notAfter = NULL;
+ }
+ if (inValidity->notBefore) {
+ PORT_Free(inValidity->notBefore);
+ inValidity->notBefore = NULL;
+ }
+ }
+ return SECSuccess;
+}
+
+SECStatus
+crmf_make_bitstring_copy(PLArenaPool *arena, SECItem *dest, SECItem *src)
+{
+ int origLenBits;
+ int bytesToCopy;
+ SECStatus rv;
+
+ origLenBits = src->len;
+ bytesToCopy = CRMF_BITS_TO_BYTES(origLenBits);
+ src->len = bytesToCopy;
+ rv = SECITEM_CopyItem(arena, dest, src);
+ src->len = origLenBits;
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ dest->len = origLenBits;
+ return SECSuccess;
+}
+
+int
+CRMF_CertRequestGetNumberOfExtensions(CRMFCertRequest *inCertReq)
+{
+ CRMFCertTemplate *certTemplate;
+ int count = 0;
+
+ certTemplate = &inCertReq->certTemplate;
+ if (certTemplate->extensions) {
+ while (certTemplate->extensions[count] != NULL)
+ count++;
+ }
+ return count;
+}
+
+SECOidTag
+CRMF_CertExtensionGetOidTag(CRMFCertExtension *inExtension)
+{
+ PORT_Assert(inExtension != NULL);
+ if (inExtension == NULL) {
+ return SEC_OID_UNKNOWN;
+ }
+ return SECOID_FindOIDTag(&inExtension->id);
+}
+
+PRBool
+CRMF_CertExtensionGetIsCritical(CRMFCertExtension *inExt)
+{
+ PORT_Assert(inExt != NULL);
+ if (inExt == NULL) {
+ return PR_FALSE;
+ }
+ return inExt->critical.data != NULL;
+}
+
+SECItem *
+CRMF_CertExtensionGetValue(CRMFCertExtension *inExtension)
+{
+ PORT_Assert(inExtension != NULL);
+ if (inExtension == NULL) {
+ return NULL;
+ }
+
+ return SECITEM_DupItem(&inExtension->value);
+}
+
+SECStatus
+CRMF_DestroyPOPOSigningKey(CRMFPOPOSigningKey *inKey)
+{
+ PORT_Assert(inKey != NULL);
+ if (inKey != NULL) {
+ if (inKey->derInput.data != NULL) {
+ SECITEM_FreeItem(&inKey->derInput, PR_FALSE);
+ }
+ if (inKey->algorithmIdentifier != NULL) {
+ SECOID_DestroyAlgorithmID(inKey->algorithmIdentifier, PR_TRUE);
+ }
+ if (inKey->signature.data != NULL) {
+ SECITEM_FreeItem(&inKey->signature, PR_FALSE);
+ }
+ PORT_Free(inKey);
+ }
+ return SECSuccess;
+}
+
+SECStatus
+CRMF_DestroyPOPOPrivKey(CRMFPOPOPrivKey *inPrivKey)
+{
+ PORT_Assert(inPrivKey != NULL);
+ if (inPrivKey != NULL) {
+ SECITEM_FreeItem(&inPrivKey->message.thisMessage, PR_FALSE);
+ PORT_Free(inPrivKey);
+ }
+ return SECSuccess;
+}
+
+int
+CRMF_CertRequestGetNumControls(CRMFCertRequest *inCertReq)
+{
+ int count = 0;
+
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return 0;
+ }
+ if (inCertReq->controls) {
+ while (inCertReq->controls[count] != NULL)
+ count++;
+ }
+ return count;
+}
diff --git a/security/nss/lib/crmf/crmfi.h b/security/nss/lib/crmf/crmfi.h
new file mode 100644
index 000000000..badfd2b05
--- /dev/null
+++ b/security/nss/lib/crmf/crmfi.h
@@ -0,0 +1,185 @@
+/* -*- 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/. */
+
+#ifndef _CRMFI_H_
+#define _CRMFI_H_
+/* This file will contain all declarations common to both
+ * encoding and decoding of CRMF Cert Requests. This header
+ * file should only be included internally by CRMF implementation
+ * files.
+ */
+#include "secasn1.h"
+#include "crmfit.h"
+#include "secerr.h"
+#include "blapit.h"
+
+#define CRMF_DEFAULT_ARENA_SIZE 1024
+
+/*
+ * Explanation for the definition of MAX_WRAPPED_KEY_LEN:
+ *
+ * It's used for internal buffers to transport a wrapped private key.
+ * The value is in BYTES.
+ * We want to define a reasonable upper bound for this value.
+ * Ideally this could be calculated, but in order to simplify the code
+ * we want to estimate the maximum requires size.
+ * See also bug 655850 for the full explanation.
+ *
+ * We know the largest wrapped keys are RSA keys.
+ * We'll estimate the maximum size needed for wrapped RSA keys,
+ * and assume it's sufficient for wrapped keys of any type we support.
+ *
+ * The maximum size of RSA keys in bits is defined elsewhere as
+ * RSA_MAX_MODULUS_BITS
+ *
+ * The idea is to define MAX_WRAPPED_KEY_LEN based on the above.
+ *
+ * A wrapped RSA key requires about
+ * ( ( RSA_MAX_MODULUS_BITS / 8 ) * 5.5) + 65
+ * bytes.
+ *
+ * Therefore, a safe upper bound is:
+ * ( ( RSA_MAX_MODULUS_BITS / 8 ) *8 ) = RSA_MAX_MODULUS_BITS
+ *
+ */
+#define MAX_WRAPPED_KEY_LEN RSA_MAX_MODULUS_BITS
+
+#define CRMF_BITS_TO_BYTES(bits) (((bits) + 7) / 8)
+#define CRMF_BYTES_TO_BITS(bytes) ((bytes)*8)
+
+struct crmfEncoderArg {
+ SECItem *buffer;
+ unsigned long allocatedLen;
+};
+
+struct crmfEncoderOutput {
+ CRMFEncoderOutputCallback fn;
+ void *outputArg;
+};
+
+/*
+ * This function is used by the API for encoding functions that are
+ * exposed through the API, ie all of the CMMF_Encode* and CRMF_Encode*
+ * functions.
+ */
+extern void
+crmf_encoder_out(void *arg, const char *buf, unsigned long len,
+ int depth, SEC_ASN1EncodingPart data_kind);
+
+/*
+ * This function is used when we want to encode something locally within
+ * the library, ie the CertRequest so that we can produce its signature.
+ */
+extern SECStatus
+crmf_init_encoder_callback_arg(struct crmfEncoderArg *encoderArg,
+ SECItem *derDest);
+
+/*
+ * This is the callback function we feed to the ASN1 encoder when doing
+ * internal DER-encodings. ie, encoding the cert request so we can
+ * produce a signature.
+ */
+extern void
+crmf_generic_encoder_callback(void *arg, const char *buf, unsigned long len,
+ int depth, SEC_ASN1EncodingPart data_kind);
+
+/* The ASN1 templates that need to be seen by internal files
+ * in order to implement CRMF.
+ */
+extern const SEC_ASN1Template CRMFCertReqMsgTemplate[];
+extern const SEC_ASN1Template CRMFRAVerifiedTemplate[];
+extern const SEC_ASN1Template CRMFPOPOSigningKeyTemplate[];
+extern const SEC_ASN1Template CRMFPOPOKeyEnciphermentTemplate[];
+extern const SEC_ASN1Template CRMFPOPOKeyAgreementTemplate[];
+extern const SEC_ASN1Template CRMFThisMessageTemplate[];
+extern const SEC_ASN1Template CRMFSubsequentMessageTemplate[];
+extern const SEC_ASN1Template CRMFDHMACTemplate[];
+extern const SEC_ASN1Template CRMFEncryptedKeyWithEncryptedValueTemplate[];
+extern const SEC_ASN1Template CRMFEncryptedValueTemplate[];
+
+/*
+ * Use these two values for encoding Boolean values.
+ */
+extern const unsigned char hexTrue;
+extern const unsigned char hexFalse;
+/*
+ * Prototypes for helper routines used internally by multiple files.
+ */
+extern SECStatus crmf_encode_integer(PLArenaPool *poolp, SECItem *dest,
+ long value);
+extern SECStatus crmf_make_bitstring_copy(PLArenaPool *arena, SECItem *dest,
+ SECItem *src);
+
+extern SECStatus crmf_copy_pkiarchiveoptions(PLArenaPool *poolp,
+ CRMFPKIArchiveOptions *destOpt,
+ CRMFPKIArchiveOptions *srcOpt);
+extern SECStatus
+crmf_destroy_pkiarchiveoptions(CRMFPKIArchiveOptions *inArchOptions,
+ PRBool freeit);
+extern const SEC_ASN1Template *
+crmf_get_pkiarchiveoptions_subtemplate(CRMFControl *inControl);
+
+extern SECStatus crmf_copy_encryptedkey(PLArenaPool *poolp,
+ CRMFEncryptedKey *srcEncrKey,
+ CRMFEncryptedKey *destEncrKey);
+extern SECStatus
+crmf_copy_encryptedvalue(PLArenaPool *poolp,
+ CRMFEncryptedValue *srcValue,
+ CRMFEncryptedValue *destValue);
+
+extern SECStatus
+crmf_copy_encryptedvalue_secalg(PLArenaPool *poolp,
+ SECAlgorithmID *srcAlgId,
+ SECAlgorithmID **destAlgId);
+
+extern SECStatus crmf_template_copy_secalg(PLArenaPool *poolp,
+ SECAlgorithmID **dest,
+ SECAlgorithmID *src);
+
+extern SECStatus crmf_copy_cert_name(PLArenaPool *poolp, CERTName **dest,
+ CERTName *src);
+
+extern SECStatus crmf_template_add_public_key(PLArenaPool *poolp,
+ CERTSubjectPublicKeyInfo **dest,
+ CERTSubjectPublicKeyInfo *pubKey);
+
+extern CRMFCertExtension *crmf_create_cert_extension(PLArenaPool *poolp,
+ SECOidTag tag,
+ PRBool isCritical,
+ SECItem *data);
+extern CRMFCertRequest *
+crmf_copy_cert_request(PLArenaPool *poolp, CRMFCertRequest *srcReq);
+
+extern SECStatus crmf_destroy_encrypted_value(CRMFEncryptedValue *inEncrValue,
+ PRBool freeit);
+
+extern CRMFEncryptedValue *
+crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey *inPrivKey,
+ SECKEYPublicKey *inPubKey,
+ CRMFEncryptedValue *destValue);
+
+extern CK_MECHANISM_TYPE
+crmf_get_mechanism_from_public_key(SECKEYPublicKey *inPubKey);
+
+extern SECStatus
+crmf_encrypted_value_unwrap_priv_key(PLArenaPool *poolp,
+ CRMFEncryptedValue *encValue,
+ SECKEYPrivateKey *privKey,
+ SECKEYPublicKey *newPubKey,
+ SECItem *nickname,
+ PK11SlotInfo *slot,
+ unsigned char keyUsage,
+ SECKEYPrivateKey **unWrappedKey,
+ void *wincx);
+
+extern SECItem *
+crmf_get_public_value(SECKEYPublicKey *pubKey, SECItem *dest);
+
+extern CRMFCertExtension *
+crmf_copy_cert_extension(PLArenaPool *poolp, CRMFCertExtension *inExtension);
+
+extern SECStatus
+crmf_create_prtime(SECItem *src, PRTime **dest);
+#endif /*_CRMFI_H_*/
diff --git a/security/nss/lib/crmf/crmfit.h b/security/nss/lib/crmf/crmfit.h
new file mode 100644
index 000000000..c5c4b96e9
--- /dev/null
+++ b/security/nss/lib/crmf/crmfit.h
@@ -0,0 +1,185 @@
+/* -*- 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/. */
+
+#ifndef _CRMFIT_H_
+#define _CRMFIT_H_
+
+struct CRMFCertReqMessagesStr {
+ CRMFCertReqMsg **messages;
+ PLArenaPool *poolp;
+};
+
+struct CRMFCertExtensionStr {
+ SECItem id;
+ SECItem critical;
+ SECItem value;
+};
+
+struct CRMFOptionalValidityStr {
+ SECItem notBefore;
+ SECItem notAfter;
+};
+
+struct CRMFCertTemplateStr {
+ SECItem version;
+ SECItem serialNumber;
+ SECAlgorithmID *signingAlg;
+ CERTName *issuer;
+ CRMFOptionalValidity *validity;
+ CERTName *subject;
+ CERTSubjectPublicKeyInfo *publicKey;
+ SECItem issuerUID;
+ SECItem subjectUID;
+ CRMFCertExtension **extensions;
+ int numExtensions;
+};
+
+struct CRMFCertIDStr {
+ SECItem issuer; /* General Name */
+ SECItem serialNumber; /*INTEGER*/
+};
+
+struct CRMFEncryptedValueStr {
+ SECAlgorithmID *intendedAlg;
+ SECAlgorithmID *symmAlg;
+ SECItem encSymmKey; /*BIT STRING */
+ SECAlgorithmID *keyAlg;
+ SECItem valueHint; /*OCTET STRING */
+ SECItem encValue; /*BIT STRING */
+};
+
+/*
+ * The field derValue will contain the actual der
+ * to include in the encoding or that was read in
+ * from a der blob.
+ */
+struct CRMFEncryptedKeyStr {
+ union {
+ SEC_PKCS7ContentInfo *envelopedData;
+ CRMFEncryptedValue encryptedValue;
+ } value;
+ CRMFEncryptedKeyChoice encKeyChoice;
+ SECItem derValue;
+};
+
+/* ASN1 must only have one of the following 3 options. */
+struct CRMFPKIArchiveOptionsStr {
+ union {
+ CRMFEncryptedKey encryptedKey;
+ SECItem keyGenParameters;
+ SECItem archiveRemGenPrivKey; /* BOOLEAN */
+ } option;
+ CRMFPKIArchiveOptionsType archOption;
+};
+
+struct CRMFPKIPublicationInfoStr {
+ SECItem action; /* Possible values */
+ /* dontPublish (0), pleasePublish (1) */
+ CRMFSinglePubInfo **pubInfos;
+};
+
+struct CRMFControlStr {
+ SECOidTag tag;
+ SECItem derTag;
+ SECItem derValue;
+ /* These will be C structures used to represent the various
+ * options. Values that can't be stored as der right away.
+ * After creating these structures, we'll place their der
+ * encoding in derValue so the encoder knows how to get to
+ * it.
+ */
+ union {
+ CRMFCertID oldCertId;
+ CRMFPKIArchiveOptions archiveOptions;
+ CRMFPKIPublicationInfo pubInfo;
+ CRMFProtocolEncrKey protEncrKey;
+ } value;
+};
+
+struct CRMFCertRequestStr {
+ SECItem certReqId;
+ CRMFCertTemplate certTemplate;
+ CRMFControl **controls;
+ /* The following members are used by the internal implementation, but
+ * are not part of the encoding.
+ */
+ PLArenaPool *poolp;
+ PRUint32 requestID; /* This is the value that will be encoded into
+ * the certReqId field.
+ */
+};
+
+struct CRMFAttributeStr {
+ SECItem derTag;
+ SECItem derValue;
+};
+
+struct CRMFCertReqMsgStr {
+ CRMFCertRequest *certReq;
+ CRMFProofOfPossession *pop;
+ CRMFAttribute **regInfo;
+ SECItem derPOP;
+ /* This arena will be used for allocating memory when decoding.
+ */
+ PLArenaPool *poolp;
+ PRBool isDecoded;
+};
+
+struct CRMFPOPOSigningKeyInputStr {
+ /* ASN1 must have only one of the next 2 options */
+ union {
+ SECItem sender; /*General Name*/
+ CRMFPKMACValue *publicKeyMAC;
+ } authInfo;
+ CERTSubjectPublicKeyInfo publicKey;
+};
+
+struct CRMFPOPOSigningKeyStr {
+ SECItem derInput; /*If in the future we support
+ *POPOSigningKeyInput, this will
+ *a C structure representation
+ *instead.
+ */
+ SECAlgorithmID *algorithmIdentifier;
+ SECItem signature; /* This is a BIT STRING. Remember */
+}; /* that when interpreting. */
+
+/* ASN1 must only choose one of these members */
+struct CRMFPOPOPrivKeyStr {
+ union {
+ SECItem thisMessage; /* BIT STRING */
+ SECItem subsequentMessage; /*INTEGER*/
+ SECItem dhMAC; /*BIT STRING*/
+ } message;
+ CRMFPOPOPrivKeyChoice messageChoice;
+};
+
+/* ASN1 must only have one of these options. */
+struct CRMFProofOfPossessionStr {
+ union {
+ SECItem raVerified;
+ CRMFPOPOSigningKey signature;
+ CRMFPOPOPrivKey keyEncipherment;
+ CRMFPOPOPrivKey keyAgreement;
+ } popChoice;
+ CRMFPOPChoice popUsed; /*Not part of encoding*/
+};
+
+struct CRMFPKMACValueStr {
+ SECAlgorithmID algID;
+ SECItem value; /*BIT STRING*/
+};
+
+struct CRMFSinglePubInfoStr {
+ SECItem pubMethod; /* Possible Values:
+ * dontCare (0)
+ * x500 (1)
+ * web (2)
+ * ldap (3)
+ */
+ CERTGeneralName *pubLocation; /* General Name */
+};
+
+#endif /* _CRMFIT_H_ */
diff --git a/security/nss/lib/crmf/crmfpop.c b/security/nss/lib/crmf/crmfpop.c
new file mode 100644
index 000000000..725f8c730
--- /dev/null
+++ b/security/nss/lib/crmf/crmfpop.c
@@ -0,0 +1,598 @@
+/* -*- 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 "secasn1.h"
+#include "keyhi.h"
+#include "cryptohi.h"
+
+#define CRMF_DEFAULT_ALLOC_SIZE 1024U
+
+SECStatus
+crmf_init_encoder_callback_arg(struct crmfEncoderArg *encoderArg,
+ SECItem *derDest)
+{
+ derDest->data = PORT_ZNewArray(unsigned char, CRMF_DEFAULT_ALLOC_SIZE);
+ if (derDest->data == NULL) {
+ return SECFailure;
+ }
+ derDest->len = 0;
+ encoderArg->allocatedLen = CRMF_DEFAULT_ALLOC_SIZE;
+ encoderArg->buffer = derDest;
+ return SECSuccess;
+}
+
+/* Caller should release or unmark the pool, instead of doing it here.
+** But there are NO callers of this function at present...
+*/
+SECStatus
+CRMF_CertReqMsgSetRAVerifiedPOP(CRMFCertReqMsg *inCertReqMsg)
+{
+ CRMFProofOfPossession *pop;
+ PLArenaPool *poolp;
+ void *mark;
+
+ PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL);
+ poolp = inCertReqMsg->poolp;
+ mark = PORT_ArenaMark(poolp);
+ if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice) {
+ return SECFailure;
+ }
+ pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
+ if (pop == NULL) {
+ goto loser;
+ }
+ pop->popUsed = crmfRAVerified;
+ pop->popChoice.raVerified.data = NULL;
+ pop->popChoice.raVerified.len = 0;
+ inCertReqMsg->pop = pop;
+ (void)SEC_ASN1EncodeItem(poolp, &(inCertReqMsg->derPOP),
+ &(pop->popChoice.raVerified),
+ CRMFRAVerifiedTemplate);
+ return SECSuccess;
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ return SECFailure;
+}
+
+static SECOidTag
+crmf_get_key_sign_tag(SECKEYPublicKey *inPubKey)
+{
+ /* maintain backward compatibility with older
+ * implementations */
+ if (inPubKey->keyType == rsaKey) {
+ return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+ }
+ return SEC_GetSignatureAlgorithmOidTag(inPubKey->keyType, SEC_OID_UNKNOWN);
+}
+
+static SECAlgorithmID *
+crmf_create_poposignkey_algid(PLArenaPool *poolp,
+ SECKEYPublicKey *inPubKey)
+{
+ SECAlgorithmID *algID;
+ SECOidTag tag;
+ SECStatus rv;
+ void *mark;
+
+ mark = PORT_ArenaMark(poolp);
+ algID = PORT_ArenaZNew(poolp, SECAlgorithmID);
+ if (algID == NULL) {
+ goto loser;
+ }
+ tag = crmf_get_key_sign_tag(inPubKey);
+ if (tag == SEC_OID_UNKNOWN) {
+ goto loser;
+ }
+ rv = SECOID_SetAlgorithmID(poolp, algID, tag, NULL);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_ArenaUnmark(poolp, mark);
+ return algID;
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ return NULL;
+}
+
+static CRMFPOPOSigningKeyInput *
+crmf_create_poposigningkeyinput(PLArenaPool *poolp, CERTCertificate *inCert,
+ CRMFMACPasswordCallback fn, void *arg)
+{
+ /* PSM isn't going to do this, so we'll fail here for now.*/
+ return NULL;
+}
+
+void
+crmf_generic_encoder_callback(void *arg, const char *buf, unsigned long len,
+ int depth, SEC_ASN1EncodingPart data_kind)
+{
+ struct crmfEncoderArg *encoderArg = (struct crmfEncoderArg *)arg;
+ unsigned char *cursor;
+
+ if (encoderArg->buffer->len + len > encoderArg->allocatedLen) {
+ int newSize = encoderArg->buffer->len + CRMF_DEFAULT_ALLOC_SIZE;
+ void *dummy = PORT_Realloc(encoderArg->buffer->data, newSize);
+ if (dummy == NULL) {
+ /* I really want to return an error code here */
+ PORT_Assert(0);
+ return;
+ }
+ encoderArg->buffer->data = dummy;
+ encoderArg->allocatedLen = newSize;
+ }
+ cursor = &(encoderArg->buffer->data[encoderArg->buffer->len]);
+ if (len) {
+ PORT_Memcpy(cursor, buf, len);
+ }
+ encoderArg->buffer->len += len;
+}
+
+static SECStatus
+crmf_encode_certreq(CRMFCertRequest *inCertReq, SECItem *derDest)
+{
+ struct crmfEncoderArg encoderArg;
+ SECStatus rv;
+
+ rv = crmf_init_encoder_callback_arg(&encoderArg, derDest);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ return SEC_ASN1Encode(inCertReq, CRMFCertRequestTemplate,
+ crmf_generic_encoder_callback, &encoderArg);
+}
+
+static SECStatus
+crmf_sign_certreq(PLArenaPool *poolp,
+ CRMFPOPOSigningKey *crmfSignKey,
+ CRMFCertRequest *certReq,
+ SECKEYPrivateKey *inKey,
+ SECAlgorithmID *inAlgId)
+{
+ SECItem derCertReq = { siBuffer, NULL, 0 };
+ SECItem certReqSig = { siBuffer, NULL, 0 };
+ SECStatus rv = SECSuccess;
+
+ rv = crmf_encode_certreq(certReq, &derCertReq);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SEC_SignData(&certReqSig, derCertReq.data, derCertReq.len,
+ inKey, SECOID_GetAlgorithmTag(inAlgId));
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Now make it a part of the POPOSigningKey */
+ rv = SECITEM_CopyItem(poolp, &(crmfSignKey->signature), &certReqSig);
+ /* Convert this length to number of bits */
+ crmfSignKey->signature.len <<= 3;
+
+loser:
+ if (derCertReq.data != NULL) {
+ PORT_Free(derCertReq.data);
+ }
+ if (certReqSig.data != NULL) {
+ PORT_Free(certReqSig.data);
+ }
+ return rv;
+}
+
+static SECStatus
+crmf_create_poposignkey(PLArenaPool *poolp,
+ CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOSigningKeyInput *signKeyInput,
+ SECKEYPrivateKey *inPrivKey,
+ SECAlgorithmID *inAlgID,
+ CRMFPOPOSigningKey *signKey)
+{
+ CRMFCertRequest *certReq;
+ void *mark;
+ PRBool useSignKeyInput;
+ SECStatus rv;
+
+ PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->certReq != NULL);
+ mark = PORT_ArenaMark(poolp);
+ if (signKey == NULL) {
+ goto loser;
+ }
+ certReq = inCertReqMsg->certReq;
+ useSignKeyInput = !(CRMF_DoesRequestHaveField(certReq, crmfSubject) &&
+ CRMF_DoesRequestHaveField(certReq, crmfPublicKey));
+
+ if (useSignKeyInput) {
+ goto loser;
+ } else {
+ rv = crmf_sign_certreq(poolp, signKey, certReq, inPrivKey, inAlgID);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ return SECFailure;
+}
+
+SECStatus
+CRMF_CertReqMsgSetSignaturePOP(CRMFCertReqMsg *inCertReqMsg,
+ SECKEYPrivateKey *inPrivKey,
+ SECKEYPublicKey *inPubKey,
+ CERTCertificate *inCertForInput,
+ CRMFMACPasswordCallback fn,
+ void *arg)
+{
+ SECAlgorithmID *algID;
+ PLArenaPool *poolp;
+ SECItem derTemp = { siBuffer, NULL, 0 };
+ void *mark;
+ SECStatus rv;
+ CRMFPOPOSigningKeyInput *signKeyInput = NULL;
+ CRMFCertRequest *certReq;
+ CRMFProofOfPossession *pop;
+ struct crmfEncoderArg encoderArg;
+
+ PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->certReq != NULL &&
+ inCertReqMsg->pop == NULL);
+ certReq = inCertReqMsg->certReq;
+ if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice ||
+ !CRMF_DoesRequestHaveField(certReq, crmfPublicKey)) {
+ return SECFailure;
+ }
+ poolp = inCertReqMsg->poolp;
+ mark = PORT_ArenaMark(poolp);
+ algID = crmf_create_poposignkey_algid(poolp, inPubKey);
+
+ if (!CRMF_DoesRequestHaveField(certReq, crmfSubject)) {
+ signKeyInput = crmf_create_poposigningkeyinput(poolp, inCertForInput,
+ fn, arg);
+ if (signKeyInput == NULL) {
+ goto loser;
+ }
+ }
+
+ pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
+ if (pop == NULL) {
+ goto loser;
+ }
+
+ rv = crmf_create_poposignkey(poolp, inCertReqMsg,
+ signKeyInput, inPrivKey, algID,
+ &(pop->popChoice.signature));
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ pop->popUsed = crmfSignature;
+ pop->popChoice.signature.algorithmIdentifier = algID;
+ inCertReqMsg->pop = pop;
+
+ rv = crmf_init_encoder_callback_arg(&encoderArg, &derTemp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SEC_ASN1Encode(&pop->popChoice.signature,
+ CRMFPOPOSigningKeyTemplate,
+ crmf_generic_encoder_callback, &encoderArg);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(poolp, &(inCertReqMsg->derPOP), &derTemp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_Free(derTemp.data);
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ if (derTemp.data != NULL) {
+ PORT_Free(derTemp.data);
+ }
+ return SECFailure;
+}
+
+static const SEC_ASN1Template *
+crmf_get_popoprivkey_subtemplate(CRMFPOPOPrivKey *inPrivKey)
+{
+ const SEC_ASN1Template *retTemplate = NULL;
+
+ switch (inPrivKey->messageChoice) {
+ case crmfThisMessage:
+ retTemplate = CRMFThisMessageTemplate;
+ break;
+ case crmfSubsequentMessage:
+ retTemplate = CRMFSubsequentMessageTemplate;
+ break;
+ case crmfDHMAC:
+ retTemplate = CRMFDHMACTemplate;
+ break;
+ default:
+ retTemplate = NULL;
+ }
+ return retTemplate;
+}
+
+static SECStatus
+crmf_encode_popoprivkey(PLArenaPool *poolp,
+ CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOPrivKey *popoPrivKey,
+ const SEC_ASN1Template *privKeyTemplate)
+{
+ struct crmfEncoderArg encoderArg;
+ SECItem derTemp = { siBuffer, NULL, 0 };
+ SECStatus rv;
+ void *mark;
+ const SEC_ASN1Template *subDerTemplate;
+
+ mark = PORT_ArenaMark(poolp);
+ rv = crmf_init_encoder_callback_arg(&encoderArg, &derTemp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ subDerTemplate = crmf_get_popoprivkey_subtemplate(popoPrivKey);
+ /* We've got a union, so a pointer to one item is a pointer to
+ * all the items in the union.
+ */
+ rv = SEC_ASN1Encode(&popoPrivKey->message.thisMessage,
+ subDerTemplate,
+ crmf_generic_encoder_callback, &encoderArg);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (encoderArg.allocatedLen > derTemp.len + 2) {
+ void *dummy = PORT_Realloc(derTemp.data, derTemp.len + 2);
+ if (dummy == NULL) {
+ goto loser;
+ }
+ derTemp.data = dummy;
+ }
+ PORT_Memmove(&derTemp.data[2], &derTemp.data[0], derTemp.len);
+ /* I couldn't figure out how to get the ASN1 encoder to implicitly
+ * tag an implicitly tagged der blob. So I'm putting in the outter-
+ * most tag myself. -javi
+ */
+ derTemp.data[0] = (unsigned char)privKeyTemplate->kind;
+ derTemp.data[1] = (unsigned char)derTemp.len;
+ derTemp.len += 2;
+ rv = SECITEM_CopyItem(poolp, &inCertReqMsg->derPOP, &derTemp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_Free(derTemp.data);
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ if (derTemp.data) {
+ PORT_Free(derTemp.data);
+ }
+ return SECFailure;
+}
+
+static const SEC_ASN1Template *
+crmf_get_template_for_privkey(CRMFPOPChoice inChoice)
+{
+ switch (inChoice) {
+ case crmfKeyAgreement:
+ return CRMFPOPOKeyAgreementTemplate;
+ case crmfKeyEncipherment:
+ return CRMFPOPOKeyEnciphermentTemplate;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static SECStatus
+crmf_add_privkey_thismessage(CRMFCertReqMsg *inCertReqMsg, SECItem *encPrivKey,
+ CRMFPOPChoice inChoice)
+{
+ PLArenaPool *poolp;
+ void *mark;
+ CRMFPOPOPrivKey *popoPrivKey;
+ CRMFProofOfPossession *pop;
+ SECStatus rv;
+
+ PORT_Assert(inCertReqMsg != NULL && encPrivKey != NULL);
+ poolp = inCertReqMsg->poolp;
+ mark = PORT_ArenaMark(poolp);
+ pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
+ if (pop == NULL) {
+ goto loser;
+ }
+ pop->popUsed = inChoice;
+ /* popChoice is a union, so getting a pointer to one
+ * field gives me a pointer to the other fields as
+ * well. This in essence points to both
+ * pop->popChoice.keyEncipherment and
+ * pop->popChoice.keyAgreement
+ */
+ popoPrivKey = &pop->popChoice.keyEncipherment;
+
+ rv = SECITEM_CopyItem(poolp, &(popoPrivKey->message.thisMessage),
+ encPrivKey);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ popoPrivKey->message.thisMessage.len <<= 3;
+ popoPrivKey->messageChoice = crmfThisMessage;
+ inCertReqMsg->pop = pop;
+ rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey,
+ crmf_get_template_for_privkey(inChoice));
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ return SECFailure;
+}
+
+static SECStatus
+crmf_add_privkey_dhmac(CRMFCertReqMsg *inCertReqMsg, SECItem *dhmac,
+ CRMFPOPChoice inChoice)
+{
+ PLArenaPool *poolp;
+ void *mark;
+ CRMFPOPOPrivKey *popoPrivKey;
+ CRMFProofOfPossession *pop;
+ SECStatus rv;
+
+ PORT_Assert(inCertReqMsg != NULL && dhmac != NULL);
+ poolp = inCertReqMsg->poolp;
+ mark = PORT_ArenaMark(poolp);
+ pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
+ if (pop == NULL) {
+ goto loser;
+ }
+ pop->popUsed = inChoice;
+ popoPrivKey = &pop->popChoice.keyAgreement;
+
+ rv = SECITEM_CopyItem(poolp, &(popoPrivKey->message.dhMAC),
+ dhmac);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ popoPrivKey->message.dhMAC.len <<= 3;
+ popoPrivKey->messageChoice = crmfDHMAC;
+ inCertReqMsg->pop = pop;
+ rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey,
+ crmf_get_template_for_privkey(inChoice));
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ return SECFailure;
+}
+
+static SECStatus
+crmf_add_privkey_subseqmessage(CRMFCertReqMsg *inCertReqMsg,
+ CRMFSubseqMessOptions subsequentMessage,
+ CRMFPOPChoice inChoice)
+{
+ void *mark;
+ PLArenaPool *poolp;
+ CRMFProofOfPossession *pop;
+ CRMFPOPOPrivKey *popoPrivKey;
+ SECStatus rv;
+ const SEC_ASN1Template *privKeyTemplate;
+
+ if (subsequentMessage == crmfNoSubseqMess) {
+ return SECFailure;
+ }
+ poolp = inCertReqMsg->poolp;
+ mark = PORT_ArenaMark(poolp);
+ pop = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
+ if (pop == NULL) {
+ goto loser;
+ }
+
+ pop->popUsed = inChoice;
+ /*
+ * We have a union, so a pointer to one member of the union
+ * is also a member to another member of that same union.
+ */
+ popoPrivKey = &pop->popChoice.keyEncipherment;
+
+ switch (subsequentMessage) {
+ case crmfEncrCert:
+ rv = crmf_encode_integer(poolp,
+ &(popoPrivKey->message.subsequentMessage),
+ 0);
+ break;
+ case crmfChallengeResp:
+ rv = crmf_encode_integer(poolp,
+ &(popoPrivKey->message.subsequentMessage),
+ 1);
+ break;
+ default:
+ goto loser;
+ }
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ popoPrivKey->messageChoice = crmfSubsequentMessage;
+ privKeyTemplate = crmf_get_template_for_privkey(inChoice);
+ inCertReqMsg->pop = pop;
+ rv = crmf_encode_popoprivkey(poolp, inCertReqMsg, popoPrivKey,
+ privKeyTemplate);
+
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_ArenaUnmark(poolp, mark);
+ return SECSuccess;
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ return SECFailure;
+}
+
+SECStatus
+CRMF_CertReqMsgSetKeyEnciphermentPOP(CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOPrivKeyChoice inKeyChoice,
+ CRMFSubseqMessOptions subseqMess,
+ SECItem *encPrivKey)
+{
+ SECStatus rv;
+
+ PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL);
+ if (CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfNoPOPChoice) {
+ return SECFailure;
+ }
+ switch (inKeyChoice) {
+ case crmfThisMessage:
+ rv = crmf_add_privkey_thismessage(inCertReqMsg, encPrivKey,
+ crmfKeyEncipherment);
+ break;
+ case crmfSubsequentMessage:
+ rv = crmf_add_privkey_subseqmessage(inCertReqMsg, subseqMess,
+ crmfKeyEncipherment);
+ break;
+ case crmfDHMAC:
+ default:
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+SECStatus
+CRMF_CertReqMsgSetKeyAgreementPOP(CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOPrivKeyChoice inKeyChoice,
+ CRMFSubseqMessOptions subseqMess,
+ SECItem *encPrivKey)
+{
+ SECStatus rv;
+
+ PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->pop == NULL);
+ switch (inKeyChoice) {
+ case crmfThisMessage:
+ rv = crmf_add_privkey_thismessage(inCertReqMsg, encPrivKey,
+ crmfKeyAgreement);
+ break;
+ case crmfSubsequentMessage:
+ rv = crmf_add_privkey_subseqmessage(inCertReqMsg, subseqMess,
+ crmfKeyAgreement);
+ break;
+ case crmfDHMAC:
+ /* In this case encPrivKey should be the calculated dhMac
+ * as specified in RFC 2511 */
+ rv = crmf_add_privkey_dhmac(inCertReqMsg, encPrivKey,
+ crmfKeyAgreement);
+ break;
+ default:
+ rv = SECFailure;
+ }
+ return rv;
+}
diff --git a/security/nss/lib/crmf/crmfreq.c b/security/nss/lib/crmf/crmfreq.c
new file mode 100644
index 000000000..e89f18228
--- /dev/null
+++ b/security/nss/lib/crmf/crmfreq.c
@@ -0,0 +1,663 @@
+/* -*- 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;
+}
diff --git a/security/nss/lib/crmf/crmft.h b/security/nss/lib/crmf/crmft.h
new file mode 100644
index 000000000..8d83cf1e6
--- /dev/null
+++ b/security/nss/lib/crmf/crmft.h
@@ -0,0 +1,186 @@
+/* -*- 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/. */
+
+/* Header file with all of the structures and types that will be exported
+ * by the security library for implementation of CRMF.
+ */
+
+#ifndef _CRMFT_H_
+#define _CRMFT_H_
+
+/* Use these enumerated values for adding fields to the certificate request */
+typedef enum {
+ crmfVersion = 0,
+ crmfSerialNumber = 1,
+ crmfSigningAlg = 2,
+ crmfIssuer = 3,
+ crmfValidity = 4,
+ crmfSubject = 5,
+ crmfPublicKey = 6,
+ crmfIssuerUID = 7,
+ crmfSubjectUID = 8,
+ crmfExtension = 9
+} CRMFCertTemplateField;
+
+/*
+ * An enumeration for the different types of controls.
+ */
+typedef enum {
+ crmfNoControl = 0,
+ crmfRegTokenControl = 1,
+ crmfAuthenticatorControl = 2,
+ crmfPKIPublicationInfoControl = 3,
+ crmfPKIArchiveOptionsControl = 4,
+ crmfOldCertIDControl = 5,
+ crmfProtocolEncrKeyControl = 6
+} CRMFControlType;
+
+/*
+ * The possible values that are passed into CRMF_CreatePKIPublicationInfo
+ */
+typedef enum {
+ crmfDontPublish = 0,
+ crmfPleasePublish = 1
+} CRMFPublicationAction;
+
+/*
+ * An enumeration for the possible for pubMethod which is a part of
+ * the SinglePubInfo ASN1 type.
+ */
+typedef enum {
+ crmfDontCare = 0,
+ crmfX500 = 1,
+ crmfWeb = 2,
+ crmfLdap = 3
+} CRMFPublicationMethod;
+
+/*
+ * An enumeration for the different options for PKIArchiveOptions type.
+ */
+typedef enum {
+ crmfNoArchiveOptions = 0,
+ crmfEncryptedPrivateKey = 1,
+ crmfKeyGenParameters = 2,
+ crmfArchiveRemGenPrivKey = 3
+} CRMFPKIArchiveOptionsType;
+
+/*
+ * An enumeration for the different options for ProofOfPossession
+ */
+typedef enum {
+ crmfNoPOPChoice = 0,
+ crmfRAVerified = 1,
+ crmfSignature = 2,
+ crmfKeyEncipherment = 3,
+ crmfKeyAgreement = 4
+} CRMFPOPChoice;
+
+/*
+ * An enumertion type for options for the authInfo field of the
+ * CRMFPOPOSigningKeyInput structure.
+ */
+typedef enum {
+ crmfSender = 0,
+ crmfPublicKeyMAC = 1
+} CRMFPOPOSkiInputAuthChoice;
+
+/*
+ * An enumeration for the SubsequentMessage Options.
+ */
+typedef enum {
+ crmfNoSubseqMess = 0,
+ crmfEncrCert = 1,
+ crmfChallengeResp = 2
+} CRMFSubseqMessOptions;
+
+/*
+ * An enumeration for the choice used by POPOPrivKey.
+ */
+typedef enum {
+ crmfNoMessage = 0,
+ crmfThisMessage = 1,
+ crmfSubsequentMessage = 2,
+ crmfDHMAC = 3
+} CRMFPOPOPrivKeyChoice;
+
+/*
+ * An enumeration for the choices for the EncryptedKey type.
+ */
+typedef enum {
+ crmfNoEncryptedKeyChoice = 0,
+ crmfEncryptedValueChoice = 1,
+ crmfEnvelopedDataChoice = 2
+} CRMFEncryptedKeyChoice;
+
+/*
+ * TYPE: CRMFEncoderOutputCallback
+ * This function type defines a prototype for a function that the CRMF
+ * library expects when encoding is performed.
+ *
+ * ARGUMENTS:
+ * arg
+ * This will be a pointer the user passed into an encoding function.
+ * The user of the library is free to use this pointer in any way.
+ * The most common use is to keep around a buffer for writing out
+ * the DER encoded bytes.
+ * buf
+ * The DER encoded bytes that should be written out.
+ * len
+ * The number of DER encoded bytes to write out.
+ *
+ */
+typedef void (*CRMFEncoderOutputCallback)(void *arg,
+ const char *buf,
+ unsigned long len);
+
+/*
+ * Type for the function that gets a password. Just in case we ever
+ * need to support publicKeyMAC for POPOSigningKeyInput
+ */
+typedef SECItem *(*CRMFMACPasswordCallback)(void *arg);
+
+typedef struct CRMFOptionalValidityStr CRMFOptionalValidity;
+typedef struct CRMFValidityCreationInfoStr CRMFGetValidity;
+typedef struct CRMFCertTemplateStr CRMFCertTemplate;
+typedef struct CRMFCertRequestStr CRMFCertRequest;
+typedef struct CRMFCertReqMsgStr CRMFCertReqMsg;
+typedef struct CRMFCertReqMessagesStr CRMFCertReqMessages;
+typedef struct CRMFProofOfPossessionStr CRMFProofOfPossession;
+typedef struct CRMFPOPOSigningKeyStr CRMFPOPOSigningKey;
+typedef struct CRMFPOPOSigningKeyInputStr CRMFPOPOSigningKeyInput;
+typedef struct CRMFPOPOPrivKeyStr CRMFPOPOPrivKey;
+typedef struct CRMFPKIPublicationInfoStr CRMFPKIPublicationInfo;
+typedef struct CRMFSinglePubInfoStr CRMFSinglePubInfo;
+typedef struct CRMFPKIArchiveOptionsStr CRMFPKIArchiveOptions;
+typedef struct CRMFEncryptedKeyStr CRMFEncryptedKey;
+typedef struct CRMFEncryptedValueStr CRMFEncryptedValue;
+typedef struct CRMFCertIDStr CRMFCertID;
+typedef struct CRMFCertIDStr CRMFOldCertID;
+typedef CERTSubjectPublicKeyInfo CRMFProtocolEncrKey;
+typedef struct CRMFValidityCreationInfoStr CRMFValidityCreationInfo;
+typedef struct CRMFCertExtCreationInfoStr CRMFCertExtCreationInfo;
+typedef struct CRMFPKMACValueStr CRMFPKMACValue;
+typedef struct CRMFAttributeStr CRMFAttribute;
+typedef struct CRMFControlStr CRMFControl;
+typedef CERTGeneralName CRMFGeneralName;
+typedef struct CRMFCertExtensionStr CRMFCertExtension;
+
+struct CRMFValidityCreationInfoStr {
+ PRTime *notBefore;
+ PRTime *notAfter;
+};
+
+struct CRMFCertExtCreationInfoStr {
+ CRMFCertExtension **extensions;
+ int numExtensions;
+};
+
+/*
+ * Some ASN1 Templates that may be needed.
+ */
+extern const SEC_ASN1Template CRMFCertReqMessagesTemplate[];
+extern const SEC_ASN1Template CRMFCertRequestTemplate[];
+
+#endif /*_CRMFT_H_*/
diff --git a/security/nss/lib/crmf/crmftmpl.c b/security/nss/lib/crmf/crmftmpl.c
new file mode 100644
index 000000000..265a15dd5
--- /dev/null
+++ b/security/nss/lib/crmf/crmftmpl.c
@@ -0,0 +1,240 @@
+/* -*- 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 "secoid.h"
+#include "secasn1.h"
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+SEC_ASN1_MKSUB(SEC_NullTemplate)
+SEC_ASN1_MKSUB(SEC_BitStringTemplate)
+SEC_ASN1_MKSUB(SEC_IntegerTemplate)
+SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
+SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
+SEC_ASN1_MKSUB(CERT_SubjectPublicKeyInfoTemplate)
+SEC_ASN1_MKSUB(CERT_NameTemplate)
+
+/*
+ * It's all implicit tagging.
+ */
+
+const SEC_ASN1Template CRMFControlTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRMFControl) },
+ { SEC_ASN1_OBJECT_ID, offsetof(CRMFControl, derTag) },
+ { SEC_ASN1_ANY, offsetof(CRMFControl, derValue) },
+ { 0 }
+};
+
+static const SEC_ASN1Template CRMFCertExtensionTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CRMFCertExtension) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CRMFCertExtension, id) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN,
+ offsetof(CRMFCertExtension, critical) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(CRMFCertExtension, value) },
+ { 0 }
+};
+
+static const SEC_ASN1Template CRMFSequenceOfCertExtensionTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, CRMFCertExtensionTemplate }
+};
+
+static const SEC_ASN1Template CRMFOptionalValidityTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRMFOptionalValidity) },
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_NO_STREAM |
+ SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN | 0,
+ offsetof(CRMFOptionalValidity, notBefore),
+ SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_NO_STREAM |
+ SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN | 1,
+ offsetof(CRMFOptionalValidity, notAfter),
+ SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
+ { 0 }
+};
+
+static const SEC_ASN1Template crmfPointerToNameTemplate[] = {
+ { SEC_ASN1_POINTER | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(CERT_NameTemplate) },
+ { 0 }
+};
+
+static const SEC_ASN1Template CRMFCertTemplateTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRMFCertTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+ offsetof(CRMFCertTemplate, version),
+ SEC_ASN1_SUB(SEC_IntegerTemplate) },
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN | 1,
+ offsetof(CRMFCertTemplate, serialNumber),
+ SEC_ASN1_SUB(SEC_IntegerTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER |
+ SEC_ASN1_XTRN | 2,
+ offsetof(CRMFCertTemplate, signingAlg),
+ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | 3,
+ offsetof(CRMFCertTemplate, issuer), crmfPointerToNameTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER | 4,
+ offsetof(CRMFCertTemplate, validity),
+ CRMFOptionalValidityTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | 5,
+ offsetof(CRMFCertTemplate, subject), crmfPointerToNameTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER |
+ SEC_ASN1_XTRN | 6,
+ offsetof(CRMFCertTemplate, publicKey),
+ SEC_ASN1_SUB(CERT_SubjectPublicKeyInfoTemplate) },
+ { SEC_ASN1_NO_STREAM | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_OPTIONAL |
+ SEC_ASN1_XTRN | 7,
+ offsetof(CRMFCertTemplate, issuerUID),
+ SEC_ASN1_SUB(SEC_BitStringTemplate) },
+ { SEC_ASN1_NO_STREAM | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_OPTIONAL |
+ SEC_ASN1_XTRN | 8,
+ offsetof(CRMFCertTemplate, subjectUID),
+ SEC_ASN1_SUB(SEC_BitStringTemplate) },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_OPTIONAL |
+ SEC_ASN1_CONTEXT_SPECIFIC | 9,
+ offsetof(CRMFCertTemplate, extensions),
+ CRMFSequenceOfCertExtensionTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template CRMFAttributeTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRMFAttribute) },
+ { SEC_ASN1_OBJECT_ID, offsetof(CRMFAttribute, derTag) },
+ { SEC_ASN1_ANY, offsetof(CRMFAttribute, derValue) },
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFCertRequestTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRMFCertRequest) },
+ { SEC_ASN1_INTEGER, offsetof(CRMFCertRequest, certReqId) },
+ { SEC_ASN1_INLINE, offsetof(CRMFCertRequest, certTemplate),
+ CRMFCertTemplateTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
+ offsetof(CRMFCertRequest, controls),
+ CRMFControlTemplate }, /* SEQUENCE SIZE (1...MAX)*/
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFCertReqMsgTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRMFCertReqMsg) },
+ { SEC_ASN1_POINTER, offsetof(CRMFCertReqMsg, certReq),
+ CRMFCertRequestTemplate },
+ { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL,
+ offsetof(CRMFCertReqMsg, derPOP) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
+ offsetof(CRMFCertReqMsg, regInfo),
+ CRMFAttributeTemplate }, /* SEQUENCE SIZE (1...MAX)*/
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFCertReqMessagesTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, offsetof(CRMFCertReqMessages, messages),
+ CRMFCertReqMsgTemplate, sizeof(CRMFCertReqMessages) }
+};
+
+const SEC_ASN1Template CRMFRAVerifiedTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 0 | SEC_ASN1_XTRN,
+ 0,
+ SEC_ASN1_SUB(SEC_NullTemplate) },
+ { 0 }
+};
+
+/* This template will need to add POPOSigningKeyInput eventually, maybe*/
+static const SEC_ASN1Template crmfPOPOSigningKeyTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRMFPOPOSigningKey) },
+ { SEC_ASN1_NO_STREAM | SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_XTRN | 0,
+ offsetof(CRMFPOPOSigningKey, derInput),
+ SEC_ASN1_SUB(SEC_AnyTemplate) },
+ { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
+ offsetof(CRMFPOPOSigningKey, algorithmIdentifier),
+ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+ { SEC_ASN1_BIT_STRING | SEC_ASN1_XTRN,
+ offsetof(CRMFPOPOSigningKey, signature),
+ SEC_ASN1_SUB(SEC_BitStringTemplate) },
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFPOPOSigningKeyTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ 0,
+ crmfPOPOSigningKeyTemplate },
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFThisMessageTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+ 0,
+ SEC_ASN1_SUB(SEC_BitStringTemplate) },
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFSubsequentMessageTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
+ 0,
+ SEC_ASN1_SUB(SEC_IntegerTemplate) },
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFDHMACTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
+ 0,
+ SEC_ASN1_SUB(SEC_BitStringTemplate) },
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFPOPOKeyEnciphermentTemplate[] = {
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
+ 0,
+ SEC_ASN1_SUB(SEC_AnyTemplate) },
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFPOPOKeyAgreementTemplate[] = {
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 3,
+ 0,
+ SEC_ASN1_SUB(SEC_AnyTemplate) },
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFEncryptedValueTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRMFEncryptedValue) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER |
+ SEC_ASN1_XTRN | 0,
+ offsetof(CRMFEncryptedValue, intendedAlg),
+ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER |
+ SEC_ASN1_XTRN | 1,
+ offsetof(CRMFEncryptedValue, symmAlg),
+ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+ { SEC_ASN1_NO_STREAM | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_OPTIONAL |
+ SEC_ASN1_XTRN | 2,
+ offsetof(CRMFEncryptedValue, encSymmKey),
+ SEC_ASN1_SUB(SEC_BitStringTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER |
+ SEC_ASN1_XTRN | 3,
+ offsetof(CRMFEncryptedValue, keyAlg),
+ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+ { SEC_ASN1_NO_STREAM | SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_XTRN | 4,
+ offsetof(CRMFEncryptedValue, valueHint),
+ SEC_ASN1_SUB(SEC_OctetStringTemplate) },
+ { SEC_ASN1_BIT_STRING, offsetof(CRMFEncryptedValue, encValue) },
+ { 0 }
+};
+
+const SEC_ASN1Template CRMFEncryptedKeyWithEncryptedValueTemplate[] = {
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ 0,
+ CRMFEncryptedValueTemplate },
+ { 0 }
+};
diff --git a/security/nss/lib/crmf/encutil.c b/security/nss/lib/crmf/encutil.c
new file mode 100644
index 000000000..8ca7007b6
--- /dev/null
+++ b/security/nss/lib/crmf/encutil.c
@@ -0,0 +1,33 @@
+/* -*- 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 "secasn1.h"
+#include "crmf.h"
+#include "crmfi.h"
+
+void
+crmf_encoder_out(void *arg, const char *buf, unsigned long len,
+ int depth, SEC_ASN1EncodingPart data_kind)
+{
+ struct crmfEncoderOutput *output;
+
+ output = (struct crmfEncoderOutput *)arg;
+ output->fn(output->outputArg, buf, len);
+}
+
+SECStatus
+cmmf_user_encode(void *src, CRMFEncoderOutputCallback inCallback, void *inArg,
+ const SEC_ASN1Template *inTemplate)
+{
+ struct crmfEncoderOutput output;
+
+ PORT_Assert(src != NULL);
+ if (src == NULL) {
+ return SECFailure;
+ }
+ output.fn = inCallback;
+ output.outputArg = inArg;
+ return SEC_ASN1Encode(src, inTemplate, crmf_encoder_out, &output);
+}
diff --git a/security/nss/lib/crmf/exports.gyp b/security/nss/lib/crmf/exports.gyp
new file mode 100644
index 000000000..fca009756
--- /dev/null
+++ b/security/nss/lib/crmf/exports.gyp
@@ -0,0 +1,37 @@
+# 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/.
+{
+ 'includes': [
+ '../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'lib_crmf_exports',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'files': [
+ 'cmmf.h',
+ 'cmmft.h',
+ 'crmf.h',
+ 'crmft.h'
+ ],
+ 'destination': '<(nss_public_dist_dir)/<(module)'
+ },
+ {
+ 'files': [
+ 'cmmfi.h',
+ 'cmmfit.h',
+ 'crmfi.h',
+ 'crmfit.h'
+ ],
+ 'destination': '<(nss_private_dist_dir)/<(module)'
+ }
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/security/nss/lib/crmf/manifest.mn b/security/nss/lib/crmf/manifest.mn
new file mode 100644
index 000000000..9f177b9ca
--- /dev/null
+++ b/security/nss/lib/crmf/manifest.mn
@@ -0,0 +1,46 @@
+#
+# 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/.
+
+CORE_DEPTH = ../..
+
+MODULE = nss
+
+EXPORTS = \
+ crmf.h \
+ crmft.h \
+ cmmf.h \
+ cmmft.h \
+ $(NULL)
+
+PRIVATE_EXPORTS = \
+ crmfi.h \
+ crmfit.h \
+ cmmfi.h \
+ cmmfit.h \
+ $(NULL)
+
+CSRCS = crmfenc.c \
+ crmftmpl.c \
+ crmfreq.c \
+ crmfpop.c \
+ crmfdec.c \
+ crmfget.c \
+ crmfcont.c \
+ cmmfasn1.c \
+ cmmfresp.c \
+ cmmfrec.c \
+ cmmfchal.c \
+ servget.c \
+ encutil.c \
+ respcli.c \
+ respcmn.c \
+ challcli.c \
+ asn1cmn.c \
+ $(NULL)
+
+LIBRARY_NAME = crmf
+
+# This part of the code, including all sub-dirs, can be optimized for size
+export ALLOW_OPT_CODE_SIZE = 1
diff --git a/security/nss/lib/crmf/respcli.c b/security/nss/lib/crmf/respcli.c
new file mode 100644
index 000000000..aaec0136f
--- /dev/null
+++ b/security/nss/lib/crmf/respcli.c
@@ -0,0 +1,136 @@
+/* -*- 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/. */
+
+/*
+ * This file will contain all routines needed by a client that has
+ * to parse a CMMFCertRepContent structure and retirieve the appropriate
+ * data.
+ */
+
+#include "cmmf.h"
+#include "cmmfi.h"
+#include "crmf.h"
+#include "crmfi.h"
+#include "secitem.h"
+#include "secder.h"
+#include "secasn1.h"
+
+CMMFCertRepContent *
+CMMF_CreateCertRepContentFromDER(CERTCertDBHandle *db, const char *buf,
+ long len)
+{
+ PLArenaPool *poolp;
+ CMMFCertRepContent *certRepContent;
+ SECStatus rv;
+ int i;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ return NULL;
+ }
+ certRepContent = PORT_ArenaZNew(poolp, CMMFCertRepContent);
+ if (certRepContent == NULL) {
+ goto loser;
+ }
+ certRepContent->poolp = poolp;
+ rv = SEC_ASN1Decode(poolp, certRepContent, CMMFCertRepContentTemplate,
+ buf, len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (certRepContent->response != NULL) {
+ for (i = 0; certRepContent->response[i] != NULL; i++) {
+ rv = cmmf_decode_process_cert_response(poolp, db,
+ certRepContent->response[i]);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ }
+ certRepContent->isDecoded = PR_TRUE;
+ return certRepContent;
+loser:
+ PORT_FreeArena(poolp, PR_FALSE);
+ return NULL;
+}
+
+long
+CMMF_CertResponseGetCertReqId(CMMFCertResponse *inCertResp)
+{
+ PORT_Assert(inCertResp != NULL);
+ if (inCertResp == NULL) {
+ return -1;
+ }
+ return DER_GetInteger(&inCertResp->certReqId);
+}
+
+PRBool
+cmmf_CertRepContentIsIndexValid(CMMFCertRepContent *inCertRepContent,
+ int inIndex)
+{
+ int numResponses;
+
+ PORT_Assert(inCertRepContent != NULL);
+ numResponses = CMMF_CertRepContentGetNumResponses(inCertRepContent);
+ return (PRBool)(inIndex >= 0 && inIndex < numResponses);
+}
+
+CMMFCertResponse *
+CMMF_CertRepContentGetResponseAtIndex(CMMFCertRepContent *inCertRepContent,
+ int inIndex)
+{
+ CMMFCertResponse *certResponse;
+ SECStatus rv;
+
+ PORT_Assert(inCertRepContent != NULL &&
+ cmmf_CertRepContentIsIndexValid(inCertRepContent, inIndex));
+ if (inCertRepContent == NULL ||
+ !cmmf_CertRepContentIsIndexValid(inCertRepContent, inIndex)) {
+ return NULL;
+ }
+ certResponse = PORT_ZNew(CMMFCertResponse);
+ if (certResponse) {
+ rv = cmmf_CopyCertResponse(NULL, certResponse,
+ inCertRepContent->response[inIndex]);
+ if (rv != SECSuccess) {
+ CMMF_DestroyCertResponse(certResponse);
+ certResponse = NULL;
+ }
+ }
+ return certResponse;
+}
+
+CMMFPKIStatus
+CMMF_CertResponseGetPKIStatusInfoStatus(CMMFCertResponse *inCertResp)
+{
+ PORT_Assert(inCertResp != NULL);
+ if (inCertResp == NULL) {
+ return cmmfNoPKIStatus;
+ }
+ return cmmf_PKIStatusInfoGetStatus(&inCertResp->status);
+}
+
+CERTCertificate *
+CMMF_CertResponseGetCertificate(CMMFCertResponse *inCertResp,
+ CERTCertDBHandle *inCertdb)
+{
+ PORT_Assert(inCertResp != NULL);
+ if (inCertResp == NULL || inCertResp->certifiedKeyPair == NULL) {
+ return NULL;
+ }
+
+ return cmmf_CertOrEncCertGetCertificate(
+ &inCertResp->certifiedKeyPair->certOrEncCert, inCertdb);
+}
+
+CERTCertList *
+CMMF_CertRepContentGetCAPubs(CMMFCertRepContent *inCertRepContent)
+{
+ PORT_Assert(inCertRepContent != NULL);
+ if (inCertRepContent == NULL || inCertRepContent->caPubs == NULL) {
+ return NULL;
+ }
+ return cmmf_MakeCertList(inCertRepContent->caPubs);
+}
diff --git a/security/nss/lib/crmf/respcmn.c b/security/nss/lib/crmf/respcmn.c
new file mode 100644
index 000000000..f9e4155a3
--- /dev/null
+++ b/security/nss/lib/crmf/respcmn.c
@@ -0,0 +1,399 @@
+/* -*- 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 "cmmf.h"
+#include "cmmfi.h"
+#include "secitem.h"
+#include "secder.h"
+
+SECStatus
+cmmf_DestroyPKIStatusInfo(CMMFPKIStatusInfo *info, PRBool freeit)
+{
+ if (info->status.data != NULL) {
+ PORT_Free(info->status.data);
+ info->status.data = NULL;
+ }
+ if (info->statusString.data != NULL) {
+ PORT_Free(info->statusString.data);
+ info->statusString.data = NULL;
+ }
+ if (info->failInfo.data != NULL) {
+ PORT_Free(info->failInfo.data);
+ info->failInfo.data = NULL;
+ }
+ if (freeit) {
+ PORT_Free(info);
+ }
+ return SECSuccess;
+}
+
+SECStatus
+CMMF_DestroyCertResponse(CMMFCertResponse *inCertResp)
+{
+ PORT_Assert(inCertResp != NULL);
+ if (inCertResp != NULL) {
+ if (inCertResp->certReqId.data != NULL) {
+ PORT_Free(inCertResp->certReqId.data);
+ }
+ cmmf_DestroyPKIStatusInfo(&inCertResp->status, PR_FALSE);
+ if (inCertResp->certifiedKeyPair != NULL) {
+ CMMF_DestroyCertifiedKeyPair(inCertResp->certifiedKeyPair);
+ }
+ PORT_Free(inCertResp);
+ }
+ return SECSuccess;
+}
+
+SECStatus
+CMMF_DestroyCertRepContent(CMMFCertRepContent *inCertRepContent)
+{
+ PORT_Assert(inCertRepContent != NULL);
+ if (inCertRepContent != NULL) {
+ CMMFCertResponse **pResponse = inCertRepContent->response;
+ if (pResponse != NULL) {
+ for (; *pResponse != NULL; pResponse++) {
+ CMMFCertifiedKeyPair *certKeyPair = (*pResponse)->certifiedKeyPair;
+ /* XXX Why not call CMMF_DestroyCertifiedKeyPair or
+ ** XXX cmmf_DestroyCertOrEncCert ?
+ */
+ if (certKeyPair != NULL &&
+ certKeyPair->certOrEncCert.choice == cmmfCertificate &&
+ certKeyPair->certOrEncCert.cert.certificate != NULL) {
+ CERT_DestroyCertificate(certKeyPair->certOrEncCert.cert.certificate);
+ certKeyPair->certOrEncCert.cert.certificate = NULL;
+ }
+ }
+ }
+ if (inCertRepContent->caPubs) {
+ CERTCertificate **caPubs = inCertRepContent->caPubs;
+ for (; *caPubs; ++caPubs) {
+ CERT_DestroyCertificate(*caPubs);
+ *caPubs = NULL;
+ }
+ }
+ if (inCertRepContent->poolp != NULL) {
+ PORT_FreeArena(inCertRepContent->poolp, PR_TRUE);
+ }
+ }
+ return SECSuccess;
+}
+
+SECStatus
+CMMF_DestroyPOPODecKeyChallContent(CMMFPOPODecKeyChallContent *inDecKeyCont)
+{
+ PORT_Assert(inDecKeyCont != NULL);
+ if (inDecKeyCont != NULL && inDecKeyCont->poolp) {
+ PORT_FreeArena(inDecKeyCont->poolp, PR_FALSE);
+ }
+ return SECSuccess;
+}
+
+SECStatus
+crmf_create_prtime(SECItem *src, PRTime **dest)
+{
+ *dest = PORT_ZNew(PRTime);
+ return DER_DecodeTimeChoice(*dest, src);
+}
+
+CRMFCertExtension *
+crmf_copy_cert_extension(PLArenaPool *poolp, CRMFCertExtension *inExtension)
+{
+ PRBool isCritical;
+ SECOidTag id;
+ SECItem *data;
+ CRMFCertExtension *newExt;
+
+ PORT_Assert(inExtension != NULL);
+ if (inExtension == NULL) {
+ return NULL;
+ }
+ id = CRMF_CertExtensionGetOidTag(inExtension);
+ isCritical = CRMF_CertExtensionGetIsCritical(inExtension);
+ data = CRMF_CertExtensionGetValue(inExtension);
+ newExt = crmf_create_cert_extension(poolp, id,
+ isCritical,
+ data);
+ SECITEM_FreeItem(data, PR_TRUE);
+ return newExt;
+}
+
+static SECItem *
+cmmf_encode_certificate(CERTCertificate *inCert)
+{
+ return SEC_ASN1EncodeItem(NULL, NULL, inCert,
+ SEC_ASN1_GET(SEC_SignedCertificateTemplate));
+}
+
+CERTCertList *
+cmmf_MakeCertList(CERTCertificate **inCerts)
+{
+ CERTCertList *certList;
+ CERTCertificate *currCert;
+ SECItem *derCert, *freeCert = NULL;
+ SECStatus rv;
+ int i;
+
+ certList = CERT_NewCertList();
+ if (certList == NULL) {
+ return NULL;
+ }
+ for (i = 0; inCerts[i] != NULL; i++) {
+ derCert = &inCerts[i]->derCert;
+ if (derCert->data == NULL) {
+ derCert = freeCert = cmmf_encode_certificate(inCerts[i]);
+ }
+ currCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
+ derCert, NULL, PR_FALSE, PR_TRUE);
+ if (freeCert != NULL) {
+ SECITEM_FreeItem(freeCert, PR_TRUE);
+ freeCert = NULL;
+ }
+ if (currCert == NULL) {
+ goto loser;
+ }
+ rv = CERT_AddCertToListTail(certList, currCert);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ return certList;
+loser:
+ CERT_DestroyCertList(certList);
+ return NULL;
+}
+
+CMMFPKIStatus
+cmmf_PKIStatusInfoGetStatus(CMMFPKIStatusInfo *inStatus)
+{
+ long derVal;
+
+ derVal = DER_GetInteger(&inStatus->status);
+ if (derVal == -1 || derVal < cmmfGranted || derVal >= cmmfNumPKIStatus) {
+ return cmmfNoPKIStatus;
+ }
+ return (CMMFPKIStatus)derVal;
+}
+
+int
+CMMF_CertRepContentGetNumResponses(CMMFCertRepContent *inCertRepContent)
+{
+ int numResponses = 0;
+ PORT_Assert(inCertRepContent != NULL);
+ if (inCertRepContent != NULL && inCertRepContent->response != NULL) {
+ while (inCertRepContent->response[numResponses] != NULL) {
+ numResponses++;
+ }
+ }
+ return numResponses;
+}
+
+SECStatus
+cmmf_DestroyCertOrEncCert(CMMFCertOrEncCert *certOrEncCert, PRBool freeit)
+{
+ switch (certOrEncCert->choice) {
+ case cmmfCertificate:
+ CERT_DestroyCertificate(certOrEncCert->cert.certificate);
+ certOrEncCert->cert.certificate = NULL;
+ break;
+ case cmmfEncryptedCert:
+ crmf_destroy_encrypted_value(certOrEncCert->cert.encryptedCert,
+ PR_TRUE);
+ certOrEncCert->cert.encryptedCert = NULL;
+ break;
+ default:
+ break;
+ }
+ if (freeit) {
+ PORT_Free(certOrEncCert);
+ }
+ return SECSuccess;
+}
+
+SECStatus
+cmmf_copy_secitem(PLArenaPool *poolp, SECItem *dest, SECItem *src)
+{
+ SECStatus rv;
+
+ if (src->data != NULL) {
+ rv = SECITEM_CopyItem(poolp, dest, src);
+ } else {
+ dest->data = NULL;
+ dest->len = 0;
+ rv = SECSuccess;
+ }
+ return rv;
+}
+
+SECStatus
+CMMF_DestroyCertifiedKeyPair(CMMFCertifiedKeyPair *inCertKeyPair)
+{
+ PORT_Assert(inCertKeyPair != NULL);
+ if (inCertKeyPair != NULL) {
+ cmmf_DestroyCertOrEncCert(&inCertKeyPair->certOrEncCert, PR_FALSE);
+ if (inCertKeyPair->privateKey) {
+ crmf_destroy_encrypted_value(inCertKeyPair->privateKey, PR_TRUE);
+ }
+ if (inCertKeyPair->derPublicationInfo.data) {
+ PORT_Free(inCertKeyPair->derPublicationInfo.data);
+ }
+ PORT_Free(inCertKeyPair);
+ }
+ return SECSuccess;
+}
+
+SECStatus
+cmmf_CopyCertResponse(PLArenaPool *poolp,
+ CMMFCertResponse *dest,
+ CMMFCertResponse *src)
+{
+ SECStatus rv;
+
+ if (src->certReqId.data != NULL) {
+ rv = SECITEM_CopyItem(poolp, &dest->certReqId, &src->certReqId);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+ rv = cmmf_CopyPKIStatusInfo(poolp, &dest->status, &src->status);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ if (src->certifiedKeyPair != NULL) {
+ CMMFCertifiedKeyPair *destKeyPair;
+
+ destKeyPair = (poolp == NULL) ? PORT_ZNew(CMMFCertifiedKeyPair) : PORT_ArenaZNew(poolp, CMMFCertifiedKeyPair);
+ if (!destKeyPair) {
+ return SECFailure;
+ }
+ rv = cmmf_CopyCertifiedKeyPair(poolp, destKeyPair,
+ src->certifiedKeyPair);
+ if (rv != SECSuccess) {
+ if (!poolp) {
+ CMMF_DestroyCertifiedKeyPair(destKeyPair);
+ }
+ return rv;
+ }
+ dest->certifiedKeyPair = destKeyPair;
+ }
+ return SECSuccess;
+}
+
+static SECStatus
+cmmf_CopyCertOrEncCert(PLArenaPool *poolp, CMMFCertOrEncCert *dest,
+ CMMFCertOrEncCert *src)
+{
+ SECStatus rv = SECSuccess;
+ CRMFEncryptedValue *encVal;
+
+ dest->choice = src->choice;
+ rv = cmmf_copy_secitem(poolp, &dest->derValue, &src->derValue);
+ switch (src->choice) {
+ case cmmfCertificate:
+ dest->cert.certificate = CERT_DupCertificate(src->cert.certificate);
+ break;
+ case cmmfEncryptedCert:
+ encVal = (poolp == NULL) ? PORT_ZNew(CRMFEncryptedValue) : PORT_ArenaZNew(poolp, CRMFEncryptedValue);
+ if (encVal == NULL) {
+ return SECFailure;
+ }
+ rv = crmf_copy_encryptedvalue(poolp, src->cert.encryptedCert, encVal);
+ if (rv != SECSuccess) {
+ if (!poolp) {
+ crmf_destroy_encrypted_value(encVal, PR_TRUE);
+ }
+ return rv;
+ }
+ dest->cert.encryptedCert = encVal;
+ break;
+ default:
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+SECStatus
+cmmf_CopyCertifiedKeyPair(PLArenaPool *poolp, CMMFCertifiedKeyPair *dest,
+ CMMFCertifiedKeyPair *src)
+{
+ SECStatus rv;
+
+ rv = cmmf_CopyCertOrEncCert(poolp, &dest->certOrEncCert,
+ &src->certOrEncCert);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ if (src->privateKey != NULL) {
+ CRMFEncryptedValue *encVal;
+
+ encVal = (poolp == NULL) ? PORT_ZNew(CRMFEncryptedValue) : PORT_ArenaZNew(poolp, CRMFEncryptedValue);
+ if (encVal == NULL) {
+ return SECFailure;
+ }
+ rv = crmf_copy_encryptedvalue(poolp, src->privateKey,
+ encVal);
+ if (rv != SECSuccess) {
+ if (!poolp) {
+ crmf_destroy_encrypted_value(encVal, PR_TRUE);
+ }
+ return rv;
+ }
+ dest->privateKey = encVal;
+ }
+ rv = cmmf_copy_secitem(poolp, &dest->derPublicationInfo,
+ &src->derPublicationInfo);
+ return rv;
+}
+
+SECStatus
+cmmf_CopyPKIStatusInfo(PLArenaPool *poolp, CMMFPKIStatusInfo *dest,
+ CMMFPKIStatusInfo *src)
+{
+ SECStatus rv;
+
+ rv = cmmf_copy_secitem(poolp, &dest->status, &src->status);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ rv = cmmf_copy_secitem(poolp, &dest->statusString, &src->statusString);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ rv = cmmf_copy_secitem(poolp, &dest->failInfo, &src->failInfo);
+ return rv;
+}
+
+CERTCertificate *
+cmmf_CertOrEncCertGetCertificate(CMMFCertOrEncCert *certOrEncCert,
+ CERTCertDBHandle *certdb)
+{
+ if (certOrEncCert->choice != cmmfCertificate ||
+ certOrEncCert->cert.certificate == NULL) {
+ return NULL;
+ }
+ return CERT_NewTempCertificate(certdb,
+ &certOrEncCert->cert.certificate->derCert,
+ NULL, PR_FALSE, PR_TRUE);
+}
+
+SECStatus
+cmmf_PKIStatusInfoSetStatus(CMMFPKIStatusInfo *statusInfo,
+ PLArenaPool *poolp,
+ CMMFPKIStatus inStatus)
+{
+ SECItem *dummy;
+
+ if (inStatus < cmmfGranted || inStatus >= cmmfNumPKIStatus) {
+ return SECFailure;
+ }
+
+ dummy = SEC_ASN1EncodeInteger(poolp, &statusInfo->status, inStatus);
+ PORT_Assert(dummy == &statusInfo->status);
+ if (dummy != &statusInfo->status) {
+ SECITEM_FreeItem(dummy, PR_TRUE);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
diff --git a/security/nss/lib/crmf/servget.c b/security/nss/lib/crmf/servget.c
new file mode 100644
index 000000000..6d576f8f1
--- /dev/null
+++ b/security/nss/lib/crmf/servget.c
@@ -0,0 +1,974 @@
+/* -*- 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 "cmmf.h"
+#include "cmmfi.h"
+#include "secitem.h"
+#include "keyhi.h"
+#include "secder.h"
+
+CRMFEncryptedKeyChoice
+CRMF_EncryptedKeyGetChoice(CRMFEncryptedKey *inEncrKey)
+{
+ PORT_Assert(inEncrKey != NULL);
+ if (inEncrKey == NULL) {
+ return crmfNoEncryptedKeyChoice;
+ }
+ return inEncrKey->encKeyChoice;
+}
+
+CRMFEncryptedValue *
+CRMF_EncryptedKeyGetEncryptedValue(CRMFEncryptedKey *inEncrKey)
+{
+ CRMFEncryptedValue *newEncrValue = NULL;
+ SECStatus rv;
+
+ PORT_Assert(inEncrKey != NULL);
+ if (inEncrKey == NULL ||
+ CRMF_EncryptedKeyGetChoice(inEncrKey) != crmfEncryptedValueChoice) {
+ goto loser;
+ }
+ newEncrValue = PORT_ZNew(CRMFEncryptedValue);
+ if (newEncrValue == NULL) {
+ goto loser;
+ }
+ rv = crmf_copy_encryptedvalue(NULL, &inEncrKey->value.encryptedValue,
+ newEncrValue);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return newEncrValue;
+loser:
+ if (newEncrValue != NULL) {
+ CRMF_DestroyEncryptedValue(newEncrValue);
+ }
+ return NULL;
+}
+
+static SECItem *
+crmf_get_encvalue_bitstring(SECItem *srcItem)
+{
+ SECItem *newItem = NULL;
+ SECStatus rv;
+
+ if (srcItem->data == NULL) {
+ return NULL;
+ }
+ newItem = PORT_ZNew(SECItem);
+ if (newItem == NULL) {
+ goto loser;
+ }
+ rv = crmf_make_bitstring_copy(NULL, newItem, srcItem);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return newItem;
+loser:
+ if (newItem != NULL) {
+ SECITEM_FreeItem(newItem, PR_TRUE);
+ }
+ return NULL;
+}
+
+SECItem *
+CRMF_EncryptedValueGetEncSymmKey(CRMFEncryptedValue *inEncValue)
+{
+ if (inEncValue == NULL) {
+ return NULL;
+ }
+ return crmf_get_encvalue_bitstring(&inEncValue->encSymmKey);
+}
+
+SECItem *
+CRMF_EncryptedValueGetEncValue(CRMFEncryptedValue *inEncrValue)
+{
+ if (inEncrValue == NULL || inEncrValue->encValue.data == NULL) {
+ return NULL;
+ }
+ return crmf_get_encvalue_bitstring(&inEncrValue->encValue);
+}
+
+static SECAlgorithmID *
+crmf_get_encvalue_algid(SECAlgorithmID *srcAlg)
+{
+ SECStatus rv;
+ SECAlgorithmID *newAlgID;
+
+ if (srcAlg == NULL) {
+ return NULL;
+ }
+ rv = crmf_copy_encryptedvalue_secalg(NULL, srcAlg, &newAlgID);
+ if (rv != SECSuccess) {
+ return NULL;
+ }
+ return newAlgID;
+}
+
+SECAlgorithmID *
+CRMF_EncryptedValueGetIntendedAlg(CRMFEncryptedValue *inEncValue)
+{
+ if (inEncValue == NULL) {
+ return NULL;
+ }
+ return crmf_get_encvalue_algid(inEncValue->intendedAlg);
+}
+
+SECAlgorithmID *
+CRMF_EncryptedValueGetKeyAlg(CRMFEncryptedValue *inEncValue)
+{
+ if (inEncValue == NULL) {
+ return NULL;
+ }
+ return crmf_get_encvalue_algid(inEncValue->keyAlg);
+}
+
+SECAlgorithmID *
+CRMF_EncryptedValueGetSymmAlg(CRMFEncryptedValue *inEncValue)
+{
+ if (inEncValue == NULL) {
+ return NULL;
+ }
+ return crmf_get_encvalue_algid(inEncValue->symmAlg);
+}
+
+SECItem *
+CRMF_EncryptedValueGetValueHint(CRMFEncryptedValue *inEncValue)
+{
+ if (inEncValue == NULL || inEncValue->valueHint.data == NULL) {
+ return NULL;
+ }
+ return SECITEM_DupItem(&inEncValue->valueHint);
+}
+
+SECStatus
+CRMF_PKIArchiveOptionsGetArchiveRemGenPrivKey(CRMFPKIArchiveOptions *inOpt,
+ PRBool *destVal)
+{
+ if (inOpt == NULL || destVal == NULL ||
+ CRMF_PKIArchiveOptionsGetOptionType(inOpt) != crmfArchiveRemGenPrivKey) {
+ return SECFailure;
+ }
+ *destVal = (inOpt->option.archiveRemGenPrivKey.data[0] == hexFalse)
+ ? PR_FALSE
+ : PR_TRUE;
+ return SECSuccess;
+}
+
+CRMFEncryptedKey *
+CRMF_PKIArchiveOptionsGetEncryptedPrivKey(CRMFPKIArchiveOptions *inOpts)
+{
+ CRMFEncryptedKey *newEncrKey = NULL;
+ SECStatus rv;
+
+ PORT_Assert(inOpts != NULL);
+ if (inOpts == NULL ||
+ CRMF_PKIArchiveOptionsGetOptionType(inOpts) != crmfEncryptedPrivateKey) {
+ return NULL;
+ }
+ newEncrKey = PORT_ZNew(CRMFEncryptedKey);
+ if (newEncrKey == NULL) {
+ goto loser;
+ }
+ rv = crmf_copy_encryptedkey(NULL, &inOpts->option.encryptedKey,
+ newEncrKey);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return newEncrKey;
+loser:
+ if (newEncrKey != NULL) {
+ CRMF_DestroyEncryptedKey(newEncrKey);
+ }
+ return NULL;
+}
+
+SECItem *
+CRMF_PKIArchiveOptionsGetKeyGenParameters(CRMFPKIArchiveOptions *inOptions)
+{
+ if (inOptions == NULL ||
+ CRMF_PKIArchiveOptionsGetOptionType(inOptions) != crmfKeyGenParameters ||
+ inOptions->option.keyGenParameters.data == NULL) {
+ return NULL;
+ }
+ return SECITEM_DupItem(&inOptions->option.keyGenParameters);
+}
+
+CRMFPKIArchiveOptionsType
+CRMF_PKIArchiveOptionsGetOptionType(CRMFPKIArchiveOptions *inOptions)
+{
+ PORT_Assert(inOptions != NULL);
+ if (inOptions == NULL) {
+ return crmfNoArchiveOptions;
+ }
+ return inOptions->archOption;
+}
+
+static SECStatus
+crmf_extract_long_from_item(SECItem *intItem, long *destLong)
+{
+ *destLong = DER_GetInteger(intItem);
+ return (*destLong == -1) ? SECFailure : SECSuccess;
+}
+
+SECStatus
+CRMF_POPOPrivGetKeySubseqMess(CRMFPOPOPrivKey *inKey,
+ CRMFSubseqMessOptions *destOpt)
+{
+ long value;
+ SECStatus rv;
+
+ PORT_Assert(inKey != NULL);
+ if (inKey == NULL ||
+ inKey->messageChoice != crmfSubsequentMessage) {
+ return SECFailure;
+ }
+ rv = crmf_extract_long_from_item(&inKey->message.subsequentMessage, &value);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ switch (value) {
+ case 0:
+ *destOpt = crmfEncrCert;
+ break;
+ case 1:
+ *destOpt = crmfChallengeResp;
+ break;
+ default:
+ rv = SECFailure;
+ }
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ return SECSuccess;
+}
+
+CRMFPOPOPrivKeyChoice
+CRMF_POPOPrivKeyGetChoice(CRMFPOPOPrivKey *inPrivKey)
+{
+ PORT_Assert(inPrivKey != NULL);
+ if (inPrivKey != NULL) {
+ return inPrivKey->messageChoice;
+ }
+ return crmfNoMessage;
+}
+
+SECStatus
+CRMF_POPOPrivKeyGetDHMAC(CRMFPOPOPrivKey *inKey, SECItem *destMAC)
+{
+ PORT_Assert(inKey != NULL);
+ if (inKey == NULL || inKey->message.dhMAC.data == NULL) {
+ return SECFailure;
+ }
+ return crmf_make_bitstring_copy(NULL, destMAC, &inKey->message.dhMAC);
+}
+
+SECStatus
+CRMF_POPOPrivKeyGetThisMessage(CRMFPOPOPrivKey *inKey,
+ SECItem *destString)
+{
+ PORT_Assert(inKey != NULL);
+ if (inKey == NULL ||
+ inKey->messageChoice != crmfThisMessage) {
+ return SECFailure;
+ }
+
+ return crmf_make_bitstring_copy(NULL, destString,
+ &inKey->message.thisMessage);
+}
+
+SECAlgorithmID *
+CRMF_POPOSigningKeyGetAlgID(CRMFPOPOSigningKey *inSignKey)
+{
+ SECAlgorithmID *newAlgId = NULL;
+ SECStatus rv;
+
+ PORT_Assert(inSignKey != NULL);
+ if (inSignKey == NULL) {
+ return NULL;
+ }
+ newAlgId = PORT_ZNew(SECAlgorithmID);
+ if (newAlgId == NULL) {
+ goto loser;
+ }
+ rv = SECOID_CopyAlgorithmID(NULL, newAlgId,
+ inSignKey->algorithmIdentifier);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return newAlgId;
+
+loser:
+ if (newAlgId != NULL) {
+ SECOID_DestroyAlgorithmID(newAlgId, PR_TRUE);
+ }
+ return NULL;
+}
+
+SECItem *
+CRMF_POPOSigningKeyGetInput(CRMFPOPOSigningKey *inSignKey)
+{
+ PORT_Assert(inSignKey != NULL);
+ if (inSignKey == NULL || inSignKey->derInput.data == NULL) {
+ return NULL;
+ }
+ return SECITEM_DupItem(&inSignKey->derInput);
+}
+
+SECItem *
+CRMF_POPOSigningKeyGetSignature(CRMFPOPOSigningKey *inSignKey)
+{
+ SECItem *newSig = NULL;
+ SECStatus rv;
+
+ PORT_Assert(inSignKey != NULL);
+ if (inSignKey == NULL) {
+ return NULL;
+ }
+ newSig = PORT_ZNew(SECItem);
+ if (newSig == NULL) {
+ goto loser;
+ }
+ rv = crmf_make_bitstring_copy(NULL, newSig, &inSignKey->signature);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return newSig;
+loser:
+ if (newSig != NULL) {
+ SECITEM_FreeItem(newSig, PR_TRUE);
+ }
+ return NULL;
+}
+
+static SECStatus
+crmf_copy_poposigningkey(PLArenaPool *poolp,
+ CRMFPOPOSigningKey *inPopoSignKey,
+ CRMFPOPOSigningKey *destPopoSignKey)
+{
+ SECStatus rv;
+
+ /* We don't support use of the POPOSigningKeyInput, so we'll only
+ * store away the DER encoding.
+ */
+ if (inPopoSignKey->derInput.data != NULL) {
+ rv = SECITEM_CopyItem(poolp, &destPopoSignKey->derInput,
+ &inPopoSignKey->derInput);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ destPopoSignKey->algorithmIdentifier = (poolp == NULL) ? PORT_ZNew(SECAlgorithmID)
+ : PORT_ArenaZNew(poolp, SECAlgorithmID);
+
+ if (destPopoSignKey->algorithmIdentifier == NULL) {
+ goto loser;
+ }
+ rv = SECOID_CopyAlgorithmID(poolp, destPopoSignKey->algorithmIdentifier,
+ inPopoSignKey->algorithmIdentifier);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = crmf_make_bitstring_copy(poolp, &destPopoSignKey->signature,
+ &inPopoSignKey->signature);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return SECSuccess;
+loser:
+ if (poolp == NULL) {
+ CRMF_DestroyPOPOSigningKey(destPopoSignKey);
+ }
+ return SECFailure;
+}
+
+static SECStatus
+crmf_copy_popoprivkey(PLArenaPool *poolp,
+ CRMFPOPOPrivKey *srcPrivKey,
+ CRMFPOPOPrivKey *destPrivKey)
+{
+ SECStatus rv;
+
+ destPrivKey->messageChoice = srcPrivKey->messageChoice;
+ switch (destPrivKey->messageChoice) {
+ case crmfThisMessage:
+ case crmfDHMAC:
+ /* I've got a union, so taking the address of one, will also give
+ * me a pointer to the other (eg, message.dhMAC)
+ */
+ rv = crmf_make_bitstring_copy(poolp, &destPrivKey->message.thisMessage,
+ &srcPrivKey->message.thisMessage);
+ break;
+ case crmfSubsequentMessage:
+ rv = SECITEM_CopyItem(poolp, &destPrivKey->message.subsequentMessage,
+ &srcPrivKey->message.subsequentMessage);
+ break;
+ default:
+ rv = SECFailure;
+ }
+
+ if (rv != SECSuccess && poolp == NULL) {
+ CRMF_DestroyPOPOPrivKey(destPrivKey);
+ }
+ return rv;
+}
+
+static CRMFProofOfPossession *
+crmf_copy_pop(PLArenaPool *poolp, CRMFProofOfPossession *srcPOP)
+{
+ CRMFProofOfPossession *newPOP;
+ SECStatus rv;
+
+ /*
+ * Proof Of Possession structures are always part of the Request
+ * message, so there will always be an arena for allocating memory.
+ */
+ if (poolp == NULL) {
+ return NULL;
+ }
+ newPOP = PORT_ArenaZNew(poolp, CRMFProofOfPossession);
+ if (newPOP == NULL) {
+ return NULL;
+ }
+ switch (srcPOP->popUsed) {
+ case crmfRAVerified:
+ newPOP->popChoice.raVerified.data = NULL;
+ newPOP->popChoice.raVerified.len = 0;
+ break;
+ case crmfSignature:
+ rv = crmf_copy_poposigningkey(poolp, &srcPOP->popChoice.signature,
+ &newPOP->popChoice.signature);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ break;
+ case crmfKeyEncipherment:
+ case crmfKeyAgreement:
+ /* We've got a union, so a pointer to one, is a pointer to the
+ * other one.
+ */
+ rv = crmf_copy_popoprivkey(poolp, &srcPOP->popChoice.keyEncipherment,
+ &newPOP->popChoice.keyEncipherment);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ break;
+ default:
+ goto loser;
+ }
+ newPOP->popUsed = srcPOP->popUsed;
+ return newPOP;
+
+loser:
+ return NULL;
+}
+
+static CRMFCertReqMsg *
+crmf_copy_cert_req_msg(CRMFCertReqMsg *srcReqMsg)
+{
+ CRMFCertReqMsg *newReqMsg;
+ PLArenaPool *poolp;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ return NULL;
+ }
+ newReqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg);
+ if (newReqMsg == NULL) {
+ PORT_FreeArena(poolp, PR_TRUE);
+ return NULL;
+ }
+
+ newReqMsg->poolp = poolp;
+ newReqMsg->certReq = crmf_copy_cert_request(poolp, srcReqMsg->certReq);
+ if (newReqMsg->certReq == NULL) {
+ goto loser;
+ }
+ newReqMsg->pop = crmf_copy_pop(poolp, srcReqMsg->pop);
+ if (newReqMsg->pop == NULL) {
+ goto loser;
+ }
+ /* None of my set/get routines operate on the regInfo field, so
+ * for now, that won't get copied over.
+ */
+ return newReqMsg;
+
+loser:
+ CRMF_DestroyCertReqMsg(newReqMsg);
+ return NULL;
+}
+
+CRMFCertReqMsg *
+CRMF_CertReqMessagesGetCertReqMsgAtIndex(CRMFCertReqMessages *inReqMsgs,
+ int index)
+{
+ int numMsgs;
+
+ PORT_Assert(inReqMsgs != NULL && index >= 0);
+ if (inReqMsgs == NULL) {
+ return NULL;
+ }
+ numMsgs = CRMF_CertReqMessagesGetNumMessages(inReqMsgs);
+ if (index < 0 || index >= numMsgs) {
+ return NULL;
+ }
+ return crmf_copy_cert_req_msg(inReqMsgs->messages[index]);
+}
+
+int
+CRMF_CertReqMessagesGetNumMessages(CRMFCertReqMessages *inCertReqMsgs)
+{
+ int numMessages = 0;
+
+ PORT_Assert(inCertReqMsgs != NULL);
+ if (inCertReqMsgs == NULL) {
+ return 0;
+ }
+ while (inCertReqMsgs->messages[numMessages] != NULL) {
+ numMessages++;
+ }
+ return numMessages;
+}
+
+CRMFCertRequest *
+CRMF_CertReqMsgGetCertRequest(CRMFCertReqMsg *inCertReqMsg)
+{
+ PLArenaPool *poolp = NULL;
+ CRMFCertRequest *newCertReq = NULL;
+
+ PORT_Assert(inCertReqMsg != NULL);
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ goto loser;
+ }
+ newCertReq = crmf_copy_cert_request(poolp, inCertReqMsg->certReq);
+ if (newCertReq == NULL) {
+ goto loser;
+ }
+ newCertReq->poolp = poolp;
+ return newCertReq;
+loser:
+ if (poolp != NULL) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ }
+ return NULL;
+}
+
+SECStatus
+CRMF_CertReqMsgGetID(CRMFCertReqMsg *inCertReqMsg, long *destID)
+{
+ PORT_Assert(inCertReqMsg != NULL && destID != NULL);
+ if (inCertReqMsg == NULL || inCertReqMsg->certReq == NULL) {
+ return SECFailure;
+ }
+ return crmf_extract_long_from_item(&inCertReqMsg->certReq->certReqId,
+ destID);
+}
+
+SECStatus
+CRMF_CertReqMsgGetPOPKeyAgreement(CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOPrivKey **destKey)
+{
+ PORT_Assert(inCertReqMsg != NULL && destKey != NULL);
+ if (inCertReqMsg == NULL || destKey == NULL ||
+ CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfKeyAgreement) {
+ return SECFailure;
+ }
+ *destKey = PORT_ZNew(CRMFPOPOPrivKey);
+ if (*destKey == NULL) {
+ return SECFailure;
+ }
+ return crmf_copy_popoprivkey(NULL,
+ &inCertReqMsg->pop->popChoice.keyAgreement,
+ *destKey);
+}
+
+SECStatus
+CRMF_CertReqMsgGetPOPKeyEncipherment(CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOPrivKey **destKey)
+{
+ PORT_Assert(inCertReqMsg != NULL && destKey != NULL);
+ if (inCertReqMsg == NULL || destKey == NULL ||
+ CRMF_CertReqMsgGetPOPType(inCertReqMsg) != crmfKeyEncipherment) {
+ return SECFailure;
+ }
+ *destKey = PORT_ZNew(CRMFPOPOPrivKey);
+ if (*destKey == NULL) {
+ return SECFailure;
+ }
+ return crmf_copy_popoprivkey(NULL,
+ &inCertReqMsg->pop->popChoice.keyEncipherment,
+ *destKey);
+}
+
+SECStatus
+CRMF_CertReqMsgGetPOPOSigningKey(CRMFCertReqMsg *inCertReqMsg,
+ CRMFPOPOSigningKey **destKey)
+{
+ CRMFProofOfPossession *pop;
+ PORT_Assert(inCertReqMsg != NULL);
+ if (inCertReqMsg == NULL) {
+ return SECFailure;
+ }
+ pop = inCertReqMsg->pop;
+ ;
+ if (pop->popUsed != crmfSignature) {
+ return SECFailure;
+ }
+ *destKey = PORT_ZNew(CRMFPOPOSigningKey);
+ if (*destKey == NULL) {
+ return SECFailure;
+ }
+ return crmf_copy_poposigningkey(NULL, &pop->popChoice.signature, *destKey);
+}
+
+static SECStatus
+crmf_copy_name(CERTName *destName, CERTName *srcName)
+{
+ PLArenaPool *poolp = NULL;
+ SECStatus rv;
+
+ if (destName->arena != NULL) {
+ poolp = destName->arena;
+ } else {
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ }
+ if (poolp == NULL) {
+ return SECFailure;
+ }
+ /* Need to do this so that CERT_CopyName doesn't free out
+ * the arena from underneath us.
+ */
+ destName->arena = NULL;
+ rv = CERT_CopyName(poolp, destName, srcName);
+ destName->arena = poolp;
+ return rv;
+}
+
+SECStatus
+CRMF_CertRequestGetCertTemplateIssuer(CRMFCertRequest *inCertReq,
+ CERTName *destIssuer)
+{
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return SECFailure;
+ }
+ if (CRMF_DoesRequestHaveField(inCertReq, crmfIssuer)) {
+ return crmf_copy_name(destIssuer,
+ inCertReq->certTemplate.issuer);
+ }
+ return SECFailure;
+}
+
+SECStatus
+CRMF_CertRequestGetCertTemplateIssuerUID(CRMFCertRequest *inCertReq,
+ SECItem *destIssuerUID)
+{
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return SECFailure;
+ }
+ if (CRMF_DoesRequestHaveField(inCertReq, crmfIssuerUID)) {
+ return crmf_make_bitstring_copy(NULL, destIssuerUID,
+ &inCertReq->certTemplate.issuerUID);
+ }
+ return SECFailure;
+}
+
+SECStatus
+CRMF_CertRequestGetCertTemplatePublicKey(CRMFCertRequest *inCertReq,
+ CERTSubjectPublicKeyInfo *destPublicKey)
+{
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return SECFailure;
+ }
+ if (CRMF_DoesRequestHaveField(inCertReq, crmfPublicKey)) {
+ return SECKEY_CopySubjectPublicKeyInfo(NULL, destPublicKey,
+ inCertReq->certTemplate.publicKey);
+ }
+ return SECFailure;
+}
+
+SECStatus
+CRMF_CertRequestGetCertTemplateSerialNumber(CRMFCertRequest *inCertReq,
+ long *serialNumber)
+{
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return SECFailure;
+ }
+ if (CRMF_DoesRequestHaveField(inCertReq, crmfSerialNumber)) {
+ return crmf_extract_long_from_item(&inCertReq->certTemplate.serialNumber,
+ serialNumber);
+ }
+ return SECFailure;
+}
+
+SECStatus
+CRMF_CertRequestGetCertTemplateSigningAlg(CRMFCertRequest *inCertReq,
+ SECAlgorithmID *destAlg)
+{
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return SECFailure;
+ }
+ if (CRMF_DoesRequestHaveField(inCertReq, crmfSigningAlg)) {
+ return SECOID_CopyAlgorithmID(NULL, destAlg,
+ inCertReq->certTemplate.signingAlg);
+ }
+ return SECFailure;
+}
+
+SECStatus
+CRMF_CertRequestGetCertTemplateSubject(CRMFCertRequest *inCertReq,
+ CERTName *destSubject)
+{
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return SECFailure;
+ }
+ if (CRMF_DoesRequestHaveField(inCertReq, crmfSubject)) {
+ return crmf_copy_name(destSubject, inCertReq->certTemplate.subject);
+ }
+ return SECFailure;
+}
+
+SECStatus
+CRMF_CertRequestGetCertTemplateSubjectUID(CRMFCertRequest *inCertReq,
+ SECItem *destSubjectUID)
+{
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return SECFailure;
+ }
+ if (CRMF_DoesRequestHaveField(inCertReq, crmfSubjectUID)) {
+ return crmf_make_bitstring_copy(NULL, destSubjectUID,
+ &inCertReq->certTemplate.subjectUID);
+ }
+ return SECFailure;
+}
+
+SECStatus
+CRMF_CertRequestGetCertTemplateVersion(CRMFCertRequest *inCertReq,
+ long *version)
+{
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return SECFailure;
+ }
+ if (CRMF_DoesRequestHaveField(inCertReq, crmfVersion)) {
+ return crmf_extract_long_from_item(&inCertReq->certTemplate.version,
+ version);
+ }
+ return SECFailure;
+}
+
+static SECStatus
+crmf_copy_validity(CRMFGetValidity *destValidity,
+ CRMFOptionalValidity *src)
+{
+ SECStatus rv;
+
+ destValidity->notBefore = destValidity->notAfter = NULL;
+ if (src->notBefore.data != NULL) {
+ rv = crmf_create_prtime(&src->notBefore,
+ &destValidity->notBefore);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+ if (src->notAfter.data != NULL) {
+ rv = crmf_create_prtime(&src->notAfter,
+ &destValidity->notAfter);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+ return SECSuccess;
+}
+
+SECStatus
+CRMF_CertRequestGetCertTemplateValidity(CRMFCertRequest *inCertReq,
+ CRMFGetValidity *destValidity)
+{
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return SECFailure;
+ }
+ if (CRMF_DoesRequestHaveField(inCertReq, crmfValidity)) {
+ return crmf_copy_validity(destValidity,
+ inCertReq->certTemplate.validity);
+ }
+ return SECFailure;
+}
+
+CRMFControl *
+CRMF_CertRequestGetControlAtIndex(CRMFCertRequest *inCertReq, int index)
+{
+ CRMFControl *newControl, *srcControl;
+ int numControls;
+ SECStatus rv;
+
+ PORT_Assert(inCertReq != NULL);
+ if (inCertReq == NULL) {
+ return NULL;
+ }
+ numControls = CRMF_CertRequestGetNumControls(inCertReq);
+ if (index >= numControls || index < 0) {
+ return NULL;
+ }
+ newControl = PORT_ZNew(CRMFControl);
+ if (newControl == NULL) {
+ return NULL;
+ }
+ srcControl = inCertReq->controls[index];
+ newControl->tag = srcControl->tag;
+ rv = SECITEM_CopyItem(NULL, &newControl->derTag, &srcControl->derTag);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = SECITEM_CopyItem(NULL, &newControl->derValue,
+ &srcControl->derValue);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ /* Copy over the PKIArchiveOptions stuff */
+ switch (srcControl->tag) {
+ case SEC_OID_PKIX_REGCTRL_REGTOKEN:
+ case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
+ /* No further processing necessary for these types. */
+ rv = SECSuccess;
+ break;
+ case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
+ case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
+ case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
+ /* These aren't supported yet, so no post-processing will
+ * be done at this time. But we don't want to fail in case
+ * we read in DER that has one of these options.
+ */
+ rv = SECSuccess;
+ break;
+ case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
+ rv = crmf_copy_pkiarchiveoptions(NULL,
+ &newControl->value.archiveOptions,
+ &srcControl->value.archiveOptions);
+ break;
+ default:
+ rv = SECFailure;
+ }
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ return newControl;
+loser:
+ CRMF_DestroyControl(newControl);
+ return NULL;
+}
+
+static SECItem *
+crmf_copy_control_value(CRMFControl *inControl)
+{
+ return SECITEM_DupItem(&inControl->derValue);
+}
+
+SECItem *
+CRMF_ControlGetAuthenticatorControlValue(CRMFControl *inControl)
+{
+ PORT_Assert(inControl != NULL);
+ if (inControl == NULL ||
+ CRMF_ControlGetControlType(inControl) != crmfAuthenticatorControl) {
+ return NULL;
+ }
+ return crmf_copy_control_value(inControl);
+}
+
+CRMFControlType
+CRMF_ControlGetControlType(CRMFControl *inControl)
+{
+ CRMFControlType retType;
+
+ PORT_Assert(inControl != NULL);
+ switch (inControl->tag) {
+ case SEC_OID_PKIX_REGCTRL_REGTOKEN:
+ retType = crmfRegTokenControl;
+ break;
+ case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
+ retType = crmfAuthenticatorControl;
+ break;
+ case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
+ retType = crmfPKIPublicationInfoControl;
+ break;
+ case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
+ retType = crmfPKIArchiveOptionsControl;
+ break;
+ case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
+ retType = crmfOldCertIDControl;
+ break;
+ case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
+ retType = crmfProtocolEncrKeyControl;
+ break;
+ default:
+ retType = crmfNoControl;
+ }
+ return retType;
+}
+
+CRMFPKIArchiveOptions *
+CRMF_ControlGetPKIArchiveOptions(CRMFControl *inControl)
+{
+ CRMFPKIArchiveOptions *newOpt = NULL;
+ SECStatus rv;
+
+ PORT_Assert(inControl != NULL);
+ if (inControl == NULL ||
+ CRMF_ControlGetControlType(inControl) != crmfPKIArchiveOptionsControl) {
+ goto loser;
+ }
+ newOpt = PORT_ZNew(CRMFPKIArchiveOptions);
+ if (newOpt == NULL) {
+ goto loser;
+ }
+ rv = crmf_copy_pkiarchiveoptions(NULL, newOpt,
+ &inControl->value.archiveOptions);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+loser:
+ if (newOpt != NULL) {
+ CRMF_DestroyPKIArchiveOptions(newOpt);
+ }
+ return NULL;
+}
+
+SECItem *
+CRMF_ControlGetRegTokenControlValue(CRMFControl *inControl)
+{
+ PORT_Assert(inControl != NULL);
+ if (inControl == NULL ||
+ CRMF_ControlGetControlType(inControl) != crmfRegTokenControl) {
+ return NULL;
+ }
+ return crmf_copy_control_value(inControl);
+ ;
+}
+
+CRMFCertExtension *
+CRMF_CertRequestGetExtensionAtIndex(CRMFCertRequest *inCertReq,
+ int index)
+{
+ int numExtensions;
+
+ PORT_Assert(inCertReq != NULL);
+ numExtensions = CRMF_CertRequestGetNumberOfExtensions(inCertReq);
+ if (index >= numExtensions || index < 0) {
+ return NULL;
+ }
+ return crmf_copy_cert_extension(NULL,
+ inCertReq->certTemplate.extensions[index]);
+}