1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11 static char *GetSubjectFromUser(unsigned long serial
);
12 static CERTCertificate
*GenerateSelfSignedObjectSigningCert(char *nickname
,
13 CERTCertDBHandle
*db
, char *subject
, unsigned long serial
, int keysize
,
15 static SECStatus
ChangeTrustAttributes(CERTCertDBHandle
*db
,
16 CERTCertificate
*cert
, char *trusts
);
17 static SECStatus
set_cert_type(CERTCertificate
*cert
, unsigned int type
);
18 static SECItem
*sign_cert(CERTCertificate
*cert
, SECKEYPrivateKey
*privk
);
19 static CERTCertificate
*install_cert(CERTCertDBHandle
*db
, SECItem
*derCert
,
21 static SECStatus
GenerateKeyPair(PK11SlotInfo
*slot
, SECKEYPublicKey
**pubk
,
22 SECKEYPrivateKey
**privk
, int keysize
);
23 static CERTCertificateRequest
*make_cert_request(char *subject
,
24 SECKEYPublicKey
*pubk
);
25 static CERTCertificate
*make_cert(CERTCertificateRequest
*req
,
26 unsigned long serial
, CERTName
*ca_subject
);
27 static void output_ca_cert (CERTCertificate
*cert
, CERTCertDBHandle
*db
);
30 /***********************************************************************
32 * G e n e r a t e C e r t
34 * Runs the whole process of creating a new cert, getting info from the
38 GenerateCert(char *nickname
, int keysize
, char *token
)
40 CERTCertDBHandle
* db
;
41 CERTCertificate
* cert
;
46 /* Print warning about having the browser open */
47 PR_fprintf(PR_STDOUT
/*always go to console*/,
48 "\nWARNING: Performing this operation while the browser is running could cause"
49 "\ncorruption of your security databases. If the browser is currently running,"
50 "\nyou should exit the browser before continuing this operation. Enter "
51 "\n\"y\" to continue, or anything else to abort: ");
52 pr_fgets(stdinbuf
, 160, PR_STDIN
);
53 PR_fprintf(PR_STDOUT
, "\n");
54 if (tolower(stdinbuf
[0]) != 'y') {
55 PR_fprintf(errorFD
, "Operation aborted at user's request.\n");
60 db
= CERT_GetDefaultCertDB();
62 FatalError("Unable to open certificate database");
65 if (PK11_FindCertFromNickname(nickname
, &pwdata
)) {
67 "ERROR: Certificate with nickname \"%s\" already exists in database. You\n"
68 "must choose a different nickname.\n", nickname
);
73 LL_L2UI(serial
, PR_Now());
75 subject
= GetSubjectFromUser(serial
);
77 cert
= GenerateSelfSignedObjectSigningCert(nickname
, db
, subject
,
78 serial
, keysize
, token
);
81 output_ca_cert(cert
, db
);
82 CERT_DestroyCertificate(cert
);
90 #undef VERBOSE_PROMPTS
92 /*********************************************************************8
93 * G e t S u b j e c t F r o m U s e r
95 * Construct the subject information line for a certificate by querying
99 GetSubjectFromUser(unsigned long serial
)
101 char buf
[STDIN_BUF_SIZE
];
102 char common_name_buf
[STDIN_BUF_SIZE
];
103 char *common_name
, *state
, *orgunit
, *country
, *org
, *locality
;
109 common_name
= state
= orgunit
= country
= org
= locality
= email
=
110 uid
= subject
= NULL
;
112 /* Get subject information */
113 PR_fprintf(PR_STDOUT
,
114 "\nEnter certificate information. All fields are optional. Acceptable\n"
115 "characters are numbers, letters, spaces, and apostrophes.\n");
117 #ifdef VERBOSE_PROMPTS
118 PR_fprintf(PR_STDOUT
, "\nCOMMON NAME\n"
119 "Enter the full name you want to give your certificate. (Example: Test-Only\n"
120 "Object Signing Certificate)\n"
123 PR_fprintf(PR_STDOUT
, "certificate common name: ");
125 fgets(buf
, STDIN_BUF_SIZE
, stdin
);
128 sprintf(common_name_buf
, "%s (%lu)", DEFAULT_COMMON_NAME
,
130 cp
= common_name_buf
;
132 common_name
= PORT_ZAlloc(strlen(cp
) + 6);
136 sprintf(common_name
, "CN=%s, ", cp
);
137 subjectlen
+= strlen(common_name
);
139 #ifdef VERBOSE_PROMPTS
140 PR_fprintf(PR_STDOUT
, "\nORGANIZATION NAME\n"
141 "Enter the name of your organization. For example, this could be the name\n"
145 PR_fprintf(PR_STDOUT
, "organization: ");
147 fgets(buf
, STDIN_BUF_SIZE
, stdin
);
150 org
= PORT_ZAlloc(strlen(cp
) + 5);
154 sprintf(org
, "O=%s, ", cp
);
155 subjectlen
+= strlen(org
);
158 #ifdef VERBOSE_PROMPTS
159 PR_fprintf(PR_STDOUT
, "\nORGANIZATION UNIT\n"
160 "Enter the name of your organization unit. For example, this could be the\n"
161 "name of your department.\n"
164 PR_fprintf(PR_STDOUT
, "organization unit: ");
166 fgets(buf
, STDIN_BUF_SIZE
, stdin
);
169 orgunit
= PORT_ZAlloc(strlen(cp
) + 6);
173 sprintf(orgunit
, "OU=%s, ", cp
);
174 subjectlen
+= strlen(orgunit
);
177 #ifdef VERBOSE_PROMPTS
178 PR_fprintf(PR_STDOUT
, "\nSTATE\n"
179 "Enter the name of your state or province.\n"
182 PR_fprintf(PR_STDOUT
, "state or province: ");
184 fgets(buf
, STDIN_BUF_SIZE
, stdin
);
187 state
= PORT_ZAlloc(strlen(cp
) + 6);
191 sprintf(state
, "ST=%s, ", cp
);
192 subjectlen
+= strlen(state
);
195 #ifdef VERBOSE_PROMPTS
196 PR_fprintf(PR_STDOUT
, "\nCOUNTRY\n"
197 "Enter the 2-character abbreviation for the name of your country.\n"
200 PR_fprintf(PR_STDOUT
, "country (must be exactly 2 characters): ");
202 fgets(buf
, STDIN_BUF_SIZE
, stdin
);
204 if (strlen(cp
) != 2) {
205 *cp
= '\0'; /* country code must be 2 chars */
208 country
= PORT_ZAlloc(strlen(cp
) + 5);
212 sprintf(country
, "C=%s, ", cp
);
213 subjectlen
+= strlen(country
);
216 #ifdef VERBOSE_PROMPTS
217 PR_fprintf(PR_STDOUT
, "\nUSERNAME\n"
218 "Enter your system username or UID\n"
221 PR_fprintf(PR_STDOUT
, "username: ");
223 fgets(buf
, STDIN_BUF_SIZE
, stdin
);
226 uid
= PORT_ZAlloc(strlen(cp
) + 7);
230 sprintf(uid
, "UID=%s, ", cp
);
231 subjectlen
+= strlen(uid
);
234 #ifdef VERBOSE_PROMPTS
235 PR_fprintf(PR_STDOUT
, "\nEMAIL ADDRESS\n"
236 "Enter your email address.\n"
239 PR_fprintf(PR_STDOUT
, "email address: ");
241 fgets(buf
, STDIN_BUF_SIZE
, stdin
);
244 email
= PORT_ZAlloc(strlen(cp
) + 5);
248 sprintf(email
, "E=%s,", cp
);
249 subjectlen
+= strlen(email
);
254 subject
= PORT_ZAlloc(subjectlen
);
259 sprintf(subject
, "%s%s%s%s%s%s%s",
260 common_name
? common_name
: "",
262 orgunit
? orgunit
: "",
264 country
? country
: "",
268 if ( (strlen(subject
) > 1) && (subject
[strlen(subject
)-1] == ' ') ) {
269 subject
[strlen(subject
)-2] = '\0';
272 PORT_Free(common_name
);
284 /**************************************************************************
286 * 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
290 static CERTCertificate
*
291 GenerateSelfSignedObjectSigningCert(char *nickname
, CERTCertDBHandle
*db
,
292 char *subject
, unsigned long serial
, int keysize
, char *token
)
294 CERTCertificate
* cert
, *temp_cert
;
296 CERTCertificateRequest
* req
;
298 PK11SlotInfo
* slot
= NULL
;
299 SECKEYPrivateKey
* privk
= NULL
;
300 SECKEYPublicKey
* pubk
= NULL
;
303 slot
= PK11_FindSlotByName(token
);
305 slot
= PK11_GetInternalKeySlot();
309 PR_fprintf(errorFD
, "Can't find PKCS11 slot %s\n",
315 if ( GenerateKeyPair(slot
, &pubk
, &privk
, keysize
) != SECSuccess
) {
316 FatalError("Error generating keypair.");
318 req
= make_cert_request (subject
, pubk
);
319 temp_cert
= make_cert (req
, serial
, &req
->subject
);
320 if (set_cert_type(temp_cert
,
321 NS_CERT_TYPE_OBJECT_SIGNING
| NS_CERT_TYPE_OBJECT_SIGNING_CA
)
323 FatalError("Unable to set cert type");
326 derCert
= sign_cert (temp_cert
, privk
);
327 cert
= install_cert(db
, derCert
, nickname
);
328 if (ChangeTrustAttributes(db
, cert
, ",,uC") != SECSuccess
) {
329 FatalError("Unable to change trust on generated certificate");
332 /* !!! Free memory ? !!! */
334 SECKEY_DestroyPrivateKey(privk
);
335 SECKEY_DestroyPublicKey(pubk
);
341 /**************************************************************************
343 * C h a n g e T r u s t A t t r i b u t e s
346 ChangeTrustAttributes(CERTCertDBHandle
*db
, CERTCertificate
*cert
, char *trusts
)
349 CERTCertTrust
* trust
;
351 if (!db
|| !cert
|| !trusts
) {
352 PR_fprintf(errorFD
, "ChangeTrustAttributes got incomplete arguments.\n");
357 trust
= (CERTCertTrust
* ) PORT_ZAlloc(sizeof(CERTCertTrust
));
359 PR_fprintf(errorFD
, "ChangeTrustAttributes unable to allocate "
365 if ( CERT_DecodeTrustString(trust
, trusts
) ) {
369 if ( CERT_ChangeCertTrust(db
, cert
, trust
) ) {
370 PR_fprintf(errorFD
, "unable to modify trust attributes for cert %s\n",
371 cert
->nickname
? cert
->nickname
: "");
380 /*************************************************************************
382 * s e t _ c e r t _ t y p e
385 set_cert_type(CERTCertificate
*cert
, unsigned int type
)
388 SECStatus status
= SECSuccess
;
392 context
= CERT_StartCertExtensions(cert
);
394 certType
.type
= siBuffer
;
395 certType
.data
= (unsigned char * ) &ctype
;
397 ctype
= (unsigned char)type
;
398 if (CERT_EncodeAndAddBitStrExtension(context
, SEC_OID_NS_CERT_EXT_CERT_TYPE
,
399 &certType
, PR_TRUE
/*critical*/) != SECSuccess
) {
403 if (CERT_FinishExtensions(context
) != SECSuccess
) {
411 /********************************************************************
416 sign_cert(CERTCertificate
*cert
, SECKEYPrivateKey
*privk
)
424 SECOidTag alg
= SEC_OID_UNKNOWN
;
426 alg
= SEC_GetSignatureAlgorithmOidTag(privk
->keyType
, SEC_OID_UNKNOWN
);
427 if (alg
== SEC_OID_UNKNOWN
) {
428 FatalError("Unknown key type");
431 rv
= SECOID_SetAlgorithmID (cert
->arena
, &cert
->signature
, alg
, 0);
433 if (rv
!= SECSuccess
) {
434 PR_fprintf(errorFD
, "%s: unable to set signature alg id\n",
443 dummy
= SEC_ASN1EncodeItem
444 (cert
->arena
, &der2
, cert
, SEC_ASN1_GET(CERT_CertificateTemplate
));
446 if (rv
!= SECSuccess
) {
447 PR_fprintf(errorFD
, "%s: error encoding cert\n", PROGRAM_NAME
);
452 result2
= (SECItem
* ) PORT_ArenaZAlloc (cert
->arena
, sizeof (SECItem
));
457 (cert
->arena
, result2
, der2
.data
, der2
.len
, privk
, alg
);
459 if (rv
!= SECSuccess
) {
460 PR_fprintf(errorFD
, "can't sign encoded certificate data\n");
463 } else if (verbosity
>= 0) {
464 PR_fprintf(outputFD
, "certificate has been signed\n");
467 cert
->derCert
= *result2
;
473 /*********************************************************************
475 * i n s t a l l _ c e r t
477 * Installs the cert in the permanent database.
479 static CERTCertificate
*
480 install_cert(CERTCertDBHandle
*db
, SECItem
*derCert
, char *nickname
)
482 CERTCertificate
* newcert
;
483 PK11SlotInfo
* newSlot
;
486 newSlot
= PK11_ImportDERCertForKey(derCert
, nickname
, &pwdata
);
487 if ( newSlot
== NULL
) {
488 PR_fprintf(errorFD
, "Unable to install certificate\n");
493 newcert
= PK11_FindCertFromDERCertItem(newSlot
, derCert
, &pwdata
);
494 PK11_FreeSlot(newSlot
);
495 if (newcert
== NULL
) {
496 PR_fprintf(errorFD
, "%s: can't find new certificate\n",
502 if (verbosity
>= 0) {
503 PR_fprintf(outputFD
, "certificate \"%s\" added to database\n",
511 /******************************************************************
513 * G e n e r a t e K e y P a i r
516 GenerateKeyPair(PK11SlotInfo
*slot
, SECKEYPublicKey
**pubk
,
517 SECKEYPrivateKey
**privk
, int keysize
)
520 PK11RSAGenParams rsaParams
;
522 if ( keysize
== -1 ) {
523 rsaParams
.keySizeInBits
= DEFAULT_RSA_KEY_SIZE
;
525 rsaParams
.keySizeInBits
= keysize
;
527 rsaParams
.pe
= 0x10001;
529 if (PK11_Authenticate( slot
, PR_FALSE
/*loadCerts*/, &pwdata
)
531 SECU_PrintError(progName
, "failure authenticating to key database.\n");
535 *privk
= PK11_GenerateKeyPair (slot
, CKM_RSA_PKCS_KEY_PAIR_GEN
, &rsaParams
,
537 pubk
, PR_TRUE
/*isPerm*/, PR_TRUE
/*isSensitive*/, &pwdata
);
539 if (*privk
!= NULL
&& *pubk
!= NULL
) {
540 if (verbosity
>= 0) {
541 PR_fprintf(outputFD
, "generated public/private key pair\n");
544 SECU_PrintError(progName
, "failure generating key pair\n");
553 /******************************************************************
555 * m a k e _ c e r t _ r e q u e s t
557 static CERTCertificateRequest
*
558 make_cert_request(char *subject
, SECKEYPublicKey
*pubk
)
561 CERTSubjectPublicKeyInfo
* spki
;
563 CERTCertificateRequest
* req
;
565 /* Create info about public key */
566 spki
= SECKEY_CreateSubjectPublicKeyInfo(pubk
);
568 SECU_PrintError(progName
, "unable to create subject public key");
572 subj
= CERT_AsciiToName (subject
);
574 FatalError("Invalid data in certificate description");
577 /* Generate certificate request */
578 req
= CERT_CreateCertificateRequest(subj
, spki
, 0);
580 SECU_PrintError(progName
, "unable to make certificate request");
584 SECKEY_DestroySubjectPublicKeyInfo(spki
);
585 CERT_DestroyName(subj
);
587 if (verbosity
>= 0) {
588 PR_fprintf(outputFD
, "certificate request generated\n");
595 /******************************************************************
599 static CERTCertificate
*
600 make_cert(CERTCertificateRequest
*req
, unsigned long serial
,
601 CERTName
*ca_subject
)
603 CERTCertificate
* cert
;
605 CERTValidity
* validity
= NULL
;
608 PRExplodedTime printableTime
;
611 PR_ExplodeTime (now
, PR_GMTParameters
, &printableTime
);
613 printableTime
.tm_month
+= 3;
614 after
= PR_ImplodeTime (&printableTime
);
616 validity
= CERT_CreateValidity (now
, after
);
618 if (validity
== NULL
) {
619 PR_fprintf(errorFD
, "%s: error creating certificate validity\n",
625 cert
= CERT_CreateCertificate
626 (serial
, ca_subject
, validity
, req
);
629 /* should probably be more precise here */
630 PR_fprintf(errorFD
, "%s: error while generating certificate\n",
640 /*************************************************************************
642 * o u t p u t _ c a _ c e r t
645 output_ca_cert (CERTCertificate
*cert
, CERTCertDBHandle
*db
)
649 SECItem
* encodedCertChain
;
650 SEC_PKCS7ContentInfo
* certChain
;
655 filename
= PORT_ZAlloc(strlen(DEFAULT_X509_BASENAME
) + 8);
659 sprintf(filename
, "%s.raw", DEFAULT_X509_BASENAME
);
660 if ((out
= fopen (filename
, "wb")) == NULL
) {
661 PR_fprintf(errorFD
, "%s: Can't open %s output file\n", PROGRAM_NAME
,
667 certChain
= SEC_PKCS7CreateCertsOnly (cert
, PR_TRUE
, db
);
669 = SEC_PKCS7EncodeItem (NULL
, NULL
, certChain
, NULL
, NULL
, NULL
);
670 SEC_PKCS7DestroyContentInfo (certChain
);
672 if (encodedCertChain
) {
673 fprintf(out
, "Content-type: application/x-x509-ca-cert\n\n");
674 fwrite (encodedCertChain
->data
, 1, encodedCertChain
->len
,
676 SECITEM_FreeItem(encodedCertChain
, PR_TRUE
);
678 PR_fprintf(errorFD
, "%s: Can't DER encode this certificate\n",
688 sprintf(filename
, "%s.cacert", 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 fprintf (out
, "%s\n%s\n%s\n",
698 BTOA_DataToAscii (cert
->derCert
.data
, cert
->derCert
.len
),
703 if (verbosity
>= 0) {
704 PR_fprintf(outputFD
, "Exported certificate to %s.raw and %s.cacert.\n",
705 DEFAULT_X509_BASENAME
, DEFAULT_X509_BASENAME
);