Blame SOURCES/keyutil.c

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