Blame SOURCES/keyutil.c

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