Fix so the encoded cert and key can be written out on cert generation

This commit is contained in:
Elio Maldonado 2009-02-20 23:00:35 +00:00
parent 02c6f8a15d
commit d5546fea8f

310
keyutil.c
View File

@ -5,16 +5,16 @@
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
In addition, as a special exception, Red Hat, Inc. gives permission In addition, as a special exception, Red Hat, Inc. gives permission
to link the code of this program with the OpenSSL library (or with to link the code of this program with the OpenSSL library (or with
modified versions of OpenSSL that use the same license as OpenSSL), modified versions of OpenSSL that use the same license as OpenSSL),
@ -72,9 +72,9 @@
* *
* Key generation, encryption, and certificate utility code based on * Key generation, encryption, and certificate utility code based on
* on code from NSS's security utilities and the certutil application. * on code from NSS's security utilities and the certutil application.
* Pem file key and certificate loading code based on code from the * Pem file key and certificate loading code based on code from the
* NSS-enabled libcurl. * NSS-enabled libcurl.
* Elio Maldonado <emaldona@redhat.com> * Elio Maldonado <emaldona@redhat.com>
* *
*/ */
#include <stdio.h> #include <stdio.h>
@ -206,7 +206,7 @@ static const struct option options[] = {
static certutilExtnList keyutil_extns; static certutilExtnList keyutil_extns;
static void static void
Usage(char *progName) Usage(char *progName)
{ {
fprintf(stderr, "Usage: %s [options] arguments\n", progName); fprintf(stderr, "Usage: %s [options] arguments\n", progName);
@ -293,10 +293,10 @@ static SECStatus nss_Init_Tokens(secuPWData *pwdata)
* @param nickname the certificate niskanme * @param nickname the certificate niskanme
*/ */
static SECStatus loadCert( static SECStatus loadCert(
PK11SlotInfo *slot, PK11SlotInfo *slot,
PRBool cacert, PRBool cacert,
const char *certfile, const char *certfile,
const char *nickname) const char *nickname)
{ {
SECStatus rv = SECSuccess; SECStatus rv = SECSuccess;
PK11GenericObject *genericObjCert; PK11GenericObject *genericObjCert;
@ -345,12 +345,12 @@ static SECStatus loadCert(
} else { } else {
rv = SECSuccess; rv = SECSuccess;
} }
} while (0); } while (0);
if (cert) if (cert)
CERT_DestroyCertificate(cert); CERT_DestroyCertificate(cert);
return rv; return rv;
} }
@ -364,10 +364,10 @@ static SECStatus loadCert(
* @param nickname the nickname of the matching certificate * @param nickname the nickname of the matching certificate
*/ */
static SECStatus loadKey( static SECStatus loadKey(
PK11SlotInfo *slot, PK11SlotInfo *slot,
const char *keyfile, const char *keyfile,
const char *nickname, const char *nickname,
secuPWData *pwdata) secuPWData *pwdata)
{ {
SECStatus rv = SECSuccess; SECStatus rv = SECSuccess;
CK_ATTRIBUTE *attrs = NULL; CK_ATTRIBUTE *attrs = NULL;
@ -421,19 +421,19 @@ static SECStatus loadKey(
GEN_BREAK(SECFailure); GEN_BREAK(SECFailure);
} }
rv = SECSuccess; rv = SECSuccess;
} while (0); } while (0);
if (cert) if (cert)
CERT_DestroyCertificate(cert); CERT_DestroyCertificate(cert);
return rv; return rv;
} }
/* /*
* Loads the certificate and private key from the specified files into * Loads the certificate and private key from the specified files into
* the PEM the module at the specified slot. * the PEM the module at the specified slot.
* *
* @param slot the slot to load into * @param slot the slot to load into
* @param certfile the certificate file * @param certfile the certificate file
* @param nickname the certificate nickname * @param nickname the certificate nickname
@ -442,34 +442,34 @@ static SECStatus loadKey(
*/ */
static SECStatus static SECStatus
loadCertAndKey( loadCertAndKey(
PK11SlotInfo *slot, PK11SlotInfo *slot,
PRBool cacert, PRBool cacert,
const char *certfile, const char *certfile,
const char *nickname, const char *nickname,
const char *keyfile, const char *keyfile,
secuPWData *pwdata) secuPWData *pwdata)
{ {
SECStatus rv = SECSuccess; SECStatus rv = SECSuccess;
/* /*
* Load the certificate first * Load the certificate first
*/ */
rv = loadCert(slot, cacert, certfile, nickname); rv = loadCert(slot, cacert, certfile, nickname);
if (rv != SECSuccess) return rv; if (rv != SECSuccess) return rv;
/* /*
* Load the private key next * Load the private key next
*/ */
rv = loadKey(slot, keyfile, nickname, pwdata); rv = loadKey(slot, keyfile, nickname, pwdata);
return rv; return rv;
} }
/* /*
* Extract the public and private keys and the subject * Extract the public and private keys and the subject
* distinguished from the cert with the given nickname * distinguished from the cert with the given nickname
* in the given slot. * in the given slot.
* *
* @param nickname the certificate nickname * @param nickname the certificate nickname
* @param slot the slot where keys it was loaded * @param slot the slot where keys it was loaded
* @param pwdat module authentication password * @param pwdat module authentication password
@ -487,13 +487,13 @@ static SECStatus extractRSAKeysAndSubject(
{ {
SECStatus rv = SECSuccess; SECStatus rv = SECSuccess;
CERTCertificate *cert = NULL; CERTCertificate *cert = NULL;
do { do {
cert = PK11_FindCertFromNickname((char *)nickname, NULL); cert = PK11_FindCertFromNickname((char *)nickname, NULL);
if (!cert) { if (!cert) {
GEN_BREAK(SECFailure); GEN_BREAK(SECFailure);
} }
*pubkey = CERT_ExtractPublicKey(cert); *pubkey = CERT_ExtractPublicKey(cert);
if (!*pubkey) { if (!*pubkey) {
SECU_PrintError(progName, SECU_PrintError(progName,
@ -518,7 +518,7 @@ static SECStatus extractRSAKeysAndSubject(
assert(((*privkey)->keyType) == rsaKey); assert(((*privkey)->keyType) == rsaKey);
*subject = CERT_AsciiToName(cert->subjectName); *subject = CERT_AsciiToName(cert->subjectName);
if (!*subject) { if (!*subject) {
SECU_PrintError(progName, SECU_PrintError(progName,
"Improperly formatted name: \"%s\"\n", "Improperly formatted name: \"%s\"\n",
@ -527,7 +527,7 @@ static SECStatus extractRSAKeysAndSubject(
} }
rv = SECSuccess; rv = SECSuccess;
} while (0); } while (0);
if (cert) if (cert)
CERT_DestroyCertificate(cert); CERT_DestroyCertificate(cert);
return rv; return rv;
@ -553,14 +553,14 @@ GetCertRequest(PRFileDesc *inFile, PRBool ascii)
if (arena == NULL) { if (arena == NULL) {
GEN_BREAK(SECFailure); GEN_BREAK(SECFailure);
} }
rv = SECU_ReadDERFromFile(&reqDER, inFile, ascii); rv = SECU_ReadDERFromFile(&reqDER, inFile, ascii);
if (rv) { if (rv) {
GEN_BREAK(rv); GEN_BREAK(rv);
} }
certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc
(arena, sizeof(CERTCertificateRequest)); (arena, sizeof(CERTCertificateRequest));
if (!certReq) { if (!certReq) {
GEN_BREAK(SECFailure); GEN_BREAK(SECFailure);
} }
certReq->arena = arena; certReq->arena = arena;
@ -569,17 +569,17 @@ GetCertRequest(PRFileDesc *inFile, PRBool ascii)
data data
*/ */
PORT_Memset(&signedData, 0, sizeof(signedData)); PORT_Memset(&signedData, 0, sizeof(signedData));
rv = SEC_ASN1DecodeItem(arena, &signedData, rv = SEC_ASN1DecodeItem(arena, &signedData,
SEC_ASN1_GET(CERT_SignedDataTemplate), &reqDER); SEC_ASN1_GET(CERT_SignedDataTemplate), &reqDER);
if (rv) { if (rv) {
GEN_BREAK(rv); GEN_BREAK(rv);
} }
rv = SEC_ASN1DecodeItem(arena, certReq, rv = SEC_ASN1DecodeItem(arena, certReq,
SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data); SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data);
if (rv) { if (rv) {
GEN_BREAK(rv); GEN_BREAK(rv);
} }
rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData, rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData,
&certReq->subjectPublicKeyInfo, NULL /* wincx */); &certReq->subjectPublicKeyInfo, NULL /* wincx */);
} while (0); } while (0);
@ -600,7 +600,7 @@ GetCertRequest(PRFileDesc *inFile, PRBool ascii)
static SECStatus static SECStatus
CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType, CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii, SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii,
const char *emailAddrs, const char *dnsNames, const char *emailAddrs, const char *dnsNames,
certutilExtnList extnList, certutilExtnList extnList,
PRFileDesc *outFile) PRFileDesc *outFile)
@ -621,7 +621,7 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
SECU_PrintError(progName, "unable to create subject public key"); SECU_PrintError(progName, "unable to create subject public key");
return SECFailure; return SECFailure;
} }
/* Generate certificate request */ /* Generate certificate request */
cr = CERT_CreateCertificateRequest(subject, spki, NULL); cr = CERT_CreateCertificateRequest(subject, spki, NULL);
if (!cr) { if (!cr) {
@ -634,7 +634,7 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
SECU_PrintError(progName, "out of memory"); SECU_PrintError(progName, "out of memory");
return SECFailure; return SECFailure;
} }
extHandle = CERT_StartCertificateRequestAttributes(cr); extHandle = CERT_StartCertificateRequestAttributes(cr);
if (extHandle == NULL) { if (extHandle == NULL) {
PORT_FreeArena (arena, PR_FALSE); PORT_FreeArena (arena, PR_FALSE);
@ -662,7 +662,7 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
SECU_PrintError(progName, "unknown Key or Hash type"); SECU_PrintError(progName, "unknown Key or Hash type");
return SECFailure; return SECFailure;
} }
rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len, rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len,
privk, signAlgTag); privk, signAlgTag);
if (rv) { if (rv) {
SECU_PrintError(progName, "signing of data failed"); SECU_PrintError(progName, "signing of data failed");
@ -704,7 +704,7 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
country = CERT_GetCountryName(subject); country = CERT_GetCountryName(subject);
if (!country) if (!country)
country = strdup("(not specified)"); country = strdup("(not specified)");
PR_fprintf(outFile, "%s\n", NS_CERTREQ_HEADER); PR_fprintf(outFile, "%s\n", NS_CERTREQ_HEADER);
numBytes = PR_Write(outFile, obuf, total); numBytes = PR_Write(outFile, obuf, total);
if (numBytes != total) { if (numBytes != total) {
@ -725,8 +725,8 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
static CERTCertificate * static CERTCertificate *
MakeV1Cert(CERTCertDBHandle *handle, MakeV1Cert(CERTCertDBHandle *handle,
CERTCertificateRequest *req, CERTCertificateRequest *req,
char *issuerNickName, char *issuerNickName,
PRBool selfsign, PRBool selfsign,
unsigned int serialNumber, unsigned int serialNumber,
int warpmonths, int warpmonths,
int validityMonths) int validityMonths)
@ -759,22 +759,22 @@ MakeV1Cert(CERTCertDBHandle *handle,
/* note that the time is now in micro-second unit */ /* note that the time is now in micro-second unit */
validity = CERT_CreateValidity (now, after); validity = CERT_CreateValidity (now, after);
if (validity) { if (validity) {
cert = CERT_CreateCertificate(serialNumber, cert = CERT_CreateCertificate(serialNumber,
(selfsign ? &req->subject (selfsign ? &req->subject
: &issuerCert->subject), : &issuerCert->subject),
validity, req); validity, req);
CERT_DestroyValidity(validity); CERT_DestroyValidity(validity);
} }
if ( issuerCert ) { if ( issuerCert ) {
CERT_DestroyCertificate (issuerCert); CERT_DestroyCertificate (issuerCert);
} }
return(cert); return(cert);
} }
static SECItem * static SECItem *
SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign, SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign,
SECOidTag hashAlgTag, SECOidTag hashAlgTag,
SECKEYPrivateKey *privKey, char *issuerNickName, void *pwarg) SECKEYPrivateKey *privKey, char *issuerNickName, void *pwarg)
{ {
@ -801,7 +801,7 @@ SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign,
return NULL; return NULL;
} }
} }
arena = cert->arena; arena = cert->arena;
algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag); algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag);
@ -854,13 +854,13 @@ done:
static SECStatus static SECStatus
CreateCert( CreateCert(
CERTCertDBHandle *handle, CERTCertDBHandle *handle,
char *issuerNickName, char *issuerNickName,
PRFileDesc *inFile, PRFileDesc *inFile,
PRFileDesc *outFile, PRFileDesc *outFile,
SECKEYPrivateKey *selfsignprivkey, SECKEYPrivateKey *selfsignprivkey,
void *pwarg, void *pwarg,
SECOidTag hashAlgTag, SECOidTag hashAlgTag,
unsigned int serialNumber, unsigned int serialNumber,
int warpmonths, int warpmonths,
int validityMonths, int validityMonths,
const char *emailAddrs, const char *emailAddrs,
@ -885,7 +885,7 @@ CreateCert(
if (!arena) { if (!arena) {
GEN_BREAK (SECFailure); GEN_BREAK (SECFailure);
} }
/* Create a certrequest object from the input cert request der */ /* Create a certrequest object from the input cert request der */
certReq = GetCertRequest(inFile, ascii); certReq = GetCertRequest(inFile, ascii);
if (certReq == NULL) { if (certReq == NULL) {
@ -897,17 +897,17 @@ CreateCert(
if (subjectCert == NULL) { if (subjectCert == NULL) {
GEN_BREAK (SECFailure) GEN_BREAK (SECFailure)
} }
extHandle = CERT_StartCertExtensions (subjectCert); extHandle = CERT_StartCertExtensions (subjectCert);
if (extHandle == NULL) { if (extHandle == NULL) {
GEN_BREAK (SECFailure) GEN_BREAK (SECFailure)
} }
rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList); rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList);
if (rv != SECSuccess) { if (rv != SECSuccess) {
GEN_BREAK (SECFailure) GEN_BREAK (SECFailure)
} }
if (certReq->attributes != NULL && if (certReq->attributes != NULL &&
certReq->attributes[0] != NULL && certReq->attributes[0] != NULL &&
certReq->attributes[0]->attrType.data != NULL && certReq->attributes[0]->attrType.data != NULL &&
@ -929,8 +929,8 @@ CreateCert(
if (certDER) { if (certDER) {
if (ascii) { if (ascii) {
PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CERT_HEADER, PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CERT_HEADER,
BTOA_DataToAscii(certDER->data, certDER->len), BTOA_DataToAscii(certDER->data, certDER->len),
NS_CERT_TRAILER); NS_CERT_TRAILER);
} else { } else {
PR_Write(outFile, certDER->data, certDER->len); PR_Write(outFile, certDER->data, certDER->len);
@ -938,7 +938,7 @@ CreateCert(
} }
} while (0); } while (0);
CERT_DestroyCertificateRequest(certReq); CERT_DestroyCertificateRequest(certReq);
PORT_FreeArena (arena, PR_FALSE); PORT_FreeArena (arena, PR_FALSE);
if (rv == SECSuccess) { if (rv == SECSuccess) {
@ -950,7 +950,7 @@ CreateCert(
if (subjectCert) if (subjectCert)
CERT_DestroyCertificate (subjectCert); CERT_DestroyCertificate (subjectCert);
} }
return (rv); return (rv);
} }
@ -1045,7 +1045,7 @@ UpdateRNG(void)
return rv; return rv;
} }
static SECStatus static SECStatus
CERTUTIL_FileForRNG(const char *noise) CERTUTIL_FileForRNG(const char *noise)
{ {
char buf[2048]; char buf[2048];
@ -1070,11 +1070,11 @@ CERTUTIL_FileForRNG(const char *noise)
} }
SECKEYPrivateKey * SECKEYPrivateKey *
GenerateRSAPrivateKey(KeyType keytype, GenerateRSAPrivateKey(KeyType keytype,
PK11SlotInfo *slot, PK11SlotInfo *slot,
int rsasize, int rsasize,
int publicExponent, int publicExponent,
char *noise, char *noise,
SECKEYPublicKey **pubkeyp, SECKEYPublicKey **pubkeyp,
secuPWData *pwdata) secuPWData *pwdata)
{ {
@ -1115,23 +1115,23 @@ GenerateRSAPrivateKey(KeyType keytype,
privKey = PK11_GenerateKeyPair(slot, privKey = PK11_GenerateKeyPair(slot,
mechanism, &rsaparams, pubkeyp, mechanism, &rsaparams, pubkeyp,
PR_FALSE /* isPerm */, PR_FALSE /* isPerm */,
PR_TRUE /* isSensitive*/, PR_TRUE /* isSensitive*/,
pwdata /* wincx */ pwdata /* wincx */
); );
assert(privKey); assert(privKey);
assert(pubkeyp); assert(pubkeyp);
return privKey; return privKey;
} }
/* /*
* Decrypt the private key * Decrypt the private key
*/ */
SECStatus DecryptKey( SECStatus DecryptKey(
SECKEYEncryptedPrivateKeyInfo *epki, SECKEYEncryptedPrivateKeyInfo *epki,
SECOidTag algTag, SECOidTag algTag,
SECItem *pwitem, SECItem *pwitem,
secuPWData *pwdata, secuPWData *pwdata,
SECItem *derPKI) SECItem *derPKI)
{ {
@ -1143,19 +1143,19 @@ SECStatus DecryptKey(
if (!pwitem) { if (!pwitem) {
return SEC_ERROR_INVALID_ARGS; return SEC_ERROR_INVALID_ARGS;
} }
do { do {
SECAlgorithmID algid = epki->algorithm; SECAlgorithmID algid = epki->algorithm;
CK_MECHANISM_TYPE cryptoMechType; CK_MECHANISM_TYPE cryptoMechType;
CK_MECHANISM cryptoMech; CK_MECHANISM cryptoMech;
CK_ATTRIBUTE_TYPE operation = CKA_DECRYPT; CK_ATTRIBUTE_TYPE operation = CKA_DECRYPT;
PK11SlotInfo *slot = NULL; PK11SlotInfo *slot = NULL;
cryptoMechType = PK11_GetPBECryptoMechanism(&algid, &cryptoParam, pwitem); cryptoMechType = PK11_GetPBECryptoMechanism(&algid, &cryptoParam, pwitem);
if (cryptoMechType == CKM_INVALID_MECHANISM) { if (cryptoMechType == CKM_INVALID_MECHANISM) {
ERROR_BREAK; ERROR_BREAK;
} }
cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMechType); cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMechType);
cryptoMech.pParameter = cryptoParam ? cryptoParam->data : NULL; cryptoMech.pParameter = cryptoParam ? cryptoParam->data : NULL;
cryptoMech.ulParameterLen = cryptoParam ? cryptoParam->len : 0; cryptoMech.ulParameterLen = cryptoParam ? cryptoParam->len : 0;
@ -1164,7 +1164,7 @@ SECStatus DecryptKey(
if (!slot) { if (!slot) {
ERROR_BREAK; ERROR_BREAK;
} }
symKey = PK11_PBEKeyGen(slot, &algid, pwitem, PR_FALSE, pwdata); symKey = PK11_PBEKeyGen(slot, &algid, pwitem, PR_FALSE, pwdata);
if (symKey == NULL) { if (symKey == NULL) {
ERROR_BREAK; ERROR_BREAK;
@ -1174,21 +1174,21 @@ SECStatus DecryptKey(
if (ctx == NULL) { if (ctx == NULL) {
ERROR_BREAK; ERROR_BREAK;
} }
rv = PK11_CipherOp(ctx, rv = PK11_CipherOp(ctx,
derPKI->data, /* out */ derPKI->data, /* out */
(int *)(&derPKI->len), /* out len */ (int *)(&derPKI->len), /* out len */
(int)epki->encryptedData.len, /* max out */ (int)epki->encryptedData.len, /* max out */
epki->encryptedData.data, /* in */ epki->encryptedData.data, /* in */
(int)epki->encryptedData.len); /* in len */ (int)epki->encryptedData.len); /* in len */
assert(derPKI->len == epki->encryptedData.len); assert(derPKI->len == epki->encryptedData.len);
assert(rv == SECSuccess); assert(rv == SECSuccess);
rv = PK11_Finalize(ctx); rv = PK11_Finalize(ctx);
assert(rv == SECSuccess); assert(rv == SECSuccess);
} while (0); } while (0);
/* cleanup */ /* cleanup */
if (symKey) { if (symKey) {
PK11_FreeSymKey(symKey); PK11_FreeSymKey(symKey);
@ -1200,7 +1200,7 @@ SECStatus DecryptKey(
if (ctx) { if (ctx) {
PK11_DestroyContext(ctx, PR_TRUE); PK11_DestroyContext(ctx, PR_TRUE);
} }
return rv; return rv;
} }
@ -1215,20 +1215,20 @@ KeyOut(const char *keyoutfile,
secuPWData *pwdata, secuPWData *pwdata,
PRBool ascii) PRBool ascii)
{ {
#define RAND_PASS_LEN 6 #define RAND_PASS_LEN 6
PRFileDesc *keyOutFile = NULL; PRFileDesc *keyOutFile = NULL;
PRUint32 total = 0; PRUint32 total = 0;
PRUint32 numBytes = 0; PRUint32 numBytes = 0;
SECItem *derEPKI = NULL; SECItem *encryptedKeyDER = NULL;
SECItem derPKI = { 0, NULL, 0 }; SECItem clearKeyDER = { 0, NULL, 0 };
SECItem pwitem = { 0, NULL, 0 }; SECItem pwitem = { 0, NULL, 0 };
PRArenaPool *arenaForEPKI = NULL; PRArenaPool *arenaForEPKI = NULL;
PLArenaPool *arenaForPKI = NULL; PLArenaPool *arenaForPKI = NULL;
SECKEYEncryptedPrivateKeyInfo *epki = NULL; SECKEYEncryptedPrivateKeyInfo *epki = NULL;
unsigned char randomPassword[RAND_PASS_LEN]; unsigned char randomPassword[RAND_PASS_LEN];
int rv = SECSuccess; int rv = SECSuccess;
do { do {
@ -1248,7 +1248,7 @@ KeyOut(const char *keyoutfile,
pwitem.len = RAND_PASS_LEN; pwitem.len = RAND_PASS_LEN;
pwitem.type = siBuffer; pwitem.type = siBuffer;
} }
keyOutFile = PR_Open(keyoutfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660); keyOutFile = PR_Open(keyoutfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);
if (!keyOutFile) { if (!keyOutFile) {
SECU_PrintError(progName, "Unable to open \"%s\" for writing\n", keyoutfile); SECU_PrintError(progName, "Unable to open \"%s\" for writing\n", keyoutfile);
@ -1262,100 +1262,102 @@ KeyOut(const char *keyoutfile,
SECU_PrintError(progName, "Can't export private key info (%d)\n", rv); SECU_PrintError(progName, "Can't export private key info (%d)\n", rv);
GEN_BREAK(rv); GEN_BREAK(rv);
} }
arenaForEPKI = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); arenaForEPKI = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
assert(arenaForEPKI); assert(arenaForEPKI);
if (keyEncPwd) { if (keyEncPwd) {
/* NULL dest to let it allocate memory for us */ /* NULL dest to let it allocate memory for us */
derEPKI = SEC_ASN1EncodeItem(arenaForEPKI, NULL, epki, encryptedKeyDER = SEC_ASN1EncodeItem(arenaForEPKI, NULL, epki,
SECKEY_EncryptedPrivateKeyInfoTemplate); SECKEY_EncryptedPrivateKeyInfoTemplate);
if (!derEPKI) { if (!encryptedKeyDER) {
rv = PR_GetError(); rv = PR_GetError();
SECU_PrintError(progName, "ASN1 Encode failed (%s)\n", SECU_PrintError(progName, "ASN1 Encode failed (%s)\n",
SECU_Strerror(rv)); SECU_Strerror(rv));
GEN_BREAK(rv); GEN_BREAK(rv);
} }
} else { } else {
/* Make a decrypted key the one to write out. */ /* Make a decrypted key the one to write out. */
arenaForPKI = PORT_NewArena(2048); arenaForPKI = PORT_NewArena(2048);
if (!arenaForPKI) { if (!arenaForPKI) {
GEN_BREAK(PR_OUT_OF_MEMORY_ERROR); GEN_BREAK(PR_OUT_OF_MEMORY_ERROR);
} }
derPKI.data = PORT_ArenaAlloc(arenaForPKI, epki->encryptedData.len); clearKeyDER.data = PORT_ArenaAlloc(arenaForPKI, epki->encryptedData.len);
derPKI.len = epki->encryptedData.len; clearKeyDER.len = epki->encryptedData.len;
derPKI.type = siBuffer; clearKeyDER.type = siBuffer;
rv = DecryptKey(epki, algTag, &pwitem, pwdata, &derPKI); rv = DecryptKey(epki, algTag, &pwitem, pwdata, &clearKeyDER);
if (rv) { if (rv != SECSuccess) {
GEN_BREAK(rv); GEN_BREAK(rv);
} }
} }
if (ascii) { if (ascii) {
/* we could be exporting a clear or encrypted key */ /* we could be exporting a clear or encrypted key */
SECItem *src = keyEncPwd ? derEPKI : &derPKI; SECItem *src = keyEncPwd ? encryptedKeyDER : &clearKeyDER;
char *header = keyEncPwd ? ENCRYPTED_KEY_HEADER : KEY_HEADER; char *header = keyEncPwd ? ENCRYPTED_KEY_HEADER : KEY_HEADER;
char *trailer = keyEncPwd ? ENCRYPTED_KEY_TRAILER : KEY_TRAILER; char *trailer = keyEncPwd ? ENCRYPTED_KEY_TRAILER : KEY_TRAILER;
char *b64 = NULL; char *b64 = NULL;
do { do {
b64 = BTOA_ConvertItemToAscii(src); b64 = BTOA_ConvertItemToAscii(src);
if (b64) if (!b64) {
break; rv = 255;
GEN_BREAK(rv);
}
total = PL_strlen(b64); total = PL_strlen(b64);
PR_fprintf(keyOutFile, "%s\n", header); PR_fprintf(keyOutFile, "%s\n", header);
numBytes = PR_Write(keyOutFile, b64, total); numBytes = PR_Write(keyOutFile, b64, total);
if (numBytes != total) { if (numBytes != total) {
printf("Wrote %d bytes, instead of %d\n", numBytes, total); printf("Wrote %d bytes, instead of %d\n", numBytes, total);
break; break;
} }
PR_fprintf(keyOutFile, "\n%s\n", trailer); PR_fprintf(keyOutFile, "\n%s\n", trailer);
} while (0); } while (0);
if (b64) { if (b64) {
PORT_Free(b64); PORT_Free(b64);
} }
} else { } else {
if (keyEncPwd) { if (keyEncPwd) {
/* Write out the encrypted key */ /* Write out the encrypted key */
numBytes = PR_Write(keyOutFile, derEPKI, derEPKI->len); numBytes = PR_Write(keyOutFile, encryptedKeyDER, encryptedKeyDER->len);
} else { } else {
/* Write out the unencrypted key */ /* Write out the unencrypted key */
numBytes = PR_Write(keyOutFile, &derPKI, derPKI.len); numBytes = PR_Write(keyOutFile, &clearKeyDER, clearKeyDER.len);
if (numBytes != derEPKI->len) { if (numBytes != clearKeyDER.len) {
printf("Wrote %d bytes, instead of %d\n", numBytes, derPKI.len); printf("Wrote %d bytes, instead of %d\n", numBytes, clearKeyDER.len);
} }
} }
} }
printf("Wrote %d bytes of encoded data to %s \n", numBytes, keyoutfile); if (rv == SECSuccess)
/* can we read it and reverse operations */ printf("Wrote %d bytes of encoded data to %s \n", numBytes, keyoutfile);
} while (0); } while (0);
if (keyOutFile) { if (keyOutFile) {
PR_Close(keyOutFile); PR_Close(keyOutFile);
} }
if (arenaForEPKI) { if (arenaForEPKI) {
PORT_FreeArena(arenaForEPKI, PR_FALSE); PORT_FreeArena(arenaForEPKI, PR_FALSE);
} }
if (arenaForPKI) { if (arenaForPKI) {
PORT_FreeArena(arenaForPKI, PR_FALSE); PORT_FreeArena(arenaForPKI, PR_FALSE);
} }
if (!keyEncPwd) { if (!keyEncPwd) {
/* paranoia, though stack-based object we clear it anyway */ /* paranoia, though stack-based object we clear it anyway */
memset(randomPassword, 0, RAND_PASS_LEN); memset(randomPassword, 0, RAND_PASS_LEN);
@ -1366,7 +1368,7 @@ KeyOut(const char *keyoutfile,
} }
memset(&pwitem, 0, sizeof(SECItem)); memset(&pwitem, 0, sizeof(SECItem));
} }
return rv; return rv;
} }
@ -1402,7 +1404,7 @@ static int keyutil_main(
SECOidTag hashAlgTag = SEC_OID_UNKNOWN; SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
PRBool doCert = certfile != NULL; PRBool doCert = certfile != NULL;
int rv; int rv;
if (access_pwd_file) { if (access_pwd_file) {
pwdata.source = PW_FROMFILE; pwdata.source = PW_FROMFILE;
pwdata.data = (char *)access_pwd_file; pwdata.data = (char *)access_pwd_file;
@ -1422,7 +1424,7 @@ static int keyutil_main(
char nickname[256]; char nickname[256];
CERTCertificate *keycert = NULL; CERTCertificate *keycert = NULL;
const char *n = cert_to_renew; const char *n = cert_to_renew;
/* Remove the path part */ /* Remove the path part */
n = strrchr(cert_to_renew, '/'); n = strrchr(cert_to_renew, '/');
if (!n) if (!n)
@ -1438,7 +1440,7 @@ static int keyutil_main(
rv = 255; rv = 255;
goto shutdown; goto shutdown;
} }
rv = loadCertAndKey(slot, cacert, rv = loadCertAndKey(slot, cacert,
cert_to_renew, nickname, input_key_file, cert_to_renew, nickname, input_key_file,
&pwdata); &pwdata);
@ -1447,7 +1449,7 @@ static int keyutil_main(
SECU_PrintError(progName, "Can't load the key or cert, bailing out\n"); SECU_PrintError(progName, "Can't load the key or cert, bailing out\n");
goto shutdown; goto shutdown;
} }
rv = extractRSAKeysAndSubject(nickname, rv = extractRSAKeysAndSubject(nickname,
slot, &pwdata, &privkey, &pubkey, &subject); slot, &pwdata, &privkey, &pubkey, &subject);
if (rv != SECSuccess) { if (rv != SECSuccess) {
@ -1468,11 +1470,17 @@ static int keyutil_main(
* This is a certificate signing request for a new cert, * This is a certificate signing request for a new cert,
* will generate a key pair * will generate a key pair
*/ */
if (!subjectstr) {
SECU_PrintError(progName, "subject string was NULL\n");
rv = 255;
goto shutdown;
}
slot = PK11_GetInternalKeySlot(); /* PK11_GetInternalSlot() ? */ slot = PK11_GetInternalKeySlot(); /* PK11_GetInternalSlot() ? */
privkey = GenerateRSAPrivateKey(keytype, slot, privkey = GenerateRSAPrivateKey(keytype, slot,
keysize, 65537L, (char *)noisefile, &pubkey, &pwdata); keysize, 65537L, (char *)noisefile, &pubkey, &pwdata);
if (!privkey) { if (!privkey) {
SECU_PrintError(progName, SECU_PrintError(progName,
"Keypair generation failed: \"%d\"\n", PORT_GetError()); "Keypair generation failed: \"%d\"\n", PORT_GetError());
@ -1480,11 +1488,6 @@ static int keyutil_main(
goto shutdown; goto shutdown;
} }
if (!subjectstr) {
SECU_PrintError(progName, "subject string was NULL\n");
rv = 255;
goto shutdown;
}
subject = CERT_AsciiToName((char *)subjectstr); subject = CERT_AsciiToName((char *)subjectstr);
if (!subject) { if (!subject) {
SECU_PrintError(progName, SECU_PrintError(progName,
@ -1524,7 +1527,7 @@ static int keyutil_main(
keyutil_extns[ext_inhibitAnyPolicy] = PR_FALSE; keyutil_extns[ext_inhibitAnyPolicy] = PR_FALSE;
hashAlgTag = SEC_OID_MD5; hashAlgTag = SEC_OID_MD5;
/* Make a cert request */ /* Make a cert request */
rv = CertReq(privkey, pubkey, rsaKey, hashAlgTag, subject, rv = CertReq(privkey, pubkey, rsaKey, hashAlgTag, subject,
NULL, /* PhoneNumber */ NULL, /* PhoneNumber */
@ -1533,7 +1536,7 @@ static int keyutil_main(
NULL, /* ExtendedDNSNames */ NULL, /* ExtendedDNSNames */
keyutil_extns, /* keyutil_extns */ keyutil_extns, /* keyutil_extns */
outFile); outFile);
PR_Close(outFile); PR_Close(outFile);
if (rv) { if (rv) {
SECU_PrintError(progName ? progName : "keyutil", SECU_PrintError(progName ? progName : "keyutil",
@ -1543,22 +1546,21 @@ static int keyutil_main(
} }
if (doCert) { if (doCert) {
/* If making a cert, we already have a cert request file. /* If making a cert, we already have a cert request file.
* without any extensions, load it with any command line extensions * without any extensions, load it with any command line extensions
* and output the cert to other file. Delete the request file. * and output the cert to other file. Delete the request file.
*/ */
PRFileDesc *inFile = NULL; PRFileDesc *inFile = NULL;
unsigned int serialNumber; unsigned int serialNumber;
/* Make a default serial number from the current time. */ /* Make a default serial number from the current time. */
PRTime now = PR_Now(); PRTime now = PR_Now();
LL_USHR(now, now, 19); LL_USHR(now, now, 19);
LL_L2UI(serialNumber, now); LL_L2UI(serialNumber, now);
privkey->wincx = &pwdata; privkey->wincx = &pwdata;
PR_Close(outFile);
inFile = PR_Open(certreqfile, PR_RDONLY, 0); inFile = PR_Open(certreqfile, PR_RDONLY, 0);
assert(inFile); assert(inFile);
if (!inFile) { if (!inFile) {
@ -1567,7 +1569,7 @@ static int keyutil_main(
rv = SECFailure; rv = SECFailure;
goto shutdown; goto shutdown;
} }
outFile = PR_Open(certfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660); outFile = PR_Open(certfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);
if (!outFile) { if (!outFile) {
SECU_PrintError(progName, "Failed to open file \"%s\" (%ld, %ld).\n", SECU_PrintError(progName, "Failed to open file \"%s\" (%ld, %ld).\n",
@ -1575,11 +1577,11 @@ static int keyutil_main(
rv = SECFailure; rv = SECFailure;
goto shutdown; goto shutdown;
} }
/* Create a certificate (-C or -S). */ /* Create a certificate (-C or -S). */
/* issuerName == subject */ /* issuerName == subject */
rv = CreateCert(certHandle, rv = CreateCert(certHandle,
"tempnickname", inFile, outFile, "tempnickname", inFile, outFile,
privkey, &pwdata, hashAlgTag, privkey, &pwdata, hashAlgTag,
serialNumber, warpmonths, validityMonths, serialNumber, warpmonths, validityMonths,
@ -1598,7 +1600,7 @@ static int keyutil_main(
printf("Created a certificate\n"); printf("Created a certificate\n");
/* Sanity check: Check cert validity against current time. */ /* Sanity check: Check cert validity against current time. */
/* for fips - must log in to get private key */ /* for fips - must log in to get private key */
if (slot && PK11_NeedLogin(slot)) { if (slot && PK11_NeedLogin(slot)) {
SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &pwdata); SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
@ -1652,11 +1654,11 @@ shutdown:
return rv == SECSuccess ? 0 : 255; return rv == SECSuccess ? 0 : 255;
} }
/* $Id: keyutil.c,v 1.12 2008/11/04 04:28:22 emaldonado Exp $ */ /* $Id: keyutil.c,v 1.13 2009/01/29 22:22:17 emaldonado Exp $ */
/* Key generation, encryption, and certificate utility code, based on /* Key generation, encryption, and certificate utility code, based on
* code from NSS's security utilities and the certutil application. * code from NSS's security utilities and the certutil application.
* Elio Maldonado <emaldona@redhat.com> * Elio Maldonado <emaldona@redhat.com>
*/ */
@ -1682,7 +1684,7 @@ int main(int argc, char **argv)
SECStatus status = 0; SECStatus status = 0;
CommandType cmd = cmd_CertReq; CommandType cmd = cmd_CertReq;
PRBool initialized = PR_FALSE; PRBool initialized = PR_FALSE;
while ((optc = getopt_long(argc, argv, "atc:rs:g:v:e:f:d:z:i:p:o:k:h", options, NULL)) != -1) { while ((optc = getopt_long(argc, argv, "atc:rs:g:v:e:f:d:z:i:p:o:k:h", options, NULL)) != -1) {
switch (optc) { switch (optc) {
case 'a': case 'a':
@ -1760,10 +1762,10 @@ int main(int argc, char **argv)
break; break;
} }
} }
/* Initialize NSPR and NSS. */ /* Initialize NSPR and NSS. */
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
status = NSS_NoDB_Init(NULL); status = NSS_NoDB_Init(NULL);
if (status != SECSuccess ) { if (status != SECSuccess ) {
printf("NSS initialization failed\n"); printf("NSS initialization failed\n");
@ -1772,7 +1774,7 @@ int main(int argc, char **argv)
if (cert_to_renew) { if (cert_to_renew) {
char *configstring = NULL; char *configstring = NULL;
/* Load our PKCS#11 module */ /* Load our PKCS#11 module */
configstring = (char *)malloc(4096); configstring = (char *)malloc(4096);
PR_snprintf(configstring, 4096, PR_snprintf(configstring, 4096,
"library=%s name=PEM parameters=\"\"", pem_library); "library=%s name=PEM parameters=\"\"", pem_library);
mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE); mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
@ -1791,10 +1793,10 @@ int main(int argc, char **argv)
} }
} }
initialized = PR_TRUE; initialized = PR_TRUE;
certHandle = CERT_GetDefaultCertDB(); certHandle = CERT_GetDefaultCertDB();
assert(certHandle); assert(certHandle);
switch (cmd) { switch (cmd) {
case cmd_CertReq: case cmd_CertReq:
/* certfile NULL signals only the request is needed */ /* certfile NULL signals only the request is needed */