From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- security/nss/cmd/crmftest/Makefile | 61 ++ security/nss/cmd/crmftest/crmftest.gyp | 25 + security/nss/cmd/crmftest/manifest.mn | 21 + security/nss/cmd/crmftest/testcrmf.c | 1655 ++++++++++++++++++++++++++++++++ 4 files changed, 1762 insertions(+) create mode 100644 security/nss/cmd/crmftest/Makefile create mode 100644 security/nss/cmd/crmftest/crmftest.gyp create mode 100644 security/nss/cmd/crmftest/manifest.mn create mode 100644 security/nss/cmd/crmftest/testcrmf.c (limited to 'security/nss/cmd/crmftest') diff --git a/security/nss/cmd/crmftest/Makefile b/security/nss/cmd/crmftest/Makefile new file mode 100644 index 0000000000..715d0b7d18 --- /dev/null +++ b/security/nss/cmd/crmftest/Makefile @@ -0,0 +1,61 @@ +#! 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) # +####################################################################### + +ifeq ($(OS_TARGET)$(OS_RELEASE), AIX4.2) +OS_LIBS += -lsvld +endif + +ifeq ($(OS_TARGET)$(OS_RELEASE), SunOS5.6) +OS_LIBS += -ldl -lxnet -lposix4 -lsocket -lnsl +endif + +EXTRA_LIBS += $(DIST)/lib/$(LIB_PREFIX)crmf.$(LIB_SUFFIX) + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +LDDIST = $(DIST)/lib + +ifeq (,$(filter-out WIN%,$(OS_TARGET))) +EXTRA_LIBS += $(LDDIST)/sectool.lib +endif + +include ../platrules.mk diff --git a/security/nss/cmd/crmftest/crmftest.gyp b/security/nss/cmd/crmftest/crmftest.gyp new file mode 100644 index 0000000000..c14bd195ab --- /dev/null +++ b/security/nss/cmd/crmftest/crmftest.gyp @@ -0,0 +1,25 @@ +# 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', + '../../cmd/platlibs.gypi' + ], + 'targets': [ + { + 'target_name': 'crmftest', + 'type': 'executable', + 'sources': [ + 'testcrmf.c' + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + '<(DEPTH)/lib/crmf/crmf.gyp:crmf' + ] + } + ], + 'variables': { + 'module': 'nss' + } +} \ No newline at end of file diff --git a/security/nss/cmd/crmftest/manifest.mn b/security/nss/cmd/crmftest/manifest.mn new file mode 100644 index 0000000000..4ac669a21b --- /dev/null +++ b/security/nss/cmd/crmftest/manifest.mn @@ -0,0 +1,21 @@ +# +# 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 = ../.. +DEPTH = . + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = \ + testcrmf.c \ + $(NULL) + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +# REQUIRES = dbm + +PROGRAM = crmftest + diff --git a/security/nss/cmd/crmftest/testcrmf.c b/security/nss/cmd/crmftest/testcrmf.c new file mode 100644 index 0000000000..1982b9d48a --- /dev/null +++ b/security/nss/cmd/crmftest/testcrmf.c @@ -0,0 +1,1655 @@ +/* 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 program does 5 separate functions. By default, it does them all. + * It can be told to do any subset of them. + * It does them in this order: + * + * 1. Generate file of CRMF cert requests. + * Generates 2 keys pairs, one for signing, one for encryption. + * Can generate RSA or DSA (XXX - DSA is only useful for signing). + * Generate a cert request for each of the two public keys. + * Generate a single CRMF cert request message that requests both certs. + * Leave the generated CRMF request message in file + * configdir/CertReqMessages.der + * + * 2. Decode CRMF Request(s) Message. + * Reads in the file configdir/CertReqMessages.der + * (either generated by step 1 above, or user supplied). + * Decodes it. NOTHING MORE. Drops these decoded results on the floor. + * The CMMF response (below) contains a completely unrelated cert. :-( + * + * 3. CMMF "Stuff". + * a) Generates a CMMF response, containing a single cert chain, as if + * it was a response to a received CRMF request. But the cert is + * simply a user cert from the user's local soft token, whose + * nickname is given in the -p option. The CMMF response has no + * relationship to the request generated above. The CMMF message + * is placed in configdir/CertRepContent.der. + * b) Decodes the newly generated CMMF response found in file + * configdir/CertRepContent.der and discards the result. 8-/ + * c) Generate a CMMF Key Escrow message + * needs 2 nicknames: + * It takes the public and private keys for the cert identified + * by -p nickname, and wraps them with a sym key that is in turn + * wrapped with the pubkey in the CA cert, whose nickname is + * given with the -s option. + * Store the message in configdir/KeyRecRepContent.der + * d) Decode the CMMF Key Escrow message generated just above. + * Get it from file configdir/KeyRecRepContent.der + * This is just a decoder test. Results are discarded. + * + * 4. Key Recovery + * This code does not yet compile, and what it was intended to do + * has not been fully determined. + * + * 5. Challenge/Response. + * Haven't analyzed this code yet. + * + * + */ + +/* KNOWN BUGS: +** 1. generates BOTH signing and encryption cert requests, even for DSA keys. +** +** 2. Does not verify the siganture in the "Proof of Posession" in the +** decoded cert requests. It only checks syntax of the POP. +** 3. CMMF "Stuff" should be broken up into separate steps, each of +** which may be optionally selected. +*/ + +#include +#include "nspr.h" +#include "nss.h" +#include "crmf.h" +#include "secerr.h" +#include "pk11func.h" +#include "keyhi.h" +#include "cmmf.h" +#include "plgetopt.h" +#include "secutil.h" +#include "pk11pqg.h" + +#if 0 +#include "pkcs11.h" +#include "secmod.h" +#include "secmodi.h" +#include "pqggen.h" +#include "secmod.h" +#include "secmodi.h" +#include "pkcs11.h" +#include "secitem.h" +#include "secasn1.h" +#include "sechash.h" +#endif + +#define MAX_KEY_LEN 1024 +#define PATH_LEN 150 +#define BUFF_SIZE 150 +#define UID_BITS 800 +#define BPB 8 +#define CRMF_FILE "CertReqMessages.der" + +PRTime notBefore; +char *personalCert = NULL; +char *recoveryEncrypter = NULL; +char *caCertName = NULL; +static secuPWData pwdata = { PW_NONE, 0 }; +char *configdir; +PRBool doingDSA = PR_FALSE; + +CERTCertDBHandle *db; + +typedef struct { + SECKEYPrivateKey *privKey; + SECKEYPublicKey *pubKey; + CRMFCertRequest *certReq; + CRMFCertReqMsg *certReqMsg; +} TESTKeyPair; + +void +debug_test(SECItem *src, char *filePath) +{ + PRFileDesc *fileDesc; + + fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf("Could not cretae file %s.\n", filePath); + return; + } + PR_Write(fileDesc, src->data, src->len); +} + +SECStatus +get_serial_number(long *dest) +{ + SECStatus rv; + + if (dest == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + rv = PK11_GenerateRandom((unsigned char *)dest, sizeof(long)); + if (rv != SECSuccess) { + /* PK11_GenerateRandom calls PORT_SetError */ + return SECFailure; + } + /* make serial number positive */ + if (*dest < 0L) + *dest = -*dest; + return SECSuccess; +} + +PK11RSAGenParams * +GetRSAParams(void) +{ + PK11RSAGenParams *rsaParams; + + rsaParams = PORT_ZNew(PK11RSAGenParams); + + if (rsaParams == NULL) + return NULL; + + rsaParams->keySizeInBits = MAX_KEY_LEN; + rsaParams->pe = 0x10001; + + return rsaParams; +} + +PQGParams * +GetDSAParams(void) +{ + PQGParams *params = NULL; + PQGVerify *vfy = NULL; + + SECStatus rv; + + rv = PK11_PQG_ParamGen(0, ¶ms, &vfy); + if (rv != SECSuccess) { + return NULL; + } + PK11_PQG_DestroyVerify(vfy); + return params; +} + +/* Generate a key pair, and then generate a subjectPublicKeyInfo +** for the public key in that pair. return all 3. +*/ +CERTSubjectPublicKeyInfo * +GetSubjectPubKeyInfo(TESTKeyPair *pair) +{ + CERTSubjectPublicKeyInfo *spki = NULL; + SECKEYPrivateKey *privKey = NULL; + SECKEYPublicKey *pubKey = NULL; + PK11SlotInfo *keySlot = NULL; + + keySlot = PK11_GetInternalKeySlot(); + PK11_Authenticate(keySlot, PR_FALSE, &pwdata); + + if (!doingDSA) { + PK11RSAGenParams *rsaParams = GetRSAParams(); + if (rsaParams == NULL) { + PK11_FreeSlot(keySlot); + return NULL; + } + privKey = PK11_GenerateKeyPair(keySlot, CKM_RSA_PKCS_KEY_PAIR_GEN, + (void *)rsaParams, &pubKey, PR_FALSE, + PR_FALSE, &pwdata); + } else { + PQGParams *dsaParams = GetDSAParams(); + if (dsaParams == NULL) { + PK11_FreeSlot(keySlot); + return NULL; + } + privKey = PK11_GenerateKeyPair(keySlot, CKM_DSA_KEY_PAIR_GEN, + (void *)dsaParams, &pubKey, PR_FALSE, + PR_FALSE, &pwdata); + } + PK11_FreeSlot(keySlot); + if (privKey == NULL || pubKey == NULL) { + if (pubKey) { + SECKEY_DestroyPublicKey(pubKey); + } + if (privKey) { + SECKEY_DestroyPrivateKey(privKey); + } + return NULL; + } + + spki = SECKEY_CreateSubjectPublicKeyInfo(pubKey); + pair->privKey = privKey; + pair->pubKey = pubKey; + return spki; +} + +SECStatus +InitPKCS11(void) +{ + PK11SlotInfo *keySlot; + + PK11_SetPasswordFunc(SECU_GetModulePassword); + + keySlot = PK11_GetInternalKeySlot(); + + if (PK11_NeedUserInit(keySlot) && PK11_NeedLogin(keySlot)) { + if (SECU_ChangePW(keySlot, NULL, NULL) != SECSuccess) { + printf("Initializing the PINs failed.\n"); + return SECFailure; + } + } + + PK11_FreeSlot(keySlot); + return SECSuccess; +} + +void +WriteItOut(void *arg, const char *buf, unsigned long len) +{ + PRFileDesc *fileDesc = (PRFileDesc *)arg; + + PR_Write(fileDesc, (void *)buf, len); +} + +CRMFCertExtCreationInfo * +GetExtensions(void) +{ + unsigned char keyUsage[4] = { 0x03, 0x02, 0x07, KU_DIGITAL_SIGNATURE }; + /* What are these magic numbers? */ + SECItem data = { 0, NULL, 0 }; + CRMFCertExtension *extension; + CRMFCertExtCreationInfo *extInfo = + PORT_ZNew(CRMFCertExtCreationInfo); + + data.data = keyUsage; + data.len = sizeof keyUsage; + + extension = + CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, PR_FALSE, &data); + if (extension && extInfo) { + extInfo->numExtensions = 1; + extInfo->extensions = PORT_ZNewArray(CRMFCertExtension *, 1); + extInfo->extensions[0] = extension; + } + return extInfo; +} + +void +FreeExtInfo(CRMFCertExtCreationInfo *extInfo) +{ + int i; + + for (i = 0; i < extInfo->numExtensions; i++) { + CRMF_DestroyCertExtension(extInfo->extensions[i]); + } + PORT_Free(extInfo->extensions); + PORT_Free(extInfo); +} + +int +InjectCertName(CRMFCertRequest *certReq, + CRMFCertTemplateField inTemplateField, + const char *inNameString) +{ + char *nameStr; + CERTName *name; + int irv = 0; + + nameStr = PORT_Strdup(inNameString); + if (!nameStr) + return 5; + name = CERT_AsciiToName(nameStr); + if (name == NULL) { + printf("Could not create CERTName structure from %s.\n", nameStr); + irv = 5; + goto finish; + } + + irv = CRMF_CertRequestSetTemplateField(certReq, inTemplateField, (void *)name); + if (irv != SECSuccess) { + printf("Could not add name to cert template\n"); + irv = 6; + } + +finish: + PORT_Free(nameStr); + if (name) + CERT_DestroyName(name); + return irv; +} + +int +CreateCertRequest(TESTKeyPair *pair, long inRequestID) +{ + CERTCertificate *caCert; + CERTSubjectPublicKeyInfo *spki; + CRMFCertExtCreationInfo *extInfo; + CRMFCertRequest *certReq; + CRMFEncryptedKey *encKey; + CRMFPKIArchiveOptions *pkiArchOpt; + SECAlgorithmID *algID; + long serialNumber; + long version = 3; + SECStatus rv; + CRMFValidityCreationInfo validity; + unsigned char UIDbuf[UID_BITS / BPB]; + SECItem issuerUID = { siBuffer, NULL, 0 }; + SECItem subjectUID = { siBuffer, NULL, 0 }; + + /* len in bits */ + issuerUID.data = UIDbuf; + issuerUID.len = UID_BITS; + subjectUID.data = UIDbuf; + subjectUID.len = UID_BITS; + + pair->certReq = NULL; + certReq = CRMF_CreateCertRequest(inRequestID); + if (certReq == NULL) { + printf("Could not initialize a certificate request.\n"); + return 1; + } + + /* set to version 3 */ + rv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, + (void *)(&version)); + if (rv != SECSuccess) { + printf("Could not add the version number to the " + "Certificate Request.\n"); + CRMF_DestroyCertRequest(certReq); + return 2; + } + + /* set serial number */ + if (get_serial_number(&serialNumber) != SECSuccess) { + printf("Could not generate a serial number for cert request.\n"); + CRMF_DestroyCertRequest(certReq); + return 3; + } + rv = CRMF_CertRequestSetTemplateField(certReq, crmfSerialNumber, + (void *)(&serialNumber)); + if (rv != SECSuccess) { + printf("Could not add serial number to certificate template\n."); + CRMF_DestroyCertRequest(certReq); + return 4; + } + + /* Set issuer name */ + rv = InjectCertName(certReq, crmfIssuer, + "CN=mozilla CA Shack,O=Information Systems"); + if (rv) { + printf("Could not add issuer to cert template\n"); + CRMF_DestroyCertRequest(certReq); + return 5; + } + + /* Set Subject Name */ + rv = InjectCertName(certReq, crmfSubject, + "CN=mozilla CA Shack ID,O=Engineering,C=US"); + if (rv) { + printf("Could not add Subject to cert template\n"); + CRMF_DestroyCertRequest(certReq); + return 5; + } + + /* Set Algorithm ID */ + algID = PK11_CreatePBEAlgorithmID(SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC, + 1, NULL); + if (algID == NULL) { + printf("Couldn't create algorithm ID\n"); + CRMF_DestroyCertRequest(certReq); + return 9; + } + rv = CRMF_CertRequestSetTemplateField(certReq, crmfSigningAlg, (void *)algID); + SECOID_DestroyAlgorithmID(algID, PR_TRUE); + if (rv != SECSuccess) { + printf("Could not add the signing algorithm to the cert template.\n"); + CRMF_DestroyCertRequest(certReq); + return 10; + } + + /* Set Validity Dates */ + validity.notBefore = ¬Before; + validity.notAfter = NULL; + notBefore = PR_Now(); + rv = CRMF_CertRequestSetTemplateField(certReq, crmfValidity, (void *)(&validity)); + if (rv != SECSuccess) { + printf("Could not add validity to cert template\n"); + CRMF_DestroyCertRequest(certReq); + return 11; + } + + /* Generate a key pair and Add the spki to the request */ + spki = GetSubjectPubKeyInfo(pair); + if (spki == NULL) { + printf("Could not create a Subject Public Key Info to add\n"); + CRMF_DestroyCertRequest(certReq); + return 12; + } + rv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, (void *)spki); + SECKEY_DestroySubjectPublicKeyInfo(spki); + if (rv != SECSuccess) { + printf("Could not add the public key to the template\n"); + CRMF_DestroyCertRequest(certReq); + return 13; + } + + /* Set the requested isser Unique ID */ + PK11_GenerateRandom(UIDbuf, sizeof UIDbuf); + CRMF_CertRequestSetTemplateField(certReq, crmfIssuerUID, (void *)&issuerUID); + + /* Set the requested Subject Unique ID */ + PK11_GenerateRandom(UIDbuf, sizeof UIDbuf); + CRMF_CertRequestSetTemplateField(certReq, crmfSubjectUID, (void *)&subjectUID); + + /* Add extensions - XXX need to understand these magic numbers */ + extInfo = GetExtensions(); + CRMF_CertRequestSetTemplateField(certReq, crmfExtension, (void *)extInfo); + FreeExtInfo(extInfo); + + /* get the recipient CA's cert */ + caCert = CERT_FindCertByNickname(db, caCertName); + if (caCert == NULL) { + printf("Could not find the certificate for %s\n", caCertName); + CRMF_DestroyCertRequest(certReq); + return 50; + } + encKey = CRMF_CreateEncryptedKeyWithEncryptedValue(pair->privKey, caCert); + CERT_DestroyCertificate(caCert); + if (encKey == NULL) { + printf("Could not create Encrypted Key with Encrypted Value.\n"); + return 14; + } + pkiArchOpt = CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encKey); + CRMF_DestroyEncryptedKey(encKey); + if (pkiArchOpt == NULL) { + printf("Could not create PKIArchiveOptions.\n"); + return 15; + } + rv = CRMF_CertRequestSetPKIArchiveOptions(certReq, pkiArchOpt); + CRMF_DestroyPKIArchiveOptions(pkiArchOpt); + if (rv != SECSuccess) { + printf("Could not add the PKIArchiveControl to Cert Request.\n"); + return 16; + } + pair->certReq = certReq; + return 0; +} + +int +Encode(CRMFCertReqMsg *inCertReq1, CRMFCertReqMsg *inCertReq2) +{ + PRFileDesc *fileDesc; + SECStatus rv; + int irv = 0; + CRMFCertReqMsg *msgArr[3]; + char filePath[PATH_LEN]; + + PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, CRMF_FILE); + fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf("Could not open file %s\n", filePath); + irv = 14; + goto finish; + } + msgArr[0] = inCertReq1; + msgArr[1] = inCertReq2; + msgArr[2] = NULL; + rv = CRMF_EncodeCertReqMessages(msgArr, WriteItOut, (void *)fileDesc); + if (rv != SECSuccess) { + printf("An error occurred while encoding.\n"); + irv = 15; + } +finish: + PR_Close(fileDesc); + return irv; +} + +int +AddProofOfPossession(TESTKeyPair *pair, + CRMFPOPChoice inPOPChoice) +{ + + switch (inPOPChoice) { + case crmfSignature: + CRMF_CertReqMsgSetSignaturePOP(pair->certReqMsg, pair->privKey, + pair->pubKey, NULL, NULL, &pwdata); + break; + case crmfRAVerified: + CRMF_CertReqMsgSetRAVerifiedPOP(pair->certReqMsg); + break; + case crmfKeyEncipherment: + CRMF_CertReqMsgSetKeyEnciphermentPOP(pair->certReqMsg, + crmfSubsequentMessage, + crmfChallengeResp, NULL); + break; + case crmfKeyAgreement: { + SECItem pendejo; + unsigned char lame[] = { 0xf0, 0x0f, 0xf0, 0x0f, 0xf0 }; + + pendejo.data = lame; + pendejo.len = 5; + + CRMF_CertReqMsgSetKeyAgreementPOP(pair->certReqMsg, crmfThisMessage, + crmfNoSubseqMess, &pendejo); + } break; + default: + return 1; + } + return 0; +} + +int +Decode(void) +{ + PRFileDesc *fileDesc; + CRMFCertReqMsg *certReqMsg; + CRMFCertRequest *certReq; + CRMFCertReqMessages *certReqMsgs; + SECStatus rv; + int numMsgs, i; + long lame; + CRMFGetValidity validity = { NULL, NULL }; + SECItem item = { siBuffer, NULL, 0 }; + char filePath[PATH_LEN]; + + PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, CRMF_FILE); + fileDesc = PR_Open(filePath, PR_RDONLY, 0644); + if (fileDesc == NULL) { + printf("Could not open file %s\n", filePath); + return 214; + } + rv = SECU_FileToItem(&item, fileDesc); + PR_Close(fileDesc); + if (rv != SECSuccess) { + return 215; + } + + certReqMsgs = CRMF_CreateCertReqMessagesFromDER((char *)item.data, item.len); + if (certReqMsgs == NULL) { + printf("Error decoding CertReqMessages.\n"); + return 202; + } + numMsgs = CRMF_CertReqMessagesGetNumMessages(certReqMsgs); + if (numMsgs <= 0) { + printf("WARNING: The DER contained %d messages.\n", numMsgs); + } + for (i = 0; i < numMsgs; i++) { + printf("crmftest: Processing cert request %d\n", i); + certReqMsg = CRMF_CertReqMessagesGetCertReqMsgAtIndex(certReqMsgs, i); + if (certReqMsg == NULL) { + printf("ERROR: Could not access the message at index %d of %s\n", + i, filePath); + } + rv = CRMF_CertReqMsgGetID(certReqMsg, &lame); + if (rv) { + SECU_PrintError("crmftest", "CRMF_CertReqMsgGetID"); + } + certReq = CRMF_CertReqMsgGetCertRequest(certReqMsg); + if (!certReq) { + SECU_PrintError("crmftest", "CRMF_CertReqMsgGetCertRequest"); + } + rv = CRMF_CertRequestGetCertTemplateValidity(certReq, &validity); + if (rv) { + SECU_PrintError("crmftest", "CRMF_CertRequestGetCertTemplateValidity"); + } + if (!validity.notBefore) { + /* We encoded a notBefore, so somthing's wrong if it's not here. */ + printf("ERROR: Validity period notBefore date missing.\n"); + } + /* XXX It's all parsed now. We probably should DO SOMETHING with it. + ** But nope. We just throw it all away. + ** Maybe this was intended to be no more than a decoder test. + */ + CRMF_DestroyGetValidity(&validity); + CRMF_DestroyCertRequest(certReq); + CRMF_DestroyCertReqMsg(certReqMsg); + } + CRMF_DestroyCertReqMessages(certReqMsgs); + SECITEM_FreeItem(&item, PR_FALSE); + return 0; +} + +int +GetBitsFromFile(const char *filePath, SECItem *item) +{ + PRFileDesc *fileDesc; + SECStatus rv; + + fileDesc = PR_Open(filePath, PR_RDONLY, 0644); + if (fileDesc == NULL) { + printf("Could not open file %s\n", filePath); + return 14; + } + + rv = SECU_FileToItem(item, fileDesc); + PR_Close(fileDesc); + + if (rv != SECSuccess) { + item->data = NULL; + item->len = 0; + return 15; + } + return 0; +} + +int +DecodeCMMFCertRepContent(char *derFile) +{ + CMMFCertRepContent *certRepContent; + int irv = 0; + SECItem fileBits = { siBuffer, NULL, 0 }; + + GetBitsFromFile(derFile, &fileBits); + if (fileBits.data == NULL) { + printf("Could not get bits from file %s\n", derFile); + return 304; + } + certRepContent = CMMF_CreateCertRepContentFromDER(db, + (char *)fileBits.data, fileBits.len); + if (certRepContent == NULL) { + printf("Error while decoding %s\n", derFile); + irv = 303; + } else { + /* That was fun. Now, let's throw it away! */ + CMMF_DestroyCertRepContent(certRepContent); + } + SECITEM_FreeItem(&fileBits, PR_FALSE); + return irv; +} + +int +EncodeCMMFCertReply(const char *filePath, + CERTCertificate *cert, + CERTCertList *list) +{ + int rv = 0; + SECStatus srv; + PRFileDesc *fileDesc = NULL; + CMMFCertRepContent *certRepContent = NULL; + CMMFCertResponse *certResp = NULL; + CMMFCertResponse *certResponses[3]; + + certResp = CMMF_CreateCertResponse(0xff123); + CMMF_CertResponseSetPKIStatusInfoStatus(certResp, cmmfGranted); + + CMMF_CertResponseSetCertificate(certResp, cert); + + certResponses[0] = certResp; + certResponses[1] = NULL; + certResponses[2] = NULL; + + certRepContent = CMMF_CreateCertRepContent(); + CMMF_CertRepContentSetCertResponses(certRepContent, certResponses, 1); + + CMMF_CertRepContentSetCAPubs(certRepContent, list); + + fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf("Could not open file %s\n", filePath); + rv = 400; + goto finish; + } + + srv = CMMF_EncodeCertRepContent(certRepContent, WriteItOut, + (void *)fileDesc); + PR_Close(fileDesc); + if (srv != SECSuccess) { + printf("CMMF_EncodeCertRepContent failed,\n"); + rv = 401; + } +finish: + if (certRepContent) { + CMMF_DestroyCertRepContent(certRepContent); + } + if (certResp) { + CMMF_DestroyCertResponse(certResp); + } + return rv; +} + +/* Extract the public key from the cert whose nickname is given. */ +int +extractPubKeyFromNamedCert(const char *nickname, SECKEYPublicKey **pPubKey) +{ + CERTCertificate *caCert = NULL; + SECKEYPublicKey *caPubKey = NULL; + int rv = 0; + + caCert = CERT_FindCertByNickname(db, (char *)nickname); + if (caCert == NULL) { + printf("Could not get the certifcate for %s\n", caCertName); + rv = 411; + goto finish; + } + caPubKey = CERT_ExtractPublicKey(caCert); + if (caPubKey == NULL) { + printf("Could not extract the public from the " + "certificate for \n%s\n", + caCertName); + rv = 412; + } +finish: + *pPubKey = caPubKey; + CERT_DestroyCertificate(caCert); + caCert = NULL; + return rv; +} + +int +EncodeCMMFRecoveryMessage(const char *filePath, + CERTCertificate *cert, + CERTCertList *list) +{ + SECKEYPublicKey *caPubKey = NULL; + SECKEYPrivateKey *privKey = NULL; + CMMFKeyRecRepContent *repContent = NULL; + PRFileDesc *fileDesc; + int rv = 0; + SECStatus srv; + + /* Extract the public key from the cert whose nickname is given in + ** the -s option. + */ + rv = extractPubKeyFromNamedCert(caCertName, &caPubKey); + if (rv) + goto finish; + + repContent = CMMF_CreateKeyRecRepContent(); + if (repContent == NULL) { + printf("Could not allocate a CMMFKeyRecRepContent structure\n"); + rv = 407; + goto finish; + } + srv = CMMF_KeyRecRepContentSetPKIStatusInfoStatus(repContent, + cmmfGrantedWithMods); + if (srv != SECSuccess) { + printf("Error trying to set PKIStatusInfo for " + "CMMFKeyRecRepContent.\n"); + rv = 406; + goto finish; + } + srv = CMMF_KeyRecRepContentSetNewSignCert(repContent, cert); + if (srv != SECSuccess) { + printf("Error trying to set the new signing certificate for " + "key recovery\n"); + rv = 408; + goto finish; + } + srv = CMMF_KeyRecRepContentSetCACerts(repContent, list); + if (srv != SECSuccess) { + printf("Errory trying to add the list of CA certs to the " + "CMMFKeyRecRepContent structure.\n"); + rv = 409; + goto finish; + } + privKey = PK11_FindKeyByAnyCert(cert, &pwdata); + if (privKey == NULL) { + printf("Could not get the private key associated with the\n" + "certificate %s\n", + personalCert); + rv = 410; + goto finish; + } + + srv = CMMF_KeyRecRepContentSetCertifiedKeyPair(repContent, cert, privKey, + caPubKey); + if (srv != SECSuccess) { + printf("Could not set the Certified Key Pair\n"); + rv = 413; + goto finish; + } + fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf("Could not open file %s\n", filePath); + rv = 414; + goto finish; + } + + srv = CMMF_EncodeKeyRecRepContent(repContent, WriteItOut, + (void *)fileDesc); + PR_Close(fileDesc); + if (srv != SECSuccess) { + printf("CMMF_EncodeKeyRecRepContent failed\n"); + rv = 415; + } +finish: + if (privKey) + SECKEY_DestroyPrivateKey(privKey); + if (caPubKey) + SECKEY_DestroyPublicKey(caPubKey); + if (repContent) + CMMF_DestroyKeyRecRepContent(repContent); + return rv; +} + +int +decodeCMMFRecoveryMessage(const char *filePath) +{ + CMMFKeyRecRepContent *repContent = NULL; + int rv = 0; + SECItem fileBits = { siBuffer, NULL, 0 }; + + GetBitsFromFile(filePath, &fileBits); + if (!fileBits.len) { + rv = 451; + goto finish; + } + repContent = + CMMF_CreateKeyRecRepContentFromDER(db, (const char *)fileBits.data, + fileBits.len); + if (repContent == NULL) { + printf("ERROR: CMMF_CreateKeyRecRepContentFromDER failed on file:\n" + "\t%s\n", + filePath); + rv = 452; + } +finish: + if (repContent) { + CMMF_DestroyKeyRecRepContent(repContent); + } + SECITEM_FreeItem(&fileBits, PR_FALSE); + return rv; +} + +int +DoCMMFStuff(void) +{ + CERTCertificate *cert = NULL; + CERTCertList *list = NULL; + int rv = 0; + char filePath[PATH_LEN]; + + /* Do common setup for the following steps. + */ + PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, "CertRepContent.der"); + + cert = CERT_FindCertByNickname(db, personalCert); + if (cert == NULL) { + printf("Could not find the certificate for %s\n", personalCert); + rv = 416; + goto finish; + } + list = CERT_GetCertChainFromCert(cert, PR_Now(), certUsageEmailSigner); + if (list == NULL) { + printf("Could not find the certificate chain for %s\n", personalCert); + rv = 418; + goto finish; + } + + /* a) Generate the CMMF response message, using a user cert named + ** by -p option, rather than a cert generated from the CRMF + ** request itself. The CMMF message is placed in + ** configdir/CertRepContent.der. + */ + rv = EncodeCMMFCertReply(filePath, cert, list); + if (rv != 0) { + goto finish; + } + + /* b) Decode the CMMF Cert granting message encoded just above, + ** found in configdir/CertRepContent.der. + ** This only tests the decoding. The decoded content is discarded. + */ + rv = DecodeCMMFCertRepContent(filePath); + if (rv != 0) { + goto finish; + } + + /* c) Generate a CMMF Key Excrow message + ** It takes the public and private keys for the cert identified + ** by -p nickname, and wraps them with a sym key that is in turn + ** wrapped with the pubkey in the CA cert, whose nickname is + ** given by the -s option. + ** Store the message in configdir/KeyRecRepContent.der + */ + PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, + "KeyRecRepContent.der"); + + rv = EncodeCMMFRecoveryMessage(filePath, cert, list); + if (rv) + goto finish; + + /* d) Decode the CMMF Key Excrow message generated just above. + ** Get it from file configdir/KeyRecRepContent.der + ** This is just a decoder test. Results are discarded. + */ + + rv = decodeCMMFRecoveryMessage(filePath); + +finish: + if (cert) { + CERT_DestroyCertificate(cert); + } + if (list) { + CERT_DestroyCertList(list); + } + return rv; +} + +#define KNOWN_MESSAGE_LENGTH 20 /*160 bits*/ + +int +DoKeyRecovery(SECKEYPrivateKey *privKey) +{ +#ifdef DOING_KEY_RECOVERY /* Doesn't compile yet. */ + SECKEYPublicKey *pubKey; + PK11SlotInfo *slot; + unsigned char *ciphertext; + unsigned char *text_compared; + SECKEYPrivateKey *unwrappedPrivKey; + SECKEYPrivateKey *caPrivKey; + CMMFKeyRecRepContent *keyRecRep; + CMMFCertifiedKeyPair *certKeyPair; + CERTCertificate *caCert; + CERTCertificate *myCert; + SECKEYPublicKey *caPubKey; + PRFileDesc *fileDesc; + CK_ULONG max_bytes_encrypted; + CK_ULONG bytes_encrypted; + CK_ULONG bytes_compared; + CK_ULONG bytes_decrypted; + CK_RV crv; + CK_OBJECT_HANDLE id; + CK_MECHANISM mech = { CKM_INVALID_MECHANISM, NULL, 0 }; + SECStatus rv; + SECItem fileBits; + SECItem nickname; + unsigned char plaintext[KNOWN_MESSAGE_LENGTH]; + char filePath[PATH_LEN]; + static const unsigned char known_message[] = { "Known Crypto Message" }; + + /*caCert = CERT_FindCertByNickname(db, caCertName);*/ + myCert = CERT_FindCertByNickname(db, personalCert); + if (myCert == NULL) { + printf("Could not find the certificate for %s\n", personalCert); + return 700; + } + caCert = CERT_FindCertByNickname(db, recoveryEncrypter); + if (caCert == NULL) { + printf("Could not find the certificate for %s\n", recoveryEncrypter); + return 701; + } + caPubKey = CERT_ExtractPublicKey(caCert); + pubKey = SECKEY_ConvertToPublicKey(privKey); + max_bytes_encrypted = PK11_GetPrivateModulusLen(privKey); + slot = PK11_GetBestSlotWithAttributes(mapWrapKeyType(privKey->keyType), + CKF_ENCRYPT, 0, NULL); + id = PK11_ImportPublicKey(slot, pubKey, PR_FALSE); + + switch (privKey->keyType) { + case rsaKey: + mech.mechanism = CKM_RSA_PKCS; + break; + case dsaKey: + mech.mechanism = CKM_DSA; + break; + case dhKey: + mech.mechanism = CKM_DH_PKCS_DERIVE; + break; + default: + printf("Bad Key type in key recovery.\n"); + return 512; + } + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_EncryptInit(slot->session, &mech, id); + if (crv != CKR_OK) { + PK11_ExitSlotMonitor(slot); + PK11_FreeSlot(slot); + printf("C_EncryptInit failed in KeyRecovery\n"); + return 500; + } + ciphertext = PORT_NewArray(unsigned char, max_bytes_encrypted); + if (ciphertext == NULL) { + PK11_ExitSlotMonitor(slot); + PK11_FreeSlot(slot); + printf("Could not allocate memory for ciphertext.\n"); + return 501; + } + bytes_encrypted = max_bytes_encrypted; + crv = PK11_GETTAB(slot)->C_Encrypt(slot->session, + known_message, + KNOWN_MESSAGE_LENGTH, + ciphertext, + &bytes_encrypted); + PK11_ExitSlotMonitor(slot); + PK11_FreeSlot(slot); + if (crv != CKR_OK) { + PORT_Free(ciphertext); + return 502; + } + /* Always use the smaller of these two values . . . */ + bytes_compared = (bytes_encrypted > KNOWN_MESSAGE_LENGTH) + ? KNOWN_MESSAGE_LENGTH + : bytes_encrypted; + + /* If there was a failure, the plaintext */ + /* goes at the end, therefore . . . */ + text_compared = (bytes_encrypted > KNOWN_MESSAGE_LENGTH) + ? (ciphertext + bytes_encrypted - + KNOWN_MESSAGE_LENGTH) + : ciphertext; + + keyRecRep = CMMF_CreateKeyRecRepContent(); + if (keyRecRep == NULL) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + CMMF_DestroyKeyRecRepContent(keyRecRep); + printf("Could not allocate a CMMFKeyRecRepContent structre.\n"); + return 503; + } + rv = CMMF_KeyRecRepContentSetPKIStatusInfoStatus(keyRecRep, + cmmfGranted); + if (rv != SECSuccess) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + CMMF_DestroyKeyRecRepContent(keyRecRep); + printf("Could not set the status for the KeyRecRepContent\n"); + return 504; + } + /* The myCert here should correspond to the certificate corresponding + * to the private key, but for this test any certificate will do. + */ + rv = CMMF_KeyRecRepContentSetCertifiedKeyPair(keyRecRep, myCert, + privKey, caPubKey); + if (rv != SECSuccess) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + CMMF_DestroyKeyRecRepContent(keyRecRep); + printf("Could not set the Certified Key Pair\n"); + return 505; + } + PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, + "KeyRecRepContent.der"); + fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + CMMF_DestroyKeyRecRepContent(keyRecRep); + printf("Could not open file %s\n", filePath); + return 506; + } + rv = CMMF_EncodeKeyRecRepContent(keyRecRep, WriteItOut, fileDesc); + CMMF_DestroyKeyRecRepContent(keyRecRep); + PR_Close(fileDesc); + + if (rv != SECSuccess) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + printf("Error while encoding CMMFKeyRecRepContent\n"); + return 507; + } + GetBitsFromFile(filePath, &fileBits); + if (fileBits.data == NULL) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + printf("Could not get the bits from file %s\n", filePath); + return 508; + } + keyRecRep = + CMMF_CreateKeyRecRepContentFromDER(db, (const char *)fileBits.data, + fileBits.len); + if (keyRecRep == NULL) { + printf("Could not decode the KeyRecRepContent in file %s\n", + filePath); + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + return 509; + } + caPrivKey = PK11_FindKeyByAnyCert(caCert, &pwdata); + if (CMMF_KeyRecRepContentGetPKIStatusInfoStatus(keyRecRep) != + cmmfGranted) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + CMMF_DestroyKeyRecRepContent(keyRecRep); + printf("A bad status came back with the " + "KeyRecRepContent structure\n"); + return 510; + } + +#define NICKNAME "Key Recovery Test Key" + nickname.data = (unsigned char *)NICKNAME; + nickname.len = PORT_Strlen(NICKNAME); + + certKeyPair = CMMF_KeyRecRepContentGetCertKeyAtIndex(keyRecRep, 0); + CMMF_DestroyKeyRecRepContent(keyRecRep); + rv = CMMF_CertifiedKeyPairUnwrapPrivKey(certKeyPair, + caPrivKey, + &nickname, + PK11_GetInternalKeySlot(), + db, + &unwrappedPrivKey, &pwdata); + CMMF_DestroyCertifiedKeyPair(certKeyPair); + if (rv != SECSuccess) { + printf("Unwrapping the private key failed.\n"); + return 511; + } + /*Now let's try to decrypt the ciphertext with the "recovered" key*/ + PK11_EnterSlotMonitor(slot); + crv = + PK11_GETTAB(slot)->C_DecryptInit(unwrappedPrivKey->pkcs11Slot->session, + &mech, + unwrappedPrivKey->pkcs11ID); + if (crv != CKR_OK) { + PK11_ExitSlotMonitor(slot); + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + printf("Decrypting with the recovered key failed.\n"); + return 513; + } + bytes_decrypted = KNOWN_MESSAGE_LENGTH; + crv = PK11_GETTAB(slot)->C_Decrypt(unwrappedPrivKey->pkcs11Slot->session, + ciphertext, + bytes_encrypted, plaintext, + &bytes_decrypted); + SECKEY_DestroyPrivateKey(unwrappedPrivKey); + PK11_ExitSlotMonitor(slot); + PORT_Free(ciphertext); + if (crv != CKR_OK) { + PK11_FreeSlot(slot); + printf("Decrypting the ciphertext with recovered key failed.\n"); + return 514; + } + if ((bytes_decrypted != KNOWN_MESSAGE_LENGTH) || + (PORT_Memcmp(plaintext, known_message, KNOWN_MESSAGE_LENGTH) != 0)) { + PK11_FreeSlot(slot); + printf("The recovered plaintext does not equal the known message:\n" + "\tKnown message: %s\n" + "\tRecovered plaintext: %s\n", + known_message, plaintext); + return 515; + } +#endif + return 0; +} + +int +DoChallengeResponse(SECKEYPrivateKey *privKey, + SECKEYPublicKey *pubKey) +{ + CMMFPOPODecKeyChallContent *chalContent = NULL; + CMMFPOPODecKeyRespContent *respContent = NULL; + CERTCertificate *myCert = NULL; + CERTGeneralName *myGenName = NULL; + PLArenaPool *poolp = NULL; + PRFileDesc *fileDesc; + SECItem *publicValue; + SECItem *keyID; + SECKEYPrivateKey *foundPrivKey; + long *randomNums; + int numChallengesFound = 0; + int numChallengesSet = 1; + int i; + long retrieved; + SECStatus rv; + SECItem DecKeyChallBits; + char filePath[PATH_LEN]; + + chalContent = CMMF_CreatePOPODecKeyChallContent(); + myCert = CERT_FindCertByNickname(db, personalCert); + if (myCert == NULL) { + printf("Could not find the certificate for %s\n", personalCert); + return 900; + } + poolp = PORT_NewArena(1024); + if (poolp == NULL) { + printf("Could no allocate a new arena in DoChallengeResponse\n"); + return 901; + } + myGenName = CERT_GetCertificateNames(myCert, poolp); + if (myGenName == NULL) { + printf("Could not get the general names for %s certificate\n", + personalCert); + return 902; + } + randomNums = PORT_ArenaNewArray(poolp, long, numChallengesSet); + PK11_GenerateRandom((unsigned char *)randomNums, + numChallengesSet * sizeof(long)); + for (i = 0; i < numChallengesSet; i++) { + rv = CMMF_POPODecKeyChallContentSetNextChallenge(chalContent, + randomNums[i], + myGenName, + pubKey, + &pwdata); + if (rv != SECSuccess) { + printf("Could not set the challenge in DoChallengeResponse\n"); + return 903; + } + } + PR_snprintf(filePath, PATH_LEN, "%s/POPODecKeyChallContent.der", + configdir); + fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf("Could not open file %s\n", filePath); + return 904; + } + rv = CMMF_EncodePOPODecKeyChallContent(chalContent, WriteItOut, + (void *)fileDesc); + PR_Close(fileDesc); + CMMF_DestroyPOPODecKeyChallContent(chalContent); + if (rv != SECSuccess) { + printf("Could not encode the POPODecKeyChallContent.\n"); + return 905; + } + GetBitsFromFile(filePath, &DecKeyChallBits); + chalContent = CMMF_CreatePOPODecKeyChallContentFromDER((const char *)DecKeyChallBits.data, DecKeyChallBits.len); + SECITEM_FreeItem(&DecKeyChallBits, PR_FALSE); + if (chalContent == NULL) { + printf("Could not create the POPODecKeyChallContent from DER\n"); + return 906; + } + numChallengesFound = + CMMF_POPODecKeyChallContentGetNumChallenges(chalContent); + if (numChallengesFound != numChallengesSet) { + printf("Number of Challenges Found (%d) does not equal the number " + "set (%d)\n", + numChallengesFound, numChallengesSet); + return 907; + } + for (i = 0; i < numChallengesSet; i++) { + publicValue = CMMF_POPODecKeyChallContentGetPublicValue(chalContent, i); + if (publicValue == NULL) { + printf("Could not get the public value for challenge at index %d\n", + i); + return 908; + } + keyID = PK11_MakeIDFromPubKey(publicValue); + SECITEM_FreeItem(publicValue, PR_TRUE); + if (keyID == NULL) { + printf("Could not make the keyID from the public value\n"); + return 909; + } + foundPrivKey = PK11_FindKeyByKeyID(privKey->pkcs11Slot, keyID, &pwdata); + SECITEM_FreeItem(keyID, PR_TRUE); + if (foundPrivKey == NULL) { + printf("Could not find the private key corresponding to the public" + " value.\n"); + return 910; + } + rv = CMMF_POPODecKeyChallContDecryptChallenge(chalContent, i, + foundPrivKey); + if (rv != SECSuccess) { + printf("Could not decrypt the challenge at index %d\n", i); + return 911; + } + rv = CMMF_POPODecKeyChallContentGetRandomNumber(chalContent, i, + &retrieved); + if (rv != SECSuccess) { + printf("Could not get the random number from the challenge at " + "index %d\n", + i); + return 912; + } + if (retrieved != randomNums[i]) { + printf("Retrieved the number (%ld), expected (%ld)\n", retrieved, + randomNums[i]); + return 913; + } + } + CMMF_DestroyPOPODecKeyChallContent(chalContent); + PR_snprintf(filePath, PATH_LEN, "%s/POPODecKeyRespContent.der", + configdir); + fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf("Could not open file %s\n", filePath); + return 914; + } + rv = CMMF_EncodePOPODecKeyRespContent(randomNums, numChallengesSet, + WriteItOut, fileDesc); + PR_Close(fileDesc); + if (rv != 0) { + printf("Could not encode the POPODecKeyRespContent\n"); + return 915; + } + GetBitsFromFile(filePath, &DecKeyChallBits); + respContent = + CMMF_CreatePOPODecKeyRespContentFromDER((const char *)DecKeyChallBits.data, + DecKeyChallBits.len); + if (respContent == NULL) { + printf("Could not decode the contents of the file %s\n", filePath); + return 916; + } + numChallengesFound = + CMMF_POPODecKeyRespContentGetNumResponses(respContent); + if (numChallengesFound != numChallengesSet) { + printf("Number of responses found (%d) does not match the number " + "of challenges set (%d)\n", + numChallengesFound, numChallengesSet); + return 917; + } + for (i = 0; i < numChallengesSet; i++) { + rv = CMMF_POPODecKeyRespContentGetResponse(respContent, i, &retrieved); + if (rv != SECSuccess) { + printf("Could not retrieve the response at index %d\n", i); + return 918; + } + if (retrieved != randomNums[i]) { + printf("Retrieved the number (%ld), expected (%ld)\n", retrieved, + randomNums[i]); + return 919; + } + } + CMMF_DestroyPOPODecKeyRespContent(respContent); + return 0; +} + +int +MakeCertRequest(TESTKeyPair *pair, CRMFPOPChoice inPOPChoice, long inRequestID) +{ + int irv; + + /* Generate a key pair and a cert request for it. */ + irv = CreateCertRequest(pair, inRequestID); + if (irv != 0 || pair->certReq == NULL) { + goto loser; + } + + pair->certReqMsg = CRMF_CreateCertReqMsg(); + if (!pair->certReqMsg) { + irv = 999; + goto loser; + } + /* copy certReq into certReqMsg */ + CRMF_CertReqMsgSetCertRequest(pair->certReqMsg, pair->certReq); + irv = AddProofOfPossession(pair, inPOPChoice); +loser: + return irv; +} + +int +DestroyPairReqAndMsg(TESTKeyPair *pair) +{ + SECStatus rv = SECSuccess; + int irv = 0; + + if (pair->certReq) { + rv = CRMF_DestroyCertRequest(pair->certReq); + pair->certReq = NULL; + if (rv != SECSuccess) { + printf("Error when destroying cert request.\n"); + irv = 100; + } + } + if (pair->certReqMsg) { + rv = CRMF_DestroyCertReqMsg(pair->certReqMsg); + pair->certReqMsg = NULL; + if (rv != SECSuccess) { + printf("Error when destroying cert request msg.\n"); + if (!irv) + irv = 101; + } + } + return irv; +} + +int +DestroyPair(TESTKeyPair *pair) +{ + int irv = 0; + + if (pair->pubKey) { + SECKEY_DestroyPublicKey(pair->pubKey); + pair->pubKey = NULL; + } + if (pair->privKey) { + SECKEY_DestroyPrivateKey(pair->privKey); + pair->privKey = NULL; + } + DestroyPairReqAndMsg(pair); + return irv; +} + +int +DoCRMFRequest(TESTKeyPair *signPair, TESTKeyPair *cryptPair) +{ + int irv, tirv = 0; + + /* Generate a key pair and a cert request for it. */ + irv = MakeCertRequest(signPair, crmfSignature, 0x0f020304); + if (irv != 0 || signPair->certReq == NULL) { + goto loser; + } + + if (!doingDSA) { + irv = MakeCertRequest(cryptPair, crmfKeyAgreement, 0x0f050607); + if (irv != 0 || cryptPair->certReq == NULL) { + goto loser; + } + } + + /* encode the cert request messages into a unified request message. + ** leave it in a file with a fixed name. :( + */ + irv = Encode(signPair->certReqMsg, cryptPair->certReqMsg); + +loser: + if (signPair->certReq) { + tirv = DestroyPairReqAndMsg(signPair); + if (tirv && !irv) + irv = tirv; + } + if (cryptPair->certReq) { + tirv = DestroyPairReqAndMsg(cryptPair); + if (tirv && !irv) + irv = tirv; + } + return irv; +} + +void +Usage(void) +{ + printf("Usage:\n" + "\tcrmftest -d [Database Directory] -p [Personal Cert]\n" + "\t -e [Encrypter] -s [CA Certificate] [-P password]\n\n" + "\t [crmf] [dsa] [decode] [cmmf] [recover] [challenge]\n" + "\t [-f password_file]\n" + "Database Directory\n" + "\tThis is the directory where the key3.db, cert7.db, and\n" + "\tsecmod.db files are located. This is also the directory\n" + "\twhere the program will place CRMF/CMMF der files\n" + "Personal Cert\n" + "\tThis is the certificate that already exists in the cert\n" + "\tdatabase to use while encoding the response. The private\n" + "\tkey associated with the certificate must also exist in the\n" + "\tkey database.\n" + "Encrypter\n" + "\tThis is the certificate to use when encrypting the the \n" + "\tkey recovery response. The private key for this cert\n" + "\tmust also be present in the key database.\n" + "CA Certificate\n" + "\tThis is the nickname of the certificate to use as the\n" + "\tCA when doing all of the encoding.\n"); +} + +#define TEST_MAKE_CRMF_REQ 0x0001 +#define TEST_USE_DSA 0x0002 +#define TEST_DECODE_CRMF_REQ 0x0004 +#define TEST_DO_CMMF_STUFF 0x0008 +#define TEST_KEY_RECOVERY 0x0010 +#define TEST_CHALLENGE_RESPONSE 0x0020 + +SECStatus +parsePositionalParam(const char *arg, PRUint32 *flags) +{ + if (!strcmp(arg, "crmf")) { + *flags |= TEST_MAKE_CRMF_REQ; + } else if (!strcmp(arg, "dsa")) { + *flags |= TEST_MAKE_CRMF_REQ | TEST_USE_DSA; + doingDSA = PR_TRUE; + } else if (!strcmp(arg, "decode")) { + *flags |= TEST_DECODE_CRMF_REQ; + } else if (!strcmp(arg, "cmmf")) { + *flags |= TEST_DO_CMMF_STUFF; + } else if (!strcmp(arg, "recover")) { + *flags |= TEST_KEY_RECOVERY; + } else if (!strcmp(arg, "challenge")) { + *flags |= TEST_CHALLENGE_RESPONSE; + } else { + printf("unknown positional paremeter: %s\n", arg); + return SECFailure; + } + return SECSuccess; +} + +/* it's not clear, in some cases, whether the desired key is from +** the sign pair or the crypt pair, so we're guessing in some places. +** This define serves to remind us of the places where we're guessing. +*/ +#define WHICH_KEY cryptPair + +int +main(int argc, char **argv) +{ + TESTKeyPair signPair, cryptPair; + PLOptState *optstate; + PLOptStatus status; + char *password = NULL; + char *pwfile = NULL; + int irv = 0; + PRUint32 flags = 0; + SECStatus rv; + PRBool nssInit = PR_FALSE; + + memset(&signPair, 0, sizeof signPair); + memset(&cryptPair, 0, sizeof cryptPair); + printf("\ncrmftest v1.0\n"); + optstate = PL_CreateOptState(argc, argv, "d:p:e:s:P:f:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case 'd': + configdir = PORT_Strdup(optstate->value); + rv = NSS_Init(configdir); + if (rv != SECSuccess) { + printf("NSS_Init (-d) failed\n"); + return 101; + } + nssInit = PR_TRUE; + break; + case 'p': + personalCert = PORT_Strdup(optstate->value); + if (personalCert == NULL) { + printf("-p failed\n"); + return 603; + } + break; + case 'e': + recoveryEncrypter = PORT_Strdup(optstate->value); + if (recoveryEncrypter == NULL) { + printf("-e failed\n"); + return 602; + } + break; + case 's': + caCertName = PORT_Strdup(optstate->value); + if (caCertName == NULL) { + printf("-s failed\n"); + return 604; + } + break; + case 'P': + password = PORT_Strdup(optstate->value); + if (password == NULL) { + printf("-P failed\n"); + return 606; + } + pwdata.source = PW_PLAINTEXT; + pwdata.data = password; + break; + case 'f': + pwfile = PORT_Strdup(optstate->value); + if (pwfile == NULL) { + printf("-f failed\n"); + return 607; + } + pwdata.source = PW_FROMFILE; + pwdata.data = pwfile; + break; + case 0: /* positional parameter */ + rv = parsePositionalParam(optstate->value, &flags); + if (rv) { + printf("bad positional parameter.\n"); + return 605; + } + break; + default: + Usage(); + return 601; + } + } + PL_DestroyOptState(optstate); + if (status == PL_OPT_BAD || !nssInit) { + Usage(); + return 600; + } + if (!flags) + flags = ~TEST_USE_DSA; + db = CERT_GetDefaultCertDB(); + InitPKCS11(); + + if (flags & TEST_MAKE_CRMF_REQ) { + printf("Generating CRMF request\n"); + irv = DoCRMFRequest(&signPair, &cryptPair); + if (irv) + goto loser; + } + + if (flags & TEST_DECODE_CRMF_REQ) { + printf("Decoding CRMF request\n"); + irv = Decode(); + if (irv != 0) { + printf("Error while decoding\n"); + goto loser; + } + } + + if (flags & TEST_DO_CMMF_STUFF) { + printf("Doing CMMF Stuff\n"); + if ((irv = DoCMMFStuff()) != 0) { + printf("CMMF tests failed.\n"); + goto loser; + } + } + + if (flags & TEST_KEY_RECOVERY) { + /* Requires some other options be set. + ** Once we know exactly what hey are, test for them here. + */ + printf("Doing Key Recovery\n"); + irv = DoKeyRecovery(WHICH_KEY.privKey); + if (irv != 0) { + printf("Error doing key recovery\n"); + goto loser; + } + } + + if (flags & TEST_CHALLENGE_RESPONSE) { + printf("Doing Challenge / Response\n"); + irv = DoChallengeResponse(WHICH_KEY.privKey, WHICH_KEY.pubKey); + if (irv != 0) { + printf("Error doing challenge-response\n"); + goto loser; + } + } + printf("Exiting successfully!!!\n\n"); + irv = 0; + +loser: + DestroyPair(&signPair); + DestroyPair(&cryptPair); + rv = NSS_Shutdown(); + if (rv) { + printf("NSS_Shutdown did not shutdown cleanly!\n"); + } + PORT_Free(configdir); + if (irv) + printf("crmftest returning %d\n", irv); + return irv; +} -- cgit v1.2.3