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 alg
= SEC_GetSignatureAlgorithmOidTag(privk
->keyType
, SEC_OID_UNKNOWN
);
459 if (alg
== SEC_OID_UNKNOWN
) {
460 FatalError("Unknown key type");
463 rv
= SECOID_SetAlgorithmID (cert
->arena
, &cert
->signature
, alg
, 0);
465 if (rv
!= SECSuccess
) {
466 PR_fprintf(errorFD
, "%s: unable to set signature alg id\n",
475 dummy
= SEC_ASN1EncodeItem
476 (cert
->arena
, &der2
, cert
, CERT_CertificateTemplate
);
478 if (rv
!= SECSuccess
) {
479 PR_fprintf(errorFD
, "%s: error encoding cert\n", PROGRAM_NAME
);
484 result2
= (SECItem
* ) PORT_ArenaZAlloc (cert
->arena
, sizeof (SECItem
));
489 (cert
->arena
, result2
, der2
.data
, der2
.len
, privk
, alg
);
491 if (rv
!= SECSuccess
) {
492 PR_fprintf(errorFD
, "can't sign encoded certificate data\n");
495 } else if (verbosity
>= 0) {
496 PR_fprintf(outputFD
, "certificate has been signed\n");
499 cert
->derCert
= *result2
;
505 /*********************************************************************
507 * i n s t a l l _ c e r t
509 * Installs the cert in the permanent database.
511 static CERTCertificate
*
512 install_cert(CERTCertDBHandle
*db
, SECItem
*derCert
, char *nickname
)
514 CERTCertificate
* newcert
;
515 PK11SlotInfo
* newSlot
;
517 newcert
= CERT_DecodeDERCertificate(derCert
, PR_TRUE
, NULL
);
519 if (newcert
== NULL
) {
520 PR_fprintf(errorFD
, "%s: can't create new certificate\n",
526 newSlot
= PK11_ImportCertForKey(newcert
, nickname
, NULL
/*wincx*/);
527 if ( newSlot
== NULL
) {
528 PR_fprintf(errorFD
, "Unable to install certificate\n");
532 PK11_FreeSlot(newSlot
);
534 if (verbosity
>= 0) {
535 PR_fprintf(outputFD
, "certificate \"%s\" added to database\n",
543 /******************************************************************
545 * G e n e r a t e K e y P a i r
548 GenerateKeyPair(PK11SlotInfo
*slot
, SECKEYPublicKey
**pubk
,
549 SECKEYPrivateKey
**privk
, int keysize
)
552 PK11RSAGenParams rsaParams
;
554 if ( keysize
== -1 ) {
555 rsaParams
.keySizeInBits
= DEFAULT_RSA_KEY_SIZE
;
557 rsaParams
.keySizeInBits
= keysize
;
559 rsaParams
.pe
= 0x10001;
561 if (PK11_Authenticate( slot
, PR_FALSE
/*loadCerts*/, NULL
/*wincx*/)
563 SECU_PrintError(progName
, "failure authenticating to key database.\n");
567 *privk
= PK11_GenerateKeyPair (slot
, CKM_RSA_PKCS_KEY_PAIR_GEN
, &rsaParams
,
569 pubk
, PR_TRUE
/*isPerm*/, PR_TRUE
/*isSensitive*/, NULL
/*wincx*/ );
571 if (*privk
!= NULL
&& *pubk
!= NULL
) {
572 if (verbosity
>= 0) {
573 PR_fprintf(outputFD
, "generated public/private key pair\n");
576 SECU_PrintError(progName
, "failure generating key pair\n");
585 /******************************************************************
587 * m a k e _ c e r t _ r e q u e s t
589 static CERTCertificateRequest
*
590 make_cert_request(char *subject
, SECKEYPublicKey
*pubk
)
593 CERTSubjectPublicKeyInfo
* spki
;
595 CERTCertificateRequest
* req
;
597 /* Create info about public key */
598 spki
= SECKEY_CreateSubjectPublicKeyInfo(pubk
);
600 SECU_PrintError(progName
, "unable to create subject public key");
604 subj
= CERT_AsciiToName (subject
);
606 FatalError("Invalid data in certificate description");
609 /* Generate certificate request */
610 req
= CERT_CreateCertificateRequest(subj
, spki
, 0);
612 SECU_PrintError(progName
, "unable to make certificate request");
616 if (verbosity
>= 0) {
617 PR_fprintf(outputFD
, "certificate request generated\n");
624 /******************************************************************
628 static CERTCertificate
*
629 make_cert(CERTCertificateRequest
*req
, unsigned long serial
,
630 CERTName
*ca_subject
)
632 CERTCertificate
* cert
;
634 CERTValidity
* validity
= NULL
;
637 PRExplodedTime printableTime
;
640 PR_ExplodeTime (now
, PR_GMTParameters
, &printableTime
);
642 printableTime
.tm_month
+= 3;
643 after
= PR_ImplodeTime (&printableTime
);
645 validity
= CERT_CreateValidity (now
, after
);
647 if (validity
== NULL
) {
648 PR_fprintf(errorFD
, "%s: error creating certificate validity\n",
654 cert
= CERT_CreateCertificate
655 (serial
, ca_subject
, validity
, req
);
658 /* should probably be more precise here */
659 PR_fprintf(errorFD
, "%s: error while generating certificate\n",
669 /*************************************************************************
671 * o u t p u t _ c a _ c e r t
674 output_ca_cert (CERTCertificate
*cert
, CERTCertDBHandle
*db
)
678 SECItem
* encodedCertChain
;
679 SEC_PKCS7ContentInfo
* certChain
;
684 filename
= PORT_ZAlloc(strlen(DEFAULT_X509_BASENAME
) + 8);
688 sprintf(filename
, "%s.raw", DEFAULT_X509_BASENAME
);
689 if ((out
= fopen (filename
, "wb")) == NULL
) {
690 PR_fprintf(errorFD
, "%s: Can't open %s output file\n", PROGRAM_NAME
,
696 certChain
= SEC_PKCS7CreateCertsOnly (cert
, PR_TRUE
, db
);
698 = SEC_PKCS7EncodeItem (NULL
, NULL
, certChain
, NULL
, NULL
, NULL
);
699 SEC_PKCS7DestroyContentInfo (certChain
);
701 if (encodedCertChain
) {
702 fprintf(out
, "Content-type: application/x-x509-ca-cert\n\n");
703 fwrite (encodedCertChain
->data
, 1, encodedCertChain
->len
,
705 SECITEM_FreeItem(encodedCertChain
, PR_TRUE
);
707 PR_fprintf(errorFD
, "%s: Can't DER encode this certificate\n",
717 sprintf(filename
, "%s.cacert", DEFAULT_X509_BASENAME
);
718 if ((out
= fopen (filename
, "wb")) == NULL
) {
719 PR_fprintf(errorFD
, "%s: Can't open %s output file\n", PROGRAM_NAME
,
725 fprintf (out
, "%s\n%s\n%s\n",
727 BTOA_DataToAscii (cert
->derCert
.data
, cert
->derCert
.len
),
732 if (verbosity
>= 0) {
733 PR_fprintf(outputFD
, "Exported certificate to %s.raw and %s.cacert.\n",
734 DEFAULT_X509_BASENAME
, DEFAULT_X509_BASENAME
);