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, &params, &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 = &notBefore;
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