Per code review, preauthenticate to modules using specially formatted

password file, fix a memory deallocation bug
This commit is contained in:
Elio Maldonado 2008-11-04 04:07:28 +00:00
parent 5d743f19fd
commit 1d3e5412f2

141
keyutil.c
View File

@ -190,7 +190,7 @@ static const struct option options[] = {
{ "subject", required_argument, NULL, 's' },
{ "gkeysize", required_argument, NULL, 'g' },
{ "validity", required_argument, NULL, 'v' },
{ "encpwdfile", required_argument, NULL, 'e' },
{ "encpwd", required_argument, NULL, 'e' },
{ "filepwdnss", required_argument, NULL, 'f' },
{ "digest", required_argument, NULL, 'd' },
{ "znoisefile", required_argument, NULL, 'z' },
@ -214,7 +214,7 @@ Usage(char *progName)
fprintf(stderr, "{-g|--gsize} key_size size in bitsof the rsa key to generate");
fprintf(stderr, "{-v|--validity} months cert validity in months");
fprintf(stderr, "{-z|--znoisefile} noisefile seed file for use in key gneration");
fprintf(stderr, "{-e|--filepwdnss} keypwdfile file with the key encryption_password");
fprintf(stderr, "{-e|--encpwd} keypwd key encryption_password");
fprintf(stderr, "{-f|--filepwdnss} modpwdfile file with the module access_password");
fprintf(stderr, "{-d|--digest} digest-algorithm digest algorithm");
fprintf(stderr, "{-i|--input} inputkey-file file with key with which to encrypt or to sign a request");
@ -227,8 +227,6 @@ Usage(char *progName)
exit(1);
}
#if(0)
/*
* Authenticates to any token that may require it.
* It also checks that the NSS database ahs been initialized.
@ -254,7 +252,7 @@ static SECStatus nss_Init_Tokens(secuPWData *pwdata)
if (PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) {
if (slot == PK11_GetInternalKeySlot()) {
SECU_PrintError(progName,
SECU_PrintError(progName ? progName : "keyutil",
"The NSS database has not been initialized\n");
} else {
SECU_PrintError(progName,
@ -268,7 +266,7 @@ static SECStatus nss_Init_Tokens(secuPWData *pwdata)
ret = PK11_Authenticate(slot, PR_TRUE, &pwdata);
if (SECSuccess != ret) {
if (PR_GetError() == SEC_ERROR_BAD_PASSWORD) {
SECU_PrintError(progName,
SECU_PrintError(progName ? progName : "keyutil",
"%s: The password for token '%s' is incorrect\n",
PK11_GetTokenName(slot));
}
@ -280,7 +278,6 @@ static SECStatus nss_Init_Tokens(secuPWData *pwdata)
return status;
}
#endif
/*
* Loads the cert from the specified file into the module at
@ -336,7 +333,7 @@ static SECStatus loadCert(
*/
cert = PK11_FindCertFromNickname((char *)nickname, NULL);
if (!cert) {
SECU_PrintError(progName,
SECU_PrintError(progName ? progName : "keyutil",
"%s: Can't find cert named (%s), bailing out\n", nickname);
rv = 255;
break;
@ -391,7 +388,7 @@ static SECStatus loadKey(
if (!object) {
rv = SEC_ERROR_BAD_KEY;
PR_SetError(rv, 0);
SECU_PrintError(progName,
SECU_PrintError(progName ? progName : "keyutil",
"Unable to create key object (%s)\n", SECU_Strerror(rv));
break;
}
@ -403,7 +400,7 @@ static SECStatus loadKey(
rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
if (rv != SECSuccess) {
SECU_PrintError(progName,
SECU_PrintError(progName ? progName : "keyutil",
"Can't authenticate\n", SECU_Strerror(rv));
break;
}
@ -417,7 +414,7 @@ static SECStatus loadKey(
privkey = PK11_FindPrivateKeyFromCert(slot, cert, pwdata);
if (!privkey) {
rv = PR_GetError();
SECU_PrintError(progName,
SECU_PrintError(progName ? progName : "keyutil",
"Unable to find the key for cert, (%s)\n", SECU_Strerror(rv));
GEN_BREAK(SECFailure);
}
@ -523,7 +520,7 @@ static SECStatus extractRSAKeysAndSubject(
if (!*subject) {
SECU_PrintError(progName,
"Improperly formatted name: \"%s\"\n",
progName, cert->subjectName);
cert->subjectName);
GEN_BREAK(SECFailure);
}
rv = SECSuccess;
@ -724,7 +721,7 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
}
static CERTCertificate *
MakeV1Cert(CERTCertDBHandle * handle,
MakeV1Cert(CERTCertDBHandle *handle,
CERTCertificateRequest *req,
char *issuerNickName,
PRBool selfsign,
@ -852,9 +849,6 @@ done:
return result;
}
/*
* Modelled after the one in certutil
*/
static SECStatus
CreateCert(
CERTCertDBHandle *handle,
@ -970,42 +964,6 @@ typedef enum _CommandType {
cmd_CreateNewCert
} CommandType;
/*
* Get the key encryption password from a password file.
* Stores the password from pwFile in pwitem.
*/
PRBool GetKeyPassword(const char *pwFile, SECItem *pwitem)
{
int i;
unsigned char phrase[200];
PRFileDesc *fd;
PRInt32 nb;
if (!pwFile)
return PR_FALSE;
fd = PR_Open(pwFile, PR_RDONLY, 0);
if (!fd)
return PR_FALSE;
nb = PR_Read(fd, phrase, sizeof(phrase));
PR_Close(fd);
/* handle the Windows EOL case */
i = 0;
while (phrase[i] != '\r' && phrase[i] != '\n' && i < nb)
i++;
phrase[i] = '\0';
if (nb == 0)
return PR_FALSE;
pwitem->data = (unsigned char *) PORT_Strdup((char*)phrase);
pwitem->len = (unsigned int) strlen((char*)phrase);
pwitem->type = siBuffer;
return PR_TRUE;
}
/* returns 0 for success, -1 for failure (EOF encountered) */
static int
UpdateRNG(void)
@ -1248,7 +1206,7 @@ SECStatus DecryptKey(
/* Output the private key to a file */
static SECStatus
KeyOut(const char *keyoutfile,
const char *key_pwd_file,
const char *keyEncPwd,
SECKEYPrivateKey *privkey,
SECKEYPublicKey *pubkey,
SECOidTag algTag,
@ -1272,12 +1230,11 @@ KeyOut(const char *keyoutfile,
int rv = SECSuccess;
do {
/* Caller wants an encrypted key. Get
* the password from the file */
if (key_pwd_file) {
if (!GetKeyPassword(key_pwd_file, &pwitem)) {
return 255;
}
/* Caller wants an encrypted key. */
if (keyEncPwd) {
pwitem.data = (unsigned char *) PORT_Strdup((char*)keyEncPwd);
pwitem.len = (unsigned int) strlen((char*)keyEncPwd);
pwitem.type = siBuffer;
} else {
/* Caller wants clear keys. Make up a dummy
* password to get NSS to export an encrypted
@ -1307,13 +1264,14 @@ KeyOut(const char *keyoutfile,
arenaForEPKI = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
assert(arenaForEPKI);
if (key_pwd_file) {
if (keyEncPwd) {
/* NULL dest to let it allocate memory for us */
derEPKI = SEC_ASN1EncodeItem(arenaForEPKI, NULL, epki,
SECKEY_EncryptedPrivateKeyInfoTemplate);
if (!derEPKI) {
SECU_PrintError(progName, "%s ASN1 Encode failed (%dl)\n",
SECU_Strerror(PR_GetError()));
rv = PR_GetError();
SECU_PrintError(progName, "ASN1 Encode failed (%s)\n",
SECU_Strerror(rv));
GEN_BREAK(rv);
}
@ -1337,9 +1295,9 @@ KeyOut(const char *keyoutfile,
if (ascii) {
/* we could be exporting a clear or encrypted key */
SECItem *src = key_pwd_file ? derEPKI : &derPKI;
char *header = key_pwd_file ? ENCRYPTED_KEY_HEADER : KEY_HEADER;
char *trailer = key_pwd_file ? ENCRYPTED_KEY_TRAILER : KEY_TRAILER;
SECItem *src = keyEncPwd ? derEPKI : &derPKI;
char *header = keyEncPwd ? ENCRYPTED_KEY_HEADER : KEY_HEADER;
char *trailer = keyEncPwd ? ENCRYPTED_KEY_TRAILER : KEY_TRAILER;
char *b64 = NULL;
do {
@ -1367,7 +1325,7 @@ KeyOut(const char *keyoutfile,
}
} else {
if (key_pwd_file) {
if (keyEncPwd) {
/* Write out the encrypted key */
numBytes = PR_Write(keyOutFile, derEPKI, derEPKI->len);
} else {
@ -1388,9 +1346,6 @@ KeyOut(const char *keyoutfile,
PR_Close(keyOutFile);
}
if (derEPKI != NULL)
PORT_Free(derEPKI);
if (arenaForEPKI) {
PORT_FreeArena(arenaForEPKI, PR_FALSE);
}
@ -1399,9 +1354,15 @@ KeyOut(const char *keyoutfile,
PORT_FreeArena(arenaForPKI, PR_FALSE);
}
if (!key_pwd_file) {
if (!keyEncPwd) {
/* paranoia, though stack-based object we clear it anyway */
memset(randomPassword, 0, RAND_PASS_LEN);
} else {
if (pwitem.data) {
memset(pwitem.data, 0, pwitem.len);
PORT_Free(pwitem.data);
}
memset(&pwitem, 0, sizeof(SECItem));
}
return rv;
@ -1414,7 +1375,7 @@ static int keyutil_main(
CERTCertDBHandle *certHandle,
const char *noisefile,
const char *access_pwd_file,
const char *key_pwd_file,
const char *keyEncPwd,
const char *cert_to_renew,
const char *input_key_file,
PRBool cacert,
@ -1445,6 +1406,10 @@ static int keyutil_main(
if (access_pwd_file) {
pwdata.source = PW_FROMFILE;
pwdata.data = (char *)access_pwd_file;
rv = nss_Init_Tokens(&pwdata);
if (SECSuccess != rv) {
goto shutdown;
}
}
if (cert_to_renew && input_key_file) {
@ -1485,7 +1450,6 @@ static int keyutil_main(
rv = extractRSAKeysAndSubject(nickname,
slot, &pwdata, &privkey, &pubkey, &subject);
if (rv != SECSuccess) {
if (keycert) {
CERT_DestroyCertificate(keycert);
@ -1497,6 +1461,8 @@ static int keyutil_main(
assert(pubkey);
assert(subject);
printf("Read keys and subject from the cert to renew\n");
} else {
/*
* This is a certificate signing request for a new cert,
@ -1520,8 +1486,8 @@ static int keyutil_main(
rv = 255;
goto shutdown;
}
printf("Made a key\n");
}
PR_fprintf(PR_STDOUT, "%s Got a key\n", progName);
outFile = PR_Open(certreqfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);
if (!outFile) {
@ -1549,13 +1515,12 @@ static int keyutil_main(
PR_Close(outFile);
if (rv) {
PR_fprintf(PR_STDERR, "%s CertReq failed: \"%d\"\n",
progName, PORT_GetError());
SECU_PrintError(progName ? progName : "keyutil",
"CertReq failed: \"%s\"\n", SECU_Strerror(rv));
rv = 255;
goto shutdown;
}
PR_fprintf(PR_STDOUT, "%s Made a cert request\n", progName);
if (doCert) {
/* If making a cert, we already have a cert request file.
@ -1583,7 +1548,6 @@ static int keyutil_main(
}
outFile = PR_Open(certfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);
if (!outFile) {
SECU_PrintError(progName, "Failed to open file \"%s\" (%ld, %ld).\n",
certfile, PR_GetError(), PR_GetOSError());
@ -1610,7 +1574,7 @@ static int keyutil_main(
rv = SECFailure;
goto shutdown;
}
PR_fprintf(PR_STDOUT, "%s Created a cert\n", progName);
printf("Created a certificate\n");
/* Sanity check: Check cert validity against current time. */
@ -1622,7 +1586,10 @@ static int keyutil_main(
PK11_GetTokenName(slot));
goto shutdown;
}
printf("Authenticated to token\n");
}
} else {
printf("Wrote the CSR to %s\n", certreqfile);
}
/* If the caller wants the private key extract it and save it to a file. */
@ -1630,13 +1597,13 @@ static int keyutil_main(
/* Two candidate tags to use: SEC_OID_DES_EDE3_CBC and
* SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
*/
rv = KeyOut(keyoutfile, key_pwd_file,
rv = KeyOut(keyoutfile, keyEncPwd,
privkey, pubkey, SEC_OID_DES_EDE3_CBC,
&pwdata, ascii);
if (rv != SECSuccess) {
SECU_PrintError(progName, "Failed to write the key");
} else {
printf("%s Wrote the key to\n%s\n", progName, keyoutfile);
printf("Wrote the key to:\n%s\n", keyoutfile);
}
}
@ -1664,7 +1631,7 @@ shutdown:
return rv == SECSuccess ? 0 : 255;
}
/* $Id: keyutil.c,v 1.9 2008/10/20 20:45:04 emaldonado Exp $ */
/* $Id: keyutil.c,v 1.10 2008/10/26 23:50:45 emaldonado Exp $ */
/* Key generation, encryption, and certificate utility code, based on
* code from NSS's security utilities and the certutil application.
@ -1685,7 +1652,7 @@ int main(int argc, char **argv)
char *cert_to_renew = NULL;
char *subject = NULL;
char *access_pwd_file = NULL;
char *key_pwd_file = NULL;
char *keyEncPwd = NULL;
char *digestAlgorithm = "md5";
char *keyoutfile = 0;
PRBool ascii = PR_FALSE;
@ -1734,12 +1701,12 @@ int main(int argc, char **argv)
printf("valid for %d months\n", validity_months);
break;
case 'e':
key_pwd_file = strdup(optarg);
printf("key encryption password from = %s\n", key_pwd_file);
keyPassword = strdup(optarg);
printf("key encryption password = ****\n");
break;
case 'f':
access_pwd_file = strdup(optarg);
printf("module access password from = %s\n", access_pwd_file);
printf("module access password from %s\n", access_pwd_file);
break;
case 'd':
digestAlgorithm = strdup(optarg);
@ -1811,14 +1778,14 @@ int main(int argc, char **argv)
case cmd_CertReq:
/* certfile NULL signals only the request is needed */
rv = keyutil_main(certHandle,
noisefile, access_pwd_file, key_pwd_file,
noisefile, access_pwd_file, keyEncPwd,
cert_to_renew, keyfile, cacert,
subject, keysize, warpmonths, validity_months,
ascii, outfile, NULL, keyoutfile);
break;
case cmd_CreateNewCert:
rv = keyutil_main(certHandle,
noisefile, access_pwd_file, key_pwd_file,
noisefile, access_pwd_file, keyEncPwd,
NULL, NULL, cacert, /* ignored */
subject, keysize, warpmonths, validity_months,
ascii, "tmprequest", outfile, keyoutfile);