Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /*
6 * This program does 5 separate functions. By default, it does them all.
7 * It can be told to do any subset of them.
8 * It does them in this order:
9 *
10 * 1. Generate file of CRMF cert requests.
11 * Generates 2 keys pairs, one for signing, one for encryption.
12 * Can generate RSA or DSA (XXX - DSA is only useful for signing).
13 * Generate a cert request for each of the two public keys.
14 * Generate a single CRMF cert request message that requests both certs.
15 * Leave the generated CRMF request message in file
16 * configdir/CertReqMessages.der
17 *
18 * 2. Decode CRMF Request(s) Message.
19 * Reads in the file configdir/CertReqMessages.der
20 * (either generated by step 1 above, or user supplied).
21 * Decodes it. NOTHING MORE. Drops these decoded results on the floor.
22 * The CMMF response (below) contains a completely unrelated cert. :-(
23 *
24 * 3. CMMF "Stuff".
25 * a) Generates a CMMF response, containing a single cert chain, as if
26 * it was a response to a received CRMF request. But the cert is
27 * simply a user cert from the user's local soft token, whose
28 * nickname is given in the -p option. The CMMF response has no
29 * relationship to the request generated above. The CMMF message
30 * is placed in configdir/CertRepContent.der.
31 * b) Decodes the newly generated CMMF response found in file
32 * configdir/CertRepContent.der and discards the result. 8-/
33 * c) Generate a CMMF Key Escrow message
34 * needs 2 nicknames:
35 * It takes the public and private keys for the cert identified
36 * by -p nickname, and wraps them with a sym key that is in turn
37 * wrapped with the pubkey in the CA cert, whose nickname is
38 * given with the -s option.
39 * Store the message in configdir/KeyRecRepContent.der
40 * d) Decode the CMMF Key Escrow message generated just above.
41 * Get it from file configdir/KeyRecRepContent.der
42 * This is just a decoder test. Results are discarded.
43 *
44 * 4. Key Recovery
45 * This code does not yet compile, and what it was intended to do
46 * has not been fully determined.
47 *
48 * 5. Challenge/Response.
49 * Haven't analyzed this code yet.
50 *
51 *
52 */
54 /* KNOWN BUGS:
55 ** 1. generates BOTH signing and encryption cert requests, even for DSA keys.
56 **
57 ** 2. Does not verify the siganture in the "Proof of Posession" in the
58 ** decoded cert requests. It only checks syntax of the POP.
59 ** 3. CMMF "Stuff" should be broken up into separate steps, each of
60 ** which may be optionally selected.
61 */
63 #include <stdio.h>
64 #include "nspr.h"
65 #include "nss.h"
66 #include "crmf.h"
67 #include "secerr.h"
68 #include "pk11func.h"
69 #include "key.h"
70 #include "cmmf.h"
71 #include "plgetopt.h"
72 #include "secutil.h"
73 #include "pk11pqg.h"
75 #if 0
76 #include "pkcs11.h"
77 #include "secmod.h"
78 #include "secmodi.h"
79 #include "pqggen.h"
80 #include "secmod.h"
81 #include "secmodi.h"
82 #include "pkcs11.h"
83 #include "secitem.h"
84 #include "secasn1.h"
85 #include "sechash.h"
86 #endif
88 #define MAX_KEY_LEN 512
89 #define PATH_LEN 150
90 #define BUFF_SIZE 150
91 #define UID_BITS 800
92 #define BPB 8
93 #define CRMF_FILE "CertReqMessages.der"
95 PRTime notBefore;
96 char *personalCert = NULL;
97 char *recoveryEncrypter = NULL;
98 char *caCertName = NULL;
99 static secuPWData pwdata = { PW_NONE, 0 };
100 char *configdir;
101 PRBool doingDSA = PR_FALSE;
103 CERTCertDBHandle *db;
105 typedef struct {
106 SECKEYPrivateKey *privKey;
107 SECKEYPublicKey *pubKey;
108 CRMFCertRequest *certReq;
109 CRMFCertReqMsg *certReqMsg;
110 } TESTKeyPair;
112 void
113 debug_test(SECItem *src, char *filePath)
114 {
115 PRFileDesc *fileDesc;
117 fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
118 0666);
119 if (fileDesc == NULL) {
120 printf ("Could not cretae file %s.\n", filePath);
121 return;
122 }
123 PR_Write(fileDesc, src->data, src->len);
125 }
127 SECStatus
128 get_serial_number(long *dest)
129 {
130 SECStatus rv;
132 if (dest == NULL) {
133 PORT_SetError(SEC_ERROR_INVALID_ARGS);
134 return SECFailure;
135 }
136 rv = PK11_GenerateRandom((unsigned char *)dest, sizeof(long));
137 /* make serial number positive */
138 if (*dest < 0L)
139 *dest = - *dest;
140 return SECSuccess;
141 }
143 PK11RSAGenParams *
144 GetRSAParams(void)
145 {
146 PK11RSAGenParams *rsaParams;
148 rsaParams = PORT_ZNew(PK11RSAGenParams);
150 if (rsaParams == NULL)
151 return NULL;
153 rsaParams->keySizeInBits = MAX_KEY_LEN;
154 rsaParams->pe = 0x10001;
156 return rsaParams;
158 }
160 PQGParams*
161 GetDSAParams(void)
162 {
163 PQGParams *params = NULL;
164 PQGVerify *vfy = NULL;
166 SECStatus rv;
168 rv = PK11_PQG_ParamGen(0, ¶ms, &vfy);
169 if (rv != SECSuccess) {
170 return NULL;
171 }
172 PK11_PQG_DestroyVerify(vfy);
173 return params;
174 }
176 /* Generate a key pair, and then generate a subjectPublicKeyInfo
177 ** for the public key in that pair. return all 3.
178 */
179 CERTSubjectPublicKeyInfo *
180 GetSubjectPubKeyInfo(TESTKeyPair *pair)
181 {
182 CERTSubjectPublicKeyInfo *spki = NULL;
183 SECKEYPrivateKey *privKey = NULL;
184 SECKEYPublicKey *pubKey = NULL;
185 PK11SlotInfo *keySlot = NULL;
187 keySlot = PK11_GetInternalKeySlot();
188 PK11_Authenticate(keySlot, PR_FALSE, &pwdata);
191 if (!doingDSA) {
192 PK11RSAGenParams *rsaParams = GetRSAParams();
193 if (rsaParams == NULL) {
194 PK11_FreeSlot(keySlot);
195 return NULL;
196 }
197 privKey = PK11_GenerateKeyPair(keySlot, CKM_RSA_PKCS_KEY_PAIR_GEN,
198 (void*)rsaParams, &pubKey, PR_FALSE,
199 PR_FALSE, &pwdata);
200 } else {
201 PQGParams *dsaParams = GetDSAParams();
202 if (dsaParams == NULL) {
203 PK11_FreeSlot(keySlot);
204 return NULL;
205 }
206 privKey = PK11_GenerateKeyPair(keySlot, CKM_DSA_KEY_PAIR_GEN,
207 (void*)dsaParams, &pubKey, PR_FALSE,
208 PR_FALSE, &pwdata);
209 }
210 PK11_FreeSlot(keySlot);
211 if (privKey == NULL || pubKey == NULL) {
212 if (pubKey) {
213 SECKEY_DestroyPublicKey(pubKey);
214 }
215 if (privKey) {
216 SECKEY_DestroyPrivateKey(privKey);
217 }
218 return NULL;
219 }
221 spki = SECKEY_CreateSubjectPublicKeyInfo(pubKey);
222 pair->privKey = privKey;
223 pair->pubKey = pubKey;
224 return spki;
225 }
228 SECStatus
229 InitPKCS11(void)
230 {
231 PK11SlotInfo *keySlot;
233 PK11_SetPasswordFunc(SECU_GetModulePassword);
235 keySlot = PK11_GetInternalKeySlot();
237 if (PK11_NeedUserInit(keySlot) && PK11_NeedLogin(keySlot)) {
238 if (SECU_ChangePW(keySlot, NULL, NULL) != SECSuccess) {
239 printf ("Initializing the PINs failed.\n");
240 return SECFailure;
241 }
242 }
244 PK11_FreeSlot(keySlot);
245 return SECSuccess;
246 }
249 void
250 WriteItOut (void *arg, const char *buf, unsigned long len)
251 {
252 PRFileDesc *fileDesc = (PRFileDesc*)arg;
254 PR_Write(fileDesc, (void*)buf, len);
255 }
259 CRMFCertExtCreationInfo*
260 GetExtensions(void)
261 {
262 unsigned char keyUsage[4] = { 0x03, 0x02, 0x07, KU_DIGITAL_SIGNATURE };
263 /* What are these magic numbers? */
264 SECItem data = { 0, NULL, 0 };
265 CRMFCertExtension *extension;
266 CRMFCertExtCreationInfo *extInfo =
267 PORT_ZNew(CRMFCertExtCreationInfo);
269 data.data = keyUsage;
270 data.len = sizeof keyUsage;
273 extension =
274 CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, PR_FALSE, &data);
275 if (extension && extInfo) {
276 extInfo->numExtensions = 1;
277 extInfo->extensions = PORT_ZNewArray(CRMFCertExtension*, 1);
278 extInfo->extensions[0] = extension;
279 }
280 return extInfo;
281 }
283 void
284 FreeExtInfo(CRMFCertExtCreationInfo *extInfo)
285 {
286 int i;
288 for (i=0; i<extInfo->numExtensions; i++) {
289 CRMF_DestroyCertExtension(extInfo->extensions[i]);
290 }
291 PORT_Free(extInfo->extensions);
292 PORT_Free(extInfo);
293 }
295 int
296 InjectCertName( CRMFCertRequest * certReq,
297 CRMFCertTemplateField inTemplateField,
298 const char * inNameString)
299 {
300 char * nameStr;
301 CERTName * name;
302 int irv = 0;
304 nameStr = PORT_Strdup(inNameString);
305 if (!nameStr)
306 return 5;
307 name = CERT_AsciiToName(nameStr);
308 if (name == NULL) {
309 printf ("Could not create CERTName structure from %s.\n", nameStr);
310 irv = 5;
311 goto finish;
312 }
314 irv = CRMF_CertRequestSetTemplateField(certReq, inTemplateField, (void*)name);
315 if (irv != SECSuccess) {
316 printf ("Could not add name to cert template\n");
317 irv = 6;
318 }
320 finish:
321 PORT_Free(nameStr);
322 if (name)
323 CERT_DestroyName(name);
324 return irv;
325 }
327 int
328 CreateCertRequest(TESTKeyPair *pair, long inRequestID)
329 {
330 CERTCertificate * caCert;
331 CERTSubjectPublicKeyInfo *spki;
332 CRMFCertExtCreationInfo * extInfo;
333 CRMFCertRequest * certReq;
334 CRMFEncryptedKey * encKey;
335 CRMFPKIArchiveOptions * pkiArchOpt;
336 SECAlgorithmID * algID;
337 long serialNumber;
338 long version = 3;
339 SECStatus rv;
340 CRMFValidityCreationInfo validity;
341 unsigned char UIDbuf[UID_BITS / BPB];
342 SECItem issuerUID = { siBuffer, NULL, 0 };
343 SECItem subjectUID = { siBuffer, NULL, 0 };
345 /* len in bits */
346 issuerUID.data = UIDbuf;
347 issuerUID.len = UID_BITS;
348 subjectUID.data = UIDbuf;
349 subjectUID.len = UID_BITS;
351 pair->certReq = NULL;
352 certReq = CRMF_CreateCertRequest(inRequestID);
353 if (certReq == NULL) {
354 printf ("Could not initialize a certificate request.\n");
355 return 1;
356 }
358 /* set to version 3 */
359 rv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion,
360 (void*)(&version));
361 if (rv != SECSuccess) {
362 printf("Could not add the version number to the "
363 "Certificate Request.\n");
364 CRMF_DestroyCertRequest(certReq);
365 return 2;
366 }
368 /* set serial number */
369 if (get_serial_number(&serialNumber) != SECSuccess) {
370 printf ("Could not generate a serial number for cert request.\n");
371 CRMF_DestroyCertRequest(certReq);
372 return 3;
373 }
374 rv = CRMF_CertRequestSetTemplateField (certReq, crmfSerialNumber,
375 (void*)(&serialNumber));
376 if (rv != SECSuccess) {
377 printf ("Could not add serial number to certificate template\n.");
378 CRMF_DestroyCertRequest(certReq);
379 return 4;
380 }
382 /* Set issuer name */
383 rv = InjectCertName(certReq, crmfIssuer,
384 "CN=mozilla CA Shack,O=Information Systems");
385 if (rv) {
386 printf ("Could not add issuer to cert template\n");
387 CRMF_DestroyCertRequest(certReq);
388 return 5;
389 }
391 /* Set Subject Name */
392 rv = InjectCertName(certReq, crmfSubject,
393 "CN=mozilla CA Shack ID,O=Engineering,C=US");
394 if (rv) {
395 printf ("Could not add Subject to cert template\n");
396 CRMF_DestroyCertRequest(certReq);
397 return 5;
398 }
400 /* Set Algorithm ID */
401 algID = PK11_CreatePBEAlgorithmID(SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC,
402 1, NULL);
403 if (algID == NULL) {
404 printf ("Couldn't create algorithm ID\n");
405 CRMF_DestroyCertRequest(certReq);
406 return 9;
407 }
408 rv = CRMF_CertRequestSetTemplateField(certReq, crmfSigningAlg, (void*)algID);
409 SECOID_DestroyAlgorithmID(algID, PR_TRUE);
410 if (rv != SECSuccess) {
411 printf ("Could not add the signing algorithm to the cert template.\n");
412 CRMF_DestroyCertRequest(certReq);
413 return 10;
414 }
416 /* Set Validity Dates */
417 validity.notBefore = ¬Before;
418 validity.notAfter = NULL;
419 notBefore = PR_Now();
420 rv = CRMF_CertRequestSetTemplateField(certReq, crmfValidity,(void*)(&validity));
421 if (rv != SECSuccess) {
422 printf ("Could not add validity to cert template\n");
423 CRMF_DestroyCertRequest(certReq);
424 return 11;
425 }
427 /* Generate a key pair and Add the spki to the request */
428 spki = GetSubjectPubKeyInfo(pair);
429 if (spki == NULL) {
430 printf ("Could not create a Subject Public Key Info to add\n");
431 CRMF_DestroyCertRequest(certReq);
432 return 12;
433 }
434 rv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, (void*)spki);
435 SECKEY_DestroySubjectPublicKeyInfo(spki);
436 if (rv != SECSuccess) {
437 printf ("Could not add the public key to the template\n");
438 CRMF_DestroyCertRequest(certReq);
439 return 13;
440 }
442 /* Set the requested isser Unique ID */
443 PK11_GenerateRandom(UIDbuf, sizeof UIDbuf);
444 CRMF_CertRequestSetTemplateField(certReq,crmfIssuerUID, (void*)&issuerUID);
446 /* Set the requested Subject Unique ID */
447 PK11_GenerateRandom(UIDbuf, sizeof UIDbuf);
448 CRMF_CertRequestSetTemplateField(certReq,crmfSubjectUID, (void*)&subjectUID);
450 /* Add extensions - XXX need to understand these magic numbers */
451 extInfo = GetExtensions();
452 CRMF_CertRequestSetTemplateField(certReq, crmfExtension, (void*)extInfo);
453 FreeExtInfo(extInfo);
455 /* get the recipient CA's cert */
456 caCert = CERT_FindCertByNickname(db, caCertName);
457 if (caCert == NULL) {
458 printf ("Could not find the certificate for %s\n", caCertName);
459 CRMF_DestroyCertRequest(certReq);
460 return 50;
461 }
462 encKey = CRMF_CreateEncryptedKeyWithEncryptedValue(pair->privKey, caCert);
463 CERT_DestroyCertificate(caCert);
464 if (encKey == NULL) {
465 printf ("Could not create Encrypted Key with Encrypted Value.\n");
466 return 14;
467 }
468 pkiArchOpt = CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encKey);
469 CRMF_DestroyEncryptedKey(encKey);
470 if (pkiArchOpt == NULL) {
471 printf ("Could not create PKIArchiveOptions.\n");
472 return 15;
473 }
474 rv = CRMF_CertRequestSetPKIArchiveOptions(certReq, pkiArchOpt);
475 CRMF_DestroyPKIArchiveOptions(pkiArchOpt);
476 if (rv != SECSuccess) {
477 printf ("Could not add the PKIArchiveControl to Cert Request.\n");
478 return 16;
479 }
480 pair->certReq = certReq;
481 return 0;
482 }
484 int
485 Encode(CRMFCertReqMsg *inCertReq1, CRMFCertReqMsg *inCertReq2)
486 {
487 PRFileDesc *fileDesc;
488 SECStatus rv;
489 int irv = 0;
490 CRMFCertReqMsg *msgArr[3];
491 char filePath[PATH_LEN];
493 PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, CRMF_FILE);
494 fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
495 0666);
496 if (fileDesc == NULL) {
497 printf ("Could not open file %s\n", filePath);
498 irv = 14;
499 goto finish;
500 }
501 msgArr[0] = inCertReq1;
502 msgArr[1] = inCertReq2;
503 msgArr[2] = NULL;
504 rv = CRMF_EncodeCertReqMessages(msgArr, WriteItOut, (void*)fileDesc);
505 if (rv != SECSuccess) {
506 printf ("An error occurred while encoding.\n");
507 irv = 15;
508 }
509 finish:
510 PR_Close(fileDesc);
511 return irv;
512 }
514 int
515 AddProofOfPossession(TESTKeyPair *pair,
516 CRMFPOPChoice inPOPChoice)
517 {
519 switch(inPOPChoice){
520 case crmfSignature:
521 CRMF_CertReqMsgSetSignaturePOP(pair->certReqMsg, pair->privKey,
522 pair->pubKey, NULL, NULL, &pwdata);
523 break;
524 case crmfRAVerified:
525 CRMF_CertReqMsgSetRAVerifiedPOP(pair->certReqMsg);
526 break;
527 case crmfKeyEncipherment:
528 CRMF_CertReqMsgSetKeyEnciphermentPOP(pair->certReqMsg,
529 crmfSubsequentMessage,
530 crmfChallengeResp, NULL);
531 break;
532 case crmfKeyAgreement:
533 {
534 SECItem pendejo;
535 unsigned char lame[] = { 0xf0, 0x0f, 0xf0, 0x0f, 0xf0 };
537 pendejo.data = lame;
538 pendejo.len = 5;
540 CRMF_CertReqMsgSetKeyAgreementPOP(pair->certReqMsg, crmfThisMessage,
541 crmfNoSubseqMess, &pendejo);
542 }
543 break;
544 default:
545 return 1;
546 }
547 return 0;
548 }
551 int
552 Decode(void)
553 {
554 PRFileDesc *fileDesc;
555 CRMFCertReqMsg *certReqMsg;
556 CRMFCertRequest *certReq;
557 CRMFCertReqMessages *certReqMsgs;
558 SECStatus rv;
559 int numMsgs, i;
560 long lame;
561 CRMFGetValidity validity = {NULL, NULL};
562 SECItem item = { siBuffer, NULL, 0 };
563 char filePath[PATH_LEN];
565 PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, CRMF_FILE);
566 fileDesc = PR_Open(filePath, PR_RDONLY, 0644);
567 if (fileDesc == NULL) {
568 printf ("Could not open file %s\n", filePath);
569 return 214;
570 }
571 rv = SECU_FileToItem(&item, fileDesc);
572 PR_Close(fileDesc);
573 if (rv != SECSuccess) {
574 return 215;
575 }
577 certReqMsgs = CRMF_CreateCertReqMessagesFromDER((char *)item.data, item.len);
578 if (certReqMsgs == NULL) {
579 printf ("Error decoding CertReqMessages.\n");
580 return 202;
581 }
582 numMsgs = CRMF_CertReqMessagesGetNumMessages(certReqMsgs);
583 if (numMsgs <= 0) {
584 printf ("WARNING: The DER contained %d messages.\n", numMsgs);
585 }
586 for (i=0; i < numMsgs; i++) {
587 SECStatus rv;
588 printf("crmftest: Processing cert request %d\n", i);
589 certReqMsg = CRMF_CertReqMessagesGetCertReqMsgAtIndex(certReqMsgs, i);
590 if (certReqMsg == NULL) {
591 printf ("ERROR: Could not access the message at index %d of %s\n",
592 i, filePath);
593 }
594 rv = CRMF_CertReqMsgGetID(certReqMsg, &lame);
595 if (rv) {
596 SECU_PrintError("crmftest", "CRMF_CertReqMsgGetID");
597 }
598 certReq = CRMF_CertReqMsgGetCertRequest(certReqMsg);
599 if (!certReq) {
600 SECU_PrintError("crmftest", "CRMF_CertReqMsgGetCertRequest");
601 }
602 rv = CRMF_CertRequestGetCertTemplateValidity(certReq, &validity);
603 if (rv) {
604 SECU_PrintError("crmftest", "CRMF_CertRequestGetCertTemplateValidity");
605 }
606 if (!validity.notBefore) {
607 /* We encoded a notBefore, so somthing's wrong if it's not here. */
608 printf("ERROR: Validity period notBefore date missing.\n");
609 }
610 /* XXX It's all parsed now. We probably should DO SOMETHING with it.
611 ** But nope. We just throw it all away.
612 ** Maybe this was intended to be no more than a decoder test.
613 */
614 CRMF_DestroyGetValidity(&validity);
615 CRMF_DestroyCertRequest(certReq);
616 CRMF_DestroyCertReqMsg(certReqMsg);
617 }
618 CRMF_DestroyCertReqMessages(certReqMsgs);
619 SECITEM_FreeItem(&item, PR_FALSE);
620 return 0;
621 }
623 int
624 GetBitsFromFile(const char *filePath, SECItem *item)
625 {
626 PRFileDesc *fileDesc;
627 SECStatus rv;
629 fileDesc = PR_Open(filePath, PR_RDONLY, 0644);
630 if (fileDesc == NULL) {
631 printf ("Could not open file %s\n", filePath);
632 return 14;
633 }
635 rv = SECU_FileToItem(item, fileDesc);
636 PR_Close(fileDesc);
638 if (rv != SECSuccess) {
639 item->data = NULL;
640 item->len = 0;
641 return 15;
642 }
643 return 0;
644 }
646 int
647 DecodeCMMFCertRepContent(char *derFile)
648 {
649 CMMFCertRepContent *certRepContent;
650 int irv = 0;
651 SECItem fileBits = { siBuffer, NULL, 0 };
653 GetBitsFromFile(derFile, &fileBits);
654 if (fileBits.data == NULL) {
655 printf("Could not get bits from file %s\n", derFile);
656 return 304;
657 }
658 certRepContent = CMMF_CreateCertRepContentFromDER(db,
659 (char*)fileBits.data, fileBits.len);
660 if (certRepContent == NULL) {
661 printf ("Error while decoding %s\n", derFile);
662 irv = 303;
663 } else {
664 /* That was fun. Now, let's throw it away! */
665 CMMF_DestroyCertRepContent(certRepContent);
666 }
667 SECITEM_FreeItem(&fileBits, PR_FALSE);
668 return irv;
669 }
671 int
672 EncodeCMMFCertReply(const char *filePath,
673 CERTCertificate *cert,
674 CERTCertList *list)
675 {
676 int rv = 0;
677 SECStatus srv;
678 PRFileDesc *fileDesc = NULL;
679 CMMFCertRepContent *certRepContent = NULL;
680 CMMFCertResponse *certResp = NULL;
681 CMMFCertResponse *certResponses[3];
683 certResp = CMMF_CreateCertResponse(0xff123);
684 CMMF_CertResponseSetPKIStatusInfoStatus(certResp, cmmfGranted);
686 CMMF_CertResponseSetCertificate(certResp, cert);
688 certResponses[0] = certResp;
689 certResponses[1] = NULL;
690 certResponses[2] = NULL;
692 certRepContent = CMMF_CreateCertRepContent();
693 CMMF_CertRepContentSetCertResponses(certRepContent, certResponses, 1);
695 CMMF_CertRepContentSetCAPubs(certRepContent, list);
697 fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
698 0666);
699 if (fileDesc == NULL) {
700 printf ("Could not open file %s\n", filePath);
701 rv = 400;
702 goto finish;
703 }
705 srv = CMMF_EncodeCertRepContent(certRepContent, WriteItOut,
706 (void*)fileDesc);
707 PR_Close(fileDesc);
708 if (srv != SECSuccess) {
709 printf ("CMMF_EncodeCertRepContent failed,\n");
710 rv = 401;
711 }
712 finish:
713 if (certRepContent) {
714 CMMF_DestroyCertRepContent(certRepContent);
715 }
716 if (certResp) {
717 CMMF_DestroyCertResponse(certResp);
718 }
719 return rv;
720 }
723 /* Extract the public key from the cert whose nickname is given. */
724 int
725 extractPubKeyFromNamedCert(const char * nickname, SECKEYPublicKey **pPubKey)
726 {
727 CERTCertificate *caCert = NULL;
728 SECKEYPublicKey *caPubKey = NULL;
729 int rv = 0;
731 caCert = CERT_FindCertByNickname(db, (char *)nickname);
732 if (caCert == NULL) {
733 printf ("Could not get the certifcate for %s\n", caCertName);
734 rv = 411;
735 goto finish;
736 }
737 caPubKey = CERT_ExtractPublicKey(caCert);
738 if (caPubKey == NULL) {
739 printf ("Could not extract the public from the "
740 "certificate for \n%s\n", caCertName);
741 rv = 412;
742 }
743 finish:
744 *pPubKey = caPubKey;
745 CERT_DestroyCertificate(caCert);
746 caCert = NULL;
747 return rv;
748 }
750 int
751 EncodeCMMFRecoveryMessage(const char * filePath,
752 CERTCertificate *cert,
753 CERTCertList *list)
754 {
755 SECKEYPublicKey *caPubKey = NULL;
756 SECKEYPrivateKey *privKey = NULL;
757 CMMFKeyRecRepContent *repContent = NULL;
758 PRFileDesc *fileDesc;
759 int rv = 0;
760 SECStatus srv;
762 /* Extract the public key from the cert whose nickname is given in
763 ** the -s option.
764 */
765 rv = extractPubKeyFromNamedCert( caCertName, &caPubKey);
766 if (rv)
767 goto finish;
769 repContent = CMMF_CreateKeyRecRepContent();
770 if (repContent == NULL) {
771 printf ("Could not allocate a CMMFKeyRecRepContent structure\n");
772 rv = 407;
773 goto finish;
774 }
775 srv = CMMF_KeyRecRepContentSetPKIStatusInfoStatus(repContent,
776 cmmfGrantedWithMods);
777 if (srv != SECSuccess) {
778 printf ("Error trying to set PKIStatusInfo for "
779 "CMMFKeyRecRepContent.\n");
780 rv = 406;
781 goto finish;
782 }
783 srv = CMMF_KeyRecRepContentSetNewSignCert(repContent, cert);
784 if (srv != SECSuccess) {
785 printf ("Error trying to set the new signing certificate for "
786 "key recovery\n");
787 rv = 408;
788 goto finish;
789 }
790 srv = CMMF_KeyRecRepContentSetCACerts(repContent, list);
791 if (srv != SECSuccess) {
792 printf ("Errory trying to add the list of CA certs to the "
793 "CMMFKeyRecRepContent structure.\n");
794 rv = 409;
795 goto finish;
796 }
797 privKey = PK11_FindKeyByAnyCert(cert, &pwdata);
798 if (privKey == NULL) {
799 printf ("Could not get the private key associated with the\n"
800 "certificate %s\n", personalCert);
801 rv = 410;
802 goto finish;
803 }
805 srv = CMMF_KeyRecRepContentSetCertifiedKeyPair(repContent, cert, privKey,
806 caPubKey);
807 if (srv != SECSuccess) {
808 printf ("Could not set the Certified Key Pair\n");
809 rv = 413;
810 goto finish;
811 }
812 fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
813 0666);
814 if (fileDesc == NULL) {
815 printf ("Could not open file %s\n", filePath);
816 rv = 414;
817 goto finish;
818 }
820 srv = CMMF_EncodeKeyRecRepContent(repContent, WriteItOut,
821 (void*)fileDesc);
822 PR_Close(fileDesc);
823 if (srv != SECSuccess) {
824 printf ("CMMF_EncodeKeyRecRepContent failed\n");
825 rv = 415;
826 }
827 finish:
828 if (privKey)
829 SECKEY_DestroyPrivateKey(privKey);
830 if (caPubKey)
831 SECKEY_DestroyPublicKey(caPubKey);
832 if (repContent)
833 CMMF_DestroyKeyRecRepContent(repContent);
834 return rv;
835 }
837 int
838 decodeCMMFRecoveryMessage(const char * filePath)
839 {
840 CMMFKeyRecRepContent *repContent = NULL;
841 int rv = 0;
842 SECItem fileBits = { siBuffer, NULL, 0 };
844 GetBitsFromFile(filePath, &fileBits);
845 if (!fileBits.len) {
846 rv = 451;
847 goto finish;
848 }
849 repContent =
850 CMMF_CreateKeyRecRepContentFromDER(db, (const char *) fileBits.data,
851 fileBits.len);
852 if (repContent == NULL) {
853 printf ("ERROR: CMMF_CreateKeyRecRepContentFromDER failed on file:\n"
854 "\t%s\n", filePath);
855 rv = 452;
856 }
857 finish:
858 if (repContent) {
859 CMMF_DestroyKeyRecRepContent(repContent);
860 }
861 SECITEM_FreeItem(&fileBits, PR_FALSE);
862 return rv;
863 }
865 int
866 DoCMMFStuff(void)
867 {
868 CERTCertificate *cert = NULL;
869 CERTCertList *list = NULL;
870 int rv = 0;
871 char filePath[PATH_LEN];
873 /* Do common setup for the following steps.
874 */
875 PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, "CertRepContent.der");
877 cert = CERT_FindCertByNickname(db, personalCert);
878 if (cert == NULL) {
879 printf ("Could not find the certificate for %s\n", personalCert);
880 rv = 416;
881 goto finish;
882 }
883 list = CERT_GetCertChainFromCert(cert, PR_Now(), certUsageEmailSigner);
884 if (list == NULL) {
885 printf ("Could not find the certificate chain for %s\n", personalCert);
886 rv = 418;
887 goto finish;
888 }
890 /* a) Generate the CMMF response message, using a user cert named
891 ** by -p option, rather than a cert generated from the CRMF
892 ** request itself. The CMMF message is placed in
893 ** configdir/CertRepContent.der.
894 */
895 rv = EncodeCMMFCertReply(filePath, cert, list);
896 if (rv != 0) {
897 goto finish;
898 }
900 /* b) Decode the CMMF Cert granting message encoded just above,
901 ** found in configdir/CertRepContent.der.
902 ** This only tests the decoding. The decoded content is discarded.
903 */
904 rv = DecodeCMMFCertRepContent(filePath);
905 if (rv != 0) {
906 goto finish;
907 }
909 /* c) Generate a CMMF Key Excrow message
910 ** It takes the public and private keys for the cert identified
911 ** by -p nickname, and wraps them with a sym key that is in turn
912 ** wrapped with the pubkey in the CA cert, whose nickname is
913 ** given by the -s option.
914 ** Store the message in configdir/KeyRecRepContent.der
915 */
916 PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir,
917 "KeyRecRepContent.der");
919 rv = EncodeCMMFRecoveryMessage(filePath, cert, list);
920 if (rv)
921 goto finish;
923 /* d) Decode the CMMF Key Excrow message generated just above.
924 ** Get it from file configdir/KeyRecRepContent.der
925 ** This is just a decoder test. Results are discarded.
926 */
928 rv = decodeCMMFRecoveryMessage(filePath);
930 finish:
931 if (cert) {
932 CERT_DestroyCertificate(cert);
933 }
934 if (list) {
935 CERT_DestroyCertList(list);
936 }
937 return rv;
938 }
940 static CK_MECHANISM_TYPE
941 mapWrapKeyType(KeyType keyType)
942 {
943 switch (keyType) {
944 case rsaKey:
945 return CKM_RSA_PKCS;
946 default:
947 break;
948 }
949 return CKM_INVALID_MECHANISM;
950 }
952 #define KNOWN_MESSAGE_LENGTH 20 /*160 bits*/
954 int
955 DoKeyRecovery( SECKEYPrivateKey *privKey)
956 {
957 #ifdef DOING_KEY_RECOVERY /* Doesn't compile yet. */
958 SECKEYPublicKey *pubKey;
959 PK11SlotInfo *slot;
960 unsigned char *ciphertext;
961 unsigned char *text_compared;
962 SECKEYPrivateKey *unwrappedPrivKey;
963 SECKEYPrivateKey *caPrivKey;
964 CMMFKeyRecRepContent *keyRecRep;
965 CMMFCertifiedKeyPair *certKeyPair;
966 CERTCertificate *caCert;
967 CERTCertificate *myCert;
968 SECKEYPublicKey *caPubKey;
969 PRFileDesc *fileDesc;
970 CK_ULONG max_bytes_encrypted;
971 CK_ULONG bytes_encrypted;
972 CK_ULONG bytes_compared;
973 CK_ULONG bytes_decrypted;
974 CK_RV crv;
975 CK_OBJECT_HANDLE id;
976 CK_MECHANISM mech = { CKM_INVALID_MECHANISM, NULL, 0};
977 SECStatus rv;
978 SECItem fileBits;
979 SECItem nickname;
980 unsigned char plaintext[KNOWN_MESSAGE_LENGTH];
981 char filePath[PATH_LEN];
982 static const unsigned char known_message[] = { "Known Crypto Message" };
984 /*caCert = CERT_FindCertByNickname(db, caCertName);*/
985 myCert = CERT_FindCertByNickname(db, personalCert);
986 if (myCert == NULL) {
987 printf ("Could not find the certificate for %s\n", personalCert);
988 return 700;
989 }
990 caCert = CERT_FindCertByNickname(db, recoveryEncrypter);
991 if (caCert == NULL) {
992 printf ("Could not find the certificate for %s\n", recoveryEncrypter);
993 return 701;
994 }
995 caPubKey = CERT_ExtractPublicKey(caCert);
996 pubKey = SECKEY_ConvertToPublicKey(privKey);
997 max_bytes_encrypted = PK11_GetPrivateModulusLen(privKey);
998 slot = PK11_GetBestSlotWithAttributes(mapWrapKeyType(privKey->keyType),
999 CKF_ENCRYPT, 0, NULL);
1000 id = PK11_ImportPublicKey(slot, pubKey, PR_FALSE);
1002 switch(privKey->keyType) {
1003 case rsaKey:
1004 mech.mechanism = CKM_RSA_PKCS;
1005 break;
1006 case dsaKey:
1007 mech.mechanism = CKM_DSA;
1008 break;
1009 case dhKey:
1010 mech.mechanism = CKM_DH_PKCS_DERIVE;
1011 break;
1012 default:
1013 printf ("Bad Key type in key recovery.\n");
1014 return 512;
1016 }
1017 PK11_EnterSlotMonitor(slot);
1018 crv = PK11_GETTAB(slot)->C_EncryptInit(slot->session, &mech, id);
1019 if (crv != CKR_OK) {
1020 PK11_ExitSlotMonitor(slot);
1021 PK11_FreeSlot(slot);
1022 printf ("C_EncryptInit failed in KeyRecovery\n");
1023 return 500;
1024 }
1025 ciphertext = PORT_NewArray(unsigned char, max_bytes_encrypted);
1026 if (ciphertext == NULL) {
1027 PK11_ExitSlotMonitor(slot);
1028 PK11_FreeSlot(slot);
1029 printf ("Could not allocate memory for ciphertext.\n");
1030 return 501;
1031 }
1032 bytes_encrypted = max_bytes_encrypted;
1033 crv = PK11_GETTAB(slot)->C_Encrypt(slot->session,
1034 known_message,
1035 KNOWN_MESSAGE_LENGTH,
1036 ciphertext,
1037 &bytes_encrypted);
1038 PK11_ExitSlotMonitor(slot);
1039 PK11_FreeSlot(slot);
1040 if (crv != CKR_OK) {
1041 PORT_Free(ciphertext);
1042 return 502;
1043 }
1044 /* Always use the smaller of these two values . . . */
1045 bytes_compared = ( bytes_encrypted > KNOWN_MESSAGE_LENGTH )
1046 ? KNOWN_MESSAGE_LENGTH
1047 : bytes_encrypted;
1049 /* If there was a failure, the plaintext */
1050 /* goes at the end, therefore . . . */
1051 text_compared = ( bytes_encrypted > KNOWN_MESSAGE_LENGTH )
1052 ? (ciphertext + bytes_encrypted -
1053 KNOWN_MESSAGE_LENGTH )
1054 : ciphertext;
1056 keyRecRep = CMMF_CreateKeyRecRepContent();
1057 if (keyRecRep == NULL) {
1058 PORT_Free(ciphertext);
1059 PK11_FreeSlot(slot);
1060 CMMF_DestroyKeyRecRepContent(keyRecRep);
1061 printf ("Could not allocate a CMMFKeyRecRepContent structre.\n");
1062 return 503;
1063 }
1064 rv = CMMF_KeyRecRepContentSetPKIStatusInfoStatus(keyRecRep,
1065 cmmfGranted);
1066 if (rv != SECSuccess) {
1067 PORT_Free(ciphertext);
1068 PK11_FreeSlot(slot);
1069 CMMF_DestroyKeyRecRepContent(keyRecRep);
1070 printf ("Could not set the status for the KeyRecRepContent\n");
1071 return 504;
1072 }
1073 /* The myCert here should correspond to the certificate corresponding
1074 * to the private key, but for this test any certificate will do.
1075 */
1076 rv = CMMF_KeyRecRepContentSetCertifiedKeyPair(keyRecRep, myCert,
1077 privKey, caPubKey);
1078 if (rv != SECSuccess) {
1079 PORT_Free(ciphertext);
1080 PK11_FreeSlot(slot);
1081 CMMF_DestroyKeyRecRepContent(keyRecRep);
1082 printf ("Could not set the Certified Key Pair\n");
1083 return 505;
1084 }
1085 PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir,
1086 "KeyRecRepContent.der");
1087 fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
1088 0666);
1089 if (fileDesc == NULL) {
1090 PORT_Free(ciphertext);
1091 PK11_FreeSlot(slot);
1092 CMMF_DestroyKeyRecRepContent(keyRecRep);
1093 printf ("Could not open file %s\n", filePath);
1094 return 506;
1095 }
1096 rv = CMMF_EncodeKeyRecRepContent(keyRecRep, WriteItOut, fileDesc);
1097 CMMF_DestroyKeyRecRepContent(keyRecRep);
1098 PR_Close(fileDesc);
1100 if (rv != SECSuccess) {
1101 PORT_Free(ciphertext);
1102 PK11_FreeSlot(slot);
1103 printf ("Error while encoding CMMFKeyRecRepContent\n");
1104 return 507;
1105 }
1106 GetBitsFromFile(filePath, &fileBits);
1107 if (fileBits.data == NULL) {
1108 PORT_Free(ciphertext);
1109 PK11_FreeSlot(slot);
1110 printf ("Could not get the bits from file %s\n", filePath);
1111 return 508;
1112 }
1113 keyRecRep =
1114 CMMF_CreateKeyRecRepContentFromDER(db,(const char*)fileBits.data,
1115 fileBits.len);
1116 if (keyRecRep == NULL) {
1117 printf ("Could not decode the KeyRecRepContent in file %s\n",
1118 filePath);
1119 PORT_Free(ciphertext);
1120 PK11_FreeSlot(slot);
1121 return 509;
1122 }
1123 caPrivKey = PK11_FindKeyByAnyCert(caCert, &pwdata);
1124 if (CMMF_KeyRecRepContentGetPKIStatusInfoStatus(keyRecRep) !=
1125 cmmfGranted) {
1126 PORT_Free(ciphertext);
1127 PK11_FreeSlot(slot);
1128 CMMF_DestroyKeyRecRepContent(keyRecRep);
1129 printf ("A bad status came back with the "
1130 "KeyRecRepContent structure\n");
1131 return 510;
1132 }
1134 #define NICKNAME "Key Recovery Test Key"
1135 nickname.data = (unsigned char*)NICKNAME;
1136 nickname.len = PORT_Strlen(NICKNAME);
1138 certKeyPair = CMMF_KeyRecRepContentGetCertKeyAtIndex(keyRecRep, 0);
1139 CMMF_DestroyKeyRecRepContent(keyRecRep);
1140 rv = CMMF_CertifiedKeyPairUnwrapPrivKey(certKeyPair,
1141 caPrivKey,
1142 &nickname,
1143 PK11_GetInternalKeySlot(),
1144 db,
1145 &unwrappedPrivKey, &pwdata);
1146 CMMF_DestroyCertifiedKeyPair(certKeyPair);
1147 if (rv != SECSuccess) {
1148 printf ("Unwrapping the private key failed.\n");
1149 return 511;
1150 }
1151 /*Now let's try to decrypt the ciphertext with the "recovered" key*/
1152 PK11_EnterSlotMonitor(slot);
1153 crv =
1154 PK11_GETTAB(slot)->C_DecryptInit(unwrappedPrivKey->pkcs11Slot->session,
1155 &mech,
1156 unwrappedPrivKey->pkcs11ID);
1157 if (crv != CKR_OK) {
1158 PK11_ExitSlotMonitor(slot);
1159 PORT_Free(ciphertext);
1160 PK11_FreeSlot(slot);
1161 printf ("Decrypting with the recovered key failed.\n");
1162 return 513;
1163 }
1164 bytes_decrypted = KNOWN_MESSAGE_LENGTH;
1165 crv = PK11_GETTAB(slot)->C_Decrypt(unwrappedPrivKey->pkcs11Slot->session,
1166 ciphertext,
1167 bytes_encrypted, plaintext,
1168 &bytes_decrypted);
1169 SECKEY_DestroyPrivateKey(unwrappedPrivKey);
1170 PK11_ExitSlotMonitor(slot);
1171 PORT_Free(ciphertext);
1172 if (crv != CKR_OK) {
1173 PK11_FreeSlot(slot);
1174 printf ("Decrypting the ciphertext with recovered key failed.\n");
1175 return 514;
1176 }
1177 if ((bytes_decrypted != KNOWN_MESSAGE_LENGTH) ||
1178 (PORT_Memcmp(plaintext, known_message, KNOWN_MESSAGE_LENGTH) != 0)) {
1179 PK11_FreeSlot(slot);
1180 printf ("The recovered plaintext does not equal the known message:\n"
1181 "\tKnown message: %s\n"
1182 "\tRecovered plaintext: %s\n", known_message, plaintext);
1183 return 515;
1184 }
1185 #endif
1186 return 0;
1187 }
1189 int
1190 DoChallengeResponse(SECKEYPrivateKey *privKey,
1191 SECKEYPublicKey *pubKey)
1192 {
1193 CMMFPOPODecKeyChallContent *chalContent = NULL;
1194 CMMFPOPODecKeyRespContent *respContent = NULL;
1195 CERTCertificate *myCert = NULL;
1196 CERTGeneralName *myGenName = NULL;
1197 PLArenaPool *poolp = NULL;
1198 PRFileDesc *fileDesc;
1199 SECItem *publicValue;
1200 SECItem *keyID;
1201 SECKEYPrivateKey *foundPrivKey;
1202 long *randomNums;
1203 int numChallengesFound = 0;
1204 int numChallengesSet = 1;
1205 int i;
1206 long retrieved;
1207 SECStatus rv;
1208 SECItem DecKeyChallBits;
1209 char filePath[PATH_LEN];
1211 chalContent = CMMF_CreatePOPODecKeyChallContent();
1212 myCert = CERT_FindCertByNickname(db, personalCert);
1213 if (myCert == NULL) {
1214 printf ("Could not find the certificate for %s\n", personalCert);
1215 return 900;
1216 }
1217 poolp = PORT_NewArena(1024);
1218 if (poolp == NULL) {
1219 printf("Could no allocate a new arena in DoChallengeResponse\n");
1220 return 901;
1221 }
1222 myGenName = CERT_GetCertificateNames(myCert, poolp);
1223 if (myGenName == NULL) {
1224 printf ("Could not get the general names for %s certificate\n",
1225 personalCert);
1226 return 902;
1227 }
1228 randomNums = PORT_ArenaNewArray(poolp,long, numChallengesSet);
1229 PK11_GenerateRandom((unsigned char *)randomNums,
1230 numChallengesSet * sizeof(long));
1231 for (i=0; i<numChallengesSet; i++) {
1232 rv = CMMF_POPODecKeyChallContentSetNextChallenge(chalContent,
1233 randomNums[i],
1234 myGenName,
1235 pubKey,
1236 &pwdata);
1237 if (rv != SECSuccess) {
1238 printf ("Could not set the challenge in DoChallengeResponse\n");
1239 return 903;
1240 }
1241 }
1242 PR_snprintf(filePath, PATH_LEN, "%s/POPODecKeyChallContent.der",
1243 configdir);
1244 fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
1245 0666);
1246 if (fileDesc == NULL) {
1247 printf ("Could not open file %s\n", filePath);
1248 return 904;
1249 }
1250 rv = CMMF_EncodePOPODecKeyChallContent(chalContent,WriteItOut,
1251 (void*)fileDesc);
1252 PR_Close(fileDesc);
1253 CMMF_DestroyPOPODecKeyChallContent(chalContent);
1254 if (rv != SECSuccess) {
1255 printf ("Could not encode the POPODecKeyChallContent.\n");
1256 return 905;
1257 }
1258 GetBitsFromFile(filePath, &DecKeyChallBits);
1259 chalContent = CMMF_CreatePOPODecKeyChallContentFromDER
1260 ((const char*)DecKeyChallBits.data, DecKeyChallBits.len);
1261 SECITEM_FreeItem(&DecKeyChallBits, PR_FALSE);
1262 if (chalContent == NULL) {
1263 printf ("Could not create the POPODecKeyChallContent from DER\n");
1264 return 906;
1265 }
1266 numChallengesFound =
1267 CMMF_POPODecKeyChallContentGetNumChallenges(chalContent);
1268 if (numChallengesFound != numChallengesSet) {
1269 printf ("Number of Challenges Found (%d) does not equal the number "
1270 "set (%d)\n", numChallengesFound, numChallengesSet);
1271 return 907;
1272 }
1273 for (i=0; i<numChallengesSet; i++) {
1274 publicValue = CMMF_POPODecKeyChallContentGetPublicValue(chalContent, i);
1275 if (publicValue == NULL) {
1276 printf("Could not get the public value for challenge at index %d\n",
1277 i);
1278 return 908;
1279 }
1280 keyID = PK11_MakeIDFromPubKey(publicValue);
1281 if (keyID == NULL) {
1282 printf ("Could not make the keyID from the public value\n");
1283 return 909;
1284 }
1285 foundPrivKey = PK11_FindKeyByKeyID(privKey->pkcs11Slot, keyID, &pwdata);
1286 if (foundPrivKey == NULL) {
1287 printf ("Could not find the private key corresponding to the public"
1288 " value.\n");
1289 return 910;
1290 }
1291 rv = CMMF_POPODecKeyChallContDecryptChallenge(chalContent, i,
1292 foundPrivKey);
1293 if (rv != SECSuccess) {
1294 printf ("Could not decrypt the challenge at index %d\n", i);
1295 return 911;
1296 }
1297 rv = CMMF_POPODecKeyChallContentGetRandomNumber(chalContent, i,
1298 &retrieved);
1299 if (rv != SECSuccess) {
1300 printf ("Could not get the random number from the challenge at "
1301 "index %d\n", i);
1302 return 912;
1303 }
1304 if (retrieved != randomNums[i]) {
1305 printf ("Retrieved the number (%ld), expected (%ld)\n", retrieved,
1306 randomNums[i]);
1307 return 913;
1308 }
1309 }
1310 CMMF_DestroyPOPODecKeyChallContent(chalContent);
1311 PR_snprintf(filePath, PATH_LEN, "%s/POPODecKeyRespContent.der",
1312 configdir);
1313 fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
1314 0666);
1315 if (fileDesc == NULL) {
1316 printf ("Could not open file %s\n", filePath);
1317 return 914;
1318 }
1319 rv = CMMF_EncodePOPODecKeyRespContent(randomNums, numChallengesSet,
1320 WriteItOut, fileDesc);
1321 PR_Close(fileDesc);
1322 if (rv != 0) {
1323 printf ("Could not encode the POPODecKeyRespContent\n");
1324 return 915;
1325 }
1326 GetBitsFromFile(filePath, &DecKeyChallBits);
1327 respContent =
1328 CMMF_CreatePOPODecKeyRespContentFromDER((const char*)DecKeyChallBits.data,
1329 DecKeyChallBits.len);
1330 if (respContent == NULL) {
1331 printf ("Could not decode the contents of the file %s\n", filePath);
1332 return 916;
1333 }
1334 numChallengesFound =
1335 CMMF_POPODecKeyRespContentGetNumResponses(respContent);
1336 if (numChallengesFound != numChallengesSet) {
1337 printf ("Number of responses found (%d) does not match the number "
1338 "of challenges set (%d)\n",
1339 numChallengesFound, numChallengesSet);
1340 return 917;
1341 }
1342 for (i=0; i<numChallengesSet; i++) {
1343 rv = CMMF_POPODecKeyRespContentGetResponse(respContent, i, &retrieved);
1344 if (rv != SECSuccess) {
1345 printf ("Could not retrieve the response at index %d\n", i);
1346 return 918;
1347 }
1348 if (retrieved != randomNums[i]) {
1349 printf ("Retrieved the number (%ld), expected (%ld)\n", retrieved,
1350 randomNums[i]);
1351 return 919;
1352 }
1354 }
1355 CMMF_DestroyPOPODecKeyRespContent(respContent);
1356 return 0;
1357 }
1359 int
1360 MakeCertRequest(TESTKeyPair *pair, CRMFPOPChoice inPOPChoice, long inRequestID)
1361 {
1362 int irv;
1364 /* Generate a key pair and a cert request for it. */
1365 irv = CreateCertRequest(pair, inRequestID);
1366 if (irv != 0 || pair->certReq == NULL) {
1367 goto loser;
1368 }
1370 pair->certReqMsg = CRMF_CreateCertReqMsg();
1371 if (!pair->certReqMsg) {
1372 irv = 999;
1373 goto loser;
1374 }
1375 /* copy certReq into certReqMsg */
1376 CRMF_CertReqMsgSetCertRequest(pair->certReqMsg, pair->certReq);
1377 irv = AddProofOfPossession(pair, inPOPChoice);
1378 loser:
1379 return irv;
1380 }
1382 int
1383 DestroyPairReqAndMsg(TESTKeyPair *pair)
1384 {
1385 SECStatus rv = SECSuccess;
1386 int irv = 0;
1388 if (pair->certReq) {
1389 rv = CRMF_DestroyCertRequest(pair->certReq);
1390 pair->certReq = NULL;
1391 if (rv != SECSuccess) {
1392 printf ("Error when destroying cert request.\n");
1393 irv = 100;
1394 }
1395 }
1396 if (pair->certReqMsg) {
1397 rv = CRMF_DestroyCertReqMsg(pair->certReqMsg);
1398 pair->certReqMsg = NULL;
1399 if (rv != SECSuccess) {
1400 printf ("Error when destroying cert request msg.\n");
1401 if (!irv)
1402 irv = 101;
1403 }
1404 }
1405 return irv;
1406 }
1408 int
1409 DestroyPair(TESTKeyPair *pair)
1410 {
1411 int irv = 0;
1413 if (pair->pubKey) {
1414 SECKEY_DestroyPublicKey(pair->pubKey);
1415 pair->pubKey = NULL;
1416 }
1417 if (pair->privKey) {
1418 SECKEY_DestroyPrivateKey(pair->privKey);
1419 pair->privKey = NULL;
1420 }
1421 DestroyPairReqAndMsg(pair);
1422 return irv;
1423 }
1425 int
1426 DoCRMFRequest(TESTKeyPair *signPair, TESTKeyPair *cryptPair)
1427 {
1428 int irv, tirv = 0;
1430 /* Generate a key pair and a cert request for it. */
1431 irv = MakeCertRequest(signPair, crmfSignature, 0x0f020304);
1432 if (irv != 0 || signPair->certReq == NULL) {
1433 goto loser;
1434 }
1436 if (!doingDSA) {
1437 irv = MakeCertRequest(cryptPair, crmfKeyAgreement, 0x0f050607);
1438 if (irv != 0 || cryptPair->certReq == NULL) {
1439 goto loser;
1440 }
1441 }
1443 /* encode the cert request messages into a unified request message.
1444 ** leave it in a file with a fixed name. :(
1445 */
1446 irv = Encode(signPair->certReqMsg, cryptPair->certReqMsg);
1448 loser:
1449 if (signPair->certReq) {
1450 tirv = DestroyPairReqAndMsg(signPair);
1451 if (tirv && !irv)
1452 irv = tirv;
1453 }
1454 if (cryptPair->certReq) {
1455 tirv = DestroyPairReqAndMsg(cryptPair);
1456 if (tirv && !irv)
1457 irv = tirv;
1458 }
1459 return irv;
1460 }
1462 void
1463 Usage (void)
1464 {
1465 printf ("Usage:\n"
1466 "\tcrmftest -d [Database Directory] -p [Personal Cert]\n"
1467 "\t -e [Encrypter] -s [CA Certificate] [-P password]\n\n"
1468 "\t [crmf] [dsa] [decode] [cmmf] [recover] [challenge]\n"
1469 "\t [-f password_file]\n"
1470 "Database Directory\n"
1471 "\tThis is the directory where the key3.db, cert7.db, and\n"
1472 "\tsecmod.db files are located. This is also the directory\n"
1473 "\twhere the program will place CRMF/CMMF der files\n"
1474 "Personal Cert\n"
1475 "\tThis is the certificate that already exists in the cert\n"
1476 "\tdatabase to use while encoding the response. The private\n"
1477 "\tkey associated with the certificate must also exist in the\n"
1478 "\tkey database.\n"
1479 "Encrypter\n"
1480 "\tThis is the certificate to use when encrypting the the \n"
1481 "\tkey recovery response. The private key for this cert\n"
1482 "\tmust also be present in the key database.\n"
1483 "CA Certificate\n"
1484 "\tThis is the nickname of the certificate to use as the\n"
1485 "\tCA when doing all of the encoding.\n");
1486 }
1488 #define TEST_MAKE_CRMF_REQ 0x0001
1489 #define TEST_USE_DSA 0x0002
1490 #define TEST_DECODE_CRMF_REQ 0x0004
1491 #define TEST_DO_CMMF_STUFF 0x0008
1492 #define TEST_KEY_RECOVERY 0x0010
1493 #define TEST_CHALLENGE_RESPONSE 0x0020
1495 SECStatus
1496 parsePositionalParam(const char * arg, PRUint32 *flags)
1497 {
1498 if (!strcmp(arg, "crmf")) {
1499 *flags |= TEST_MAKE_CRMF_REQ;
1500 } else if (!strcmp(arg, "dsa")) {
1501 *flags |= TEST_MAKE_CRMF_REQ | TEST_USE_DSA;
1502 doingDSA = PR_TRUE;
1503 } else if (!strcmp(arg, "decode")) {
1504 *flags |= TEST_DECODE_CRMF_REQ;
1505 } else if (!strcmp(arg, "cmmf")) {
1506 *flags |= TEST_DO_CMMF_STUFF;
1507 } else if (!strcmp(arg, "recover")) {
1508 *flags |= TEST_KEY_RECOVERY;
1509 } else if (!strcmp(arg, "challenge")) {
1510 *flags |= TEST_CHALLENGE_RESPONSE;
1511 } else {
1512 printf("unknown positional paremeter: %s\n", arg);
1513 return SECFailure;
1514 }
1515 return SECSuccess;
1516 }
1518 /* it's not clear, in some cases, whether the desired key is from
1519 ** the sign pair or the crypt pair, so we're guessing in some places.
1520 ** This define serves to remind us of the places where we're guessing.
1521 */
1522 #define WHICH_KEY cryptPair
1524 int
1525 main(int argc, char **argv)
1526 {
1527 TESTKeyPair signPair, cryptPair;
1528 PLOptState *optstate;
1529 PLOptStatus status;
1530 char *password = NULL;
1531 char *pwfile = NULL;
1532 int irv = 0;
1533 PRUint32 flags = 0;
1534 SECStatus rv;
1535 PRBool nssInit = PR_FALSE;
1536 PRBool pArg = PR_FALSE;
1537 PRBool eArg = PR_FALSE;
1538 PRBool sArg = PR_FALSE;
1539 PRBool PArg = PR_FALSE;
1541 memset( &signPair, 0, sizeof signPair);
1542 memset( &cryptPair, 0, sizeof cryptPair);
1543 printf ("\ncrmftest v1.0\n");
1544 optstate = PL_CreateOptState(argc, argv, "d:p:e:s:P:f:");
1545 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
1546 switch (optstate->option) {
1547 case 'd':
1548 configdir = PORT_Strdup(optstate->value);
1549 rv = NSS_Init(configdir);
1550 if (rv != SECSuccess) {
1551 printf ("NSS_Init (-d) failed\n");
1552 return 101;
1553 }
1554 nssInit = PR_TRUE;
1555 break;
1556 case 'p':
1557 personalCert = PORT_Strdup(optstate->value);
1558 if (personalCert == NULL) {
1559 printf ("-p failed\n");
1560 return 603;
1561 }
1562 pArg = PR_TRUE;
1563 break;
1564 case 'e':
1565 recoveryEncrypter = PORT_Strdup(optstate->value);
1566 if (recoveryEncrypter == NULL) {
1567 printf ("-e failed\n");
1568 return 602;
1569 }
1570 eArg = PR_TRUE;
1571 break;
1572 case 's':
1573 caCertName = PORT_Strdup(optstate->value);
1574 if (caCertName == NULL) {
1575 printf ("-s failed\n");
1576 return 604;
1577 }
1578 sArg = PR_TRUE;
1579 break;
1580 case 'P':
1581 password = PORT_Strdup(optstate->value);
1582 if (password == NULL) {
1583 printf ("-P failed\n");
1584 return 606;
1585 }
1586 pwdata.source = PW_PLAINTEXT;
1587 pwdata.data = password;
1588 PArg = PR_TRUE;
1589 break;
1590 case 'f':
1591 pwfile = PORT_Strdup(optstate->value);
1592 if (pwfile == NULL) {
1593 printf ("-f failed\n");
1594 return 607;
1595 }
1596 pwdata.source = PW_FROMFILE;
1597 pwdata.data = pwfile;
1598 break;
1599 case 0: /* positional parameter */
1600 rv = parsePositionalParam(optstate->value, &flags);
1601 if (rv) {
1602 printf ("bad positional parameter.\n");
1603 return 605;
1604 }
1605 break;
1606 default:
1607 Usage();
1608 return 601;
1609 }
1610 }
1611 PL_DestroyOptState(optstate);
1612 if (status == PL_OPT_BAD || !nssInit) {
1613 Usage();
1614 return 600;
1615 }
1616 if (!flags)
1617 flags = ~ TEST_USE_DSA;
1618 db = CERT_GetDefaultCertDB();
1619 InitPKCS11();
1621 if (flags & TEST_MAKE_CRMF_REQ) {
1622 printf("Generating CRMF request\n");
1623 irv = DoCRMFRequest(&signPair, &cryptPair);
1624 if (irv)
1625 goto loser;
1626 }
1628 if (flags & TEST_DECODE_CRMF_REQ) {
1629 printf("Decoding CRMF request\n");
1630 irv = Decode();
1631 if (irv != 0) {
1632 printf("Error while decoding\n");
1633 goto loser;
1634 }
1635 }
1637 if (flags & TEST_DO_CMMF_STUFF) {
1638 printf("Doing CMMF Stuff\n");
1639 if ((irv = DoCMMFStuff()) != 0) {
1640 printf ("CMMF tests failed.\n");
1641 goto loser;
1642 }
1643 }
1645 if (flags & TEST_KEY_RECOVERY) {
1646 /* Requires some other options be set.
1647 ** Once we know exactly what hey are, test for them here.
1648 */
1649 printf("Doing Key Recovery\n");
1650 irv = DoKeyRecovery(WHICH_KEY.privKey);
1651 if (irv != 0) {
1652 printf ("Error doing key recovery\n");
1653 goto loser;
1654 }
1655 }
1657 if (flags & TEST_CHALLENGE_RESPONSE) {
1658 printf("Doing Challenge / Response\n");
1659 irv = DoChallengeResponse(WHICH_KEY.privKey, WHICH_KEY.pubKey);
1660 if (irv != 0) {
1661 printf ("Error doing challenge-response\n");
1662 goto loser;
1663 }
1664 }
1665 printf ("Exiting successfully!!!\n\n");
1666 irv = 0;
1668 loser:
1669 DestroyPair(&signPair);
1670 DestroyPair(&cryptPair);
1671 rv = NSS_Shutdown();
1672 if (rv) {
1673 printf("NSS_Shutdown did not shutdown cleanly!\n");
1674 }
1675 PORT_Free(configdir);
1676 if (irv)
1677 printf("crmftest returning %d\n", irv);
1678 return irv;
1679 }