1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
* The contents of this file are subject to the Mozilla Public License Version
5
* 1.1 (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
7
* http://www.mozilla.org/MPL/
9
* Software distributed under the License is distributed on an "AS IS" basis,
10
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
* for the specific language governing rights and limitations under the
14
* The Original Code is the Netscape security libraries.
16
* The Initial Developer of the Original Code is
17
* Netscape Communications Corporation.
18
* Portions created by the Initial Developer are Copyright (C) 1994-2000
19
* the Initial Developer. All Rights Reserved.
23
* Alternatively, the contents of this file may be used under the terms of
24
* either the GNU General Public License Version 2 or later (the "GPL"), or
25
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26
* in which case the provisions of the GPL or the LGPL are applicable instead
27
* of those above. If you wish to allow use of your version of this file only
28
* under the terms of either the GPL or the LGPL, and not to allow others to
29
* use your version of this file under the terms of the MPL, indicate your
30
* decision by deleting the provisions above and replace them with the notice
31
* and other provisions required by the GPL or the LGPL. If you do not delete
32
* the provisions above, a recipient may use your version of this file under
33
* the terms of any one of the MPL, the GPL or the LGPL.
35
* ***** END LICENSE BLOCK ***** */
43
static char *GetSubjectFromUser(unsigned long serial);
44
static CERTCertificate*GenerateSelfSignedObjectSigningCert(char *nickname,
45
CERTCertDBHandle *db, char *subject, unsigned long serial, int keysize,
47
static SECStatus ChangeTrustAttributes(CERTCertDBHandle *db,
48
CERTCertificate *cert, char *trusts);
49
static SECStatus set_cert_type(CERTCertificate *cert, unsigned int type);
50
static SECItem *sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk);
51
static CERTCertificate*install_cert(CERTCertDBHandle *db, SECItem *derCert,
53
static SECStatus GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk,
54
SECKEYPrivateKey **privk, int keysize);
55
static CERTCertificateRequest*make_cert_request(char *subject,
56
SECKEYPublicKey *pubk);
57
static CERTCertificate *make_cert(CERTCertificateRequest *req,
58
unsigned long serial, CERTName *ca_subject);
59
static void output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db);
62
/***********************************************************************
64
* G e n e r a t e C e r t
66
* Runs the whole process of creating a new cert, getting info from the
70
GenerateCert(char *nickname, int keysize, char *token)
72
CERTCertDBHandle * db;
73
CERTCertificate * cert;
78
/* Print warning about having the browser open */
79
PR_fprintf(PR_STDOUT /*always go to console*/,
80
"\nWARNING: Performing this operation while the browser is running could cause"
81
"\ncorruption of your security databases. If the browser is currently running,"
82
"\nyou should exit the browser before continuing this operation. Enter "
83
"\n\"y\" to continue, or anything else to abort: ");
84
pr_fgets(stdinbuf, 160, PR_STDIN);
85
PR_fprintf(PR_STDOUT, "\n");
86
if (tolower(stdinbuf[0]) != 'y') {
87
PR_fprintf(errorFD, "Operation aborted at user's request.\n");
92
db = CERT_GetDefaultCertDB();
94
FatalError("Unable to open certificate database");
97
if (PK11_FindCertFromNickname(nickname, NULL)) {
99
"ERROR: Certificate with nickname \"%s\" already exists in database. You\n"
100
"must choose a different nickname.\n", nickname);
105
LL_L2UI(serial, PR_Now());
107
subject = GetSubjectFromUser(serial);
109
cert = GenerateSelfSignedObjectSigningCert(nickname, db, subject,
110
serial, keysize, token);
113
output_ca_cert(cert, db);
114
CERT_DestroyCertificate(cert);
122
#undef VERBOSE_PROMPTS
124
/*********************************************************************8
125
* G e t S u b j e c t F r o m U s e r
127
* Construct the subject information line for a certificate by querying
131
GetSubjectFromUser(unsigned long serial)
133
char buf[STDIN_BUF_SIZE];
134
char common_name_buf[STDIN_BUF_SIZE];
135
char *common_name, *state, *orgunit, *country, *org, *locality;
141
common_name = state = orgunit = country = org = locality = email =
142
uid = subject = NULL;
144
/* Get subject information */
145
PR_fprintf(PR_STDOUT,
146
"\nEnter certificate information. All fields are optional. Acceptable\n"
147
"characters are numbers, letters, spaces, and apostrophes.\n");
149
#ifdef VERBOSE_PROMPTS
150
PR_fprintf(PR_STDOUT, "\nCOMMON NAME\n"
151
"Enter the full name you want to give your certificate. (Example: Test-Only\n"
152
"Object Signing Certificate)\n"
155
PR_fprintf(PR_STDOUT, "certificate common name: ");
157
fgets(buf, STDIN_BUF_SIZE, stdin);
160
sprintf(common_name_buf, "%s (%lu)", DEFAULT_COMMON_NAME,
162
cp = common_name_buf;
164
common_name = PORT_ZAlloc(strlen(cp) + 6);
168
sprintf(common_name, "CN=%s, ", cp);
169
subjectlen += strlen(common_name);
171
#ifdef VERBOSE_PROMPTS
172
PR_fprintf(PR_STDOUT, "\nORGANIZATION NAME\n"
173
"Enter the name of your organization. For example, this could be the name\n"
177
PR_fprintf(PR_STDOUT, "organization: ");
179
fgets(buf, STDIN_BUF_SIZE, stdin);
182
org = PORT_ZAlloc(strlen(cp) + 5);
186
sprintf(org, "O=%s, ", cp);
187
subjectlen += strlen(org);
190
#ifdef VERBOSE_PROMPTS
191
PR_fprintf(PR_STDOUT, "\nORGANIZATION UNIT\n"
192
"Enter the name of your organization unit. For example, this could be the\n"
193
"name of your department.\n"
196
PR_fprintf(PR_STDOUT, "organization unit: ");
198
fgets(buf, STDIN_BUF_SIZE, stdin);
201
orgunit = PORT_ZAlloc(strlen(cp) + 6);
205
sprintf(orgunit, "OU=%s, ", cp);
206
subjectlen += strlen(orgunit);
209
#ifdef VERBOSE_PROMPTS
210
PR_fprintf(PR_STDOUT, "\nSTATE\n"
211
"Enter the name of your state or province.\n"
214
PR_fprintf(PR_STDOUT, "state or province: ");
216
fgets(buf, STDIN_BUF_SIZE, stdin);
219
state = PORT_ZAlloc(strlen(cp) + 6);
223
sprintf(state, "ST=%s, ", cp);
224
subjectlen += strlen(state);
227
#ifdef VERBOSE_PROMPTS
228
PR_fprintf(PR_STDOUT, "\nCOUNTRY\n"
229
"Enter the 2-character abbreviation for the name of your country.\n"
232
PR_fprintf(PR_STDOUT, "country (must be exactly 2 characters): ");
234
fgets(buf, STDIN_BUF_SIZE, stdin);
236
if (strlen(cp) != 2) {
237
*cp = '\0'; /* country code must be 2 chars */
240
country = PORT_ZAlloc(strlen(cp) + 5);
244
sprintf(country, "C=%s, ", cp);
245
subjectlen += strlen(country);
248
#ifdef VERBOSE_PROMPTS
249
PR_fprintf(PR_STDOUT, "\nUSERNAME\n"
250
"Enter your system username or UID\n"
253
PR_fprintf(PR_STDOUT, "username: ");
255
fgets(buf, STDIN_BUF_SIZE, stdin);
258
uid = PORT_ZAlloc(strlen(cp) + 7);
262
sprintf(uid, "UID=%s, ", cp);
263
subjectlen += strlen(uid);
266
#ifdef VERBOSE_PROMPTS
267
PR_fprintf(PR_STDOUT, "\nEMAIL ADDRESS\n"
268
"Enter your email address.\n"
271
PR_fprintf(PR_STDOUT, "email address: ");
273
fgets(buf, STDIN_BUF_SIZE, stdin);
276
email = PORT_ZAlloc(strlen(cp) + 5);
280
sprintf(email, "E=%s,", cp);
281
subjectlen += strlen(email);
286
subject = PORT_ZAlloc(subjectlen);
291
sprintf(subject, "%s%s%s%s%s%s%s",
292
common_name ? common_name : "",
294
orgunit ? orgunit : "",
296
country ? country : "",
300
if ( (strlen(subject) > 1) && (subject[strlen(subject)-1] == ' ') ) {
301
subject[strlen(subject)-2] = '\0';
304
PORT_Free(common_name);
316
/**************************************************************************
318
* 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
322
static CERTCertificate*
323
GenerateSelfSignedObjectSigningCert(char *nickname, CERTCertDBHandle *db,
324
char *subject, unsigned long serial, int keysize, char *token)
326
CERTCertificate * cert, *temp_cert;
328
CERTCertificateRequest * req;
330
PK11SlotInfo * slot = NULL;
331
SECKEYPrivateKey * privk = NULL;
332
SECKEYPublicKey * pubk = NULL;
335
slot = PK11_FindSlotByName(token);
337
slot = PK11_GetInternalKeySlot();
341
PR_fprintf(errorFD, "Can't find PKCS11 slot %s\n",
347
if ( GenerateKeyPair(slot, &pubk, &privk, keysize) != SECSuccess) {
348
FatalError("Error generating keypair.");
350
req = make_cert_request (subject, pubk);
351
temp_cert = make_cert (req, serial, &req->subject);
352
if (set_cert_type(temp_cert,
353
NS_CERT_TYPE_OBJECT_SIGNING | NS_CERT_TYPE_OBJECT_SIGNING_CA)
355
FatalError("Unable to set cert type");
358
derCert = sign_cert (temp_cert, privk);
359
cert = install_cert(db, derCert, nickname);
360
if (ChangeTrustAttributes(db, cert, ",,uC") != SECSuccess) {
361
FatalError("Unable to change trust on generated certificate");
364
/* !!! Free memory ? !!! */
366
SECKEY_DestroyPrivateKey(privk);
367
SECKEY_DestroyPublicKey(pubk);
373
/**************************************************************************
375
* C h a n g e T r u s t A t t r i b u t e s
378
ChangeTrustAttributes(CERTCertDBHandle *db, CERTCertificate *cert, char *trusts)
381
CERTCertTrust * trust;
383
if (!db || !cert || !trusts) {
384
PR_fprintf(errorFD, "ChangeTrustAttributes got incomplete arguments.\n");
389
trust = (CERTCertTrust * ) PORT_ZAlloc(sizeof(CERTCertTrust));
391
PR_fprintf(errorFD, "ChangeTrustAttributes unable to allocate "
397
if ( CERT_DecodeTrustString(trust, trusts) ) {
401
if ( CERT_ChangeCertTrust(db, cert, trust) ) {
402
PR_fprintf(errorFD, "unable to modify trust attributes for cert %s\n",
403
cert->nickname ? cert->nickname : "");
412
/*************************************************************************
414
* s e t _ c e r t _ t y p e
417
set_cert_type(CERTCertificate *cert, unsigned int type)
420
SECStatus status = SECSuccess;
424
context = CERT_StartCertExtensions(cert);
426
certType.type = siBuffer;
427
certType.data = (unsigned char * ) &ctype;
429
ctype = (unsigned char)type;
430
if (CERT_EncodeAndAddBitStrExtension(context, SEC_OID_NS_CERT_EXT_CERT_TYPE,
431
&certType, PR_TRUE /*critical*/) != SECSuccess) {
435
if (CERT_FinishExtensions(context) != SECSuccess) {
443
/********************************************************************
448
sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk)
456
SECOidTag alg = SEC_OID_UNKNOWN;
458
switch (privk->keyType) {
460
alg = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
464
alg = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
467
FatalError("Unknown key type");
469
PORT_Assert(alg != SEC_OID_UNKNOWN);
471
rv = SECOID_SetAlgorithmID (cert->arena, &cert->signature, alg, 0);
473
if (rv != SECSuccess) {
474
PR_fprintf(errorFD, "%s: unable to set signature alg id\n",
483
dummy = SEC_ASN1EncodeItem
484
(cert->arena, &der2, cert, CERT_CertificateTemplate);
486
if (rv != SECSuccess) {
487
PR_fprintf(errorFD, "%s: error encoding cert\n", PROGRAM_NAME);
492
result2 = (SECItem * ) PORT_ArenaZAlloc (cert->arena, sizeof (SECItem));
497
(cert->arena, result2, der2.data, der2.len, privk, alg);
499
if (rv != SECSuccess) {
500
PR_fprintf(errorFD, "can't sign encoded certificate data\n");
503
} else if (verbosity >= 0) {
504
PR_fprintf(outputFD, "certificate has been signed\n");
507
cert->derCert = *result2;
513
/*********************************************************************
515
* i n s t a l l _ c e r t
517
* Installs the cert in the permanent database.
519
static CERTCertificate*
520
install_cert(CERTCertDBHandle *db, SECItem *derCert, char *nickname)
522
CERTCertificate * newcert;
523
PK11SlotInfo * newSlot;
525
newcert = CERT_DecodeDERCertificate(derCert, PR_TRUE, NULL);
527
if (newcert == NULL) {
528
PR_fprintf(errorFD, "%s: can't create new certificate\n",
534
newSlot = PK11_ImportCertForKey(newcert, nickname, NULL /*wincx*/);
535
if ( newSlot == NULL ) {
536
PR_fprintf(errorFD, "Unable to install certificate\n");
540
PK11_FreeSlot(newSlot);
542
if (verbosity >= 0) {
543
PR_fprintf(outputFD, "certificate \"%s\" added to database\n",
551
/******************************************************************
553
* G e n e r a t e K e y P a i r
556
GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk,
557
SECKEYPrivateKey **privk, int keysize)
560
PK11RSAGenParams rsaParams;
562
if ( keysize == -1 ) {
563
rsaParams.keySizeInBits = DEFAULT_RSA_KEY_SIZE;
565
rsaParams.keySizeInBits = keysize;
567
rsaParams.pe = 0x10001;
569
if (PK11_Authenticate( slot, PR_FALSE /*loadCerts*/, NULL /*wincx*/)
571
SECU_PrintError(progName, "failure authenticating to key database.\n");
575
*privk = PK11_GenerateKeyPair (slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams,
577
pubk, PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, NULL /*wincx*/ );
579
if (*privk != NULL && *pubk != NULL) {
580
if (verbosity >= 0) {
581
PR_fprintf(outputFD, "generated public/private key pair\n");
584
SECU_PrintError(progName, "failure generating key pair\n");
593
/******************************************************************
595
* m a k e _ c e r t _ r e q u e s t
597
static CERTCertificateRequest*
598
make_cert_request(char *subject, SECKEYPublicKey *pubk)
601
CERTSubjectPublicKeyInfo * spki;
603
CERTCertificateRequest * req;
605
/* Create info about public key */
606
spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
608
SECU_PrintError(progName, "unable to create subject public key");
612
subj = CERT_AsciiToName (subject);
614
FatalError("Invalid data in certificate description");
617
/* Generate certificate request */
618
req = CERT_CreateCertificateRequest(subj, spki, 0);
620
SECU_PrintError(progName, "unable to make certificate request");
624
if (verbosity >= 0) {
625
PR_fprintf(outputFD, "certificate request generated\n");
632
/******************************************************************
636
static CERTCertificate *
637
make_cert(CERTCertificateRequest *req, unsigned long serial,
638
CERTName *ca_subject)
640
CERTCertificate * cert;
642
CERTValidity * validity = NULL;
645
PRExplodedTime printableTime;
648
PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
650
printableTime.tm_month += 3;
651
after = PR_ImplodeTime (&printableTime);
653
validity = CERT_CreateValidity (now, after);
655
if (validity == NULL) {
656
PR_fprintf(errorFD, "%s: error creating certificate validity\n",
662
cert = CERT_CreateCertificate
663
(serial, ca_subject, validity, req);
666
/* should probably be more precise here */
667
PR_fprintf(errorFD, "%s: error while generating certificate\n",
677
/*************************************************************************
679
* o u t p u t _ c a _ c e r t
682
output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db)
686
SECItem * encodedCertChain;
687
SEC_PKCS7ContentInfo * certChain;
692
filename = PORT_ZAlloc(strlen(DEFAULT_X509_BASENAME) + 8);
696
sprintf(filename, "%s.raw", DEFAULT_X509_BASENAME);
697
if ((out = fopen (filename, "wb")) == NULL) {
698
PR_fprintf(errorFD, "%s: Can't open %s output file\n", PROGRAM_NAME,
704
certChain = SEC_PKCS7CreateCertsOnly (cert, PR_TRUE, db);
706
= SEC_PKCS7EncodeItem (NULL, NULL, certChain, NULL, NULL, NULL);
707
SEC_PKCS7DestroyContentInfo (certChain);
709
if (encodedCertChain) {
710
fprintf(out, "Content-type: application/x-x509-ca-cert\n\n");
711
fwrite (encodedCertChain->data, 1, encodedCertChain->len,
713
SECITEM_FreeItem(encodedCertChain, PR_TRUE);
715
PR_fprintf(errorFD, "%s: Can't DER encode this certificate\n",
725
sprintf(filename, "%s.cacert", DEFAULT_X509_BASENAME);
726
if ((out = fopen (filename, "wb")) == NULL) {
727
PR_fprintf(errorFD, "%s: Can't open %s output file\n", PROGRAM_NAME,
733
fprintf (out, "%s\n%s\n%s\n",
735
BTOA_DataToAscii (cert->derCert.data, cert->derCert.len),
740
if (verbosity >= 0) {
741
PR_fprintf(outputFD, "Exported certificate to %s.raw and %s.cacert.\n",
742
DEFAULT_X509_BASENAME, DEFAULT_X509_BASENAME);