summaryrefslogtreecommitdiffstats
path: root/security/nss/cmd/crmftest/testcrmf.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/cmd/crmftest/testcrmf.c')
-rw-r--r--security/nss/cmd/crmftest/testcrmf.c1655
1 files changed, 1655 insertions, 0 deletions
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 <stdio.h>
+#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, &params, &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 = &notBefore;
+ 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;
+}