2008-05-01 01:06:47 +00:00
|
|
|
/*
|
|
|
|
Copyright 2005 Red Hat, Inc.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
In addition, as a special exception, Red Hat, Inc. gives permission
|
|
|
|
to link the code of this program with the OpenSSL library (or with
|
|
|
|
modified versions of OpenSSL that use the same license as OpenSSL),
|
|
|
|
and distribute linked combinations including the two. You must obey
|
|
|
|
the GNU General Public License in all respects for all of the code
|
|
|
|
used other than OpenSSL. If you modify this file, you may extend
|
|
|
|
this exception to your version of the file, but you are not
|
|
|
|
obligated to do so. If you do not wish to do so, delete this
|
|
|
|
exception statement from your version.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* ***** 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):
|
|
|
|
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
|
|
|
|
*
|
|
|
|
* 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 ***** */
|
|
|
|
|
|
|
|
/*
|
2008-10-01 21:22:49 +00:00
|
|
|
* keyutil.c
|
|
|
|
*
|
2008-10-20 20:45:04 +00:00
|
|
|
* Command line utility for generating certificates and certificate signing requests.
|
|
|
|
* It is invoked by crypto-utils' genkey when used in OpenSSL compatibility mode.
|
2008-10-01 21:22:49 +00:00
|
|
|
*
|
2008-10-20 20:45:04 +00:00
|
|
|
* Key generation, encryption, and certificate utility code based on
|
|
|
|
* on code from NSS's security utilities and the certutil application.
|
|
|
|
* Pem file key and certificate loading code based on code from the
|
|
|
|
* NSS-enabled libcurl.
|
2008-10-01 21:22:49 +00:00
|
|
|
* Elio Maldonado <emaldona@redhat.com>
|
|
|
|
*
|
|
|
|
*/
|
2008-05-01 01:06:47 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <termios.h>
|
|
|
|
|
|
|
|
#include <prerror.h>
|
|
|
|
#include <secerr.h>
|
|
|
|
|
|
|
|
#include <nspr.h>
|
|
|
|
#include <nss.h>
|
|
|
|
#include <cert.h>
|
|
|
|
#include <certt.h>
|
|
|
|
#include <prio.h>
|
|
|
|
#include <prlong.h>
|
|
|
|
#include <prtime.h>
|
2008-05-02 23:42:20 +00:00
|
|
|
#include <pkcs11.h>
|
2008-05-01 01:06:47 +00:00
|
|
|
#include <pk11pub.h>
|
|
|
|
#include <pkcs11t.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <secmod.h>
|
|
|
|
#include <base64.h>
|
|
|
|
#include <seccomon.h>
|
|
|
|
#include <secmodt.h>
|
|
|
|
#include <secoidt.h>
|
|
|
|
#include <keythi.h>
|
|
|
|
#include <keyhi.h>
|
|
|
|
#include <cryptohi.h>
|
|
|
|
#include <plarenas.h>
|
|
|
|
#include <secasn1.h>
|
|
|
|
|
2008-05-02 23:42:20 +00:00
|
|
|
#include <secpkcs5.h>
|
|
|
|
#include <keythi.h>
|
|
|
|
#include <secmodt.h>
|
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include "keyutil.h"
|
|
|
|
#include "secutil.h"
|
|
|
|
|
2008-05-03 22:54:55 +00:00
|
|
|
#define MIN_KEY_BITS 512
|
2008-05-01 01:06:47 +00:00
|
|
|
/* MAX_KEY_BITS should agree with MAX_RSA_MODULUS in freebl */
|
2008-05-03 22:54:55 +00:00
|
|
|
#define MAX_KEY_BITS 8192
|
|
|
|
#define DEFAULT_KEY_BITS 1024
|
2008-05-01 01:06:47 +00:00
|
|
|
|
2008-05-03 22:54:55 +00:00
|
|
|
#define SEC_CT_PRIVATE_KEY "private-key"
|
|
|
|
#define SEC_CT_PUBLIC_KEY "public-key"
|
|
|
|
#define SEC_CT_CERTIFICATE "certificate"
|
|
|
|
#define SEC_CT_CERTIFICATE_REQUEST "certificate-request"
|
|
|
|
#define SEC_CT_PKCS7 "pkcs7"
|
|
|
|
#define SEC_CT_CRL "crl"
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
#define NS_CERTREQ_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
|
|
|
|
#define NS_CERTREQ_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
|
|
|
|
|
|
|
|
#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----"
|
|
|
|
#define NS_CERT_TRAILER "-----END CERTIFICATE-----"
|
|
|
|
|
|
|
|
#define NS_CRL_HEADER "-----BEGIN CRL-----"
|
|
|
|
#define NS_CRL_TRAILER "-----END CRL-----"
|
|
|
|
|
|
|
|
#define KEY_HEADER "-----BEGIN PRIVATE KEY-----"
|
|
|
|
#define KEY_TRAILER "-----END PRIVATE KEY-----"
|
|
|
|
|
|
|
|
#define ENCRYPTED_KEY_HEADER "-----BEGIN ENCRYPTED PRIVATE KEY-----"
|
|
|
|
#define ENCRYPTED_KEY_TRAILER "-----END ENCRYPTED PRIVATE KEY-----"
|
|
|
|
|
|
|
|
#define REP_MECHANISM mechanism[testId/2/2%46]
|
|
|
|
|
|
|
|
#define NUM_KEYSTROKES 120
|
|
|
|
#define RAND_BUF_SIZE 60
|
|
|
|
|
|
|
|
#define ERROR_BREAK rv = SECFailure;break;
|
|
|
|
|
|
|
|
#define GEN_BREAK(e) rv=e; break;
|
|
|
|
|
|
|
|
struct tuple_str {
|
2008-05-03 22:54:55 +00:00
|
|
|
PRErrorCode errNum;
|
2008-05-01 01:06:47 +00:00
|
|
|
const char * errString;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct tuple_str tuple_str;
|
|
|
|
|
|
|
|
#define ER2(a,b) {a, b},
|
|
|
|
#define ER3(a,b,c) {a, c},
|
|
|
|
|
|
|
|
#include "secerr.h"
|
|
|
|
#include "sslerr.h"
|
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
#ifndef PK11_SETATTRS
|
|
|
|
#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
|
|
|
|
(x)->pValue=(v); (x)->ulValueLen = (l);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SECMODModule* mod = NULL; /* the pem module */
|
|
|
|
static const char* pem_library = "libnsspem.so";
|
|
|
|
/* will use this slot only */
|
|
|
|
CK_SLOT_ID slotID = 1;
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
char *progName;
|
|
|
|
|
2008-10-19 17:50:08 +00:00
|
|
|
static const struct option options[] = {
|
|
|
|
{ "command", required_argument, NULL, 'c' },
|
|
|
|
{ "renew", required_argument, NULL, 'r' },
|
|
|
|
{ "subject", required_argument, NULL, 's' },
|
|
|
|
{ "gkeysize", required_argument, NULL, 'g' },
|
|
|
|
{ "validity", required_argument, NULL, 'v' },
|
|
|
|
{ "encpwdfile", required_argument, NULL, 'e' },
|
|
|
|
{ "filepwdnss", required_argument, NULL, 'f' },
|
|
|
|
{ "digest", required_argument, NULL, 'd' },
|
|
|
|
{ "znoisefile", required_argument, NULL, 'z' },
|
|
|
|
{ "input", required_argument, NULL, 'i' }, /* key in */
|
|
|
|
{ "passout", required_argument, NULL, 'p' },
|
|
|
|
{ "output", required_argument, NULL, 'o' }, /* reg, cert, enckey */
|
|
|
|
{ "keyout", required_argument, NULL, 'k' }, /* plaintext key */
|
|
|
|
{ "ascii", no_argument, NULL, 'a' }, /* ascii */
|
|
|
|
{ "cacert", no_argument, NULL, 't' }, /* ca cert renewal */
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
static void
|
|
|
|
Usage(char *progName)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Usage: %s [options] arguments\n", progName);
|
2008-10-19 17:50:08 +00:00
|
|
|
fprintf(stderr, "{-c|--command} command, one of [genreq|makecert]");
|
2008-10-26 23:50:45 +00:00
|
|
|
fprintf(stderr, "{-r|--renew} cert-to-renew the file with the certifificast to renew");
|
2008-10-19 17:50:08 +00:00
|
|
|
fprintf(stderr, "{-s|--subject} subject subject distinguished name");
|
|
|
|
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");
|
2008-10-26 23:50:45 +00:00
|
|
|
fprintf(stderr, "{-e|--filepwdnss} keypwdfile file with the key encryption_password");
|
2008-10-19 17:50:08 +00:00
|
|
|
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");
|
|
|
|
fprintf(stderr, "{-p|--passout} pbe-password the password for encrypting of the key");
|
|
|
|
fprintf(stderr, "{-o|--output} out-file output file for a csr or cert");
|
|
|
|
fprintf(stderr, "{-k|--keyfile} out-key-file output key file, with csr or certgen");
|
|
|
|
fprintf(stderr, "{-t|--cacert} indicates that cert renewal is for a ca");
|
|
|
|
fprintf(stderr, "{-h|--help} print this help message");
|
2008-05-03 22:54:55 +00:00
|
|
|
fprintf(stderr, "\n");
|
|
|
|
exit(1);
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
2008-10-26 23:50:45 +00:00
|
|
|
|
|
|
|
#if(0)
|
|
|
|
/*
|
|
|
|
* Authenticates to any token that may require it.
|
|
|
|
* It also checks that the NSS database ahs been initialized.
|
|
|
|
* This function is modeled after the one in libcurl.
|
|
|
|
*/
|
|
|
|
static SECStatus nss_Init_Tokens(secuPWData *pwdata)
|
|
|
|
{
|
|
|
|
PK11SlotList *slotList;
|
|
|
|
PK11SlotListElement *listEntry;
|
|
|
|
SECStatus ret, status = SECSuccess;
|
|
|
|
|
|
|
|
PK11_SetPasswordFunc(SECU_GetModulePassword);
|
|
|
|
|
|
|
|
/* List all currently available tokens and traverse
|
|
|
|
* the list authenticating to them
|
|
|
|
*/
|
|
|
|
slotList = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL);
|
|
|
|
|
|
|
|
for (listEntry = PK11_GetFirstSafe(slotList);
|
|
|
|
listEntry; listEntry = listEntry->next) {
|
|
|
|
|
|
|
|
PK11SlotInfo *slot = listEntry->slot;
|
|
|
|
|
|
|
|
if (PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) {
|
|
|
|
if (slot == PK11_GetInternalKeySlot()) {
|
|
|
|
SECU_PrintError(progName,
|
|
|
|
"The NSS database has not been initialized\n");
|
|
|
|
} else {
|
|
|
|
SECU_PrintError(progName,
|
|
|
|
"The token %s has not been initialized",
|
|
|
|
PK11_GetTokenName(slot));
|
|
|
|
}
|
|
|
|
PK11_FreeSlot(slot);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = PK11_Authenticate(slot, PR_TRUE, &pwdata);
|
|
|
|
if (SECSuccess != ret) {
|
|
|
|
if (PR_GetError() == SEC_ERROR_BAD_PASSWORD) {
|
|
|
|
SECU_PrintError(progName,
|
|
|
|
"%s: The password for token '%s' is incorrect\n",
|
|
|
|
PK11_GetTokenName(slot));
|
|
|
|
}
|
|
|
|
status = SECFailure;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PK11_FreeSlot(slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
/*
|
2008-10-19 05:08:53 +00:00
|
|
|
* Loads the cert from the specified file into the module at
|
|
|
|
* the specified slot.
|
|
|
|
*
|
|
|
|
* This function is modelled after the one in libcurl.
|
|
|
|
*
|
|
|
|
* @param slot the slot to load the cert into
|
|
|
|
* @param cacert true if the cert is for a ca, false otherwise
|
|
|
|
* @param certfile pem encoded file with the certificate
|
|
|
|
* @param nickname the certificate niskanme
|
2008-10-01 21:22:49 +00:00
|
|
|
*/
|
|
|
|
static SECStatus loadCert(
|
|
|
|
PK11SlotInfo *slot,
|
2008-10-19 05:08:53 +00:00
|
|
|
PRBool cacert,
|
2008-10-01 21:22:49 +00:00
|
|
|
const char *certfile,
|
|
|
|
const char *nickname)
|
|
|
|
{
|
2008-10-20 20:45:04 +00:00
|
|
|
SECStatus rv = SECSuccess;
|
2008-10-01 21:22:49 +00:00
|
|
|
PK11GenericObject *genericObjCert;
|
|
|
|
CK_ATTRIBUTE theCertTemplate[20];
|
|
|
|
CK_ATTRIBUTE *attrs = NULL;
|
|
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
|
|
CK_BBOOL ckfalse = CK_FALSE;
|
|
|
|
CK_OBJECT_CLASS certObjClass = CKO_CERTIFICATE;
|
|
|
|
CERTCertificate *cert = NULL;
|
|
|
|
|
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* Load the certificate
|
|
|
|
*/
|
2008-10-20 20:45:04 +00:00
|
|
|
attrs = theCertTemplate;
|
2008-10-01 21:22:49 +00:00
|
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &certObjClass, sizeof(certObjClass)); attrs++;
|
|
|
|
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); attrs++;
|
|
|
|
PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)certfile, strlen(certfile)+1); attrs++;
|
|
|
|
if (cacert) {
|
|
|
|
PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
|
|
|
|
} else {
|
|
|
|
PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load the certificate in our PEM module into the appropriate slot. */
|
|
|
|
genericObjCert = PK11_CreateGenericObject(slot, theCertTemplate, 4, PR_FALSE /* isPerm */);
|
|
|
|
if (!genericObjCert) {
|
2008-10-20 20:45:04 +00:00
|
|
|
rv = PR_GetError();
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
|
|
|
"Unable to create object for cert, (%s)", SECU_Strerror(rv));
|
2008-10-01 21:22:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!cacert) {
|
|
|
|
/* Double-check that the certificate or nickname requested exists in
|
|
|
|
* either the token or the NSS certificate database.
|
|
|
|
*/
|
|
|
|
cert = PK11_FindCertFromNickname((char *)nickname, NULL);
|
2008-10-20 20:45:04 +00:00
|
|
|
if (!cert) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
|
|
|
"%s: Can't find cert named (%s), bailing out\n", nickname);
|
2008-10-20 20:45:04 +00:00
|
|
|
rv = 255;
|
|
|
|
break;
|
2008-10-01 21:22:49 +00:00
|
|
|
} else {
|
|
|
|
rv = SECSuccess;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rv = SECSuccess;
|
2008-10-19 05:08:53 +00:00
|
|
|
}
|
2008-10-01 21:22:49 +00:00
|
|
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
if (cert)
|
2008-10-20 20:45:04 +00:00
|
|
|
CERT_DestroyCertificate(cert);
|
2008-10-01 21:22:49 +00:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-10-19 05:08:53 +00:00
|
|
|
* Loads the key from the specified file into the module at
|
|
|
|
* the specified slot.
|
|
|
|
*
|
|
|
|
* function is modelled after the one in libcurl.
|
|
|
|
* @param slot the slot into which the key will be loaded
|
|
|
|
* @param keyfile the file from which the key will be read
|
|
|
|
* @param nickname the nickname of the matching certificate
|
2008-10-01 21:22:49 +00:00
|
|
|
*/
|
|
|
|
static SECStatus loadKey(
|
2008-10-20 20:45:04 +00:00
|
|
|
PK11SlotInfo *slot,
|
|
|
|
const char *keyfile,
|
|
|
|
const char *nickname,
|
|
|
|
secuPWData *pwdata)
|
2008-10-01 21:22:49 +00:00
|
|
|
{
|
|
|
|
SECStatus rv = SECSuccess;
|
|
|
|
CK_ATTRIBUTE *attrs = NULL;
|
|
|
|
CK_BBOOL cktrue = CK_TRUE;
|
|
|
|
PRBool isPresent;
|
|
|
|
PK11GenericObject *object;
|
|
|
|
CK_ATTRIBUTE theTemplate[20];
|
|
|
|
CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
|
|
|
|
CERTCertificate *cert = NULL;
|
|
|
|
SECKEYPrivateKey *privkey = NULL;
|
|
|
|
|
2008-10-20 20:45:04 +00:00
|
|
|
do {
|
2008-10-01 21:22:49 +00:00
|
|
|
attrs = theTemplate;
|
|
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
|
|
|
|
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
|
|
|
|
PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)keyfile, strlen(keyfile)+1); attrs++;
|
|
|
|
|
|
|
|
/* When adding an encrypted key the PKCS#11 will be set as removed */
|
|
|
|
object = PK11_CreateGenericObject(slot, theTemplate, 3, PR_FALSE /* isPerm */);
|
2008-10-19 05:08:53 +00:00
|
|
|
if (!object) {
|
2008-10-20 20:45:04 +00:00
|
|
|
rv = SEC_ERROR_BAD_KEY;
|
|
|
|
PR_SetError(rv, 0);
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
|
|
|
"Unable to create key object (%s)\n", SECU_Strerror(rv));
|
2008-10-20 20:45:04 +00:00
|
|
|
break;
|
2008-10-01 21:22:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This will force the token to be seen as re-inserted */
|
|
|
|
(void) SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
|
|
|
|
isPresent = PK11_IsPresent(slot);
|
|
|
|
assert(isPresent);
|
|
|
|
|
2008-10-26 23:50:45 +00:00
|
|
|
rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
SECU_PrintError(progName,
|
|
|
|
"Can't authenticate\n", SECU_Strerror(rv));
|
2008-10-01 21:22:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-10-19 05:08:53 +00:00
|
|
|
/* must find it again because "reinsertion" */
|
|
|
|
cert = PK11_FindCertFromNickname((char *)nickname, NULL);
|
|
|
|
assert(cert);
|
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
/* Can we find the key? */
|
|
|
|
|
2008-10-26 23:50:45 +00:00
|
|
|
privkey = PK11_FindPrivateKeyFromCert(slot, cert, pwdata);
|
2008-10-01 21:22:49 +00:00
|
|
|
if (!privkey) {
|
2008-10-20 20:45:04 +00:00
|
|
|
rv = PR_GetError();
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
|
|
|
"Unable to find the key for cert, (%s)\n", SECU_Strerror(rv));
|
2008-10-01 21:22:49 +00:00
|
|
|
GEN_BREAK(SECFailure);
|
|
|
|
}
|
|
|
|
rv = SECSuccess;
|
|
|
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
if (cert)
|
2008-10-20 20:45:04 +00:00
|
|
|
CERT_DestroyCertificate(cert);
|
2008-10-01 21:22:49 +00:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loads the certificate and private key from the specified files into
|
|
|
|
* the PEM the module at the specified slot.
|
|
|
|
*
|
|
|
|
* @param slot the slot to load into
|
|
|
|
* @param certfile the certificate file
|
|
|
|
* @param nickname the certificate nickname
|
|
|
|
* @param keyfile the key file
|
|
|
|
* @param pwdata access password
|
|
|
|
*/
|
2008-10-20 20:45:04 +00:00
|
|
|
static SECStatus
|
|
|
|
loadCertAndKey(
|
|
|
|
PK11SlotInfo *slot,
|
|
|
|
PRBool cacert,
|
|
|
|
const char *certfile,
|
|
|
|
const char *nickname,
|
|
|
|
const char *keyfile,
|
|
|
|
secuPWData *pwdata)
|
2008-10-01 21:22:49 +00:00
|
|
|
{
|
2008-10-20 20:45:04 +00:00
|
|
|
SECStatus rv = SECSuccess;
|
2008-10-01 21:22:49 +00:00
|
|
|
|
2008-10-19 05:08:53 +00:00
|
|
|
/*
|
|
|
|
* Load the certificate first
|
2008-10-20 20:45:04 +00:00
|
|
|
*/
|
2008-10-19 05:08:53 +00:00
|
|
|
rv = loadCert(slot, cacert, certfile, nickname);
|
|
|
|
if (rv != SECSuccess) return rv;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Load the private key next
|
|
|
|
*/
|
|
|
|
rv = loadKey(slot, keyfile, nickname, pwdata);
|
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2008-10-19 05:08:53 +00:00
|
|
|
/*
|
|
|
|
* Extract the public and private keys and the subject
|
|
|
|
* distinguished from the cert with the given nickname
|
|
|
|
* in the given slot.
|
|
|
|
*
|
|
|
|
* @param nickname the certificate nickname
|
|
|
|
* @param slot the slot where keys it was loaded
|
2008-10-26 23:50:45 +00:00
|
|
|
* @param pwdat module authentication password
|
2008-10-19 05:08:53 +00:00
|
|
|
* @param privkey private key out
|
|
|
|
* @param pubkey public key out
|
|
|
|
* @param subject subject out
|
|
|
|
*/
|
2008-10-01 21:22:49 +00:00
|
|
|
static SECStatus extractRSAKeysAndSubject(
|
|
|
|
const char *nickname,
|
|
|
|
PK11SlotInfo *slot,
|
2008-10-26 23:50:45 +00:00
|
|
|
secuPWData *pwdata,
|
2008-10-01 21:22:49 +00:00
|
|
|
SECKEYPrivateKey **privkey,
|
|
|
|
SECKEYPublicKey **pubkey,
|
|
|
|
CERTName **subject)
|
|
|
|
{
|
2008-10-20 20:45:04 +00:00
|
|
|
SECStatus rv = SECSuccess;
|
|
|
|
CERTCertificate *cert = NULL;
|
2008-10-01 21:22:49 +00:00
|
|
|
|
|
|
|
do {
|
2008-10-20 20:45:04 +00:00
|
|
|
cert = PK11_FindCertFromNickname((char *)nickname, NULL);
|
|
|
|
if (!cert) {
|
|
|
|
GEN_BREAK(SECFailure);
|
|
|
|
}
|
2008-10-01 21:22:49 +00:00
|
|
|
|
|
|
|
*pubkey = CERT_ExtractPublicKey(cert);
|
|
|
|
if (!*pubkey) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
|
|
|
"Could not get public key from cert, (%s)\n",
|
|
|
|
SECU_Strerror(PR_GetError()));
|
2008-10-20 20:45:04 +00:00
|
|
|
GEN_BREAK(SECFailure);
|
2008-10-01 21:22:49 +00:00
|
|
|
}
|
|
|
|
|
2008-10-26 23:50:45 +00:00
|
|
|
*privkey = PK11_FindKeyByDERCert(slot, cert, pwdata);
|
2008-10-01 21:22:49 +00:00
|
|
|
if (!*privkey) {
|
2008-10-20 20:45:04 +00:00
|
|
|
rv = PR_GetError();
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
|
|
|
"Unable to find the key with PK11_FindKeyByDERCert, (%s)\n",
|
|
|
|
SECU_Strerror(rv));
|
2008-10-20 20:45:04 +00:00
|
|
|
*privkey= PK11_FindKeyByAnyCert(cert, &pwdata);
|
|
|
|
rv = PR_GetError();
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
|
|
|
"Unable to find the key with PK11_FindKeyByAnyCert, (%s)\n",
|
|
|
|
SECU_Strerror(rv));
|
2008-10-01 21:22:49 +00:00
|
|
|
GEN_BREAK(SECFailure);
|
|
|
|
}
|
|
|
|
|
2008-10-20 20:45:04 +00:00
|
|
|
assert(((*privkey)->keyType) == rsaKey);
|
2008-10-01 21:22:49 +00:00
|
|
|
*subject = CERT_AsciiToName(cert->subjectName);
|
|
|
|
|
2008-10-20 20:45:04 +00:00
|
|
|
if (!*subject) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
|
|
|
"Improperly formatted name: \"%s\"\n",
|
|
|
|
progName, cert->subjectName);
|
2008-10-20 20:45:04 +00:00
|
|
|
GEN_BREAK(SECFailure);
|
|
|
|
}
|
|
|
|
rv = SECSuccess;
|
2008-10-01 21:22:49 +00:00
|
|
|
} while (0);
|
|
|
|
|
|
|
|
if (cert)
|
|
|
|
CERT_DestroyCertificate(cert);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
/*
|
2008-10-20 20:45:04 +00:00
|
|
|
* GetCertRequest, CertReq, MakeV1Cert, SignCert, and CreateCert
|
|
|
|
* are modeled after the corresponding ones in certutil.
|
2008-05-11 02:53:02 +00:00
|
|
|
*/
|
2008-10-20 20:45:04 +00:00
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
static CERTCertificateRequest *
|
|
|
|
GetCertRequest(PRFileDesc *inFile, PRBool ascii)
|
|
|
|
{
|
|
|
|
CERTCertificateRequest *certReq = NULL;
|
|
|
|
CERTSignedData signedData;
|
|
|
|
PRArenaPool *arena = NULL;
|
|
|
|
SECItem reqDER;
|
|
|
|
SECStatus rv;
|
|
|
|
|
|
|
|
reqDER.data = NULL;
|
|
|
|
do {
|
2008-05-03 22:54:55 +00:00
|
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
|
|
if (arena == NULL) {
|
2008-05-11 02:53:02 +00:00
|
|
|
GEN_BREAK(SECFailure);
|
2008-05-03 22:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rv = SECU_ReadDERFromFile(&reqDER, inFile, ascii);
|
|
|
|
if (rv) {
|
2008-05-11 02:53:02 +00:00
|
|
|
GEN_BREAK(rv);
|
2008-05-03 22:54:55 +00:00
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc
|
2008-05-03 22:54:55 +00:00
|
|
|
(arena, sizeof(CERTCertificateRequest));
|
2008-05-01 01:06:47 +00:00
|
|
|
if (!certReq) {
|
2008-05-11 02:53:02 +00:00
|
|
|
GEN_BREAK(SECFailure);
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
2008-05-03 22:54:55 +00:00
|
|
|
certReq->arena = arena;
|
|
|
|
|
|
|
|
/* Since cert request is a signed data, must decode to get the inner
|
|
|
|
data
|
|
|
|
*/
|
|
|
|
PORT_Memset(&signedData, 0, sizeof(signedData));
|
|
|
|
rv = SEC_ASN1DecodeItem(arena, &signedData,
|
2008-05-11 02:53:02 +00:00
|
|
|
SEC_ASN1_GET(CERT_SignedDataTemplate), &reqDER);
|
2008-05-03 22:54:55 +00:00
|
|
|
if (rv) {
|
2008-05-11 02:53:02 +00:00
|
|
|
GEN_BREAK(rv);
|
2008-05-03 22:54:55 +00:00
|
|
|
}
|
|
|
|
rv = SEC_ASN1DecodeItem(arena, certReq,
|
|
|
|
SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data);
|
|
|
|
if (rv) {
|
2008-05-11 02:53:02 +00:00
|
|
|
GEN_BREAK(rv);
|
2008-05-03 22:54:55 +00:00
|
|
|
}
|
|
|
|
rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData,
|
2008-05-11 02:53:02 +00:00
|
|
|
&certReq->subjectPublicKeyInfo, NULL /* wincx */);
|
2008-05-01 01:06:47 +00:00
|
|
|
} while (0);
|
|
|
|
|
|
|
|
if (reqDER.data) {
|
2008-05-03 22:54:55 +00:00
|
|
|
SECITEM_FreeItem(&reqDER, PR_FALSE);
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rv) {
|
2008-05-03 22:54:55 +00:00
|
|
|
SECU_PrintError(progName, "bad certificate request\n");
|
|
|
|
if (arena) {
|
2008-05-11 02:53:02 +00:00
|
|
|
PORT_FreeArena(arena, PR_FALSE);
|
2008-05-03 22:54:55 +00:00
|
|
|
}
|
|
|
|
certReq = NULL;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return certReq;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SECStatus
|
|
|
|
CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
|
|
|
|
SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii,
|
2008-05-03 22:54:55 +00:00
|
|
|
const char *emailAddrs, const char *dnsNames,
|
2008-05-01 01:06:47 +00:00
|
|
|
certutilExtnList extnList,
|
|
|
|
PRFileDesc *outFile)
|
|
|
|
{
|
|
|
|
CERTSubjectPublicKeyInfo *spki;
|
|
|
|
CERTCertificateRequest *cr;
|
|
|
|
SECItem *encoding;
|
|
|
|
SECOidTag signAlgTag;
|
|
|
|
SECItem result;
|
|
|
|
SECStatus rv;
|
|
|
|
PRArenaPool *arena;
|
|
|
|
PRInt32 numBytes;
|
|
|
|
void *extHandle;
|
|
|
|
|
|
|
|
/* Create info about public key */
|
|
|
|
spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
|
|
|
|
if (!spki) {
|
2008-05-11 02:53:02 +00:00
|
|
|
SECU_PrintError(progName, "unable to create subject public key");
|
|
|
|
return SECFailure;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate certificate request */
|
|
|
|
cr = CERT_CreateCertificateRequest(subject, spki, NULL);
|
|
|
|
if (!cr) {
|
2008-05-11 02:53:02 +00:00
|
|
|
SECU_PrintError(progName, "unable to make certificate request");
|
|
|
|
return SECFailure;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
|
|
if ( !arena ) {
|
2008-05-11 02:53:02 +00:00
|
|
|
SECU_PrintError(progName, "out of memory");
|
|
|
|
return SECFailure;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
extHandle = CERT_StartCertificateRequestAttributes(cr);
|
|
|
|
if (extHandle == NULL) {
|
|
|
|
PORT_FreeArena (arena, PR_FALSE);
|
2008-05-03 22:54:55 +00:00
|
|
|
return SECFailure;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList)
|
|
|
|
!= SECSuccess) {
|
|
|
|
PORT_FreeArena (arena, PR_FALSE);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
CERT_FinishExtensions(extHandle);
|
|
|
|
CERT_FinishCertificateRequestAttributes(cr);
|
|
|
|
|
|
|
|
/* Der encode the request */
|
|
|
|
encoding = SEC_ASN1EncodeItem(arena, NULL, cr,
|
|
|
|
SEC_ASN1_GET(CERT_CertificateRequestTemplate));
|
|
|
|
if (encoding == NULL) {
|
2008-05-11 02:53:02 +00:00
|
|
|
SECU_PrintError(progName, "der encoding of request failed");
|
|
|
|
return SECFailure;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Sign the request */
|
|
|
|
signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
|
|
|
|
if (signAlgTag == SEC_OID_UNKNOWN) {
|
2008-05-11 02:53:02 +00:00
|
|
|
SECU_PrintError(progName, "unknown Key or Hash type");
|
|
|
|
return SECFailure;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len,
|
2008-05-03 22:54:55 +00:00
|
|
|
privk, signAlgTag);
|
2008-05-01 01:06:47 +00:00
|
|
|
if (rv) {
|
2008-05-11 02:53:02 +00:00
|
|
|
SECU_PrintError(progName, "signing of data failed");
|
|
|
|
return SECFailure;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Encode request in specified format */
|
|
|
|
if (ascii) {
|
2008-05-11 02:53:02 +00:00
|
|
|
char *obuf;
|
|
|
|
char *name, *email, *org, *state, *country;
|
|
|
|
SECItem *it;
|
|
|
|
int total;
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
it = &result;
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
obuf = BTOA_ConvertItemToAscii(it);
|
|
|
|
total = PL_strlen(obuf);
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
name = CERT_GetCommonName(subject);
|
|
|
|
if (!name) {
|
|
|
|
name = strdup("(not specified)");
|
|
|
|
}
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
if (!phone)
|
|
|
|
phone = strdup("(not specified)");
|
|
|
|
|
|
|
|
email = CERT_GetCertEmailAddress(subject);
|
|
|
|
if (!email)
|
|
|
|
email = strdup("(not specified)");
|
|
|
|
|
|
|
|
org = CERT_GetOrgName(subject);
|
|
|
|
if (!org)
|
|
|
|
org = strdup("(not specified)");
|
|
|
|
|
|
|
|
state = CERT_GetStateName(subject);
|
|
|
|
if (!state)
|
|
|
|
state = strdup("(not specified)");
|
|
|
|
|
|
|
|
country = CERT_GetCountryName(subject);
|
|
|
|
if (!country)
|
|
|
|
country = strdup("(not specified)");
|
|
|
|
|
|
|
|
PR_fprintf(outFile, "%s\n", NS_CERTREQ_HEADER);
|
|
|
|
numBytes = PR_Write(outFile, obuf, total);
|
|
|
|
if (numBytes != total) {
|
|
|
|
SECU_PrintSystemError(progName, "write error");
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
PR_fprintf(outFile, "\n%s\n", NS_CERTREQ_TRAILER);
|
|
|
|
} else {
|
|
|
|
numBytes = PR_Write(outFile, result.data, result.len);
|
|
|
|
if (numBytes != (int)result.len) {
|
|
|
|
SECU_PrintSystemError(progName, "write error");
|
|
|
|
return SECFailure;
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
return SECSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
static CERTCertificate *
|
2008-05-03 22:54:55 +00:00
|
|
|
MakeV1Cert(CERTCertDBHandle * handle,
|
|
|
|
CERTCertificateRequest *req,
|
|
|
|
char *issuerNickName,
|
|
|
|
PRBool selfsign,
|
|
|
|
unsigned int serialNumber,
|
|
|
|
int warpmonths,
|
2008-05-01 01:06:47 +00:00
|
|
|
int validityMonths)
|
|
|
|
{
|
|
|
|
CERTCertificate *issuerCert = NULL;
|
|
|
|
CERTValidity *validity;
|
|
|
|
CERTCertificate *cert = NULL;
|
|
|
|
PRExplodedTime printableTime;
|
|
|
|
PRTime now, after;
|
|
|
|
|
|
|
|
if ( !selfsign ) {
|
2008-05-03 22:54:55 +00:00
|
|
|
issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName);
|
|
|
|
if (!issuerCert) {
|
|
|
|
SECU_PrintError(progName, "could not find certificate named \"%s\"",
|
|
|
|
issuerNickName);
|
2008-05-11 02:53:02 +00:00
|
|
|
return NULL;
|
2008-05-03 22:54:55 +00:00
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
now = PR_Now();
|
|
|
|
PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
|
2008-05-11 02:53:02 +00:00
|
|
|
if ( warpmonths ) {
|
|
|
|
printableTime.tm_month += warpmonths;
|
|
|
|
now = PR_ImplodeTime (&printableTime);
|
|
|
|
PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
printableTime.tm_month += validityMonths;
|
|
|
|
after = PR_ImplodeTime (&printableTime);
|
|
|
|
|
|
|
|
/* note that the time is now in micro-second unit */
|
|
|
|
validity = CERT_CreateValidity (now, after);
|
|
|
|
if (validity) {
|
|
|
|
cert = CERT_CreateCertificate(serialNumber,
|
2008-05-03 22:54:55 +00:00
|
|
|
(selfsign ? &req->subject
|
|
|
|
: &issuerCert->subject),
|
|
|
|
validity, req);
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
CERT_DestroyValidity(validity);
|
|
|
|
}
|
|
|
|
if ( issuerCert ) {
|
2008-05-11 02:53:02 +00:00
|
|
|
CERT_DestroyCertificate (issuerCert);
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return(cert);
|
|
|
|
}
|
|
|
|
|
|
|
|
static SECItem *
|
|
|
|
SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign,
|
|
|
|
SECOidTag hashAlgTag,
|
|
|
|
SECKEYPrivateKey *privKey, char *issuerNickName, void *pwarg)
|
|
|
|
{
|
|
|
|
SECItem der;
|
|
|
|
SECItem *result = NULL;
|
|
|
|
SECKEYPrivateKey *caPrivateKey = NULL;
|
|
|
|
SECStatus rv;
|
|
|
|
PRArenaPool *arena;
|
|
|
|
SECOidTag algID;
|
|
|
|
void *dummy;
|
|
|
|
|
2008-05-03 22:54:55 +00:00
|
|
|
if ( !selfsign ) {
|
2008-05-01 01:06:47 +00:00
|
|
|
CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg);
|
|
|
|
if ( (CERTCertificate *)NULL == issuer ) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "unable to find issuer with nickname %s",
|
2008-05-03 22:54:55 +00:00
|
|
|
issuerNickName);
|
2008-05-01 01:06:47 +00:00
|
|
|
return (SECItem *)NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg);
|
|
|
|
CERT_DestroyCertificate(issuer);
|
|
|
|
if (caPrivateKey == NULL) {
|
2008-05-03 22:54:55 +00:00
|
|
|
SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName);
|
|
|
|
return NULL;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
}
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
arena = cert->arena;
|
|
|
|
|
|
|
|
algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag);
|
|
|
|
if (algID == SEC_OID_UNKNOWN) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Unknown key or hash type for issuer.");
|
2008-05-11 02:53:02 +00:00
|
|
|
goto done;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
|
|
|
|
if (rv != SECSuccess) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Could not set signature algorithm id.");
|
2008-05-11 02:53:02 +00:00
|
|
|
goto done;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* we only deal with cert v3 here */
|
|
|
|
*(cert->version.data) = 2;
|
|
|
|
cert->version.len = 1;
|
|
|
|
|
|
|
|
der.len = 0;
|
|
|
|
der.data = NULL;
|
|
|
|
dummy = SEC_ASN1EncodeItem (arena, &der, cert,
|
2008-05-03 22:54:55 +00:00
|
|
|
SEC_ASN1_GET(CERT_CertificateTemplate));
|
2008-05-01 01:06:47 +00:00
|
|
|
if (!dummy) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Could not encode certificate.\n");
|
2008-05-11 02:53:02 +00:00
|
|
|
goto done;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
result = (SECItem *) PORT_ArenaZAlloc (arena, sizeof (SECItem));
|
|
|
|
if (result == NULL) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Could not allocate item for certificate data.\n");
|
2008-05-11 02:53:02 +00:00
|
|
|
goto done;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rv = SEC_DerSignData(arena, result, der.data, der.len, privKey, algID);
|
|
|
|
if (rv != SECSuccess) {
|
2008-05-11 02:53:02 +00:00
|
|
|
fprintf (stderr, "Could not sign encoded certificate data.\n");
|
|
|
|
/* result allocated out of the arena, it will be freed
|
|
|
|
* when the arena is freed */
|
|
|
|
result = NULL;
|
|
|
|
goto done;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
cert->derCert = *result;
|
|
|
|
done:
|
|
|
|
if (caPrivateKey) {
|
2008-05-03 22:54:55 +00:00
|
|
|
SECKEY_DestroyPrivateKey(caPrivateKey);
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2008-10-19 05:08:53 +00:00
|
|
|
/*
|
|
|
|
* Modelled after the one in certutil
|
|
|
|
*/
|
2008-05-01 01:06:47 +00:00
|
|
|
static SECStatus
|
|
|
|
CreateCert(
|
2008-05-03 22:54:55 +00:00
|
|
|
CERTCertDBHandle *handle,
|
|
|
|
char *issuerNickName,
|
|
|
|
PRFileDesc *inFile,
|
|
|
|
PRFileDesc *outFile,
|
|
|
|
SECKEYPrivateKey *selfsignprivkey,
|
|
|
|
void *pwarg,
|
|
|
|
SECOidTag hashAlgTag,
|
|
|
|
unsigned int serialNumber,
|
|
|
|
int warpmonths,
|
|
|
|
int validityMonths,
|
|
|
|
const char *emailAddrs,
|
|
|
|
const char *dnsNames,
|
|
|
|
PRBool ascii,
|
|
|
|
PRBool selfsign,
|
|
|
|
certutilExtnList extnList,
|
2008-05-01 01:06:47 +00:00
|
|
|
CERTCertificate **outCert)
|
|
|
|
{
|
|
|
|
void *extHandle;
|
|
|
|
SECItem *certDER;
|
2008-05-03 22:54:55 +00:00
|
|
|
PRArenaPool *arena = NULL;
|
2008-05-01 01:06:47 +00:00
|
|
|
SECItem reqDER;
|
|
|
|
CERTCertExtension **CRexts;
|
2008-05-03 22:54:55 +00:00
|
|
|
CERTCertificate *subjectCert = NULL;
|
|
|
|
CERTCertificateRequest *certReq = NULL;
|
|
|
|
SECStatus rv = SECSuccess;
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
reqDER.data = NULL;
|
|
|
|
do {
|
2008-05-03 22:54:55 +00:00
|
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
|
|
if (!arena) {
|
|
|
|
GEN_BREAK (SECFailure);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a certrequest object from the input cert request der */
|
|
|
|
certReq = GetCertRequest(inFile, ascii);
|
|
|
|
if (certReq == NULL) {
|
|
|
|
GEN_BREAK (SECFailure)
|
|
|
|
}
|
|
|
|
|
|
|
|
subjectCert = MakeV1Cert (handle, certReq, issuerNickName, selfsign,
|
|
|
|
serialNumber, warpmonths, validityMonths);
|
|
|
|
if (subjectCert == NULL) {
|
|
|
|
GEN_BREAK (SECFailure)
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
extHandle = CERT_StartCertExtensions (subjectCert);
|
2008-05-03 22:54:55 +00:00
|
|
|
if (extHandle == NULL) {
|
2008-05-11 02:53:02 +00:00
|
|
|
GEN_BREAK (SECFailure)
|
2008-05-03 22:54:55 +00:00
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList);
|
|
|
|
if (rv != SECSuccess) {
|
2008-05-11 02:53:02 +00:00
|
|
|
GEN_BREAK (SECFailure)
|
2008-05-03 22:54:55 +00:00
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
if (certReq->attributes != NULL &&
|
|
|
|
certReq->attributes[0] != NULL &&
|
2008-05-03 22:54:55 +00:00
|
|
|
certReq->attributes[0]->attrType.data != NULL &&
|
|
|
|
certReq->attributes[0]->attrType.len > 0 &&
|
2008-05-01 01:06:47 +00:00
|
|
|
SECOID_FindOIDTag(&certReq->attributes[0]->attrType)
|
|
|
|
== SEC_OID_PKCS9_EXTENSION_REQUEST) {
|
|
|
|
rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts);
|
|
|
|
if (rv != SECSuccess)
|
|
|
|
break;
|
|
|
|
rv = CERT_MergeExtensions(extHandle, CRexts);
|
|
|
|
if (rv != SECSuccess)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
CERT_FinishExtensions(extHandle);
|
|
|
|
|
|
|
|
certDER = SignCert(handle, subjectCert, selfsign, hashAlgTag,
|
2008-05-03 22:54:55 +00:00
|
|
|
selfsignprivkey, issuerNickName,pwarg);
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
if (certDER) {
|
|
|
|
if (ascii) {
|
|
|
|
PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CERT_HEADER,
|
|
|
|
BTOA_DataToAscii(certDER->data, certDER->len),
|
2008-05-03 22:54:55 +00:00
|
|
|
NS_CERT_TRAILER);
|
2008-05-01 01:06:47 +00:00
|
|
|
} else {
|
|
|
|
PR_Write(outFile, certDER->data, certDER->len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
CERT_DestroyCertificateRequest(certReq);
|
|
|
|
PORT_FreeArena (arena, PR_FALSE);
|
|
|
|
if (rv == SECSuccess) {
|
2008-05-03 22:54:55 +00:00
|
|
|
PR_fprintf(PR_STDOUT, "%s Copying the cert pointer\n", progName);
|
2008-05-01 01:06:47 +00:00
|
|
|
*outCert = subjectCert;
|
|
|
|
} else {
|
2008-05-03 22:54:55 +00:00
|
|
|
PRErrorCode perr = PR_GetError();
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Unable to create cert, (%s)\n", SECU_Strerror(perr));
|
|
|
|
if (subjectCert)
|
2008-05-01 01:06:47 +00:00
|
|
|
CERT_DestroyCertificate (subjectCert);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct KeyPairStr KeyPair;
|
|
|
|
|
|
|
|
typedef struct _PrivateKeyStr PrivateKey;
|
|
|
|
|
|
|
|
|
|
|
|
/* Keyutil commands */
|
|
|
|
typedef enum _CommandType {
|
|
|
|
cmd_CertReq,
|
2008-05-11 02:53:02 +00:00
|
|
|
cmd_CreateNewCert
|
2008-05-01 01:06:47 +00:00
|
|
|
} CommandType;
|
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
/*
|
|
|
|
* Get the key encryption password from a password file.
|
|
|
|
* Stores the password from pwFile in pwitem.
|
|
|
|
*/
|
2008-05-01 01:06:47 +00:00
|
|
|
PRBool GetKeyPassword(const char *pwFile, SECItem *pwitem)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char phrase[200];
|
|
|
|
PRFileDesc *fd;
|
|
|
|
PRInt32 nb;
|
|
|
|
|
|
|
|
if (!pwFile)
|
2008-05-03 22:54:55 +00:00
|
|
|
return PR_FALSE;
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
fd = PR_Open(pwFile, PR_RDONLY, 0);
|
|
|
|
if (!fd)
|
2008-05-03 22:54:55 +00:00
|
|
|
return PR_FALSE;
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
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)
|
2008-05-03 22:54:55 +00:00
|
|
|
i++;
|
2008-05-01 01:06:47 +00:00
|
|
|
phrase[i] = '\0';
|
|
|
|
if (nb == 0)
|
|
|
|
return PR_FALSE;
|
|
|
|
|
2008-05-03 22:54:55 +00:00
|
|
|
pwitem->data = (unsigned char *) PORT_Strdup((char*)phrase);
|
|
|
|
pwitem->len = (unsigned int) strlen((char*)phrase);
|
|
|
|
pwitem->type = siBuffer;
|
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns 0 for success, -1 for failure (EOF encountered) */
|
|
|
|
static int
|
|
|
|
UpdateRNG(void)
|
|
|
|
{
|
|
|
|
char randbuf[RAND_BUF_SIZE];
|
|
|
|
int fd, count;
|
|
|
|
int c;
|
2008-05-03 22:54:55 +00:00
|
|
|
int rv = 0;
|
2008-05-01 01:06:47 +00:00
|
|
|
cc_t orig_cc_min;
|
|
|
|
cc_t orig_cc_time;
|
|
|
|
tcflag_t orig_lflag;
|
|
|
|
struct termios tio;
|
|
|
|
char meter[] = {
|
|
|
|
"\r| |" };
|
|
|
|
|
|
|
|
#define FPS fprintf(stderr,
|
|
|
|
FPS "\n");
|
|
|
|
FPS "A random seed must be generated that will be used in the\n");
|
|
|
|
FPS "creation of your key. One of the easiest ways to create a\n");
|
|
|
|
FPS "random seed is to use the timing of keystrokes on a keyboard.\n");
|
|
|
|
FPS "\n");
|
|
|
|
FPS "To begin, type keys on the keyboard until this progress meter\n");
|
|
|
|
FPS "is full. DO NOT USE THE AUTOREPEAT FUNCTION ON YOUR KEYBOARD!\n");
|
|
|
|
FPS "\n");
|
|
|
|
FPS "\n");
|
|
|
|
FPS "Continue typing until the progress meter is full:\n\n");
|
|
|
|
FPS meter);
|
|
|
|
FPS "\r|");
|
|
|
|
|
|
|
|
/* turn off echo on stdin & return on 1 char instead of NL */
|
|
|
|
fd = fileno(stdin);
|
|
|
|
|
|
|
|
tcgetattr(fd, &tio);
|
|
|
|
orig_lflag = tio.c_lflag;
|
|
|
|
orig_cc_min = tio.c_cc[VMIN];
|
|
|
|
orig_cc_time = tio.c_cc[VTIME];
|
|
|
|
tio.c_lflag &= ~ECHO;
|
|
|
|
tio.c_lflag &= ~ICANON;
|
|
|
|
tio.c_cc[VMIN] = 1;
|
|
|
|
tio.c_cc[VTIME] = 0;
|
|
|
|
tcsetattr(fd, TCSAFLUSH, &tio);
|
|
|
|
|
|
|
|
/* Get random noise from keyboard strokes */
|
|
|
|
count = 0;
|
|
|
|
while (count < sizeof randbuf) {
|
2008-05-03 22:54:55 +00:00
|
|
|
c = getc(stdin);
|
|
|
|
if (c == EOF) {
|
|
|
|
rv = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
randbuf[count] = c;
|
|
|
|
if (count == 0 || c != randbuf[count-1]) {
|
|
|
|
count++;
|
|
|
|
FPS "*");
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
PK11_RandomUpdate(randbuf, sizeof randbuf);
|
|
|
|
memset(randbuf, 0, sizeof randbuf);
|
|
|
|
|
|
|
|
FPS "\n\n");
|
|
|
|
FPS "Finished. Press enter to continue: ");
|
|
|
|
|
|
|
|
while ((c = getc(stdin)) != '\n' && c != EOF)
|
2008-05-03 22:54:55 +00:00
|
|
|
;
|
2008-05-01 01:06:47 +00:00
|
|
|
if (c == EOF)
|
2008-05-03 22:54:55 +00:00
|
|
|
rv = -1;
|
2008-05-01 01:06:47 +00:00
|
|
|
FPS "\n");
|
|
|
|
|
|
|
|
#undef FPS
|
|
|
|
|
|
|
|
/* set back termio the way it was */
|
|
|
|
tio.c_lflag = orig_lflag;
|
|
|
|
tio.c_cc[VMIN] = orig_cc_min;
|
|
|
|
tio.c_cc[VTIME] = orig_cc_time;
|
|
|
|
tcsetattr(fd, TCSAFLUSH, &tio);
|
2008-05-11 02:53:02 +00:00
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SECStatus
|
|
|
|
CERTUTIL_FileForRNG(const char *noise)
|
|
|
|
{
|
|
|
|
char buf[2048];
|
|
|
|
PRFileDesc *fd;
|
|
|
|
PRInt32 count;
|
|
|
|
|
|
|
|
fd = PR_Open(noise,PR_RDONLY,0);
|
|
|
|
if (!fd) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Failed to open noise file %s\n", noise);
|
2008-05-03 22:54:55 +00:00
|
|
|
return SECFailure;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2008-05-03 22:54:55 +00:00
|
|
|
count = PR_Read(fd,buf,sizeof(buf));
|
|
|
|
if (count > 0) {
|
|
|
|
PK11_RandomUpdate(buf,count);
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
} while (count > 0);
|
|
|
|
|
|
|
|
PR_Close(fd);
|
|
|
|
return SECSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECKEYPrivateKey *
|
|
|
|
GenerateRSAPrivateKey(KeyType keytype,
|
2008-05-03 22:54:55 +00:00
|
|
|
PK11SlotInfo *slot,
|
2008-05-01 01:06:47 +00:00
|
|
|
int rsasize,
|
|
|
|
int publicExponent,
|
2008-05-03 22:54:55 +00:00
|
|
|
char *noise,
|
2008-05-01 01:06:47 +00:00
|
|
|
SECKEYPublicKey **pubkeyp,
|
2008-10-01 21:22:49 +00:00
|
|
|
secuPWData *pwdata)
|
2008-05-01 01:06:47 +00:00
|
|
|
{
|
|
|
|
CK_MECHANISM_TYPE mechanism;
|
|
|
|
PK11RSAGenParams rsaparams;
|
|
|
|
SECKEYPrivateKey * privKey = NULL;
|
|
|
|
|
|
|
|
if (slot == NULL)
|
2008-05-03 22:54:55 +00:00
|
|
|
return NULL;
|
2008-05-01 01:06:47 +00:00
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
if (PK11_Authenticate(slot, PR_TRUE, pwdata) != SECSuccess)
|
2008-05-03 22:54:55 +00:00
|
|
|
return NULL;
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Do some random-number initialization.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (noise) {
|
2008-05-03 22:54:55 +00:00
|
|
|
SECStatus rv = CERTUTIL_FileForRNG(noise);
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
PORT_SetError(PR_END_OF_FILE_ERROR); /* XXX */
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
} else {
|
2008-05-03 22:54:55 +00:00
|
|
|
int rv = UpdateRNG();
|
|
|
|
if (rv) {
|
|
|
|
PORT_SetError(PR_END_OF_FILE_ERROR);
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rsaparams.keySizeInBits = rsasize;
|
|
|
|
rsaparams.pe = publicExponent;
|
|
|
|
mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
|
|
|
|
|
|
|
|
fprintf(stderr, "\n\n");
|
|
|
|
fprintf(stderr, "Generating key. This may take a few moments...\n\n");
|
|
|
|
|
|
|
|
privKey = PK11_GenerateKeyPair(slot,
|
2008-05-03 22:54:55 +00:00
|
|
|
mechanism, &rsaparams, pubkeyp,
|
2008-05-01 01:06:47 +00:00
|
|
|
PR_FALSE /* isPerm */,
|
|
|
|
PR_TRUE /* isSensitive*/,
|
2008-10-01 21:22:49 +00:00
|
|
|
pwdata /* wincx */
|
2008-05-01 01:06:47 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
assert(privKey);
|
|
|
|
assert(pubkeyp);
|
|
|
|
return privKey;
|
|
|
|
}
|
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
/*
|
|
|
|
* Decrypt the private key
|
2008-05-01 01:06:47 +00:00
|
|
|
*/
|
2008-05-02 23:42:20 +00:00
|
|
|
SECStatus DecryptKey(
|
2008-05-03 22:54:55 +00:00
|
|
|
SECKEYEncryptedPrivateKeyInfo *epki,
|
2008-05-02 23:42:20 +00:00
|
|
|
SECOidTag algTag,
|
|
|
|
SECItem *pwitem,
|
2008-10-01 21:22:49 +00:00
|
|
|
secuPWData *pwdata,
|
2008-05-11 02:53:02 +00:00
|
|
|
SECItem *derPKI)
|
2008-05-02 23:42:20 +00:00
|
|
|
{
|
2008-05-03 22:54:55 +00:00
|
|
|
SECItem *cryptoParam = NULL;
|
|
|
|
PK11SymKey *symKey = NULL;
|
|
|
|
PK11Context *ctx = NULL;
|
|
|
|
SECStatus rv = SECSuccess;
|
2008-05-02 23:42:20 +00:00
|
|
|
|
|
|
|
if (!pwitem) {
|
2008-05-03 22:54:55 +00:00
|
|
|
return SEC_ERROR_INVALID_ARGS;
|
2008-05-02 23:42:20 +00:00
|
|
|
}
|
2008-05-03 22:54:55 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
SECAlgorithmID algid = epki->algorithm;
|
|
|
|
CK_MECHANISM_TYPE cryptoMechType;
|
|
|
|
CK_MECHANISM cryptoMech;
|
|
|
|
CK_ATTRIBUTE_TYPE operation = CKA_DECRYPT;
|
2008-05-11 02:53:02 +00:00
|
|
|
PK11SlotInfo *slot = NULL;
|
|
|
|
|
2008-05-03 22:54:55 +00:00
|
|
|
cryptoMechType = PK11_GetPBECryptoMechanism(&algid, &cryptoParam, pwitem);
|
|
|
|
if (cryptoMechType == CKM_INVALID_MECHANISM) {
|
|
|
|
ERROR_BREAK;
|
|
|
|
}
|
|
|
|
|
|
|
|
cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMechType);
|
|
|
|
cryptoMech.pParameter = cryptoParam ? cryptoParam->data : NULL;
|
|
|
|
cryptoMech.ulParameterLen = cryptoParam ? cryptoParam->len : 0;
|
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
slot = PK11_GetBestSlot(cryptoMechType, NULL);
|
|
|
|
if (!slot) {
|
|
|
|
ERROR_BREAK;
|
|
|
|
}
|
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
symKey = PK11_PBEKeyGen(slot, &algid, pwitem, PR_FALSE, pwdata);
|
2008-05-11 02:53:02 +00:00
|
|
|
if (symKey == NULL) {
|
|
|
|
ERROR_BREAK;
|
|
|
|
}
|
|
|
|
|
2008-05-03 22:54:55 +00:00
|
|
|
ctx = PK11_CreateContextBySymKey(cryptoMechType, operation, symKey, cryptoParam);
|
|
|
|
if (ctx == NULL) {
|
|
|
|
ERROR_BREAK;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = PK11_CipherOp(ctx,
|
2008-05-11 02:53:02 +00:00
|
|
|
derPKI->data, /* out */
|
|
|
|
(int *)(&derPKI->len), /* out len */
|
2008-05-03 22:54:55 +00:00
|
|
|
(int)epki->encryptedData.len, /* max out */
|
|
|
|
epki->encryptedData.data, /* in */
|
|
|
|
(int)epki->encryptedData.len); /* in len */
|
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
assert(derPKI->len == epki->encryptedData.len);
|
2008-05-03 22:54:55 +00:00
|
|
|
assert(rv == SECSuccess);
|
|
|
|
rv = PK11_Finalize(ctx);
|
|
|
|
assert(rv == SECSuccess);
|
|
|
|
|
2008-05-02 23:42:20 +00:00
|
|
|
} while (0);
|
|
|
|
|
2008-05-03 22:54:55 +00:00
|
|
|
/* cleanup */
|
|
|
|
if (symKey) {
|
|
|
|
PK11_FreeSymKey(symKey);
|
|
|
|
}
|
2008-05-02 23:42:20 +00:00
|
|
|
if (cryptoParam) {
|
2008-05-03 22:54:55 +00:00
|
|
|
SECITEM_ZfreeItem(cryptoParam, PR_TRUE);
|
|
|
|
cryptoParam = NULL;
|
|
|
|
}
|
|
|
|
if (ctx) {
|
|
|
|
PK11_DestroyContext(ctx, PR_TRUE);
|
2008-05-02 23:42:20 +00:00
|
|
|
}
|
2008-05-03 22:54:55 +00:00
|
|
|
|
|
|
|
return rv;
|
2008-05-02 23:42:20 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
/* Output the private key to a file */
|
|
|
|
static SECStatus
|
|
|
|
KeyOut(const char *keyoutfile,
|
2008-05-03 22:54:55 +00:00
|
|
|
const char *key_pwd_file,
|
2008-05-01 01:06:47 +00:00
|
|
|
SECKEYPrivateKey *privkey,
|
|
|
|
SECKEYPublicKey *pubkey,
|
|
|
|
SECOidTag algTag,
|
2008-10-01 21:22:49 +00:00
|
|
|
secuPWData *pwdata,
|
2008-05-01 01:06:47 +00:00
|
|
|
PRBool ascii)
|
|
|
|
{
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
#define RAND_PASS_LEN 6
|
2008-05-03 22:54:55 +00:00
|
|
|
|
|
|
|
PRFileDesc *keyOutFile = NULL;
|
|
|
|
PRUint32 total = 0;
|
|
|
|
PRUint32 numBytes = 0;
|
|
|
|
SECItem *derEPKI = NULL;
|
2008-05-11 02:53:02 +00:00
|
|
|
SECItem derPKI = { 0, NULL, 0 };
|
2008-05-03 22:54:55 +00:00
|
|
|
SECItem pwitem = { 0, NULL, 0 };
|
2008-05-11 02:53:02 +00:00
|
|
|
PRArenaPool *arenaForEPKI = NULL;
|
|
|
|
PLArenaPool *arenaForPKI = NULL;
|
2008-05-03 22:54:55 +00:00
|
|
|
SECKEYEncryptedPrivateKeyInfo *epki = NULL;
|
2008-05-11 02:53:02 +00:00
|
|
|
unsigned char randomPassword[RAND_PASS_LEN];
|
2008-05-03 22:54:55 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Caller wants clear keys. Make up a dummy
|
|
|
|
* password to get NSS to export an encrypted
|
|
|
|
* key which we will decrypt.
|
|
|
|
*/
|
2008-05-11 02:53:02 +00:00
|
|
|
rv = PK11_GenerateRandom(randomPassword, RAND_PASS_LEN);
|
2008-10-26 23:50:45 +00:00
|
|
|
if (rv != SECSuccess) GEN_BREAK(rv);
|
2008-05-03 22:54:55 +00:00
|
|
|
pwitem.data = randomPassword;
|
2008-05-11 02:53:02 +00:00
|
|
|
pwitem.len = RAND_PASS_LEN;
|
2008-05-03 22:54:55 +00:00
|
|
|
pwitem.type = siBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
keyOutFile = PR_Open(keyoutfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);
|
|
|
|
if (!keyOutFile) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Unable to open \"%s\" for writing\n", keyoutfile);
|
2008-05-03 22:54:55 +00:00
|
|
|
GEN_BREAK(255);
|
|
|
|
}
|
|
|
|
|
|
|
|
epki = PK11_ExportEncryptedPrivKeyInfo(NULL,
|
2008-10-01 21:22:49 +00:00
|
|
|
algTag, &pwitem, privkey, 1000, pwdata);
|
2008-05-03 22:54:55 +00:00
|
|
|
if (!epki) {
|
|
|
|
rv = PORT_GetError();
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Can't export private key info (%d)\n", rv);
|
2008-05-03 22:54:55 +00:00
|
|
|
GEN_BREAK(rv);
|
|
|
|
}
|
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
arenaForEPKI = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
|
|
assert(arenaForEPKI);
|
2008-05-03 22:54:55 +00:00
|
|
|
|
|
|
|
if (key_pwd_file) {
|
|
|
|
/* NULL dest to let it allocate memory for us */
|
2008-05-11 02:53:02 +00:00
|
|
|
derEPKI = SEC_ASN1EncodeItem(arenaForEPKI, NULL, epki,
|
2008-10-26 23:50:45 +00:00
|
|
|
SECKEY_EncryptedPrivateKeyInfoTemplate);
|
|
|
|
if (!derEPKI) {
|
|
|
|
SECU_PrintError(progName, "%s ASN1 Encode failed (%dl)\n",
|
|
|
|
SECU_Strerror(PR_GetError()));
|
2008-05-03 22:54:55 +00:00
|
|
|
GEN_BREAK(rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* Make a decrypted key the one to write out. */
|
2008-05-11 02:53:02 +00:00
|
|
|
|
|
|
|
arenaForPKI = PORT_NewArena(2048);
|
|
|
|
if (!arenaForPKI) {
|
|
|
|
GEN_BREAK(PR_OUT_OF_MEMORY_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
derPKI.data = PORT_ArenaAlloc(arenaForPKI, epki->encryptedData.len);
|
|
|
|
derPKI.len = epki->encryptedData.len;
|
|
|
|
derPKI.type = siBuffer;
|
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
rv = DecryptKey(epki, algTag, &pwitem, pwdata, &derPKI);
|
2008-05-03 22:54:55 +00:00
|
|
|
if (rv) {
|
|
|
|
GEN_BREAK(rv);
|
|
|
|
}
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
if (ascii) {
|
2008-05-03 22:54:55 +00:00
|
|
|
/* we could be exporting a clear or encrypted key */
|
2008-05-11 02:53:02 +00:00
|
|
|
SECItem *src = key_pwd_file ? derEPKI : &derPKI;
|
2008-05-03 22:54:55 +00:00
|
|
|
char *header = key_pwd_file ? ENCRYPTED_KEY_HEADER : KEY_HEADER;
|
|
|
|
char *trailer = key_pwd_file ? ENCRYPTED_KEY_TRAILER : KEY_TRAILER;
|
2008-05-11 02:53:02 +00:00
|
|
|
char *b64 = NULL;
|
|
|
|
do {
|
|
|
|
|
|
|
|
b64 = BTOA_ConvertItemToAscii(src);
|
|
|
|
if (b64)
|
|
|
|
break;
|
|
|
|
|
|
|
|
total = PL_strlen(b64);
|
2008-05-01 01:06:47 +00:00
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
PR_fprintf(keyOutFile, "%s\n", header);
|
|
|
|
|
|
|
|
numBytes = PR_Write(keyOutFile, b64, total);
|
|
|
|
|
|
|
|
if (numBytes != total) {
|
|
|
|
printf("Wrote %d bytes, instead of %d\n", numBytes, total);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_fprintf(keyOutFile, "\n%s\n", trailer);
|
|
|
|
|
|
|
|
} while (0);
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
if (b64) {
|
|
|
|
PORT_Free(b64);
|
2008-05-02 23:42:20 +00:00
|
|
|
}
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
} else {
|
2008-05-03 22:54:55 +00:00
|
|
|
if (key_pwd_file) {
|
2008-05-11 02:53:02 +00:00
|
|
|
/* Write out the encrypted key */
|
2008-05-03 22:54:55 +00:00
|
|
|
numBytes = PR_Write(keyOutFile, derEPKI, derEPKI->len);
|
|
|
|
} else {
|
2008-05-11 02:53:02 +00:00
|
|
|
/* Write out the unencrypted key */
|
|
|
|
numBytes = PR_Write(keyOutFile, &derPKI, derPKI.len);
|
2008-05-02 23:42:20 +00:00
|
|
|
if (numBytes != derEPKI->len) {
|
2008-05-11 02:53:02 +00:00
|
|
|
printf("Wrote %d bytes, instead of %d\n", numBytes, derPKI.len);
|
2008-05-02 23:42:20 +00:00
|
|
|
}
|
2008-05-03 22:54:55 +00:00
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
2008-05-03 22:54:55 +00:00
|
|
|
|
|
|
|
printf("Wrote %d bytes of encoded data to %s \n", numBytes, keyoutfile);
|
|
|
|
/* can we read it and reverse operations */
|
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
} while (0);
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
if (keyOutFile) {
|
|
|
|
PR_Close(keyOutFile);
|
|
|
|
}
|
2008-05-11 02:53:02 +00:00
|
|
|
|
|
|
|
if (derEPKI != NULL)
|
|
|
|
PORT_Free(derEPKI);
|
|
|
|
|
|
|
|
if (arenaForEPKI) {
|
|
|
|
PORT_FreeArena(arenaForEPKI, PR_FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arenaForPKI) {
|
|
|
|
PORT_FreeArena(arenaForPKI, PR_FALSE);
|
2008-05-03 22:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!key_pwd_file) {
|
2008-05-11 02:53:02 +00:00
|
|
|
/* paranoia, though stack-based object we clear it anyway */
|
|
|
|
memset(randomPassword, 0, RAND_PASS_LEN);
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
2008-05-11 02:53:02 +00:00
|
|
|
|
2008-05-03 22:54:55 +00:00
|
|
|
return rv;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate a certificate signing request
|
|
|
|
* or a self_signed certificate.
|
|
|
|
*/
|
|
|
|
static int keyutil_main(
|
2008-05-03 22:54:55 +00:00
|
|
|
CERTCertDBHandle *certHandle,
|
|
|
|
const char *noisefile,
|
2008-05-02 23:42:20 +00:00
|
|
|
const char *access_pwd_file,
|
|
|
|
const char *key_pwd_file,
|
2008-10-01 21:22:49 +00:00
|
|
|
const char *cert_to_renew,
|
|
|
|
const char *input_key_file,
|
2008-10-19 05:08:53 +00:00
|
|
|
PRBool cacert,
|
2008-05-01 01:06:47 +00:00
|
|
|
const char *subjectstr,
|
|
|
|
int keysize,
|
2008-05-03 22:54:55 +00:00
|
|
|
int warpmonths,
|
|
|
|
int validityMonths,
|
|
|
|
PRBool ascii,
|
2008-05-01 01:06:47 +00:00
|
|
|
const char *certreqfile,
|
|
|
|
const char *certfile,
|
|
|
|
const char *keyoutfile)
|
|
|
|
{
|
2008-05-03 22:54:55 +00:00
|
|
|
static certutilExtnList nullextnlist = {PR_FALSE};
|
|
|
|
|
|
|
|
CERTCertificate *cert = NULL;
|
|
|
|
PRFileDesc *outFile = NULL;
|
|
|
|
PRFileDesc *keyOutFile = NULL;
|
2008-05-01 01:06:47 +00:00
|
|
|
CERTName *subject = NULL;
|
2008-05-03 22:54:55 +00:00
|
|
|
SECKEYPrivateKey *privkey = NULL;
|
|
|
|
SECKEYPublicKey *pubkey = NULL;
|
2008-10-01 21:22:49 +00:00
|
|
|
PK11SlotInfo *slot = NULL;
|
|
|
|
secuPWData pwdata = { PW_NONE, 0 };
|
2008-05-01 01:06:47 +00:00
|
|
|
KeyType keytype = rsaKey;
|
|
|
|
SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
|
|
|
|
PRBool doCert = certfile != NULL;
|
2008-05-03 22:54:55 +00:00
|
|
|
int rv;
|
2008-10-01 21:22:49 +00:00
|
|
|
|
2008-10-26 23:50:45 +00:00
|
|
|
if (access_pwd_file) {
|
|
|
|
pwdata.source = PW_FROMFILE;
|
|
|
|
pwdata.data = (char *)access_pwd_file;
|
|
|
|
}
|
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
if (cert_to_renew && input_key_file) {
|
2008-10-11 19:45:12 +00:00
|
|
|
/*
|
|
|
|
* This certificate request is for a renewal,
|
|
|
|
* using existing keys.
|
|
|
|
*/
|
2008-10-19 05:08:53 +00:00
|
|
|
CK_SLOT_ID slotID = cacert ? 0 : 1;
|
2008-10-01 21:22:49 +00:00
|
|
|
char slotname[32];
|
|
|
|
char nickname[256];
|
|
|
|
CERTCertificate *keycert = NULL;
|
|
|
|
const char *n = cert_to_renew;
|
|
|
|
|
|
|
|
/* Remove the path part */
|
|
|
|
n = strrchr(cert_to_renew, '/');
|
|
|
|
if (!n)
|
2008-10-11 19:45:12 +00:00
|
|
|
n = cert_to_renew;
|
2008-10-01 21:22:49 +00:00
|
|
|
else
|
2008-10-11 19:45:12 +00:00
|
|
|
n++;
|
2008-10-01 21:22:49 +00:00
|
|
|
|
|
|
|
snprintf(slotname, 32, "PEM Token #%ld", slotID);
|
|
|
|
snprintf(nickname, 256, "PEM Token #%ld:%s", slotID, n);
|
|
|
|
slot = PK11_FindSlotByName(slotname);
|
|
|
|
if (!slot) {
|
2008-10-11 19:45:12 +00:00
|
|
|
printf("%s: Can't find slot for %s\n", progName, slotname);
|
|
|
|
rv = 255;
|
|
|
|
goto shutdown;
|
2008-10-01 21:22:49 +00:00
|
|
|
}
|
|
|
|
|
2008-10-19 05:08:53 +00:00
|
|
|
rv = loadCertAndKey(slot, cacert,
|
2008-10-01 21:22:49 +00:00
|
|
|
cert_to_renew, nickname, input_key_file,
|
|
|
|
&pwdata);
|
2008-05-01 01:06:47 +00:00
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
if (rv != SECSuccess) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Can't load the key or cert, bailing out\n");
|
2008-10-11 19:45:12 +00:00
|
|
|
goto shutdown;
|
2008-10-01 21:22:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rv = extractRSAKeysAndSubject(nickname,
|
|
|
|
slot, &pwdata, &privkey, &pubkey, &subject);
|
|
|
|
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
if (keycert) {
|
|
|
|
CERT_DestroyCertificate(keycert);
|
|
|
|
}
|
|
|
|
goto shutdown;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(privkey);
|
|
|
|
assert(pubkey);
|
|
|
|
assert(subject);
|
|
|
|
|
|
|
|
} else {
|
2008-10-11 19:45:12 +00:00
|
|
|
/*
|
2008-10-26 23:50:45 +00:00
|
|
|
* This is a certificate signing request for a new cert,
|
2008-10-11 19:45:12 +00:00
|
|
|
* will generate a key pair
|
|
|
|
*/
|
|
|
|
slot = PK11_GetInternalKeySlot(); /* PK11_GetInternalSlot() ? */
|
2008-05-01 01:06:47 +00:00
|
|
|
|
2008-10-11 19:45:12 +00:00
|
|
|
privkey = GenerateRSAPrivateKey(keytype, slot,
|
2008-10-01 21:22:49 +00:00
|
|
|
keysize, 65537L, (char *)noisefile, &pubkey, &pwdata);
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-10-11 19:45:12 +00:00
|
|
|
if (!privkey) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
|
|
|
"Keypair generation failed: \"%d\"\n", PORT_GetError());
|
2008-10-11 19:45:12 +00:00
|
|
|
rv = 255;
|
|
|
|
goto shutdown;
|
|
|
|
}
|
|
|
|
subject = CERT_AsciiToName((char *)subjectstr);
|
|
|
|
if (!subject) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
|
|
|
"Improperly formatted name: \"%s\"\n", subjectstr);
|
2008-10-11 19:45:12 +00:00
|
|
|
rv = 255;
|
|
|
|
goto shutdown;
|
|
|
|
}
|
2008-10-01 21:22:49 +00:00
|
|
|
}
|
|
|
|
PR_fprintf(PR_STDOUT, "%s Got a key\n", progName);
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
outFile = PR_Open(certreqfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);
|
|
|
|
if (!outFile) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName,
|
2008-10-01 21:22:49 +00:00
|
|
|
"%s -o: unable to open \"%s\" for writing (%ld, %ld)\n",
|
2008-10-26 23:50:45 +00:00
|
|
|
certreqfile, PR_GetError(), PR_GetOSError());
|
2008-10-01 21:22:49 +00:00
|
|
|
return 255;
|
|
|
|
}
|
|
|
|
printf("Opened %s for writing\n", certreqfile);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Certificate request
|
|
|
|
*/
|
2008-05-03 22:54:55 +00:00
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
hashAlgTag = SEC_OID_MD5;
|
|
|
|
|
2008-05-01 01:06:47 +00:00
|
|
|
/* Make a cert request */
|
2008-05-03 22:54:55 +00:00
|
|
|
rv = CertReq(privkey, pubkey, rsaKey, hashAlgTag, subject,
|
|
|
|
NULL, /* PhoneNumber */
|
|
|
|
ascii, /* ASCIIForIO */
|
|
|
|
NULL, /* ExtendedEmailAddrs */
|
|
|
|
NULL, /* ExtendedDNSNames */
|
|
|
|
nullextnlist, /* certutil_extns */
|
|
|
|
outFile);
|
2008-05-01 01:06:47 +00:00
|
|
|
|
2008-05-03 22:54:55 +00:00
|
|
|
PR_Close(outFile);
|
|
|
|
if (rv) {
|
|
|
|
PR_fprintf(PR_STDERR, "%s CertReq failed: \"%d\"\n",
|
|
|
|
progName, PORT_GetError());
|
|
|
|
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.
|
|
|
|
* without any extensions, load it with any command line extensions
|
|
|
|
* and output the cert to other file. Delete the request file.
|
|
|
|
*/
|
|
|
|
PRFileDesc *inFile = NULL;
|
|
|
|
unsigned int serialNumber;
|
|
|
|
|
|
|
|
/* Make a default serial number from the current time. */
|
|
|
|
PRTime now = PR_Now();
|
|
|
|
LL_USHR(now, now, 19);
|
|
|
|
LL_L2UI(serialNumber, now);
|
|
|
|
|
2008-10-01 21:22:49 +00:00
|
|
|
privkey->wincx = &pwdata;
|
2008-05-03 22:54:55 +00:00
|
|
|
PR_Close(outFile);
|
|
|
|
|
|
|
|
inFile = PR_Open(certreqfile, PR_RDONLY, 0);
|
|
|
|
assert(inFile);
|
|
|
|
if (!inFile) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Failed to open file \"%s\" (%ld, %ld) for reading.\n",
|
2008-05-03 22:54:55 +00:00
|
|
|
certreqfile, PR_GetError(), PR_GetOSError());
|
|
|
|
rv = SECFailure;
|
|
|
|
goto shutdown;
|
|
|
|
}
|
|
|
|
|
|
|
|
outFile = PR_Open(certfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);
|
|
|
|
|
|
|
|
if (!outFile) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Failed to open file \"%s\" (%ld, %ld).\n",
|
2008-05-03 22:54:55 +00:00
|
|
|
certfile, PR_GetError(), PR_GetOSError());
|
|
|
|
rv = SECFailure;
|
|
|
|
goto shutdown;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a certificate (-C or -S). */
|
|
|
|
|
|
|
|
/* issuerName == subject */
|
|
|
|
rv = CreateCert(certHandle,
|
|
|
|
"tempnickname", inFile, outFile,
|
2008-10-01 21:22:49 +00:00
|
|
|
privkey, &pwdata, hashAlgTag,
|
2008-05-03 22:54:55 +00:00
|
|
|
serialNumber, warpmonths, validityMonths,
|
|
|
|
NULL, NULL, ascii, PR_TRUE, NULL,
|
|
|
|
&cert);
|
|
|
|
/*
|
|
|
|
ExtendedEmailAddrs,ExtendedDNSNames,
|
|
|
|
ASCIIForIO,SelfSign,certutil_extns, thecert
|
|
|
|
*/
|
|
|
|
if (rv) {
|
2008-10-26 23:50:45 +00:00
|
|
|
SECU_PrintError(progName, "Failed to create certificate \"%s\" (%ld).\n",
|
2008-05-03 22:54:55 +00:00
|
|
|
outFile, PR_GetError());
|
|
|
|
rv = SECFailure;
|
|
|
|
goto shutdown;
|
|
|
|
}
|
|
|
|
PR_fprintf(PR_STDOUT, "%s Created a cert\n", progName);
|
|
|
|
|
|
|
|
/* Sanity check: Check cert validity against current time. */
|
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
/* for fips - must log in to get private key */
|
2008-05-03 22:54:55 +00:00
|
|
|
if (slot && PK11_NeedLogin(slot)) {
|
2008-10-01 21:22:49 +00:00
|
|
|
SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
|
2008-05-03 22:54:55 +00:00
|
|
|
if (newrv != SECSuccess) {
|
|
|
|
SECU_PrintError(progName, "could not authenticate to token %s.",
|
|
|
|
PK11_GetTokenName(slot));
|
|
|
|
goto shutdown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
/* If the caller wants the private key extract it and save it to a file. */
|
2008-05-03 22:54:55 +00:00
|
|
|
if (keyoutfile) {
|
|
|
|
/* 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,
|
2008-05-02 23:42:20 +00:00
|
|
|
privkey, pubkey, SEC_OID_DES_EDE3_CBC,
|
2008-10-01 21:22:49 +00:00
|
|
|
&pwdata, ascii);
|
2008-05-03 22:54:55 +00:00
|
|
|
if (rv != SECSuccess) {
|
|
|
|
SECU_PrintError(progName, "Failed to write the key");
|
|
|
|
} else {
|
|
|
|
printf("%s Wrote the key to\n%s\n", progName, keyoutfile);
|
|
|
|
}
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
shutdown:
|
|
|
|
if (cert) {
|
2008-05-03 22:54:55 +00:00
|
|
|
CERT_DestroyCertificate(cert);
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
if (keyOutFile) {
|
|
|
|
PR_Close(keyOutFile);
|
|
|
|
}
|
2008-05-03 22:54:55 +00:00
|
|
|
if (slot) {
|
|
|
|
PK11_FreeSlot(slot);
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
if (privkey) {
|
2008-05-03 22:54:55 +00:00
|
|
|
SECKEY_DestroyPrivateKey(privkey);
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
if (pubkey) {
|
2008-05-03 22:54:55 +00:00
|
|
|
SECKEY_DestroyPublicKey(pubkey);
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
2008-10-01 21:22:49 +00:00
|
|
|
if (mod) {
|
|
|
|
rv = SECMOD_UnloadUserModule(mod);
|
|
|
|
mod = NULL;
|
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
|
2008-05-11 02:53:02 +00:00
|
|
|
return rv == SECSuccess ? 0 : 255;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
2008-10-26 23:50:45 +00:00
|
|
|
/* $Id: keyutil.c,v 1.9 2008/10/20 20:45:04 emaldonado Exp $ */
|
2008-05-01 01:06:47 +00:00
|
|
|
|
|
|
|
/* Key generation, encryption, and certificate utility code, based on
|
|
|
|
* code from NSS's security utilities and the certutil application.
|
|
|
|
* Elio Maldonado <emaldona@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int optc, rv = 0;
|
|
|
|
char *cmdstr = NULL;
|
|
|
|
char *noisefile = NULL;
|
|
|
|
int keysize = 1024;
|
2008-05-03 22:54:55 +00:00
|
|
|
int warpmonths = 0;
|
|
|
|
int validity_months = 24;
|
2008-05-01 01:06:47 +00:00
|
|
|
char *keyfile = NULL;
|
|
|
|
char *outfile = NULL;
|
2008-10-01 21:22:49 +00:00
|
|
|
char *cert_to_renew = NULL;
|
2008-05-01 01:06:47 +00:00
|
|
|
char *subject = NULL;
|
2008-05-02 23:42:20 +00:00
|
|
|
char *access_pwd_file = NULL;
|
|
|
|
char *key_pwd_file = NULL;
|
2008-05-01 01:06:47 +00:00
|
|
|
char *digestAlgorithm = "md5";
|
|
|
|
char *keyoutfile = 0;
|
|
|
|
PRBool ascii = PR_FALSE;
|
2008-10-19 05:08:53 +00:00
|
|
|
PRBool cacert = PR_FALSE;
|
2008-05-01 01:06:47 +00:00
|
|
|
CERTCertDBHandle *certHandle = 0;
|
|
|
|
SECStatus status = 0;
|
|
|
|
CommandType cmd = cmd_CertReq;
|
|
|
|
PRBool initialized = PR_FALSE;
|
2008-10-01 21:22:49 +00:00
|
|
|
|
2008-10-19 05:08:53 +00:00
|
|
|
while ((optc = getopt_long(argc, argv, "atc:rs:g:v:e:f:d:z:i:p:o:k:h", options, NULL)) != -1) {
|
2008-05-01 01:06:47 +00:00
|
|
|
switch (optc) {
|
|
|
|
case 'a':
|
2008-05-03 22:54:55 +00:00
|
|
|
ascii = PR_TRUE;
|
|
|
|
break;
|
2008-10-19 05:08:53 +00:00
|
|
|
case 't':
|
|
|
|
cacert = PR_TRUE;
|
|
|
|
break;
|
2008-05-01 01:06:47 +00:00
|
|
|
case 'c':
|
|
|
|
cmdstr = strdup(optarg);
|
|
|
|
printf("cmdstr: %s\n", cmdstr);
|
2008-05-11 02:53:02 +00:00
|
|
|
if (strcmp(cmdstr, "genreq") == 0) {
|
2008-05-01 01:06:47 +00:00
|
|
|
cmd = cmd_CertReq;
|
|
|
|
printf("\ncmd_CertReq\n");
|
|
|
|
} else if (strcmp(cmdstr, "makecert") == 0) {
|
|
|
|
cmd = cmd_CreateNewCert;
|
|
|
|
printf("\ncmd_CreateNewCert\n");
|
|
|
|
} else {
|
|
|
|
printf("\nInvalid argument: %s\n", cmdstr);
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
printf("command: %s\n", cmdstr);
|
|
|
|
break;
|
2008-10-01 21:22:49 +00:00
|
|
|
case 'r':
|
|
|
|
cert_to_renew = strdup(optarg);
|
|
|
|
break;
|
2008-05-01 01:06:47 +00:00
|
|
|
case 's':
|
|
|
|
subject = strdup(optarg);
|
|
|
|
printf("subject = %s\n", subject);
|
|
|
|
break;
|
|
|
|
case 'g':
|
2008-05-03 22:54:55 +00:00
|
|
|
keysize = atoi(optarg);
|
|
|
|
printf("keysize = %d bits\n", keysize);
|
2008-05-01 01:06:47 +00:00
|
|
|
break;
|
|
|
|
case 'v':
|
2008-05-03 22:54:55 +00:00
|
|
|
validity_months = atoi(optarg);
|
|
|
|
printf("valid for %d months\n", validity_months);
|
|
|
|
break;
|
2008-05-02 23:42:20 +00:00
|
|
|
case 'e':
|
2008-05-03 22:54:55 +00:00
|
|
|
key_pwd_file = strdup(optarg);
|
|
|
|
printf("key encryption password from = %s\n", key_pwd_file);
|
|
|
|
break;
|
2008-05-01 01:06:47 +00:00
|
|
|
case 'f':
|
2008-05-03 22:54:55 +00:00
|
|
|
access_pwd_file = strdup(optarg);
|
|
|
|
printf("module access password from = %s\n", access_pwd_file);
|
|
|
|
break;
|
2008-05-01 01:06:47 +00:00
|
|
|
case 'd':
|
|
|
|
digestAlgorithm = strdup(optarg);
|
|
|
|
printf("message digest %s\n", digestAlgorithm);
|
|
|
|
break;
|
|
|
|
case 'z':
|
2008-05-03 22:54:55 +00:00
|
|
|
noisefile = strdup(optarg);
|
|
|
|
printf("random seed from %s\n", noisefile);
|
2008-05-01 01:06:47 +00:00
|
|
|
break;
|
|
|
|
case 'i':
|
2008-05-03 22:54:55 +00:00
|
|
|
keyfile = strdup(optarg);
|
|
|
|
printf("will process a key from %s\n", keyfile);
|
2008-05-01 01:06:47 +00:00
|
|
|
break;
|
|
|
|
case 'o':
|
2008-05-03 22:54:55 +00:00
|
|
|
/* could be req or cert */
|
|
|
|
outfile = strdup(optarg);
|
|
|
|
printf("output will be written to %s\n", outfile);
|
2008-05-01 01:06:47 +00:00
|
|
|
break;
|
|
|
|
case 'k':
|
2008-05-03 22:54:55 +00:00
|
|
|
/* private key out in plaintext - side effect of req and cert */
|
|
|
|
keyoutfile = strdup(optarg);
|
|
|
|
printf("output key written to %s\n", keyoutfile);
|
|
|
|
break;
|
2008-05-11 02:53:02 +00:00
|
|
|
case 'h':
|
2008-10-11 19:45:12 +00:00
|
|
|
Usage(progName);
|
2008-05-11 02:53:02 +00:00
|
|
|
break;
|
2008-05-01 01:06:47 +00:00
|
|
|
default:
|
2008-05-03 22:54:55 +00:00
|
|
|
printf("Bad arguments\n");
|
2008-05-01 01:06:47 +00:00
|
|
|
Usage(progName);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize NSPR and NSS. */
|
|
|
|
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
|
|
|
|
|
|
|
|
status = NSS_NoDB_Init(NULL);
|
|
|
|
if (status != SECSuccess ) {
|
2008-05-03 22:54:55 +00:00
|
|
|
printf("NSS initialization failed\n");
|
2008-05-01 01:06:47 +00:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2008-10-01 21:22:49 +00:00
|
|
|
if (cert_to_renew) {
|
|
|
|
char *configstring = NULL;
|
|
|
|
/* Load our PKCS#11 module */
|
|
|
|
configstring = (char *)malloc(4096);
|
|
|
|
PR_snprintf(configstring, 4096,
|
|
|
|
"library=%s name=PEM parameters=\"\"", pem_library);
|
|
|
|
mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
|
|
|
|
if (!mod || !mod->loaded) {
|
|
|
|
printf("%s: Failed to load %s\n", progName, pem_library);
|
|
|
|
}
|
|
|
|
free(configstring);
|
2008-10-20 20:45:04 +00:00
|
|
|
if (!mod) {
|
2008-10-01 21:22:49 +00:00
|
|
|
NSS_Shutdown();
|
|
|
|
PR_Cleanup();
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2008-10-26 23:50:45 +00:00
|
|
|
if (PK11_IsFIPS() && !access_pwd_file) {
|
|
|
|
printf("Default module in FIPS mode requires password\n");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2008-10-01 21:22:49 +00:00
|
|
|
}
|
2008-05-01 01:06:47 +00:00
|
|
|
initialized = PR_TRUE;
|
|
|
|
|
|
|
|
certHandle = CERT_GetDefaultCertDB();
|
|
|
|
assert(certHandle);
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case cmd_CertReq:
|
|
|
|
/* certfile NULL signals only the request is needed */
|
|
|
|
rv = keyutil_main(certHandle,
|
2008-05-02 23:42:20 +00:00
|
|
|
noisefile, access_pwd_file, key_pwd_file,
|
2008-10-19 05:08:53 +00:00
|
|
|
cert_to_renew, keyfile, cacert,
|
2008-05-02 23:42:20 +00:00
|
|
|
subject, keysize, warpmonths, validity_months,
|
2008-05-01 01:06:47 +00:00
|
|
|
ascii, outfile, NULL, keyoutfile);
|
|
|
|
break;
|
|
|
|
case cmd_CreateNewCert:
|
2008-05-03 22:54:55 +00:00
|
|
|
rv = keyutil_main(certHandle,
|
2008-05-02 23:42:20 +00:00
|
|
|
noisefile, access_pwd_file, key_pwd_file,
|
2008-10-19 05:08:53 +00:00
|
|
|
NULL, NULL, cacert, /* ignored */
|
2008-05-02 23:42:20 +00:00
|
|
|
subject, keysize, warpmonths, validity_months,
|
2008-05-01 01:06:47 +00:00
|
|
|
ascii, "tmprequest", outfile, keyoutfile);
|
|
|
|
break;
|
|
|
|
default:
|
2008-05-03 22:54:55 +00:00
|
|
|
printf("\nEntered an inconsistent state, bailing out\n");
|
|
|
|
rv = -1;
|
|
|
|
break;
|
2008-05-01 01:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((initialized == PR_TRUE) && NSS_Shutdown() != SECSuccess) {
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
PR_Cleanup();
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|