Blame SOURCES/keyutil.c

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
}