| /* 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 512 |
| #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; |
| } |