diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /security/nss/lib/crmf | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
30 files changed, 10714 insertions, 0 deletions
diff --git a/security/nss/lib/crmf/Makefile b/security/nss/lib/crmf/Makefile new file mode 100644 index 0000000000..609d4adefe --- /dev/null +++ b/security/nss/lib/crmf/Makefile @@ -0,0 +1,46 @@ +#! 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). # +####################################################################### + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + diff --git a/security/nss/lib/crmf/asn1cmn.c b/security/nss/lib/crmf/asn1cmn.c new file mode 100644 index 0000000000..6cf469fb4c --- /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 0000000000..a928438948 --- /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 0000000000..1e39a8d2d2 --- /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 0000000000..64915b3392 --- /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 0000000000..2fee983c96 --- /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 0000000000..9336ccfc23 --- /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 0000000000..014413f075 --- /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 0000000000..3c55350158 --- /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.len ? keyUsageValue.data[0] : 0; + 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 0000000000..c4b59b8e98 --- /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 0000000000..e39f19ed3a --- /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/crmf.gyp b/security/nss/lib/crmf/crmf.gyp new file mode 100644 index 0000000000..f8fa8a48d6 --- /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 0000000000..c56e28913b --- /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 0000000000..5df2bd8283 --- /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 0000000000..ac6e872686 --- /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 0000000000..6d01a45cea --- /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 0000000000..d6f9374384 --- /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 0000000000..5c1d2aa192 --- /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 0000000000..badfd2b053 --- /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 0000000000..c5c4b96e90 --- /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 0000000000..725f8c730e --- /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 0000000000..e89f18228c --- /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 0000000000..8d83cf1e61 --- /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 0000000000..265a15dd5d --- /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 0000000000..8ca7007b6c --- /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 0000000000..fca0097565 --- /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 0000000000..8c687ea243 --- /dev/null +++ b/security/nss/lib/crmf/manifest.mn @@ -0,0 +1,47 @@ +# +# 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 +SHARED_LIBRARY = $(NULL) + +# 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 0000000000..aaec0136f1 --- /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 0000000000..f9e4155a33 --- /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 0000000000..6d576f8f10 --- /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]); +} |