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