|
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/. */ |
|
4 |
|
5 #include "signtool.h" |
|
6 |
|
7 #include "secoid.h" |
|
8 #include "cryptohi.h" |
|
9 #include "certdb.h" |
|
10 |
|
11 static char *GetSubjectFromUser(unsigned long serial); |
|
12 static CERTCertificate*GenerateSelfSignedObjectSigningCert(char *nickname, |
|
13 CERTCertDBHandle *db, char *subject, unsigned long serial, int keysize, |
|
14 char *token); |
|
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, |
|
20 char *nickname); |
|
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); |
|
28 |
|
29 |
|
30 /*********************************************************************** |
|
31 * |
|
32 * G e n e r a t e C e r t |
|
33 * |
|
34 * Runs the whole process of creating a new cert, getting info from the |
|
35 * user, etc. |
|
36 */ |
|
37 int |
|
38 GenerateCert(char *nickname, int keysize, char *token) |
|
39 { |
|
40 CERTCertDBHandle * db; |
|
41 CERTCertificate * cert; |
|
42 char *subject; |
|
43 unsigned long serial; |
|
44 char stdinbuf[160]; |
|
45 |
|
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"); |
|
56 errorCount++; |
|
57 return - 1; |
|
58 } |
|
59 |
|
60 db = CERT_GetDefaultCertDB(); |
|
61 if (!db) { |
|
62 FatalError("Unable to open certificate database"); |
|
63 } |
|
64 |
|
65 if (PK11_FindCertFromNickname(nickname, &pwdata)) { |
|
66 PR_fprintf(errorFD, |
|
67 "ERROR: Certificate with nickname \"%s\" already exists in database. You\n" |
|
68 "must choose a different nickname.\n", nickname); |
|
69 errorCount++; |
|
70 exit(ERRX); |
|
71 } |
|
72 |
|
73 LL_L2UI(serial, PR_Now()); |
|
74 |
|
75 subject = GetSubjectFromUser(serial); |
|
76 |
|
77 cert = GenerateSelfSignedObjectSigningCert(nickname, db, subject, |
|
78 serial, keysize, token); |
|
79 |
|
80 if (cert) { |
|
81 output_ca_cert(cert, db); |
|
82 CERT_DestroyCertificate(cert); |
|
83 } |
|
84 |
|
85 PORT_Free(subject); |
|
86 return 0; |
|
87 } |
|
88 |
|
89 |
|
90 #undef VERBOSE_PROMPTS |
|
91 |
|
92 /*********************************************************************8 |
|
93 * G e t S u b j e c t F r o m U s e r |
|
94 * |
|
95 * Construct the subject information line for a certificate by querying |
|
96 * the user on stdin. |
|
97 */ |
|
98 static char * |
|
99 GetSubjectFromUser(unsigned long serial) |
|
100 { |
|
101 char buf[STDIN_BUF_SIZE]; |
|
102 char common_name_buf[STDIN_BUF_SIZE]; |
|
103 char *common_name, *state, *orgunit, *country, *org, *locality; |
|
104 char *email, *uid; |
|
105 char *subject; |
|
106 char *cp; |
|
107 int subjectlen = 0; |
|
108 |
|
109 common_name = state = orgunit = country = org = locality = email = |
|
110 uid = subject = NULL; |
|
111 |
|
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"); |
|
116 |
|
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" |
|
121 "-->"); |
|
122 #else |
|
123 PR_fprintf(PR_STDOUT, "certificate common name: "); |
|
124 #endif |
|
125 fgets(buf, STDIN_BUF_SIZE, stdin); |
|
126 cp = chop(buf); |
|
127 if (*cp == '\0') { |
|
128 sprintf(common_name_buf, "%s (%lu)", DEFAULT_COMMON_NAME, |
|
129 serial); |
|
130 cp = common_name_buf; |
|
131 } |
|
132 common_name = PORT_ZAlloc(strlen(cp) + 6); |
|
133 if (!common_name) { |
|
134 out_of_memory(); |
|
135 } |
|
136 sprintf(common_name, "CN=%s, ", cp); |
|
137 subjectlen += strlen(common_name); |
|
138 |
|
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" |
|
142 "of your company.\n" |
|
143 "-->"); |
|
144 #else |
|
145 PR_fprintf(PR_STDOUT, "organization: "); |
|
146 #endif |
|
147 fgets(buf, STDIN_BUF_SIZE, stdin); |
|
148 cp = chop(buf); |
|
149 if (*cp != '\0') { |
|
150 org = PORT_ZAlloc(strlen(cp) + 5); |
|
151 if (!org) { |
|
152 out_of_memory(); |
|
153 } |
|
154 sprintf(org, "O=%s, ", cp); |
|
155 subjectlen += strlen(org); |
|
156 } |
|
157 |
|
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" |
|
162 "-->"); |
|
163 #else |
|
164 PR_fprintf(PR_STDOUT, "organization unit: "); |
|
165 #endif |
|
166 fgets(buf, STDIN_BUF_SIZE, stdin); |
|
167 cp = chop(buf); |
|
168 if (*cp != '\0') { |
|
169 orgunit = PORT_ZAlloc(strlen(cp) + 6); |
|
170 if (!orgunit) { |
|
171 out_of_memory(); |
|
172 } |
|
173 sprintf(orgunit, "OU=%s, ", cp); |
|
174 subjectlen += strlen(orgunit); |
|
175 } |
|
176 |
|
177 #ifdef VERBOSE_PROMPTS |
|
178 PR_fprintf(PR_STDOUT, "\nSTATE\n" |
|
179 "Enter the name of your state or province.\n" |
|
180 "-->"); |
|
181 #else |
|
182 PR_fprintf(PR_STDOUT, "state or province: "); |
|
183 #endif |
|
184 fgets(buf, STDIN_BUF_SIZE, stdin); |
|
185 cp = chop(buf); |
|
186 if (*cp != '\0') { |
|
187 state = PORT_ZAlloc(strlen(cp) + 6); |
|
188 if (!state) { |
|
189 out_of_memory(); |
|
190 } |
|
191 sprintf(state, "ST=%s, ", cp); |
|
192 subjectlen += strlen(state); |
|
193 } |
|
194 |
|
195 #ifdef VERBOSE_PROMPTS |
|
196 PR_fprintf(PR_STDOUT, "\nCOUNTRY\n" |
|
197 "Enter the 2-character abbreviation for the name of your country.\n" |
|
198 "-->"); |
|
199 #else |
|
200 PR_fprintf(PR_STDOUT, "country (must be exactly 2 characters): "); |
|
201 #endif |
|
202 fgets(buf, STDIN_BUF_SIZE, stdin); |
|
203 cp = chop(cp); |
|
204 if (strlen(cp) != 2) { |
|
205 *cp = '\0'; /* country code must be 2 chars */ |
|
206 } |
|
207 if (*cp != '\0') { |
|
208 country = PORT_ZAlloc(strlen(cp) + 5); |
|
209 if (!country) { |
|
210 out_of_memory(); |
|
211 } |
|
212 sprintf(country, "C=%s, ", cp); |
|
213 subjectlen += strlen(country); |
|
214 } |
|
215 |
|
216 #ifdef VERBOSE_PROMPTS |
|
217 PR_fprintf(PR_STDOUT, "\nUSERNAME\n" |
|
218 "Enter your system username or UID\n" |
|
219 "-->"); |
|
220 #else |
|
221 PR_fprintf(PR_STDOUT, "username: "); |
|
222 #endif |
|
223 fgets(buf, STDIN_BUF_SIZE, stdin); |
|
224 cp = chop(buf); |
|
225 if (*cp != '\0') { |
|
226 uid = PORT_ZAlloc(strlen(cp) + 7); |
|
227 if (!uid) { |
|
228 out_of_memory(); |
|
229 } |
|
230 sprintf(uid, "UID=%s, ", cp); |
|
231 subjectlen += strlen(uid); |
|
232 } |
|
233 |
|
234 #ifdef VERBOSE_PROMPTS |
|
235 PR_fprintf(PR_STDOUT, "\nEMAIL ADDRESS\n" |
|
236 "Enter your email address.\n" |
|
237 "-->"); |
|
238 #else |
|
239 PR_fprintf(PR_STDOUT, "email address: "); |
|
240 #endif |
|
241 fgets(buf, STDIN_BUF_SIZE, stdin); |
|
242 cp = chop(buf); |
|
243 if (*cp != '\0') { |
|
244 email = PORT_ZAlloc(strlen(cp) + 5); |
|
245 if (!email) { |
|
246 out_of_memory(); |
|
247 } |
|
248 sprintf(email, "E=%s,", cp); |
|
249 subjectlen += strlen(email); |
|
250 } |
|
251 |
|
252 subjectlen++; |
|
253 |
|
254 subject = PORT_ZAlloc(subjectlen); |
|
255 if (!subject) { |
|
256 out_of_memory(); |
|
257 } |
|
258 |
|
259 sprintf(subject, "%s%s%s%s%s%s%s", |
|
260 common_name ? common_name : "", |
|
261 org ? org : "", |
|
262 orgunit ? orgunit : "", |
|
263 state ? state : "", |
|
264 country ? country : "", |
|
265 uid ? uid : "", |
|
266 email ? email : "" |
|
267 ); |
|
268 if ( (strlen(subject) > 1) && (subject[strlen(subject)-1] == ' ') ) { |
|
269 subject[strlen(subject)-2] = '\0'; |
|
270 } |
|
271 |
|
272 PORT_Free(common_name); |
|
273 PORT_Free(org); |
|
274 PORT_Free(orgunit); |
|
275 PORT_Free(state); |
|
276 PORT_Free(country); |
|
277 PORT_Free(uid); |
|
278 PORT_Free(email); |
|
279 |
|
280 return subject; |
|
281 } |
|
282 |
|
283 |
|
284 /************************************************************************** |
|
285 * |
|
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 |
|
287 * *phew*^ |
|
288 * |
|
289 */ |
|
290 static CERTCertificate* |
|
291 GenerateSelfSignedObjectSigningCert(char *nickname, CERTCertDBHandle *db, |
|
292 char *subject, unsigned long serial, int keysize, char *token) |
|
293 { |
|
294 CERTCertificate * cert, *temp_cert; |
|
295 SECItem * derCert; |
|
296 CERTCertificateRequest * req; |
|
297 |
|
298 PK11SlotInfo * slot = NULL; |
|
299 SECKEYPrivateKey * privk = NULL; |
|
300 SECKEYPublicKey * pubk = NULL; |
|
301 |
|
302 if ( token ) { |
|
303 slot = PK11_FindSlotByName(token); |
|
304 } else { |
|
305 slot = PK11_GetInternalKeySlot(); |
|
306 } |
|
307 |
|
308 if (slot == NULL) { |
|
309 PR_fprintf(errorFD, "Can't find PKCS11 slot %s\n", |
|
310 token ? token : ""); |
|
311 errorCount++; |
|
312 exit (ERRX); |
|
313 } |
|
314 |
|
315 if ( GenerateKeyPair(slot, &pubk, &privk, keysize) != SECSuccess) { |
|
316 FatalError("Error generating keypair."); |
|
317 } |
|
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) |
|
322 != SECSuccess) { |
|
323 FatalError("Unable to set cert type"); |
|
324 } |
|
325 |
|
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"); |
|
330 } |
|
331 |
|
332 /* !!! Free memory ? !!! */ |
|
333 PK11_FreeSlot(slot); |
|
334 SECKEY_DestroyPrivateKey(privk); |
|
335 SECKEY_DestroyPublicKey(pubk); |
|
336 |
|
337 return cert; |
|
338 } |
|
339 |
|
340 |
|
341 /************************************************************************** |
|
342 * |
|
343 * C h a n g e T r u s t A t t r i b u t e s |
|
344 */ |
|
345 static SECStatus |
|
346 ChangeTrustAttributes(CERTCertDBHandle *db, CERTCertificate *cert, char *trusts) |
|
347 { |
|
348 |
|
349 CERTCertTrust * trust; |
|
350 |
|
351 if (!db || !cert || !trusts) { |
|
352 PR_fprintf(errorFD, "ChangeTrustAttributes got incomplete arguments.\n"); |
|
353 errorCount++; |
|
354 return SECFailure; |
|
355 } |
|
356 |
|
357 trust = (CERTCertTrust * ) PORT_ZAlloc(sizeof(CERTCertTrust)); |
|
358 if (!trust) { |
|
359 PR_fprintf(errorFD, "ChangeTrustAttributes unable to allocate " |
|
360 "CERTCertTrust\n"); |
|
361 errorCount++; |
|
362 return SECFailure; |
|
363 } |
|
364 |
|
365 if ( CERT_DecodeTrustString(trust, trusts) ) { |
|
366 return SECFailure; |
|
367 } |
|
368 |
|
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 : ""); |
|
372 errorCount++; |
|
373 return SECFailure; |
|
374 } |
|
375 |
|
376 return SECSuccess; |
|
377 } |
|
378 |
|
379 |
|
380 /************************************************************************* |
|
381 * |
|
382 * s e t _ c e r t _ t y p e |
|
383 */ |
|
384 static SECStatus |
|
385 set_cert_type(CERTCertificate *cert, unsigned int type) |
|
386 { |
|
387 void *context; |
|
388 SECStatus status = SECSuccess; |
|
389 SECItem certType; |
|
390 char ctype; |
|
391 |
|
392 context = CERT_StartCertExtensions(cert); |
|
393 |
|
394 certType.type = siBuffer; |
|
395 certType.data = (unsigned char * ) &ctype; |
|
396 certType.len = 1; |
|
397 ctype = (unsigned char)type; |
|
398 if (CERT_EncodeAndAddBitStrExtension(context, SEC_OID_NS_CERT_EXT_CERT_TYPE, |
|
399 &certType, PR_TRUE /*critical*/) != SECSuccess) { |
|
400 status = SECFailure; |
|
401 } |
|
402 |
|
403 if (CERT_FinishExtensions(context) != SECSuccess) { |
|
404 status = SECFailure; |
|
405 } |
|
406 |
|
407 return status; |
|
408 } |
|
409 |
|
410 |
|
411 /******************************************************************** |
|
412 * |
|
413 * s i g n _ c e r t |
|
414 */ |
|
415 static SECItem * |
|
416 sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk) |
|
417 { |
|
418 SECStatus rv; |
|
419 |
|
420 SECItem der2; |
|
421 SECItem * result2; |
|
422 |
|
423 void *dummy; |
|
424 SECOidTag alg = SEC_OID_UNKNOWN; |
|
425 |
|
426 alg = SEC_GetSignatureAlgorithmOidTag(privk->keyType, SEC_OID_UNKNOWN); |
|
427 if (alg == SEC_OID_UNKNOWN) { |
|
428 FatalError("Unknown key type"); |
|
429 } |
|
430 |
|
431 rv = SECOID_SetAlgorithmID (cert->arena, &cert->signature, alg, 0); |
|
432 |
|
433 if (rv != SECSuccess) { |
|
434 PR_fprintf(errorFD, "%s: unable to set signature alg id\n", |
|
435 PROGRAM_NAME); |
|
436 errorCount++; |
|
437 exit (ERRX); |
|
438 } |
|
439 |
|
440 der2.len = 0; |
|
441 der2.data = NULL; |
|
442 |
|
443 dummy = SEC_ASN1EncodeItem |
|
444 (cert->arena, &der2, cert, SEC_ASN1_GET(CERT_CertificateTemplate)); |
|
445 |
|
446 if (rv != SECSuccess) { |
|
447 PR_fprintf(errorFD, "%s: error encoding cert\n", PROGRAM_NAME); |
|
448 errorCount++; |
|
449 exit (ERRX); |
|
450 } |
|
451 |
|
452 result2 = (SECItem * ) PORT_ArenaZAlloc (cert->arena, sizeof (SECItem)); |
|
453 if (result2 == NULL) |
|
454 out_of_memory(); |
|
455 |
|
456 rv = SEC_DerSignData |
|
457 (cert->arena, result2, der2.data, der2.len, privk, alg); |
|
458 |
|
459 if (rv != SECSuccess) { |
|
460 PR_fprintf(errorFD, "can't sign encoded certificate data\n"); |
|
461 errorCount++; |
|
462 exit (ERRX); |
|
463 } else if (verbosity >= 0) { |
|
464 PR_fprintf(outputFD, "certificate has been signed\n"); |
|
465 } |
|
466 |
|
467 cert->derCert = *result2; |
|
468 |
|
469 return result2; |
|
470 } |
|
471 |
|
472 |
|
473 /********************************************************************* |
|
474 * |
|
475 * i n s t a l l _ c e r t |
|
476 * |
|
477 * Installs the cert in the permanent database. |
|
478 */ |
|
479 static CERTCertificate* |
|
480 install_cert(CERTCertDBHandle *db, SECItem *derCert, char *nickname) |
|
481 { |
|
482 CERTCertificate * newcert; |
|
483 PK11SlotInfo * newSlot; |
|
484 |
|
485 |
|
486 newSlot = PK11_ImportDERCertForKey(derCert, nickname, &pwdata); |
|
487 if ( newSlot == NULL ) { |
|
488 PR_fprintf(errorFD, "Unable to install certificate\n"); |
|
489 errorCount++; |
|
490 exit(ERRX); |
|
491 } |
|
492 |
|
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", |
|
497 PROGRAM_NAME); |
|
498 errorCount++; |
|
499 exit (ERRX); |
|
500 } |
|
501 |
|
502 if (verbosity >= 0) { |
|
503 PR_fprintf(outputFD, "certificate \"%s\" added to database\n", |
|
504 nickname); |
|
505 } |
|
506 |
|
507 return newcert; |
|
508 } |
|
509 |
|
510 |
|
511 /****************************************************************** |
|
512 * |
|
513 * G e n e r a t e K e y P a i r |
|
514 */ |
|
515 static SECStatus |
|
516 GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk, |
|
517 SECKEYPrivateKey **privk, int keysize) |
|
518 { |
|
519 |
|
520 PK11RSAGenParams rsaParams; |
|
521 |
|
522 if ( keysize == -1 ) { |
|
523 rsaParams.keySizeInBits = DEFAULT_RSA_KEY_SIZE; |
|
524 } else { |
|
525 rsaParams.keySizeInBits = keysize; |
|
526 } |
|
527 rsaParams.pe = 0x10001; |
|
528 |
|
529 if (PK11_Authenticate( slot, PR_FALSE /*loadCerts*/, &pwdata) |
|
530 != SECSuccess) { |
|
531 SECU_PrintError(progName, "failure authenticating to key database.\n"); |
|
532 exit(ERRX); |
|
533 } |
|
534 |
|
535 *privk = PK11_GenerateKeyPair (slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, |
|
536 |
|
537 pubk, PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, &pwdata); |
|
538 |
|
539 if (*privk != NULL && *pubk != NULL) { |
|
540 if (verbosity >= 0) { |
|
541 PR_fprintf(outputFD, "generated public/private key pair\n"); |
|
542 } |
|
543 } else { |
|
544 SECU_PrintError(progName, "failure generating key pair\n"); |
|
545 exit (ERRX); |
|
546 } |
|
547 |
|
548 return SECSuccess; |
|
549 } |
|
550 |
|
551 |
|
552 |
|
553 /****************************************************************** |
|
554 * |
|
555 * m a k e _ c e r t _ r e q u e s t |
|
556 */ |
|
557 static CERTCertificateRequest* |
|
558 make_cert_request(char *subject, SECKEYPublicKey *pubk) |
|
559 { |
|
560 CERTName * subj; |
|
561 CERTSubjectPublicKeyInfo * spki; |
|
562 |
|
563 CERTCertificateRequest * req; |
|
564 |
|
565 /* Create info about public key */ |
|
566 spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); |
|
567 if (!spki) { |
|
568 SECU_PrintError(progName, "unable to create subject public key"); |
|
569 exit (ERRX); |
|
570 } |
|
571 |
|
572 subj = CERT_AsciiToName (subject); |
|
573 if (subj == NULL) { |
|
574 FatalError("Invalid data in certificate description"); |
|
575 } |
|
576 |
|
577 /* Generate certificate request */ |
|
578 req = CERT_CreateCertificateRequest(subj, spki, 0); |
|
579 if (!req) { |
|
580 SECU_PrintError(progName, "unable to make certificate request"); |
|
581 exit (ERRX); |
|
582 } |
|
583 |
|
584 SECKEY_DestroySubjectPublicKeyInfo(spki); |
|
585 CERT_DestroyName(subj); |
|
586 |
|
587 if (verbosity >= 0) { |
|
588 PR_fprintf(outputFD, "certificate request generated\n"); |
|
589 } |
|
590 |
|
591 return req; |
|
592 } |
|
593 |
|
594 |
|
595 /****************************************************************** |
|
596 * |
|
597 * m a k e _ c e r t |
|
598 */ |
|
599 static CERTCertificate * |
|
600 make_cert(CERTCertificateRequest *req, unsigned long serial, |
|
601 CERTName *ca_subject) |
|
602 { |
|
603 CERTCertificate * cert; |
|
604 |
|
605 CERTValidity * validity = NULL; |
|
606 |
|
607 PRTime now, after; |
|
608 PRExplodedTime printableTime; |
|
609 |
|
610 now = PR_Now(); |
|
611 PR_ExplodeTime (now, PR_GMTParameters, &printableTime); |
|
612 |
|
613 printableTime.tm_month += 3; |
|
614 after = PR_ImplodeTime (&printableTime); |
|
615 |
|
616 validity = CERT_CreateValidity (now, after); |
|
617 |
|
618 if (validity == NULL) { |
|
619 PR_fprintf(errorFD, "%s: error creating certificate validity\n", |
|
620 PROGRAM_NAME); |
|
621 errorCount++; |
|
622 exit (ERRX); |
|
623 } |
|
624 |
|
625 cert = CERT_CreateCertificate |
|
626 (serial, ca_subject, validity, req); |
|
627 |
|
628 if (cert == NULL) { |
|
629 /* should probably be more precise here */ |
|
630 PR_fprintf(errorFD, "%s: error while generating certificate\n", |
|
631 PROGRAM_NAME); |
|
632 errorCount++; |
|
633 exit (ERRX); |
|
634 } |
|
635 |
|
636 return cert; |
|
637 } |
|
638 |
|
639 |
|
640 /************************************************************************* |
|
641 * |
|
642 * o u t p u t _ c a _ c e r t |
|
643 */ |
|
644 static void |
|
645 output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db) |
|
646 { |
|
647 FILE * out; |
|
648 |
|
649 SECItem * encodedCertChain; |
|
650 SEC_PKCS7ContentInfo * certChain; |
|
651 char *filename; |
|
652 |
|
653 /* the raw */ |
|
654 |
|
655 filename = PORT_ZAlloc(strlen(DEFAULT_X509_BASENAME) + 8); |
|
656 if (!filename) |
|
657 out_of_memory(); |
|
658 |
|
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, |
|
662 filename); |
|
663 errorCount++; |
|
664 exit(ERRX); |
|
665 } |
|
666 |
|
667 certChain = SEC_PKCS7CreateCertsOnly (cert, PR_TRUE, db); |
|
668 encodedCertChain |
|
669 = SEC_PKCS7EncodeItem (NULL, NULL, certChain, NULL, NULL, NULL); |
|
670 SEC_PKCS7DestroyContentInfo (certChain); |
|
671 |
|
672 if (encodedCertChain) { |
|
673 fprintf(out, "Content-type: application/x-x509-ca-cert\n\n"); |
|
674 fwrite (encodedCertChain->data, 1, encodedCertChain->len, |
|
675 out); |
|
676 SECITEM_FreeItem(encodedCertChain, PR_TRUE); |
|
677 } else { |
|
678 PR_fprintf(errorFD, "%s: Can't DER encode this certificate\n", |
|
679 PROGRAM_NAME); |
|
680 errorCount++; |
|
681 exit(ERRX); |
|
682 } |
|
683 |
|
684 fclose (out); |
|
685 |
|
686 /* and the cooked */ |
|
687 |
|
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, |
|
691 filename); |
|
692 errorCount++; |
|
693 return; |
|
694 } |
|
695 |
|
696 fprintf (out, "%s\n%s\n%s\n", |
|
697 NS_CERT_HEADER, |
|
698 BTOA_DataToAscii (cert->derCert.data, cert->derCert.len), |
|
699 NS_CERT_TRAILER); |
|
700 |
|
701 fclose (out); |
|
702 |
|
703 if (verbosity >= 0) { |
|
704 PR_fprintf(outputFD, "Exported certificate to %s.raw and %s.cacert.\n", |
|
705 DEFAULT_X509_BASENAME, DEFAULT_X509_BASENAME); |
|
706 } |
|
707 } |
|
708 |
|
709 |