2008-06-06 05:40:11 -07:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is the Netscape security libraries.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "signtool.h"
|
|
|
|
|
|
|
|
#include "secoid.h"
|
|
|
|
#include "cryptohi.h"
|
|
|
|
#include "certdb.h"
|
|
|
|
|
|
|
|
static char *GetSubjectFromUser(unsigned long serial);
|
|
|
|
static CERTCertificate*GenerateSelfSignedObjectSigningCert(char *nickname,
|
|
|
|
CERTCertDBHandle *db, char *subject, unsigned long serial, int keysize,
|
|
|
|
char *token);
|
|
|
|
static SECStatus ChangeTrustAttributes(CERTCertDBHandle *db,
|
|
|
|
CERTCertificate *cert, char *trusts);
|
|
|
|
static SECStatus set_cert_type(CERTCertificate *cert, unsigned int type);
|
|
|
|
static SECItem *sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk);
|
|
|
|
static CERTCertificate*install_cert(CERTCertDBHandle *db, SECItem *derCert,
|
|
|
|
char *nickname);
|
|
|
|
static SECStatus GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk,
|
|
|
|
SECKEYPrivateKey **privk, int keysize);
|
|
|
|
static CERTCertificateRequest*make_cert_request(char *subject,
|
|
|
|
SECKEYPublicKey *pubk);
|
|
|
|
static CERTCertificate *make_cert(CERTCertificateRequest *req,
|
|
|
|
unsigned long serial, CERTName *ca_subject);
|
|
|
|
static void output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db);
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
*
|
|
|
|
* G e n e r a t e C e r t
|
|
|
|
*
|
|
|
|
* Runs the whole process of creating a new cert, getting info from the
|
|
|
|
* user, etc.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
GenerateCert(char *nickname, int keysize, char *token)
|
|
|
|
{
|
|
|
|
CERTCertDBHandle * db;
|
|
|
|
CERTCertificate * cert;
|
|
|
|
char *subject;
|
|
|
|
unsigned long serial;
|
|
|
|
char stdinbuf[160];
|
|
|
|
|
|
|
|
/* Print warning about having the browser open */
|
|
|
|
PR_fprintf(PR_STDOUT /*always go to console*/,
|
|
|
|
"\nWARNING: Performing this operation while the browser is running could cause"
|
|
|
|
"\ncorruption of your security databases. If the browser is currently running,"
|
|
|
|
"\nyou should exit the browser before continuing this operation. Enter "
|
|
|
|
"\n\"y\" to continue, or anything else to abort: ");
|
|
|
|
pr_fgets(stdinbuf, 160, PR_STDIN);
|
|
|
|
PR_fprintf(PR_STDOUT, "\n");
|
|
|
|
if (tolower(stdinbuf[0]) != 'y') {
|
|
|
|
PR_fprintf(errorFD, "Operation aborted at user's request.\n");
|
|
|
|
errorCount++;
|
|
|
|
return - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
db = CERT_GetDefaultCertDB();
|
|
|
|
if (!db) {
|
|
|
|
FatalError("Unable to open certificate database");
|
|
|
|
}
|
|
|
|
|
2008-08-14 21:12:54 -07:00
|
|
|
if (PK11_FindCertFromNickname(nickname, &pwdata)) {
|
2008-06-06 05:40:11 -07:00
|
|
|
PR_fprintf(errorFD,
|
|
|
|
"ERROR: Certificate with nickname \"%s\" already exists in database. You\n"
|
|
|
|
"must choose a different nickname.\n", nickname);
|
|
|
|
errorCount++;
|
|
|
|
exit(ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
LL_L2UI(serial, PR_Now());
|
|
|
|
|
|
|
|
subject = GetSubjectFromUser(serial);
|
|
|
|
|
|
|
|
cert = GenerateSelfSignedObjectSigningCert(nickname, db, subject,
|
|
|
|
serial, keysize, token);
|
|
|
|
|
|
|
|
if (cert) {
|
|
|
|
output_ca_cert(cert, db);
|
|
|
|
CERT_DestroyCertificate(cert);
|
|
|
|
}
|
|
|
|
|
|
|
|
PORT_Free(subject);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#undef VERBOSE_PROMPTS
|
|
|
|
|
|
|
|
/*********************************************************************8
|
|
|
|
* G e t S u b j e c t F r o m U s e r
|
|
|
|
*
|
|
|
|
* Construct the subject information line for a certificate by querying
|
|
|
|
* the user on stdin.
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
GetSubjectFromUser(unsigned long serial)
|
|
|
|
{
|
|
|
|
char buf[STDIN_BUF_SIZE];
|
|
|
|
char common_name_buf[STDIN_BUF_SIZE];
|
|
|
|
char *common_name, *state, *orgunit, *country, *org, *locality;
|
|
|
|
char *email, *uid;
|
|
|
|
char *subject;
|
|
|
|
char *cp;
|
|
|
|
int subjectlen = 0;
|
|
|
|
|
|
|
|
common_name = state = orgunit = country = org = locality = email =
|
|
|
|
uid = subject = NULL;
|
|
|
|
|
|
|
|
/* Get subject information */
|
|
|
|
PR_fprintf(PR_STDOUT,
|
|
|
|
"\nEnter certificate information. All fields are optional. Acceptable\n"
|
|
|
|
"characters are numbers, letters, spaces, and apostrophes.\n");
|
|
|
|
|
|
|
|
#ifdef VERBOSE_PROMPTS
|
|
|
|
PR_fprintf(PR_STDOUT, "\nCOMMON NAME\n"
|
|
|
|
"Enter the full name you want to give your certificate. (Example: Test-Only\n"
|
|
|
|
"Object Signing Certificate)\n"
|
|
|
|
"-->");
|
|
|
|
#else
|
|
|
|
PR_fprintf(PR_STDOUT, "certificate common name: ");
|
|
|
|
#endif
|
|
|
|
fgets(buf, STDIN_BUF_SIZE, stdin);
|
|
|
|
cp = chop(buf);
|
|
|
|
if (*cp == '\0') {
|
|
|
|
sprintf(common_name_buf, "%s (%lu)", DEFAULT_COMMON_NAME,
|
|
|
|
serial);
|
|
|
|
cp = common_name_buf;
|
|
|
|
}
|
|
|
|
common_name = PORT_ZAlloc(strlen(cp) + 6);
|
|
|
|
if (!common_name) {
|
|
|
|
out_of_memory();
|
|
|
|
}
|
|
|
|
sprintf(common_name, "CN=%s, ", cp);
|
|
|
|
subjectlen += strlen(common_name);
|
|
|
|
|
|
|
|
#ifdef VERBOSE_PROMPTS
|
|
|
|
PR_fprintf(PR_STDOUT, "\nORGANIZATION NAME\n"
|
|
|
|
"Enter the name of your organization. For example, this could be the name\n"
|
|
|
|
"of your company.\n"
|
|
|
|
"-->");
|
|
|
|
#else
|
|
|
|
PR_fprintf(PR_STDOUT, "organization: ");
|
|
|
|
#endif
|
|
|
|
fgets(buf, STDIN_BUF_SIZE, stdin);
|
|
|
|
cp = chop(buf);
|
|
|
|
if (*cp != '\0') {
|
|
|
|
org = PORT_ZAlloc(strlen(cp) + 5);
|
|
|
|
if (!org) {
|
|
|
|
out_of_memory();
|
|
|
|
}
|
|
|
|
sprintf(org, "O=%s, ", cp);
|
|
|
|
subjectlen += strlen(org);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERBOSE_PROMPTS
|
|
|
|
PR_fprintf(PR_STDOUT, "\nORGANIZATION UNIT\n"
|
|
|
|
"Enter the name of your organization unit. For example, this could be the\n"
|
|
|
|
"name of your department.\n"
|
|
|
|
"-->");
|
|
|
|
#else
|
|
|
|
PR_fprintf(PR_STDOUT, "organization unit: ");
|
|
|
|
#endif
|
|
|
|
fgets(buf, STDIN_BUF_SIZE, stdin);
|
|
|
|
cp = chop(buf);
|
|
|
|
if (*cp != '\0') {
|
|
|
|
orgunit = PORT_ZAlloc(strlen(cp) + 6);
|
|
|
|
if (!orgunit) {
|
|
|
|
out_of_memory();
|
|
|
|
}
|
|
|
|
sprintf(orgunit, "OU=%s, ", cp);
|
|
|
|
subjectlen += strlen(orgunit);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERBOSE_PROMPTS
|
|
|
|
PR_fprintf(PR_STDOUT, "\nSTATE\n"
|
|
|
|
"Enter the name of your state or province.\n"
|
|
|
|
"-->");
|
|
|
|
#else
|
|
|
|
PR_fprintf(PR_STDOUT, "state or province: ");
|
|
|
|
#endif
|
|
|
|
fgets(buf, STDIN_BUF_SIZE, stdin);
|
|
|
|
cp = chop(buf);
|
|
|
|
if (*cp != '\0') {
|
|
|
|
state = PORT_ZAlloc(strlen(cp) + 6);
|
|
|
|
if (!state) {
|
|
|
|
out_of_memory();
|
|
|
|
}
|
|
|
|
sprintf(state, "ST=%s, ", cp);
|
|
|
|
subjectlen += strlen(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERBOSE_PROMPTS
|
|
|
|
PR_fprintf(PR_STDOUT, "\nCOUNTRY\n"
|
|
|
|
"Enter the 2-character abbreviation for the name of your country.\n"
|
|
|
|
"-->");
|
|
|
|
#else
|
|
|
|
PR_fprintf(PR_STDOUT, "country (must be exactly 2 characters): ");
|
|
|
|
#endif
|
|
|
|
fgets(buf, STDIN_BUF_SIZE, stdin);
|
|
|
|
cp = chop(cp);
|
|
|
|
if (strlen(cp) != 2) {
|
|
|
|
*cp = '\0'; /* country code must be 2 chars */
|
|
|
|
}
|
|
|
|
if (*cp != '\0') {
|
|
|
|
country = PORT_ZAlloc(strlen(cp) + 5);
|
|
|
|
if (!country) {
|
|
|
|
out_of_memory();
|
|
|
|
}
|
|
|
|
sprintf(country, "C=%s, ", cp);
|
|
|
|
subjectlen += strlen(country);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERBOSE_PROMPTS
|
|
|
|
PR_fprintf(PR_STDOUT, "\nUSERNAME\n"
|
|
|
|
"Enter your system username or UID\n"
|
|
|
|
"-->");
|
|
|
|
#else
|
|
|
|
PR_fprintf(PR_STDOUT, "username: ");
|
|
|
|
#endif
|
|
|
|
fgets(buf, STDIN_BUF_SIZE, stdin);
|
|
|
|
cp = chop(buf);
|
|
|
|
if (*cp != '\0') {
|
|
|
|
uid = PORT_ZAlloc(strlen(cp) + 7);
|
|
|
|
if (!uid) {
|
|
|
|
out_of_memory();
|
|
|
|
}
|
|
|
|
sprintf(uid, "UID=%s, ", cp);
|
|
|
|
subjectlen += strlen(uid);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERBOSE_PROMPTS
|
|
|
|
PR_fprintf(PR_STDOUT, "\nEMAIL ADDRESS\n"
|
|
|
|
"Enter your email address.\n"
|
|
|
|
"-->");
|
|
|
|
#else
|
|
|
|
PR_fprintf(PR_STDOUT, "email address: ");
|
|
|
|
#endif
|
|
|
|
fgets(buf, STDIN_BUF_SIZE, stdin);
|
|
|
|
cp = chop(buf);
|
|
|
|
if (*cp != '\0') {
|
|
|
|
email = PORT_ZAlloc(strlen(cp) + 5);
|
|
|
|
if (!email) {
|
|
|
|
out_of_memory();
|
|
|
|
}
|
|
|
|
sprintf(email, "E=%s,", cp);
|
|
|
|
subjectlen += strlen(email);
|
|
|
|
}
|
|
|
|
|
|
|
|
subjectlen++;
|
|
|
|
|
|
|
|
subject = PORT_ZAlloc(subjectlen);
|
|
|
|
if (!subject) {
|
|
|
|
out_of_memory();
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(subject, "%s%s%s%s%s%s%s",
|
|
|
|
common_name ? common_name : "",
|
|
|
|
org ? org : "",
|
|
|
|
orgunit ? orgunit : "",
|
|
|
|
state ? state : "",
|
|
|
|
country ? country : "",
|
|
|
|
uid ? uid : "",
|
|
|
|
email ? email : ""
|
|
|
|
);
|
|
|
|
if ( (strlen(subject) > 1) && (subject[strlen(subject)-1] == ' ') ) {
|
|
|
|
subject[strlen(subject)-2] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
PORT_Free(common_name);
|
|
|
|
PORT_Free(org);
|
|
|
|
PORT_Free(orgunit);
|
|
|
|
PORT_Free(state);
|
|
|
|
PORT_Free(country);
|
|
|
|
PORT_Free(uid);
|
|
|
|
PORT_Free(email);
|
|
|
|
|
|
|
|
return subject;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* G e n e r a t e S e l f S i g n e d O b j e c t S i g n i n g C e r t
|
|
|
|
* *phew*^
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static CERTCertificate*
|
|
|
|
GenerateSelfSignedObjectSigningCert(char *nickname, CERTCertDBHandle *db,
|
|
|
|
char *subject, unsigned long serial, int keysize, char *token)
|
|
|
|
{
|
|
|
|
CERTCertificate * cert, *temp_cert;
|
|
|
|
SECItem * derCert;
|
|
|
|
CERTCertificateRequest * req;
|
|
|
|
|
|
|
|
PK11SlotInfo * slot = NULL;
|
|
|
|
SECKEYPrivateKey * privk = NULL;
|
|
|
|
SECKEYPublicKey * pubk = NULL;
|
|
|
|
|
|
|
|
if ( token ) {
|
|
|
|
slot = PK11_FindSlotByName(token);
|
|
|
|
} else {
|
|
|
|
slot = PK11_GetInternalKeySlot();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slot == NULL) {
|
|
|
|
PR_fprintf(errorFD, "Can't find PKCS11 slot %s\n",
|
|
|
|
token ? token : "");
|
|
|
|
errorCount++;
|
|
|
|
exit (ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( GenerateKeyPair(slot, &pubk, &privk, keysize) != SECSuccess) {
|
|
|
|
FatalError("Error generating keypair.");
|
|
|
|
}
|
|
|
|
req = make_cert_request (subject, pubk);
|
|
|
|
temp_cert = make_cert (req, serial, &req->subject);
|
|
|
|
if (set_cert_type(temp_cert,
|
|
|
|
NS_CERT_TYPE_OBJECT_SIGNING | NS_CERT_TYPE_OBJECT_SIGNING_CA)
|
|
|
|
!= SECSuccess) {
|
|
|
|
FatalError("Unable to set cert type");
|
|
|
|
}
|
|
|
|
|
|
|
|
derCert = sign_cert (temp_cert, privk);
|
|
|
|
cert = install_cert(db, derCert, nickname);
|
|
|
|
if (ChangeTrustAttributes(db, cert, ",,uC") != SECSuccess) {
|
|
|
|
FatalError("Unable to change trust on generated certificate");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* !!! Free memory ? !!! */
|
|
|
|
PK11_FreeSlot(slot);
|
|
|
|
SECKEY_DestroyPrivateKey(privk);
|
|
|
|
SECKEY_DestroyPublicKey(pubk);
|
|
|
|
|
|
|
|
return cert;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
*
|
|
|
|
* C h a n g e T r u s t A t t r i b u t e s
|
|
|
|
*/
|
|
|
|
static SECStatus
|
|
|
|
ChangeTrustAttributes(CERTCertDBHandle *db, CERTCertificate *cert, char *trusts)
|
|
|
|
{
|
|
|
|
|
|
|
|
CERTCertTrust * trust;
|
|
|
|
|
|
|
|
if (!db || !cert || !trusts) {
|
|
|
|
PR_fprintf(errorFD, "ChangeTrustAttributes got incomplete arguments.\n");
|
|
|
|
errorCount++;
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
trust = (CERTCertTrust * ) PORT_ZAlloc(sizeof(CERTCertTrust));
|
|
|
|
if (!trust) {
|
|
|
|
PR_fprintf(errorFD, "ChangeTrustAttributes unable to allocate "
|
|
|
|
"CERTCertTrust\n");
|
|
|
|
errorCount++;
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( CERT_DecodeTrustString(trust, trusts) ) {
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( CERT_ChangeCertTrust(db, cert, trust) ) {
|
|
|
|
PR_fprintf(errorFD, "unable to modify trust attributes for cert %s\n",
|
|
|
|
cert->nickname ? cert->nickname : "");
|
|
|
|
errorCount++;
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SECSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
*
|
|
|
|
* s e t _ c e r t _ t y p e
|
|
|
|
*/
|
|
|
|
static SECStatus
|
|
|
|
set_cert_type(CERTCertificate *cert, unsigned int type)
|
|
|
|
{
|
|
|
|
void *context;
|
|
|
|
SECStatus status = SECSuccess;
|
|
|
|
SECItem certType;
|
|
|
|
char ctype;
|
|
|
|
|
|
|
|
context = CERT_StartCertExtensions(cert);
|
|
|
|
|
|
|
|
certType.type = siBuffer;
|
|
|
|
certType.data = (unsigned char * ) &ctype;
|
|
|
|
certType.len = 1;
|
|
|
|
ctype = (unsigned char)type;
|
|
|
|
if (CERT_EncodeAndAddBitStrExtension(context, SEC_OID_NS_CERT_EXT_CERT_TYPE,
|
|
|
|
&certType, PR_TRUE /*critical*/) != SECSuccess) {
|
|
|
|
status = SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CERT_FinishExtensions(context) != SECSuccess) {
|
|
|
|
status = SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/********************************************************************
|
|
|
|
*
|
|
|
|
* s i g n _ c e r t
|
|
|
|
*/
|
|
|
|
static SECItem *
|
|
|
|
sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk)
|
|
|
|
{
|
|
|
|
SECStatus rv;
|
|
|
|
|
|
|
|
SECItem der2;
|
|
|
|
SECItem * result2;
|
|
|
|
|
|
|
|
void *dummy;
|
|
|
|
SECOidTag alg = SEC_OID_UNKNOWN;
|
|
|
|
|
|
|
|
alg = SEC_GetSignatureAlgorithmOidTag(privk->keyType, SEC_OID_UNKNOWN);
|
|
|
|
if (alg == SEC_OID_UNKNOWN) {
|
|
|
|
FatalError("Unknown key type");
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = SECOID_SetAlgorithmID (cert->arena, &cert->signature, alg, 0);
|
|
|
|
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
PR_fprintf(errorFD, "%s: unable to set signature alg id\n",
|
|
|
|
PROGRAM_NAME);
|
|
|
|
errorCount++;
|
|
|
|
exit (ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
der2.len = 0;
|
|
|
|
der2.data = NULL;
|
|
|
|
|
|
|
|
dummy = SEC_ASN1EncodeItem
|
2008-08-14 21:12:54 -07:00
|
|
|
(cert->arena, &der2, cert, SEC_ASN1_GET(CERT_CertificateTemplate));
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
PR_fprintf(errorFD, "%s: error encoding cert\n", PROGRAM_NAME);
|
|
|
|
errorCount++;
|
|
|
|
exit (ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
result2 = (SECItem * ) PORT_ArenaZAlloc (cert->arena, sizeof (SECItem));
|
|
|
|
if (result2 == NULL)
|
|
|
|
out_of_memory();
|
|
|
|
|
|
|
|
rv = SEC_DerSignData
|
|
|
|
(cert->arena, result2, der2.data, der2.len, privk, alg);
|
|
|
|
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
PR_fprintf(errorFD, "can't sign encoded certificate data\n");
|
|
|
|
errorCount++;
|
|
|
|
exit (ERRX);
|
|
|
|
} else if (verbosity >= 0) {
|
|
|
|
PR_fprintf(outputFD, "certificate has been signed\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
cert->derCert = *result2;
|
|
|
|
|
|
|
|
return result2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
*
|
|
|
|
* i n s t a l l _ c e r t
|
|
|
|
*
|
|
|
|
* Installs the cert in the permanent database.
|
|
|
|
*/
|
|
|
|
static CERTCertificate*
|
|
|
|
install_cert(CERTCertDBHandle *db, SECItem *derCert, char *nickname)
|
|
|
|
{
|
|
|
|
CERTCertificate * newcert;
|
|
|
|
PK11SlotInfo * newSlot;
|
|
|
|
|
|
|
|
|
2008-08-14 21:12:54 -07:00
|
|
|
newSlot = PK11_ImportDERCertForKey(derCert, nickname, &pwdata);
|
2008-06-06 05:40:11 -07:00
|
|
|
if ( newSlot == NULL ) {
|
|
|
|
PR_fprintf(errorFD, "Unable to install certificate\n");
|
|
|
|
errorCount++;
|
|
|
|
exit(ERRX);
|
|
|
|
}
|
2008-08-14 21:12:54 -07:00
|
|
|
|
|
|
|
newcert = PK11_FindCertFromDERCertItem(newSlot, derCert, &pwdata);
|
2008-06-06 05:40:11 -07:00
|
|
|
PK11_FreeSlot(newSlot);
|
2008-08-14 21:12:54 -07:00
|
|
|
if (newcert == NULL) {
|
|
|
|
PR_fprintf(errorFD, "%s: can't find new certificate\n",
|
|
|
|
PROGRAM_NAME);
|
|
|
|
errorCount++;
|
|
|
|
exit (ERRX);
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
if (verbosity >= 0) {
|
|
|
|
PR_fprintf(outputFD, "certificate \"%s\" added to database\n",
|
|
|
|
nickname);
|
|
|
|
}
|
|
|
|
|
|
|
|
return newcert;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
*
|
|
|
|
* G e n e r a t e K e y P a i r
|
|
|
|
*/
|
|
|
|
static SECStatus
|
|
|
|
GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk,
|
|
|
|
SECKEYPrivateKey **privk, int keysize)
|
|
|
|
{
|
|
|
|
|
|
|
|
PK11RSAGenParams rsaParams;
|
|
|
|
|
|
|
|
if ( keysize == -1 ) {
|
|
|
|
rsaParams.keySizeInBits = DEFAULT_RSA_KEY_SIZE;
|
|
|
|
} else {
|
|
|
|
rsaParams.keySizeInBits = keysize;
|
|
|
|
}
|
|
|
|
rsaParams.pe = 0x10001;
|
|
|
|
|
2008-08-14 21:12:54 -07:00
|
|
|
if (PK11_Authenticate( slot, PR_FALSE /*loadCerts*/, &pwdata)
|
2008-06-06 05:40:11 -07:00
|
|
|
!= SECSuccess) {
|
|
|
|
SECU_PrintError(progName, "failure authenticating to key database.\n");
|
|
|
|
exit(ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
*privk = PK11_GenerateKeyPair (slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams,
|
|
|
|
|
2008-08-14 21:12:54 -07:00
|
|
|
pubk, PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, &pwdata);
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
if (*privk != NULL && *pubk != NULL) {
|
|
|
|
if (verbosity >= 0) {
|
|
|
|
PR_fprintf(outputFD, "generated public/private key pair\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SECU_PrintError(progName, "failure generating key pair\n");
|
|
|
|
exit (ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SECSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
*
|
|
|
|
* m a k e _ c e r t _ r e q u e s t
|
|
|
|
*/
|
|
|
|
static CERTCertificateRequest*
|
|
|
|
make_cert_request(char *subject, SECKEYPublicKey *pubk)
|
|
|
|
{
|
|
|
|
CERTName * subj;
|
|
|
|
CERTSubjectPublicKeyInfo * spki;
|
|
|
|
|
|
|
|
CERTCertificateRequest * req;
|
|
|
|
|
|
|
|
/* Create info about public key */
|
|
|
|
spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
|
|
|
|
if (!spki) {
|
|
|
|
SECU_PrintError(progName, "unable to create subject public key");
|
|
|
|
exit (ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
subj = CERT_AsciiToName (subject);
|
|
|
|
if (subj == NULL) {
|
|
|
|
FatalError("Invalid data in certificate description");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate certificate request */
|
|
|
|
req = CERT_CreateCertificateRequest(subj, spki, 0);
|
|
|
|
if (!req) {
|
|
|
|
SECU_PrintError(progName, "unable to make certificate request");
|
|
|
|
exit (ERRX);
|
|
|
|
}
|
|
|
|
|
2010-02-07 03:54:28 -08:00
|
|
|
SECKEY_DestroySubjectPublicKeyInfo(spki);
|
|
|
|
CERT_DestroyName(subj);
|
|
|
|
|
2008-06-06 05:40:11 -07:00
|
|
|
if (verbosity >= 0) {
|
|
|
|
PR_fprintf(outputFD, "certificate request generated\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return req;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
*
|
|
|
|
* m a k e _ c e r t
|
|
|
|
*/
|
|
|
|
static CERTCertificate *
|
|
|
|
make_cert(CERTCertificateRequest *req, unsigned long serial,
|
|
|
|
CERTName *ca_subject)
|
|
|
|
{
|
|
|
|
CERTCertificate * cert;
|
|
|
|
|
|
|
|
CERTValidity * validity = NULL;
|
|
|
|
|
|
|
|
PRTime now, after;
|
|
|
|
PRExplodedTime printableTime;
|
|
|
|
|
|
|
|
now = PR_Now();
|
|
|
|
PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
|
|
|
|
|
|
|
|
printableTime.tm_month += 3;
|
|
|
|
after = PR_ImplodeTime (&printableTime);
|
|
|
|
|
|
|
|
validity = CERT_CreateValidity (now, after);
|
|
|
|
|
|
|
|
if (validity == NULL) {
|
|
|
|
PR_fprintf(errorFD, "%s: error creating certificate validity\n",
|
|
|
|
PROGRAM_NAME);
|
|
|
|
errorCount++;
|
|
|
|
exit (ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
cert = CERT_CreateCertificate
|
|
|
|
(serial, ca_subject, validity, req);
|
|
|
|
|
|
|
|
if (cert == NULL) {
|
|
|
|
/* should probably be more precise here */
|
|
|
|
PR_fprintf(errorFD, "%s: error while generating certificate\n",
|
|
|
|
PROGRAM_NAME);
|
|
|
|
errorCount++;
|
|
|
|
exit (ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
return cert;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
*
|
|
|
|
* o u t p u t _ c a _ c e r t
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db)
|
|
|
|
{
|
|
|
|
FILE * out;
|
|
|
|
|
|
|
|
SECItem * encodedCertChain;
|
|
|
|
SEC_PKCS7ContentInfo * certChain;
|
|
|
|
char *filename;
|
|
|
|
|
|
|
|
/* the raw */
|
|
|
|
|
|
|
|
filename = PORT_ZAlloc(strlen(DEFAULT_X509_BASENAME) + 8);
|
|
|
|
if (!filename)
|
|
|
|
out_of_memory();
|
|
|
|
|
|
|
|
sprintf(filename, "%s.raw", DEFAULT_X509_BASENAME);
|
|
|
|
if ((out = fopen (filename, "wb")) == NULL) {
|
|
|
|
PR_fprintf(errorFD, "%s: Can't open %s output file\n", PROGRAM_NAME,
|
|
|
|
filename);
|
|
|
|
errorCount++;
|
|
|
|
exit(ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
certChain = SEC_PKCS7CreateCertsOnly (cert, PR_TRUE, db);
|
|
|
|
encodedCertChain
|
|
|
|
= SEC_PKCS7EncodeItem (NULL, NULL, certChain, NULL, NULL, NULL);
|
|
|
|
SEC_PKCS7DestroyContentInfo (certChain);
|
|
|
|
|
|
|
|
if (encodedCertChain) {
|
|
|
|
fprintf(out, "Content-type: application/x-x509-ca-cert\n\n");
|
|
|
|
fwrite (encodedCertChain->data, 1, encodedCertChain->len,
|
|
|
|
out);
|
|
|
|
SECITEM_FreeItem(encodedCertChain, PR_TRUE);
|
|
|
|
} else {
|
|
|
|
PR_fprintf(errorFD, "%s: Can't DER encode this certificate\n",
|
|
|
|
PROGRAM_NAME);
|
|
|
|
errorCount++;
|
|
|
|
exit(ERRX);
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose (out);
|
|
|
|
|
|
|
|
/* and the cooked */
|
|
|
|
|
|
|
|
sprintf(filename, "%s.cacert", DEFAULT_X509_BASENAME);
|
|
|
|
if ((out = fopen (filename, "wb")) == NULL) {
|
|
|
|
PR_fprintf(errorFD, "%s: Can't open %s output file\n", PROGRAM_NAME,
|
|
|
|
filename);
|
|
|
|
errorCount++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf (out, "%s\n%s\n%s\n",
|
|
|
|
NS_CERT_HEADER,
|
|
|
|
BTOA_DataToAscii (cert->derCert.data, cert->derCert.len),
|
|
|
|
NS_CERT_TRAILER);
|
|
|
|
|
|
|
|
fclose (out);
|
|
|
|
|
|
|
|
if (verbosity >= 0) {
|
|
|
|
PR_fprintf(outputFD, "Exported certificate to %s.raw and %s.cacert.\n",
|
|
|
|
DEFAULT_X509_BASENAME, DEFAULT_X509_BASENAME);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|