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