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