Back to index

lightning-sunbird  0.9+nobinonly
testcrmf.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  * This program does 5 separate functions.  By default, it does them all.
00039  * It can be told to do any subset of them.
00040  * It does them in this order:
00041  *
00042  * 1. Generate file of CRMF cert requests.
00043  *     Generates 2 keys pairs, one for signing, one for encryption.
00044  *     Can generate RSA or DSA (XXX - DSA is only useful for signing).
00045  *     Generate a cert request for each of the two public keys.
00046  *     Generate a single CRMF cert request message that requests both certs.
00047  *     Leave the generated CRMF request message in file
00048  *         configdir/CertReqMessages.der
00049  *
00050  * 2. Decode CRMF Request(s) Message.
00051  *     Reads in the file   configdir/CertReqMessages.der
00052  *     (either generated by step 1 above, or user supplied).
00053  *     Decodes it.  NOTHING MORE.  Drops these decoded results on the floor.
00054  *     The CMMF response (below) contains a completely unrelated cert.  :-(
00055  *
00056  * 3. CMMF "Stuff".
00057  *  a)  Generates a CMMF response, containing a single cert chain, as if 
00058  *     it was a response to a received CRMF request.  But the cert is 
00059  *     simply a user cert from the user's local soft token, whose 
00060  *     nickname is given in the -p option.  The CMMF response has no
00061  *     relationship to the request generated above.  The CMMF message
00062  *     is placed in configdir/CertRepContent.der.
00063  *  b)  Decodes the newly generated CMMF response found in file
00064  *     configdir/CertRepContent.der and discards the result.  8-/
00065  *  c)  Generate a CMMF Key Escrow message
00066  *      needs 2 nicknames: 
00067  *      It takes the public and private keys for the cert identified
00068  *      by -p nickname, and wraps them with a sym key that is in turn
00069  *      wrapped with the pubkey in the CA cert, whose nickname is 
00070  *      given with the -s option.
00071  *      Store the message in configdir/KeyRecRepContent.der
00072  *  d)  Decode the CMMF Key Escrow message generated just above.
00073  *      Get it from file configdir/KeyRecRepContent.der
00074  *      This is just a decoder test.  Results are discarded.
00075  *
00076  * 4. Key Recovery
00077  *     This code does not yet compile, and what it was intended to do
00078  *     has not been fully determined.
00079  *
00080  * 5. Challenge/Response.
00081  *     Haven't analyzed this code yet.
00082  *
00083  *
00084  */
00085 
00086 /* KNOWN BUGS:
00087 ** 1. generates BOTH signing and encryption cert requests, even for DSA keys.
00088 **
00089 ** 2. Does not verify the siganture in the "Proof of Posession" in the
00090 **     decoded cert requests.  It only checks syntax of the POP.
00091 ** 3. CMMF "Stuff" should be broken up into separate steps, each of 
00092 **     which may be optionally selected.
00093 */
00094 
00095 #include <stdio.h>
00096 #include "nspr.h"
00097 #include "nss.h"
00098 #include "crmf.h"
00099 #include "secerr.h"
00100 #include "pk11func.h"
00101 #include "key.h"
00102 #include "cmmf.h"
00103 #include "plgetopt.h"
00104 #include "secutil.h"
00105 #include "pk11pqg.h"
00106 
00107 #if 0
00108 #include "pkcs11.h"
00109 #include "secmod.h"
00110 #include "secmodi.h"
00111 #include "pqggen.h"
00112 #include "secmod.h"
00113 #include "secmodi.h"
00114 #include "pkcs11.h"
00115 #include "secitem.h"
00116 #include "secasn1.h"
00117 #include "sechash.h"
00118 #endif
00119 
00120 #define MAX_KEY_LEN 512
00121 #define PATH_LEN    150
00122 #define BUFF_SIZE   150
00123 #define UID_BITS    800
00124 #define BPB           8
00125 #define CRMF_FILE   "CertReqMessages.der"
00126 
00127 PRTime notBefore;
00128 char *personalCert      = NULL;
00129 char *recoveryEncrypter = NULL;
00130 char *caCertName        = NULL;
00131 static secuPWData pwdata = { PW_NONE, 0 };
00132 char *configdir;
00133 PRBool doingDSA         = PR_FALSE;
00134 
00135 CERTCertDBHandle *db;
00136 
00137 typedef struct {
00138     SECKEYPrivateKey *privKey;
00139     SECKEYPublicKey  *pubKey;
00140     CRMFCertRequest  *certReq;
00141     CRMFCertReqMsg   *certReqMsg;
00142 } TESTKeyPair;
00143 
00144 void 
00145 debug_test(SECItem *src, char *filePath)
00146 {
00147     PRFileDesc *fileDesc;
00148 
00149     fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 
00150                      0666);
00151     if (fileDesc == NULL) {
00152         printf ("Could not cretae file %s.\n", filePath);
00153        return;
00154     }
00155     PR_Write(fileDesc, src->data, src->len);
00156     
00157 }
00158 
00159 SECStatus
00160 get_serial_number(long *dest)
00161 {
00162    SECStatus   rv;
00163 
00164    if (dest == NULL) {
00165        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00166        return SECFailure;
00167    }
00168     rv = PK11_GenerateRandom((unsigned char *)dest, sizeof(long));
00169     /* make serial number positive */
00170     if (*dest < 0L)
00171        *dest = - *dest;
00172     return SECSuccess;
00173 }
00174 
00175 PK11RSAGenParams *
00176 GetRSAParams(void) 
00177 {
00178     PK11RSAGenParams *rsaParams;
00179 
00180     rsaParams = PORT_ZNew(PK11RSAGenParams);
00181 
00182     if (rsaParams == NULL)
00183       return NULL;
00184 
00185     rsaParams->keySizeInBits = MAX_KEY_LEN;
00186     rsaParams->pe = 0x10001;
00187     
00188     return rsaParams;
00189     
00190 }
00191 
00192 PQGParams*
00193 GetDSAParams(void)
00194 {
00195     PQGParams *params = NULL;
00196     PQGVerify *vfy = NULL;
00197 
00198     SECStatus  rv;
00199 
00200     rv = PK11_PQG_ParamGen(0, &params, &vfy);
00201     if (rv != SECSuccess) {
00202         return NULL;
00203     }
00204     PK11_PQG_DestroyVerify(vfy);
00205     return params;
00206 }
00207 
00208 /* Generate a key pair, and then generate a subjectPublicKeyInfo
00209 ** for the public key in that pair.  return all 3.
00210 */
00211 CERTSubjectPublicKeyInfo *
00212 GetSubjectPubKeyInfo(TESTKeyPair *pair)
00213 {
00214     CERTSubjectPublicKeyInfo *spki       = NULL;
00215     SECKEYPrivateKey         *privKey    = NULL;
00216     SECKEYPublicKey          *pubKey     = NULL;
00217     PK11SlotInfo             *keySlot    = NULL;
00218     
00219     keySlot = PK11_GetInternalKeySlot();
00220     PK11_Authenticate(keySlot, PR_FALSE, &pwdata);
00221 
00222 
00223     if (!doingDSA) {
00224        PK11RSAGenParams *rsaParams = GetRSAParams();
00225        if (rsaParams == NULL) {
00226            PK11_FreeSlot(keySlot);
00227            return NULL;
00228        }
00229        privKey = PK11_GenerateKeyPair(keySlot, CKM_RSA_PKCS_KEY_PAIR_GEN,
00230                                    (void*)rsaParams, &pubKey, PR_FALSE,
00231                                    PR_FALSE, &pwdata);
00232     } else {
00233        PQGParams *dsaParams = GetDSAParams();
00234        if (dsaParams == NULL) {
00235            PK11_FreeSlot(keySlot);
00236            return NULL;
00237        }
00238        privKey = PK11_GenerateKeyPair(keySlot, CKM_DSA_KEY_PAIR_GEN,
00239                                    (void*)dsaParams, &pubKey, PR_FALSE,
00240                                    PR_FALSE, &pwdata);
00241     }
00242     PK11_FreeSlot(keySlot);
00243     if (privKey == NULL || pubKey == NULL) {
00244         if (pubKey) {
00245            SECKEY_DestroyPublicKey(pubKey);
00246        }
00247        if (privKey) {
00248            SECKEY_DestroyPrivateKey(privKey);
00249        }
00250        return NULL;
00251     }
00252 
00253     spki = SECKEY_CreateSubjectPublicKeyInfo(pubKey);
00254     pair->privKey = privKey;
00255     pair->pubKey  = pubKey;
00256     return spki;
00257 }
00258 
00259 
00260 SECStatus
00261 InitPKCS11(void)
00262 {
00263     PK11SlotInfo *keySlot;
00264 
00265     PK11_SetPasswordFunc(SECU_GetModulePassword);
00266 
00267     keySlot    = PK11_GetInternalKeySlot();
00268     
00269     if (PK11_NeedUserInit(keySlot) && PK11_NeedLogin(keySlot)) {
00270         if (SECU_ChangePW(keySlot, NULL, NULL) != SECSuccess) {
00271            printf ("Initializing the PINs failed.\n");
00272            return SECFailure;
00273        }
00274     }
00275 
00276     PK11_FreeSlot(keySlot);
00277     return SECSuccess;
00278 }
00279 
00280 
00281 void 
00282 WriteItOut (void *arg, const char *buf, unsigned long len)
00283 {
00284     PRFileDesc *fileDesc = (PRFileDesc*)arg;
00285 
00286     PR_Write(fileDesc, (void*)buf, len);
00287 }
00288 
00289 
00290 
00291 CRMFCertExtCreationInfo*
00292 GetExtensions(void)
00293 {
00294     unsigned char keyUsage[4] = { 0x03, 0x02, 0x07, KU_DIGITAL_SIGNATURE };
00295                             /* What are these magic numbers? */
00296     SECItem data = { 0, NULL, 0 };
00297     CRMFCertExtension *extension; 
00298     CRMFCertExtCreationInfo *extInfo =
00299            PORT_ZNew(CRMFCertExtCreationInfo);
00300 
00301     data.data = keyUsage;
00302     data.len = sizeof keyUsage;
00303 
00304 
00305     extension = 
00306            CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, PR_FALSE, &data);
00307     if (extension && extInfo) {
00308        extInfo->numExtensions = 1;
00309        extInfo->extensions    = PORT_ZNewArray(CRMFCertExtension*, 1);
00310        extInfo->extensions[0] = extension;
00311     }
00312     return extInfo;
00313 }
00314 
00315 void
00316 FreeExtInfo(CRMFCertExtCreationInfo *extInfo)
00317 {
00318     int i;
00319     
00320     for (i=0; i<extInfo->numExtensions; i++) {
00321         CRMF_DestroyCertExtension(extInfo->extensions[i]);
00322     }
00323     PORT_Free(extInfo->extensions);
00324     PORT_Free(extInfo);
00325 }
00326 
00327 int
00328 InjectCertName( CRMFCertRequest       * certReq,
00329                CRMFCertTemplateField   inTemplateField,
00330               const char            * inNameString)
00331 {
00332     char      * nameStr;
00333     CERTName  * name;
00334     int         irv   = 0;
00335 
00336     nameStr = PORT_Strdup(inNameString);
00337     if (!nameStr) 
00338        return 5;
00339     name = CERT_AsciiToName(nameStr);
00340     if (name == NULL) {
00341         printf ("Could not create CERTName structure from %s.\n", nameStr);
00342        irv = 5;
00343        goto finish;
00344     }
00345 
00346     irv = CRMF_CertRequestSetTemplateField(certReq, inTemplateField, (void*)name);
00347     if (irv != SECSuccess) {
00348         printf ("Could not add name to cert template\n");
00349        irv = 6;
00350     }
00351 
00352 finish:
00353     PORT_Free(nameStr);
00354     if (name)
00355        CERT_DestroyName(name);
00356     return irv;
00357 }
00358 
00359 int
00360 CreateCertRequest(TESTKeyPair *pair, long inRequestID)
00361 {
00362     CERTCertificate         * caCert;
00363     CERTSubjectPublicKeyInfo *spki;
00364     CRMFCertExtCreationInfo * extInfo;
00365     CRMFCertRequest         * certReq;
00366     CRMFEncryptedKey        * encKey;
00367     CRMFPKIArchiveOptions   * pkiArchOpt;
00368     SECAlgorithmID          * algID;
00369     long                      serialNumber;
00370     long                      version       = 3;
00371     SECStatus                 rv;
00372     CRMFValidityCreationInfo  validity;
00373     unsigned char             UIDbuf[UID_BITS / BPB];
00374     SECItem                   issuerUID  = { siBuffer, UIDbuf, UID_BITS };
00375     SECItem                   subjectUID = { siBuffer, UIDbuf, UID_BITS };
00376                                                                /* len in bits */
00377 
00378     pair->certReq = NULL;
00379     certReq = CRMF_CreateCertRequest(inRequestID);
00380     if (certReq == NULL) {
00381         printf ("Could not initialize a certificate request.\n");
00382        return 1;
00383     }
00384 
00385     /* set to version 3 */
00386     rv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, 
00387                                           (void*)(&version));
00388     if (rv != SECSuccess) {
00389         printf("Could not add the version number to the "
00390               "Certificate Request.\n");
00391        CRMF_DestroyCertRequest(certReq);
00392        return 2;
00393     }
00394 
00395     /* set serial number */
00396     if (get_serial_number(&serialNumber) != SECSuccess) {
00397         printf ("Could not generate a serial number for cert request.\n");
00398        CRMF_DestroyCertRequest(certReq);
00399        return 3;
00400     }
00401     rv = CRMF_CertRequestSetTemplateField (certReq, crmfSerialNumber, 
00402                                   (void*)(&serialNumber));
00403     if (rv != SECSuccess) {
00404         printf ("Could not add serial number to certificate template\n.");
00405        CRMF_DestroyCertRequest(certReq);
00406        return 4;
00407     }
00408 
00409     /* Set issuer name */
00410     rv = InjectCertName(certReq, crmfIssuer, 
00411                      "CN=mozilla CA Shack,O=Information Systems");
00412     if (rv) {
00413         printf ("Could not add issuer to cert template\n");
00414        CRMF_DestroyCertRequest(certReq);
00415        return 5;
00416     }
00417 
00418     /* Set Subject Name */
00419     rv = InjectCertName(certReq, crmfSubject, 
00420                      "CN=mozilla CA Shack ID,O=Engineering,C=US");
00421     if (rv) {
00422         printf ("Could not add Subject to cert template\n");
00423        CRMF_DestroyCertRequest(certReq);
00424        return 5;
00425     }
00426 
00427     /* Set Algorithm ID */
00428     algID = PK11_CreatePBEAlgorithmID(SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC,
00429                                    1, NULL);
00430     if (algID == NULL) {
00431         printf ("Couldn't create algorithm ID\n");
00432        CRMF_DestroyCertRequest(certReq);
00433        return 9;
00434     }
00435     rv = CRMF_CertRequestSetTemplateField(certReq, crmfSigningAlg, (void*)algID);
00436     SECOID_DestroyAlgorithmID(algID, PR_TRUE);
00437     if (rv != SECSuccess) {
00438         printf ("Could not add the signing algorithm to the cert template.\n");
00439        CRMF_DestroyCertRequest(certReq);
00440        return 10;
00441     }
00442 
00443     /* Set Validity Dates */
00444     validity.notBefore = &notBefore;
00445     validity.notAfter  = NULL;
00446     notBefore = PR_Now();
00447     rv = CRMF_CertRequestSetTemplateField(certReq, crmfValidity,(void*)(&validity));
00448     if (rv != SECSuccess) {
00449         printf ("Could not add validity to cert template\n");
00450        CRMF_DestroyCertRequest(certReq);
00451        return 11;
00452     }
00453 
00454     /* Generate a key pair and Add the spki to the request */
00455     spki = GetSubjectPubKeyInfo(pair);
00456     if (spki == NULL) {
00457         printf ("Could not create a Subject Public Key Info to add\n");
00458        CRMF_DestroyCertRequest(certReq);
00459        return 12;
00460     }
00461     rv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, (void*)spki);
00462     SECKEY_DestroySubjectPublicKeyInfo(spki);
00463     if (rv != SECSuccess) {
00464         printf ("Could not add the public key to the template\n");
00465        CRMF_DestroyCertRequest(certReq);
00466        return 13;
00467     }
00468     
00469     /* Set the requested isser Unique ID */
00470     PK11_GenerateRandom(UIDbuf, sizeof UIDbuf);
00471     CRMF_CertRequestSetTemplateField(certReq,crmfIssuerUID,  (void*)&issuerUID);
00472 
00473     /* Set the requested Subject Unique ID */
00474     PK11_GenerateRandom(UIDbuf, sizeof UIDbuf);
00475     CRMF_CertRequestSetTemplateField(certReq,crmfSubjectUID, (void*)&subjectUID);
00476 
00477     /* Add extensions - XXX need to understand these magic numbers */
00478     extInfo = GetExtensions();
00479     CRMF_CertRequestSetTemplateField(certReq, crmfExtension, (void*)extInfo);
00480     FreeExtInfo(extInfo);
00481 
00482     /* get the recipient CA's cert */
00483     caCert = CERT_FindCertByNickname(db, caCertName);
00484     if (caCert == NULL) {
00485         printf ("Could not find the certificate for %s\n", caCertName);
00486         CRMF_DestroyCertRequest(certReq);
00487        return 50;
00488     }
00489     encKey = CRMF_CreateEncryptedKeyWithEncryptedValue(pair->privKey, caCert);
00490     CERT_DestroyCertificate(caCert);
00491     if (encKey == NULL) {
00492         printf ("Could not create Encrypted Key with Encrypted Value.\n");
00493        return 14;
00494     }
00495     pkiArchOpt = CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encKey);
00496     CRMF_DestroyEncryptedKey(encKey);
00497     if (pkiArchOpt == NULL) {
00498         printf ("Could not create PKIArchiveOptions.\n");
00499        return 15;
00500     }
00501     rv  = CRMF_CertRequestSetPKIArchiveOptions(certReq, pkiArchOpt);
00502     CRMF_DestroyPKIArchiveOptions(pkiArchOpt);
00503     if (rv != SECSuccess) {
00504         printf ("Could not add the PKIArchiveControl to Cert Request.\n");
00505        return 16;
00506     }
00507     pair->certReq = certReq;
00508     return 0;
00509 }
00510 
00511 int 
00512 Encode(CRMFCertReqMsg *inCertReq1, CRMFCertReqMsg *inCertReq2)
00513 {   
00514     PRFileDesc     *fileDesc;
00515     SECStatus       rv;
00516     int             irv = 0;
00517     CRMFCertReqMsg *msgArr[3];
00518     char            filePath[PATH_LEN];
00519 
00520     PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, CRMF_FILE);
00521     fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 
00522                      0666);
00523     if (fileDesc == NULL) {
00524         printf ("Could not open file %s\n", filePath);
00525        irv = 14;
00526        goto finish;
00527     }
00528     msgArr[0] = inCertReq1;
00529     msgArr[1] = inCertReq2;
00530     msgArr[2] = NULL;
00531     rv = CRMF_EncodeCertReqMessages(msgArr, WriteItOut, (void*)fileDesc);
00532     if (rv != SECSuccess) {
00533         printf ("An error occurred while encoding.\n");
00534        irv = 15;
00535     }
00536 finish:
00537     PR_Close(fileDesc);
00538     return irv;
00539 }
00540 
00541 int
00542 AddProofOfPossession(TESTKeyPair *pair,
00543                    CRMFPOPChoice inPOPChoice)
00544 {
00545 
00546     switch(inPOPChoice){
00547     case crmfSignature:
00548       CRMF_CertReqMsgSetSignaturePOP(pair->certReqMsg, pair->privKey, 
00549                                      pair->pubKey, NULL, NULL, &pwdata);
00550       break;
00551     case crmfRAVerified:
00552       CRMF_CertReqMsgSetRAVerifiedPOP(pair->certReqMsg);
00553       break;
00554     case crmfKeyEncipherment:
00555       CRMF_CertReqMsgSetKeyEnciphermentPOP(pair->certReqMsg,
00556                                       crmfSubsequentMessage, 
00557                                       crmfChallengeResp, NULL);
00558       break;
00559     case crmfKeyAgreement:
00560       {
00561        SECItem pendejo;
00562        unsigned char lame[] = { 0xf0, 0x0f, 0xf0, 0x0f, 0xf0 };
00563 
00564        pendejo.data = lame;
00565        pendejo.len  = 5;
00566        
00567        CRMF_CertReqMsgSetKeyAgreementPOP(pair->certReqMsg, crmfThisMessage, 
00568                                      crmfNoSubseqMess, &pendejo);
00569       }
00570       break;
00571     default:
00572       return 1;
00573     }
00574     return 0;
00575 }
00576 
00577 
00578 int
00579 Decode(void)
00580 {
00581     PRFileDesc          *fileDesc;
00582     CRMFCertReqMsg      *certReqMsg;
00583     CRMFCertRequest     *certReq;
00584     CRMFCertReqMessages *certReqMsgs;
00585     SECStatus            rv;
00586     int                  numMsgs, i;
00587     long                 lame;
00588     CRMFGetValidity      validity        = {NULL, NULL};
00589     SECItem              item            = { siBuffer, NULL, 0 };
00590     char                 filePath[PATH_LEN];
00591 
00592     PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, CRMF_FILE);
00593     fileDesc = PR_Open(filePath, PR_RDONLY, 0644);
00594     if (fileDesc == NULL) {
00595         printf ("Could not open file %s\n", filePath);
00596        return 214;
00597     }
00598     rv = SECU_FileToItem(&item, fileDesc);
00599     PR_Close(fileDesc);
00600     if (rv != SECSuccess) {
00601        return 215;
00602     }
00603 
00604     certReqMsgs = CRMF_CreateCertReqMessagesFromDER((char *)item.data, item.len);
00605     if (certReqMsgs == NULL) {
00606         printf ("Error decoding CertReqMessages.\n");
00607        return 202;
00608     }
00609     numMsgs = CRMF_CertReqMessagesGetNumMessages(certReqMsgs);
00610     if (numMsgs <= 0) {
00611         printf ("WARNING: The DER contained %d messages.\n", numMsgs);
00612     }
00613     for (i=0; i < numMsgs; i++) {
00614        SECStatus rv;
00615        printf("crmftest: Processing cert request %d\n", i);
00616         certReqMsg = CRMF_CertReqMessagesGetCertReqMsgAtIndex(certReqMsgs, i);
00617        if (certReqMsg == NULL) {
00618            printf ("ERROR: Could not access the message at index %d of %s\n",
00619                   i, filePath);
00620        }
00621        rv = CRMF_CertReqMsgGetID(certReqMsg, &lame);
00622        if (rv) {
00623            SECU_PrintError("crmftest", "CRMF_CertReqMsgGetID");
00624        }
00625        certReq = CRMF_CertReqMsgGetCertRequest(certReqMsg);
00626        if (!certReq) {
00627            SECU_PrintError("crmftest", "CRMF_CertReqMsgGetCertRequest");
00628        }
00629        rv = CRMF_CertRequestGetCertTemplateValidity(certReq, &validity);
00630        if (rv) {
00631            SECU_PrintError("crmftest", "CRMF_CertRequestGetCertTemplateValidity");
00632        }
00633        if (!validity.notBefore) {
00634            /* We encoded a notBefore, so somthing's wrong if it's not here. */
00635            printf("ERROR: Validity period notBefore date missing.\n");
00636        }
00637        /* XXX It's all parsed now.  We probably should DO SOMETHING with it.
00638        ** But nope.  We just throw it all away.
00639        ** Maybe this was intended to be no more than a decoder test.
00640        */
00641        CRMF_DestroyGetValidity(&validity);
00642        CRMF_DestroyCertRequest(certReq);
00643        CRMF_DestroyCertReqMsg(certReqMsg);
00644     }
00645     CRMF_DestroyCertReqMessages(certReqMsgs);
00646     SECITEM_FreeItem(&item, PR_FALSE);
00647     return 0;
00648 }
00649 
00650 int
00651 GetBitsFromFile(const char *filePath, SECItem *item)
00652 {
00653     PRFileDesc *fileDesc;
00654     SECStatus   rv;
00655 
00656     fileDesc = PR_Open(filePath, PR_RDONLY, 0644);
00657     if (fileDesc == NULL) {
00658         printf ("Could not open file %s\n", filePath);
00659        return 14;
00660     }
00661 
00662     rv = SECU_FileToItem(item, fileDesc);
00663     PR_Close(fileDesc);
00664 
00665     if (rv != SECSuccess) {
00666        item->data = NULL;
00667        item->len  = 0;
00668        return 15;
00669     }
00670     return 0;
00671 } 
00672 
00673 int
00674 DecodeCMMFCertRepContent(char *derFile)
00675 {
00676     CMMFCertRepContent *certRepContent;
00677     int                 irv             = 0;
00678     SECItem             fileBits   = { siBuffer, NULL, 0 };
00679 
00680     GetBitsFromFile(derFile, &fileBits);
00681     if (fileBits.data == NULL) {
00682         printf("Could not get bits from file %s\n", derFile);
00683         return 304;
00684     }
00685     certRepContent = CMMF_CreateCertRepContentFromDER(db, 
00686                                      (char*)fileBits.data, fileBits.len);
00687     if (certRepContent == NULL) {
00688         printf ("Error while decoding %s\n", derFile);
00689        irv = 303;
00690     } else {
00691        /* That was fun.  Now, let's throw it away!  */
00692        CMMF_DestroyCertRepContent(certRepContent);
00693     }
00694     SECITEM_FreeItem(&fileBits, PR_FALSE);
00695     return irv;
00696 }
00697 
00698 int
00699 EncodeCMMFCertReply(const char       *filePath, 
00700                     CERTCertificate  *cert,
00701                   CERTCertList     *list)
00702 {
00703     int                    rv                   = 0;
00704     SECStatus              srv;
00705     PRFileDesc            *fileDesc              = NULL;
00706     CMMFCertRepContent    *certRepContent = NULL;
00707     CMMFCertResponse      *certResp              = NULL;
00708     CMMFCertResponse      *certResponses[3];
00709 
00710     certResp = CMMF_CreateCertResponse(0xff123);
00711     CMMF_CertResponseSetPKIStatusInfoStatus(certResp, cmmfGranted);
00712 
00713     CMMF_CertResponseSetCertificate(certResp, cert);
00714 
00715     certResponses[0] = certResp;
00716     certResponses[1] = NULL;
00717     certResponses[2] = NULL;
00718 
00719     certRepContent = CMMF_CreateCertRepContent();
00720     CMMF_CertRepContentSetCertResponses(certRepContent, certResponses, 1);
00721 
00722     CMMF_CertRepContentSetCAPubs(certRepContent, list);
00723 
00724     fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 
00725                      0666);
00726     if (fileDesc == NULL) {
00727         printf ("Could not open file %s\n", filePath);
00728        rv = 400;
00729        goto finish;
00730     }
00731     
00732     srv = CMMF_EncodeCertRepContent(certRepContent, WriteItOut, 
00733                                 (void*)fileDesc);
00734     PR_Close(fileDesc);
00735     if (srv != SECSuccess) {
00736         printf ("CMMF_EncodeCertRepContent failed,\n");
00737        rv = 401;
00738     }
00739 finish:
00740     if (certRepContent) {
00741         CMMF_DestroyCertRepContent(certRepContent);
00742     }
00743     if (certResp) {
00744         CMMF_DestroyCertResponse(certResp);
00745     }
00746     return rv;
00747 }
00748 
00749 
00750 /* Extract the public key from the cert whose nickname is given. */
00751 int
00752 extractPubKeyFromNamedCert(const char * nickname, SECKEYPublicKey **pPubKey)
00753 {
00754     CERTCertificate  *caCert     = NULL;
00755     SECKEYPublicKey  *caPubKey   = NULL;
00756     int               rv         = 0;
00757 
00758     caCert = CERT_FindCertByNickname(db, (char *)nickname);
00759     if (caCert == NULL) {
00760         printf ("Could not get the certifcate for %s\n", caCertName);
00761        rv = 411;
00762        goto finish;
00763     }
00764     caPubKey = CERT_ExtractPublicKey(caCert);
00765     if (caPubKey == NULL) {
00766         printf ("Could not extract the public from the "
00767               "certificate for \n%s\n", caCertName);
00768        rv = 412;
00769     }
00770 finish:
00771     *pPubKey = caPubKey;
00772     CERT_DestroyCertificate(caCert);
00773     caCert = NULL;
00774     return rv;
00775 }
00776 
00777 int
00778 EncodeCMMFRecoveryMessage(const char * filePath, 
00779                     CERTCertificate  *cert,
00780                   CERTCertList     *list)
00781 {
00782     SECKEYPublicKey       *caPubKey              = NULL;
00783     SECKEYPrivateKey      *privKey               = NULL;
00784     CMMFKeyRecRepContent  *repContent            = NULL;
00785     PRFileDesc            *fileDesc;
00786     int                    rv                    = 0;
00787     SECStatus              srv;
00788 
00789     /* Extract the public key from the cert whose nickname is given in
00790     ** the -s option.
00791     */
00792     rv = extractPubKeyFromNamedCert( caCertName, &caPubKey);
00793     if (rv) 
00794        goto finish;
00795 
00796     repContent = CMMF_CreateKeyRecRepContent();
00797     if (repContent == NULL) {
00798         printf ("Could not allocate a CMMFKeyRecRepContent structure\n");
00799        rv = 407;
00800        goto finish;
00801     }
00802     srv = CMMF_KeyRecRepContentSetPKIStatusInfoStatus(repContent, 
00803                                                 cmmfGrantedWithMods);
00804     if (srv != SECSuccess) {
00805         printf ("Error trying to set PKIStatusInfo for "
00806               "CMMFKeyRecRepContent.\n");
00807        rv = 406;
00808        goto finish;
00809     }
00810     srv = CMMF_KeyRecRepContentSetNewSignCert(repContent, cert);
00811     if (srv != SECSuccess) {
00812         printf ("Error trying to set the new signing certificate for "
00813               "key recovery\n");
00814        rv = 408;
00815        goto finish;
00816     }
00817     srv = CMMF_KeyRecRepContentSetCACerts(repContent, list);
00818     if (srv != SECSuccess) {
00819         printf ("Errory trying to add the list of CA certs to the "
00820               "CMMFKeyRecRepContent structure.\n");
00821        rv = 409;
00822        goto finish;
00823     }
00824     privKey = PK11_FindKeyByAnyCert(cert, &pwdata);
00825     if (privKey == NULL) {
00826         printf ("Could not get the private key associated with the\n"
00827               "certificate %s\n", personalCert);
00828        rv = 410;
00829        goto finish;
00830     }
00831 
00832     srv = CMMF_KeyRecRepContentSetCertifiedKeyPair(repContent, cert, privKey,
00833                                              caPubKey);
00834     if (srv != SECSuccess) {
00835         printf ("Could not set the Certified Key Pair\n");
00836        rv = 413;
00837        goto finish;
00838     }
00839     fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 
00840                      0666);
00841     if (fileDesc == NULL) {
00842         printf ("Could not open file %s\n", filePath);
00843        rv = 414;
00844        goto finish;
00845     }
00846     
00847     srv = CMMF_EncodeKeyRecRepContent(repContent, WriteItOut, 
00848                                   (void*)fileDesc);
00849     PR_Close(fileDesc);
00850     if (srv != SECSuccess) {
00851         printf ("CMMF_EncodeKeyRecRepContent failed\n");
00852        rv = 415;
00853     }
00854 finish:
00855     if (privKey)
00856        SECKEY_DestroyPrivateKey(privKey);
00857     if (caPubKey)
00858        SECKEY_DestroyPublicKey(caPubKey);
00859     if (repContent)
00860        CMMF_DestroyKeyRecRepContent(repContent);
00861     return rv;
00862 }
00863 
00864 int
00865 decodeCMMFRecoveryMessage(const char * filePath)
00866 {
00867     CMMFKeyRecRepContent  *repContent = NULL;
00868     int                    rv         = 0;
00869     SECItem                fileBits   = { siBuffer, NULL, 0 };
00870 
00871     GetBitsFromFile(filePath, &fileBits);
00872     if (!fileBits.len) {
00873        rv = 451;
00874        goto finish;
00875     }
00876     repContent = 
00877         CMMF_CreateKeyRecRepContentFromDER(db, (const char *) fileBits.data,
00878                                       fileBits.len);
00879     if (repContent == NULL) {
00880         printf ("ERROR: CMMF_CreateKeyRecRepContentFromDER failed on file:\n"
00881               "\t%s\n", filePath);
00882        rv = 452;
00883     }
00884 finish:
00885     if (repContent) {
00886         CMMF_DestroyKeyRecRepContent(repContent);
00887     }
00888     SECITEM_FreeItem(&fileBits, PR_FALSE);
00889     return rv;
00890 }
00891 
00892 int
00893 DoCMMFStuff(void)
00894 {
00895     CERTCertificate       *cert                  = NULL;
00896     CERTCertList          *list                  = NULL;
00897     int                    rv                    = 0;
00898     char                   filePath[PATH_LEN];
00899 
00900     /* Do common setup for the following steps.
00901     */
00902     PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, "CertRepContent.der");
00903 
00904     cert = CERT_FindCertByNickname(db, personalCert);
00905     if (cert == NULL) {
00906         printf ("Could not find the certificate for %s\n", personalCert);
00907         rv = 416;
00908         goto finish;
00909     } 
00910     list = CERT_GetCertChainFromCert(cert, PR_Now(), certUsageEmailSigner);
00911     if (list == NULL) {
00912         printf ("Could not find the certificate chain for %s\n", personalCert);
00913         rv = 418;
00914         goto finish;
00915     } 
00916 
00917     /* a) Generate the CMMF response message, using a user cert named
00918     **    by -p option, rather than a cert generated from the CRMF
00919     **    request itself.   The CMMF message is placed in 
00920     **    configdir/CertRepContent.der.
00921     */
00922     rv = EncodeCMMFCertReply(filePath, cert, list);
00923     if (rv != 0) {
00924         goto finish;
00925     }
00926 
00927     /* b) Decode the CMMF Cert granting message encoded just above,
00928     **    found in configdir/CertRepContent.der.
00929     **    This only tests the decoding.  The decoded content is discarded.
00930     */
00931     rv = DecodeCMMFCertRepContent(filePath);
00932     if (rv != 0) {
00933         goto finish;
00934     }
00935 
00936     /* c) Generate a CMMF Key Excrow message
00937     **    It takes the public and private keys for the cert identified
00938     **    by -p nickname, and wraps them with a sym key that is in turn
00939     **    wrapped with the pubkey in the CA cert, whose nickname is 
00940     **    given by the -s option.
00941     **    Store the message in configdir/KeyRecRepContent.der
00942     */
00943     PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, 
00944               "KeyRecRepContent.der");
00945 
00946     rv = EncodeCMMFRecoveryMessage(filePath, cert, list);
00947     if (rv)
00948        goto finish;
00949 
00950     /* d) Decode the CMMF Key Excrow message generated just above.
00951     **    Get it from file configdir/KeyRecRepContent.der
00952     **    This is just a decoder test.  Results are discarded.
00953     */
00954 
00955     rv = decodeCMMFRecoveryMessage(filePath);
00956 
00957  finish:
00958     if (cert) {
00959         CERT_DestroyCertificate(cert);
00960     }
00961     if (list) {
00962         CERT_DestroyCertList(list);
00963     }
00964     return rv;
00965 }
00966 
00967 static CK_MECHANISM_TYPE
00968 mapWrapKeyType(KeyType keyType)
00969 {
00970     switch (keyType) {
00971     case rsaKey:
00972         return CKM_RSA_PKCS;
00973     default:
00974         break;
00975     }
00976     return CKM_INVALID_MECHANISM;
00977 } 
00978 
00979 #define KNOWN_MESSAGE_LENGTH 20 /*160 bits*/
00980 
00981 int
00982 DoKeyRecovery( SECKEYPrivateKey *privKey)
00983 {
00984 #ifdef DOING_KEY_RECOVERY  /* Doesn't compile yet. */
00985     SECKEYPublicKey      *pubKey;
00986     PK11SlotInfo         *slot;
00987     unsigned char        *ciphertext;
00988     unsigned char        *text_compared;
00989     SECKEYPrivateKey     *unwrappedPrivKey;
00990     SECKEYPrivateKey     *caPrivKey;
00991     CMMFKeyRecRepContent *keyRecRep;
00992     CMMFCertifiedKeyPair *certKeyPair;
00993     CERTCertificate      *caCert;
00994     CERTCertificate      *myCert;
00995     SECKEYPublicKey      *caPubKey;
00996     PRFileDesc           *fileDesc;
00997     CK_ULONG              max_bytes_encrypted;
00998     CK_ULONG              bytes_encrypted;
00999     CK_ULONG              bytes_compared;
01000     CK_ULONG              bytes_decrypted;
01001     CK_RV                 crv;
01002     CK_OBJECT_HANDLE      id;
01003     CK_MECHANISM          mech      = { CKM_INVALID_MECHANISM, NULL, 0};
01004     SECStatus             rv;
01005     SECItem               fileBits;
01006     SECItem               nickname;
01007     unsigned char         plaintext[KNOWN_MESSAGE_LENGTH];
01008     char                  filePath[PATH_LEN];
01009     static const unsigned char known_message[] = { "Known Crypto Message" };
01010 
01011     /*caCert = CERT_FindCertByNickname(db, caCertName);*/
01012     myCert = CERT_FindCertByNickname(db, personalCert);
01013     if (myCert == NULL) {
01014         printf ("Could not find the certificate for %s\n", personalCert);
01015         return 700;
01016     }
01017     caCert = CERT_FindCertByNickname(db, recoveryEncrypter);
01018     if (caCert == NULL) {
01019         printf ("Could not find the certificate for %s\n", recoveryEncrypter);
01020         return 701;
01021     }
01022     caPubKey = CERT_ExtractPublicKey(caCert);
01023     pubKey   = SECKEY_ConvertToPublicKey(privKey);
01024     max_bytes_encrypted = PK11_GetPrivateModulusLen(privKey);
01025     slot = PK11_GetBestSlot(mapWrapKeyType(privKey->keyType), NULL);
01026     id   = PK11_ImportPublicKey(slot, pubKey, PR_FALSE);
01027 
01028     switch(privKey->keyType) {
01029     case rsaKey:
01030         mech.mechanism = CKM_RSA_PKCS;
01031        break;
01032     case dsaKey:
01033         mech.mechanism = CKM_DSA;
01034        break;
01035     case dhKey:
01036         mech.mechanism = CKM_DH_PKCS_DERIVE;
01037        break;
01038     default:
01039         printf ("Bad Key type in key recovery.\n");
01040        return 512;
01041 
01042     }
01043     PK11_EnterSlotMonitor(slot);
01044     crv = PK11_GETTAB(slot)->C_EncryptInit(slot->session, &mech, id);
01045     if (crv != CKR_OK) {
01046         PK11_ExitSlotMonitor(slot);
01047        PK11_FreeSlot(slot);
01048        printf ("C_EncryptInit failed in KeyRecovery\n");
01049        return 500;
01050     }
01051     ciphertext = PORT_NewArray(unsigned char, max_bytes_encrypted);
01052     if (ciphertext == NULL) {
01053         PK11_ExitSlotMonitor(slot);
01054        PK11_FreeSlot(slot);
01055        printf ("Could not allocate memory for ciphertext.\n");
01056        return 501;
01057     }
01058     bytes_encrypted = max_bytes_encrypted;
01059     crv = PK11_GETTAB(slot)->C_Encrypt(slot->session, 
01060                                    known_message,
01061                                    KNOWN_MESSAGE_LENGTH,
01062                                    ciphertext,
01063                                    &bytes_encrypted);
01064     PK11_ExitSlotMonitor(slot);
01065     PK11_FreeSlot(slot);
01066     if (crv != CKR_OK) {
01067        PORT_Free(ciphertext);
01068        return 502;
01069     }
01070     /* Always use the smaller of these two values . . . */
01071     bytes_compared = ( bytes_encrypted > KNOWN_MESSAGE_LENGTH )
01072                       ? KNOWN_MESSAGE_LENGTH
01073                       : bytes_encrypted;
01074  
01075     /* If there was a failure, the plaintext */
01076     /* goes at the end, therefore . . .      */
01077     text_compared = ( bytes_encrypted > KNOWN_MESSAGE_LENGTH )
01078                     ? (ciphertext + bytes_encrypted -
01079                      KNOWN_MESSAGE_LENGTH )
01080                      : ciphertext;  
01081 
01082     keyRecRep = CMMF_CreateKeyRecRepContent();
01083     if (keyRecRep == NULL) {
01084         PORT_Free(ciphertext);
01085        PK11_FreeSlot(slot);
01086        CMMF_DestroyKeyRecRepContent(keyRecRep);
01087        printf ("Could not allocate a CMMFKeyRecRepContent structre.\n");
01088        return 503;
01089     }
01090     rv = CMMF_KeyRecRepContentSetPKIStatusInfoStatus(keyRecRep,
01091                                                cmmfGranted);
01092     if (rv != SECSuccess) {
01093         PORT_Free(ciphertext);
01094        PK11_FreeSlot(slot);
01095        CMMF_DestroyKeyRecRepContent(keyRecRep);
01096        printf ("Could not set the status for the KeyRecRepContent\n");
01097        return 504;
01098     }
01099     /* The myCert here should correspond to the certificate corresponding
01100      * to the private key, but for this test any certificate will do.
01101      */
01102     rv = CMMF_KeyRecRepContentSetCertifiedKeyPair(keyRecRep, myCert,
01103                                             privKey, caPubKey);
01104     if (rv != SECSuccess) {
01105         PORT_Free(ciphertext);
01106        PK11_FreeSlot(slot);
01107        CMMF_DestroyKeyRecRepContent(keyRecRep);
01108        printf ("Could not set the Certified Key Pair\n");
01109        return 505;
01110     }
01111     PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, 
01112               "KeyRecRepContent.der");
01113     fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 
01114                      0666);
01115     if (fileDesc == NULL) {
01116         PORT_Free(ciphertext);
01117        PK11_FreeSlot(slot);
01118        CMMF_DestroyKeyRecRepContent(keyRecRep);
01119         printf ("Could not open file %s\n", filePath);
01120        return 506;
01121     }
01122     rv = CMMF_EncodeKeyRecRepContent(keyRecRep, WriteItOut, fileDesc);
01123     CMMF_DestroyKeyRecRepContent(keyRecRep);
01124     PR_Close(fileDesc);
01125 
01126     if (rv != SECSuccess) {
01127         PORT_Free(ciphertext);
01128        PK11_FreeSlot(slot);
01129        printf ("Error while encoding CMMFKeyRecRepContent\n");
01130        return 507;
01131     }
01132     GetBitsFromFile(filePath, &fileBits);
01133     if (fileBits.data == NULL) {
01134         PORT_Free(ciphertext);
01135        PK11_FreeSlot(slot);
01136         printf ("Could not get the bits from file %s\n", filePath);
01137        return 508;
01138     }
01139     keyRecRep = 
01140         CMMF_CreateKeyRecRepContentFromDER(db,(const char*)fileBits.data,
01141                                       fileBits.len);
01142     if (keyRecRep == NULL) {
01143         printf ("Could not decode the KeyRecRepContent in file %s\n", 
01144               filePath);
01145        PORT_Free(ciphertext);
01146        PK11_FreeSlot(slot);
01147        return 509;
01148     }
01149     caPrivKey = PK11_FindKeyByAnyCert(caCert, &pwdata);
01150     if (CMMF_KeyRecRepContentGetPKIStatusInfoStatus(keyRecRep) != 
01151                                                              cmmfGranted) {
01152         PORT_Free(ciphertext);
01153        PK11_FreeSlot(slot);
01154        CMMF_DestroyKeyRecRepContent(keyRecRep);
01155        printf ("A bad status came back with the "
01156               "KeyRecRepContent structure\n");
01157        return 510;
01158     }
01159 
01160 #define NICKNAME "Key Recovery Test Key"
01161     nickname.data = (unsigned char*)NICKNAME;
01162     nickname.len  = PORT_Strlen(NICKNAME);
01163 
01164     certKeyPair = CMMF_KeyRecRepContentGetCertKeyAtIndex(keyRecRep, 0);
01165     CMMF_DestroyKeyRecRepContent(keyRecRep);
01166     rv = CMMF_CertifiedKeyPairUnwrapPrivKey(certKeyPair,
01167                                        caPrivKey,
01168                                        &nickname,
01169                                        PK11_GetInternalKeySlot(),
01170                                        db,
01171                                        &unwrappedPrivKey, &pwdata);
01172     CMMF_DestroyCertifiedKeyPair(certKeyPair);
01173     if (rv != SECSuccess) {
01174         printf ("Unwrapping the private key failed.\n");
01175        return 511;
01176     }
01177     /*Now let's try to decrypt the ciphertext with the "recovered" key*/
01178     PK11_EnterSlotMonitor(slot);
01179     crv = 
01180       PK11_GETTAB(slot)->C_DecryptInit(unwrappedPrivKey->pkcs11Slot->session,
01181                                    &mech,
01182                                    unwrappedPrivKey->pkcs11ID);
01183     if (crv != CKR_OK) {
01184         PK11_ExitSlotMonitor(slot);
01185        PORT_Free(ciphertext);
01186        PK11_FreeSlot(slot);
01187        printf ("Decrypting with the recovered key failed.\n");
01188        return 513;
01189     }
01190     bytes_decrypted = KNOWN_MESSAGE_LENGTH;
01191     crv = PK11_GETTAB(slot)->C_Decrypt(unwrappedPrivKey->pkcs11Slot->session,
01192                                    ciphertext, 
01193                                    bytes_encrypted, plaintext,
01194                                    &bytes_decrypted);
01195     SECKEY_DestroyPrivateKey(unwrappedPrivKey);
01196     PK11_ExitSlotMonitor(slot);
01197     PORT_Free(ciphertext);
01198     if (crv != CKR_OK) {
01199         PK11_FreeSlot(slot);
01200        printf ("Decrypting the ciphertext with recovered key failed.\n");
01201        return 514;
01202     }
01203     if ((bytes_decrypted != KNOWN_MESSAGE_LENGTH) || 
01204        (PORT_Memcmp(plaintext, known_message, KNOWN_MESSAGE_LENGTH) != 0)) {
01205         PK11_FreeSlot(slot);
01206        printf ("The recovered plaintext does not equal the known message:\n"
01207               "\tKnown message:       %s\n"
01208               "\tRecovered plaintext: %s\n", known_message, plaintext);
01209        return 515;
01210     }
01211 #endif
01212     return 0;
01213 }
01214 
01215 int
01216 DoChallengeResponse(SECKEYPrivateKey *privKey,
01217                   SECKEYPublicKey *pubKey)
01218 {
01219     CMMFPOPODecKeyChallContent *chalContent = NULL;
01220     CMMFPOPODecKeyRespContent  *respContent = NULL;
01221     CERTCertificate            *myCert      = NULL;
01222     CERTGeneralName            *myGenName   = NULL;
01223     PRArenaPool                *poolp       = NULL;
01224     PRFileDesc                 *fileDesc;
01225     SECItem                    *publicValue;
01226     SECItem                    *keyID;
01227     SECKEYPrivateKey           *foundPrivKey;
01228     long                       *randomNums;
01229     int                         numChallengesFound   = 0;
01230     int                         numChallengesSet     = 1;
01231     int                         i;
01232     long                        retrieved;
01233     SECStatus                   rv;
01234     SECItem                     DecKeyChallBits;
01235     char                        filePath[PATH_LEN];
01236 
01237     chalContent = CMMF_CreatePOPODecKeyChallContent();
01238     myCert = CERT_FindCertByNickname(db, personalCert);
01239     if (myCert == NULL) {
01240         printf ("Could not find the certificate for %s\n", personalCert);
01241         return 900;
01242     }
01243     poolp = PORT_NewArena(1024);
01244     if (poolp == NULL) {
01245         printf("Could no allocate a new arena in DoChallengeResponse\n");
01246        return 901;
01247     }
01248     myGenName = CERT_GetCertificateNames(myCert, poolp);
01249     if (myGenName == NULL) {
01250         printf ("Could not get the general names for %s certificate\n", 
01251               personalCert);
01252        return 902;
01253     }
01254     randomNums = PORT_ArenaNewArray(poolp,long, numChallengesSet);
01255     PK11_GenerateRandom((unsigned char *)randomNums, 
01256                         numChallengesSet * sizeof(long));
01257     for (i=0; i<numChallengesSet; i++) {
01258        rv = CMMF_POPODecKeyChallContentSetNextChallenge(chalContent,
01259                                                   randomNums[i],
01260                                                   myGenName,
01261                                                   pubKey,
01262                                                   &pwdata);
01263        if (rv != SECSuccess) {
01264            printf ("Could not set the challenge in DoChallengeResponse\n");
01265            return 903;
01266        }
01267     }
01268     PR_snprintf(filePath, PATH_LEN, "%s/POPODecKeyChallContent.der", 
01269               configdir);
01270     fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
01271                      0666);
01272     if (fileDesc == NULL) {
01273         printf ("Could not open file %s\n", filePath);
01274        return 904;
01275     }
01276     rv = CMMF_EncodePOPODecKeyChallContent(chalContent,WriteItOut, 
01277                                       (void*)fileDesc);
01278     PR_Close(fileDesc);
01279     CMMF_DestroyPOPODecKeyChallContent(chalContent);
01280     if (rv != SECSuccess) {
01281         printf ("Could not encode the POPODecKeyChallContent.\n");
01282        return 905;
01283     }
01284     GetBitsFromFile(filePath, &DecKeyChallBits);
01285     chalContent = CMMF_CreatePOPODecKeyChallContentFromDER
01286                     ((const char*)DecKeyChallBits.data, DecKeyChallBits.len);
01287     SECITEM_FreeItem(&DecKeyChallBits, PR_FALSE);
01288     if (chalContent == NULL) {
01289         printf ("Could not create the POPODecKeyChallContent from DER\n");
01290        return 906;
01291     }
01292     numChallengesFound = 
01293            CMMF_POPODecKeyChallContentGetNumChallenges(chalContent);
01294     if (numChallengesFound != numChallengesSet) {
01295         printf ("Number of Challenges Found (%d) does not equal the number "
01296               "set (%d)\n", numChallengesFound, numChallengesSet);
01297        return 907;
01298     }
01299     for (i=0; i<numChallengesSet; i++) {
01300         publicValue = CMMF_POPODecKeyChallContentGetPublicValue(chalContent, i);
01301        if (publicValue == NULL) {
01302          printf("Could not get the public value for challenge at index %d\n",
01303                i);
01304          return 908;
01305        }
01306        keyID = PK11_MakeIDFromPubKey(publicValue);
01307        if (keyID == NULL) {
01308            printf ("Could not make the keyID from the public value\n");
01309            return 909;
01310        }
01311        foundPrivKey = PK11_FindKeyByKeyID(privKey->pkcs11Slot, keyID, &pwdata);
01312        if (foundPrivKey == NULL) {
01313            printf ("Could not find the private key corresponding to the public"
01314                   " value.\n");
01315            return 910;
01316        }
01317        rv = CMMF_POPODecKeyChallContDecryptChallenge(chalContent, i, 
01318                                                 foundPrivKey);
01319        if (rv != SECSuccess) {
01320            printf ("Could not decrypt the challenge at index %d\n", i);
01321            return 911;
01322        }
01323        rv = CMMF_POPODecKeyChallContentGetRandomNumber(chalContent, i, 
01324                                                  &retrieved);
01325        if (rv != SECSuccess) {
01326            printf ("Could not get the random number from the challenge at "
01327                   "index %d\n", i);
01328            return 912;
01329        }
01330        if (retrieved != randomNums[i]) {
01331            printf ("Retrieved the number (%d), expected (%d)\n", retrieved,
01332                   randomNums[i]);
01333            return 913;
01334        }
01335     }
01336     CMMF_DestroyPOPODecKeyChallContent(chalContent);
01337     PR_snprintf(filePath, PATH_LEN, "%s/POPODecKeyRespContent.der", 
01338               configdir);
01339     fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
01340                      0666);
01341     if (fileDesc == NULL) {
01342         printf ("Could not open file %s\n", filePath);
01343        return 914;
01344     }
01345     rv = CMMF_EncodePOPODecKeyRespContent(randomNums, numChallengesSet,
01346                                      WriteItOut, fileDesc);
01347     PR_Close(fileDesc);
01348     if (rv != 0) {
01349         printf ("Could not encode the POPODecKeyRespContent\n");
01350        return 915;
01351     }
01352     GetBitsFromFile(filePath, &DecKeyChallBits);
01353     respContent = 
01354      CMMF_CreatePOPODecKeyRespContentFromDER((const char*)DecKeyChallBits.data,
01355                                         DecKeyChallBits.len);
01356     if (respContent == NULL) {
01357         printf ("Could not decode the contents of the file %s\n", filePath);
01358        return 916;
01359     }
01360     numChallengesFound = 
01361          CMMF_POPODecKeyRespContentGetNumResponses(respContent);
01362     if (numChallengesFound != numChallengesSet) {
01363         printf ("Number of responses found (%d) does not match the number "
01364               "of challenges set (%d)\n",
01365               numChallengesFound, numChallengesSet);
01366        return 917;
01367     }
01368     for (i=0; i<numChallengesSet; i++) {
01369         rv = CMMF_POPODecKeyRespContentGetResponse(respContent, i, &retrieved);
01370        if (rv != SECSuccess) {
01371            printf ("Could not retrieve the response at index %d\n", i);
01372            return 918;
01373        }
01374        if (retrieved != randomNums[i]) {
01375            printf ("Retrieved the number (%ld), expected (%ld)\n", retrieved,
01376                   randomNums[i]);
01377            return 919;
01378        }
01379                                                    
01380     }
01381     CMMF_DestroyPOPODecKeyRespContent(respContent);
01382     return 0;
01383 }
01384 
01385 int
01386 MakeCertRequest(TESTKeyPair *pair, CRMFPOPChoice inPOPChoice, long inRequestID)
01387 {
01388     int               irv;
01389 
01390     /* Generate a key pair and a cert request for it. */
01391     irv = CreateCertRequest(pair, inRequestID);
01392     if (irv != 0 || pair->certReq == NULL) {
01393         goto loser;
01394     }
01395 
01396     pair->certReqMsg = CRMF_CreateCertReqMsg();
01397     if (!pair->certReqMsg) {
01398        irv = 999;
01399        goto loser;
01400     }
01401     /* copy certReq into certReqMsg */
01402     CRMF_CertReqMsgSetCertRequest(pair->certReqMsg, pair->certReq);
01403     irv = AddProofOfPossession(pair, inPOPChoice);
01404 loser:
01405     return irv;
01406 }
01407 
01408 int
01409 DestroyPairReqAndMsg(TESTKeyPair *pair)
01410 {
01411     SECStatus rv  = SECSuccess;
01412     int       irv = 0;
01413 
01414     if (pair->certReq) {
01415        rv = CRMF_DestroyCertRequest(pair->certReq);
01416        pair->certReq = NULL;
01417        if (rv != SECSuccess) {
01418            printf ("Error when destroying cert request.\n");
01419            irv = 100;
01420        }
01421     }
01422     if (pair->certReqMsg) {
01423        rv = CRMF_DestroyCertReqMsg(pair->certReqMsg);
01424        pair->certReqMsg = NULL;
01425        if (rv != SECSuccess) {
01426            printf ("Error when destroying cert request msg.\n");
01427            if (!irv)
01428               irv = 101;
01429        }
01430     }
01431     return irv;
01432 }
01433 
01434 int
01435 DestroyPair(TESTKeyPair *pair)
01436 {
01437     SECStatus rv  = SECSuccess;
01438     int       irv = 0;
01439 
01440     if (pair->pubKey) {
01441        SECKEY_DestroyPublicKey(pair->pubKey);
01442        pair->pubKey = NULL;
01443     }
01444     if (pair->privKey) {
01445        SECKEY_DestroyPrivateKey(pair->privKey);
01446        pair->privKey = NULL;
01447     }
01448     DestroyPairReqAndMsg(pair);
01449     return irv;
01450 }
01451 
01452 int
01453 DoCRMFRequest(TESTKeyPair *signPair, TESTKeyPair *cryptPair)
01454 {
01455     int irv, tirv = 0;
01456 
01457     /* Generate a key pair and a cert request for it. */
01458     irv = MakeCertRequest(signPair, crmfSignature, 0x0f020304);
01459     if (irv != 0 || signPair->certReq == NULL) {
01460         goto loser;
01461     }
01462 
01463     if (!doingDSA) {
01464        irv = MakeCertRequest(cryptPair, crmfKeyAgreement, 0x0f050607);
01465        if (irv != 0 || cryptPair->certReq == NULL) {
01466            goto loser;
01467        }
01468     }
01469 
01470     /* encode the cert request messages into a unified request message.
01471     ** leave it in a file with a fixed name.  :(
01472     */
01473     irv = Encode(signPair->certReqMsg, cryptPair->certReqMsg);
01474 
01475 loser:
01476     if (signPair->certReq) {
01477        tirv = DestroyPairReqAndMsg(signPair);
01478        if (tirv && !irv)
01479            irv = tirv;
01480     }
01481     if (cryptPair->certReq) {
01482        tirv = DestroyPairReqAndMsg(cryptPair);
01483        if (tirv && !irv)
01484            irv = tirv;
01485     }
01486     return irv;
01487 }
01488 
01489 void
01490 Usage (void)
01491 {
01492     printf ("Usage:\n"
01493            "\tcrmftest -d [Database Directory] -p [Personal Cert]\n"
01494            "\t         -e [Encrypter] -s [CA Certificate] [-P password]\n\n"
01495            "\t         [crmf] [dsa] [decode] [cmmf] [recover] [challenge]\n"
01496            "Database Directory\n"
01497            "\tThis is the directory where the key3.db, cert7.db, and\n"
01498            "\tsecmod.db files are located.  This is also the directory\n"
01499            "\twhere the program will place CRMF/CMMF der files\n"
01500            "Personal Cert\n"
01501            "\tThis is the certificate that already exists in the cert\n"
01502            "\tdatabase to use while encoding the response.  The private\n"
01503            "\tkey associated with the certificate must also exist in the\n"
01504            "\tkey database.\n"
01505            "Encrypter\n"
01506            "\tThis is the certificate to use when encrypting the the \n"
01507            "\tkey recovery response.  The private key for this cert\n"
01508            "\tmust also be present in the key database.\n"
01509            "CA Certificate\n"
01510            "\tThis is the nickname of the certificate to use as the\n"
01511            "\tCA when doing all of the encoding.\n");
01512 }
01513 
01514 #define TEST_MAKE_CRMF_REQ      0x0001  
01515 #define TEST_USE_DSA            0x0002  
01516 #define TEST_DECODE_CRMF_REQ    0x0004  
01517 #define TEST_DO_CMMF_STUFF      0x0008  
01518 #define TEST_KEY_RECOVERY       0x0010  
01519 #define TEST_CHALLENGE_RESPONSE 0x0020  
01520 
01521 SECStatus
01522 parsePositionalParam(const char * arg, PRUint32 *flags)
01523 {
01524     if (!strcmp(arg, "crmf")) {
01525        *flags |= TEST_MAKE_CRMF_REQ;
01526     } else if (!strcmp(arg, "dsa")) {
01527        *flags |= TEST_MAKE_CRMF_REQ | TEST_USE_DSA;
01528        doingDSA = PR_TRUE;
01529     } else if (!strcmp(arg, "decode")) {
01530        *flags |= TEST_DECODE_CRMF_REQ;
01531     } else if (!strcmp(arg, "cmmf")) {
01532        *flags |= TEST_DO_CMMF_STUFF;
01533     } else if (!strcmp(arg, "recover")) {
01534        *flags |= TEST_KEY_RECOVERY;
01535     } else if (!strcmp(arg, "challenge")) {
01536        *flags |= TEST_CHALLENGE_RESPONSE;
01537     } else {
01538        printf("unknown positional paremeter: %s\n", arg);
01539        return SECFailure;
01540     }
01541     return SECSuccess;
01542 }
01543 
01544 /* it's not clear, in some cases, whether the desired key is from 
01545 ** the sign pair or the crypt pair, so we're guessing in some places.  
01546 ** This define serves to remind us of the places where we're guessing.
01547 */
01548 #define WHICH_KEY cryptPair
01549 
01550 int
01551 main(int argc, char **argv) 
01552 {
01553     TESTKeyPair       signPair, cryptPair;
01554     PLOptState       *optstate;
01555     PLOptStatus       status;
01556     char             *password = NULL;
01557     int               irv     = 0;
01558     PRUint32          flags   = 0;
01559     SECStatus         rv;
01560     PRBool            nssInit = PR_FALSE;
01561     PRBool            pArg    = PR_FALSE;
01562     PRBool            eArg    = PR_FALSE;
01563     PRBool            sArg    = PR_FALSE;
01564     PRBool            PArg    = PR_FALSE;
01565 
01566     memset( &signPair,  0, sizeof signPair);
01567     memset( &cryptPair, 0, sizeof cryptPair);
01568     printf ("\ncrmftest v1.0\n");
01569     optstate = PL_CreateOptState(argc, argv, "d:p:e:s:P:");
01570     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
01571        switch (optstate->option) {
01572        case 'd':
01573            configdir = PORT_Strdup(optstate->value);
01574            rv = NSS_Init(configdir);
01575            if (rv != SECSuccess) {
01576                printf ("NSS_Init (-d) failed\n");
01577               return 101;
01578            }        
01579            nssInit = PR_TRUE;
01580            break;
01581        case 'p':
01582            personalCert = PORT_Strdup(optstate->value);
01583            if (personalCert == NULL) {
01584                printf ("-p  failed\n");
01585                return 603;
01586            }
01587            pArg = PR_TRUE;
01588            break;
01589        case 'e':
01590            recoveryEncrypter = PORT_Strdup(optstate->value);
01591            if (recoveryEncrypter == NULL) {
01592                printf ("-e  failed\n");
01593                return 602;
01594            }
01595            eArg = PR_TRUE;
01596            break;
01597        case 's':
01598            caCertName = PORT_Strdup(optstate->value);
01599            if (caCertName == NULL) {
01600                printf ("-s  failed\n");
01601                return 604;
01602            }
01603            sArg = PR_TRUE;
01604            break;
01605        case 'P':
01606            password = PORT_Strdup(optstate->value);
01607            if (password == NULL) {
01608                printf ("-P  failed\n");
01609                return 606;
01610            }
01611            PArg = PR_TRUE;
01612            break;
01613        case 0:  /* positional parameter */
01614            rv = parsePositionalParam(optstate->value, &flags);
01615            if (rv) {
01616                printf ("bad positional parameter.\n");
01617                return 605;
01618            }
01619            break;
01620        default:
01621            Usage();
01622            return 601;
01623        }
01624     }
01625     PL_DestroyOptState(optstate);
01626     if (status == PL_OPT_BAD || !nssInit) {
01627         Usage();
01628        return 600;
01629     }
01630     if (!flags) 
01631        flags = ~ TEST_USE_DSA;
01632     db = CERT_GetDefaultCertDB();
01633     InitPKCS11();
01634     if (password) {
01635        pwdata.source = PW_PLAINTEXT;
01636        pwdata.data = password;
01637     }
01638 
01639     if (flags & TEST_MAKE_CRMF_REQ) {
01640        printf("Generating CRMF request\n");
01641        irv = DoCRMFRequest(&signPair, &cryptPair);
01642        if (irv)
01643            goto loser;
01644     }
01645 
01646     if (flags & TEST_DECODE_CRMF_REQ) {
01647        printf("Decoding CRMF request\n");
01648        irv = Decode();
01649        if (irv != 0) {
01650            printf("Error while decoding\n");
01651            goto loser;
01652        }
01653     }
01654 
01655     if (flags & TEST_DO_CMMF_STUFF) {
01656        printf("Doing CMMF Stuff\n");
01657        if ((irv = DoCMMFStuff()) != 0) {
01658            printf ("CMMF tests failed.\n");
01659            goto loser;
01660        }
01661     }
01662 
01663     if (flags & TEST_KEY_RECOVERY) {
01664        /* Requires some other options be set.
01665        ** Once we know exactly what hey are, test for them here. 
01666        */
01667        printf("Doing Key Recovery\n");
01668        irv = DoKeyRecovery(WHICH_KEY.privKey);
01669        if (irv != 0) {
01670            printf ("Error doing key recovery\n");
01671            goto loser;
01672        }
01673     }
01674 
01675     if (flags & TEST_CHALLENGE_RESPONSE) {
01676        printf("Doing Challenge / Response\n");
01677        irv = DoChallengeResponse(WHICH_KEY.privKey, WHICH_KEY.pubKey);
01678        if (irv != 0) {
01679            printf ("Error doing challenge-response\n");
01680            goto loser;
01681        }
01682     }
01683     printf ("Exiting successfully!!!\n\n");
01684     irv = 0;
01685 
01686  loser:
01687     DestroyPair(&signPair);
01688     DestroyPair(&cryptPair);
01689     rv = NSS_Shutdown();
01690     if (rv) {
01691        printf("NSS_Shutdown did not shutdown cleanly!\n");
01692     }
01693     PORT_Free(configdir);
01694     if (irv)
01695        printf("crmftest returning %d\n", irv);
01696     return irv;
01697 }