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