diff options
Diffstat (limited to 'src/usr.bin/openssl/x509.c')
-rw-r--r-- | src/usr.bin/openssl/x509.c | 1713 |
1 files changed, 0 insertions, 1713 deletions
diff --git a/src/usr.bin/openssl/x509.c b/src/usr.bin/openssl/x509.c deleted file mode 100644 index e430d16f1f..0000000000 --- a/src/usr.bin/openssl/x509.c +++ /dev/null | |||
@@ -1,1713 +0,0 @@ | |||
1 | /* $OpenBSD: x509.c,v 1.42 2025/01/19 13:14:22 tb Exp $ */ | ||
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This package is an SSL implementation written | ||
6 | * by Eric Young (eay@cryptsoft.com). | ||
7 | * The implementation was written so as to conform with Netscapes SSL. | ||
8 | * | ||
9 | * This library is free for commercial and non-commercial use as long as | ||
10 | * the following conditions are aheared to. The following conditions | ||
11 | * apply to all code found in this distribution, be it the RC4, RSA, | ||
12 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation | ||
13 | * included with this distribution is covered by the same copyright terms | ||
14 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). | ||
15 | * | ||
16 | * Copyright remains Eric Young's, and as such any Copyright notices in | ||
17 | * the code are not to be removed. | ||
18 | * If this package is used in a product, Eric Young should be given attribution | ||
19 | * as the author of the parts of the library used. | ||
20 | * This can be in the form of a textual message at program startup or | ||
21 | * in documentation (online or textual) provided with the package. | ||
22 | * | ||
23 | * Redistribution and use in source and binary forms, with or without | ||
24 | * modification, are permitted provided that the following conditions | ||
25 | * are met: | ||
26 | * 1. Redistributions of source code must retain the copyright | ||
27 | * notice, this list of conditions and the following disclaimer. | ||
28 | * 2. Redistributions in binary form must reproduce the above copyright | ||
29 | * notice, this list of conditions and the following disclaimer in the | ||
30 | * documentation and/or other materials provided with the distribution. | ||
31 | * 3. All advertising materials mentioning features or use of this software | ||
32 | * must display the following acknowledgement: | ||
33 | * "This product includes cryptographic software written by | ||
34 | * Eric Young (eay@cryptsoft.com)" | ||
35 | * The word 'cryptographic' can be left out if the rouines from the library | ||
36 | * being used are not cryptographic related :-). | ||
37 | * 4. If you include any Windows specific code (or a derivative thereof) from | ||
38 | * the apps directory (application code) you must include an acknowledgement: | ||
39 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | ||
40 | * | ||
41 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND | ||
42 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
45 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
46 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
47 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
51 | * SUCH DAMAGE. | ||
52 | * | ||
53 | * The licence and distribution terms for any publically available version or | ||
54 | * derivative of this code cannot be changed. i.e. this code cannot simply be | ||
55 | * copied and put under another distribution licence | ||
56 | * [including the GNU Public Licence.] | ||
57 | */ | ||
58 | |||
59 | #include <assert.h> | ||
60 | #include <limits.h> | ||
61 | #include <stdio.h> | ||
62 | #include <stdlib.h> | ||
63 | #include <string.h> | ||
64 | |||
65 | #include "apps.h" | ||
66 | |||
67 | #include <openssl/asn1.h> | ||
68 | #include <openssl/bio.h> | ||
69 | #include <openssl/bn.h> | ||
70 | #include <openssl/dsa.h> | ||
71 | #include <openssl/err.h> | ||
72 | #include <openssl/evp.h> | ||
73 | #include <openssl/objects.h> | ||
74 | #include <openssl/pem.h> | ||
75 | #include <openssl/rsa.h> | ||
76 | #include <openssl/x509.h> | ||
77 | #include <openssl/x509v3.h> | ||
78 | |||
79 | #define POSTFIX ".srl" | ||
80 | #define DEF_DAYS 30 | ||
81 | |||
82 | static int callb(int ok, X509_STORE_CTX *ctx); | ||
83 | static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, | ||
84 | const EVP_MD *digest, CONF *conf, char *section, X509_NAME *issuer, | ||
85 | char *force_pubkey); | ||
86 | static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, | ||
87 | X509 *x, X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts, | ||
88 | char *serial, int create, int days, int clrext, CONF *conf, char *section, | ||
89 | ASN1_INTEGER *sno, X509_NAME *issuer); | ||
90 | static int purpose_print(BIO *bio, X509 *cert, const X509_PURPOSE *pt); | ||
91 | |||
92 | static struct { | ||
93 | char *alias; | ||
94 | int aliasout; | ||
95 | int badops; | ||
96 | int CA_createserial; | ||
97 | int CA_flag; | ||
98 | char *CAfile; | ||
99 | int CAformat; | ||
100 | char *CAkeyfile; | ||
101 | int CAkeyformat; | ||
102 | char *CAserial; | ||
103 | unsigned long certflag; | ||
104 | int checkend; | ||
105 | int checkoffset; | ||
106 | unsigned long chtype; | ||
107 | int clrext; | ||
108 | int clrreject; | ||
109 | int clrtrust; | ||
110 | int days; | ||
111 | const EVP_MD *digest; | ||
112 | int email; | ||
113 | int enddate; | ||
114 | char *extfile; | ||
115 | char *extsect; | ||
116 | int fingerprint; | ||
117 | char *force_pubkey; | ||
118 | char *infile; | ||
119 | int informat; | ||
120 | int issuer; | ||
121 | int issuer_hash; | ||
122 | #ifndef OPENSSL_NO_MD5 | ||
123 | int issuer_hash_old; | ||
124 | #endif | ||
125 | char *keyfile; | ||
126 | int keyformat; | ||
127 | const EVP_MD *md_alg; | ||
128 | int modulus; | ||
129 | int multirdn; | ||
130 | int new; | ||
131 | int next_serial; | ||
132 | unsigned long nmflag; | ||
133 | int noout; | ||
134 | int num; | ||
135 | int ocspid; | ||
136 | ASN1_OBJECT *objtmp; | ||
137 | int ocsp_uri; | ||
138 | char *outfile; | ||
139 | int outformat; | ||
140 | char *passargin; | ||
141 | int pprint; | ||
142 | int pubkey; | ||
143 | STACK_OF(ASN1_OBJECT) *reject; | ||
144 | int reqfile; | ||
145 | int serial; | ||
146 | char *set_issuer; | ||
147 | char *set_subject; | ||
148 | int sign_flag; | ||
149 | STACK_OF(OPENSSL_STRING) *sigopts; | ||
150 | ASN1_INTEGER *sno; | ||
151 | int startdate; | ||
152 | int subject; | ||
153 | int subject_hash; | ||
154 | #ifndef OPENSSL_NO_MD5 | ||
155 | int subject_hash_old; | ||
156 | #endif | ||
157 | int text; | ||
158 | STACK_OF(ASN1_OBJECT) *trust; | ||
159 | int trustout; | ||
160 | int x509req; | ||
161 | } cfg; | ||
162 | |||
163 | static int | ||
164 | x509_opt_addreject(char *arg) | ||
165 | { | ||
166 | if ((cfg.objtmp = OBJ_txt2obj(arg, 0)) == NULL) { | ||
167 | BIO_printf(bio_err, "Invalid reject object value %s\n", arg); | ||
168 | return (1); | ||
169 | } | ||
170 | |||
171 | if (cfg.reject == NULL && | ||
172 | (cfg.reject = sk_ASN1_OBJECT_new_null()) == NULL) | ||
173 | return (1); | ||
174 | |||
175 | if (!sk_ASN1_OBJECT_push(cfg.reject, cfg.objtmp)) | ||
176 | return (1); | ||
177 | |||
178 | cfg.trustout = 1; | ||
179 | return (0); | ||
180 | } | ||
181 | |||
182 | static int | ||
183 | x509_opt_addtrust(char *arg) | ||
184 | { | ||
185 | if ((cfg.objtmp = OBJ_txt2obj(arg, 0)) == NULL) { | ||
186 | BIO_printf(bio_err, "Invalid trust object value %s\n", arg); | ||
187 | return (1); | ||
188 | } | ||
189 | |||
190 | if (cfg.trust == NULL && | ||
191 | (cfg.trust = sk_ASN1_OBJECT_new_null()) == NULL) | ||
192 | return (1); | ||
193 | |||
194 | if (!sk_ASN1_OBJECT_push(cfg.trust, cfg.objtmp)) | ||
195 | return (1); | ||
196 | |||
197 | cfg.trustout = 1; | ||
198 | return (0); | ||
199 | } | ||
200 | |||
201 | static int | ||
202 | x509_opt_ca(char *arg) | ||
203 | { | ||
204 | cfg.CAfile = arg; | ||
205 | cfg.CA_flag = ++cfg.num; | ||
206 | return (0); | ||
207 | } | ||
208 | |||
209 | static int | ||
210 | x509_opt_certopt(char *arg) | ||
211 | { | ||
212 | if (!set_cert_ex(&cfg.certflag, arg)) | ||
213 | return (1); | ||
214 | |||
215 | return (0); | ||
216 | } | ||
217 | |||
218 | static int | ||
219 | x509_opt_checkend(char *arg) | ||
220 | { | ||
221 | const char *errstr; | ||
222 | |||
223 | cfg.checkoffset = strtonum(arg, 0, INT_MAX, &errstr); | ||
224 | if (errstr != NULL) { | ||
225 | BIO_printf(bio_err, "checkend unusable: %s\n", errstr); | ||
226 | return (1); | ||
227 | } | ||
228 | cfg.checkend = 1; | ||
229 | return (0); | ||
230 | } | ||
231 | |||
232 | static int | ||
233 | x509_opt_dates(void) | ||
234 | { | ||
235 | cfg.startdate = ++cfg.num; | ||
236 | cfg.enddate = ++cfg.num; | ||
237 | return (0); | ||
238 | } | ||
239 | |||
240 | static int | ||
241 | x509_opt_days(char *arg) | ||
242 | { | ||
243 | const char *errstr; | ||
244 | |||
245 | cfg.days = strtonum(arg, 1, INT_MAX, &errstr); | ||
246 | if (errstr != NULL) { | ||
247 | BIO_printf(bio_err, "bad number of days: %s\n", errstr); | ||
248 | return (1); | ||
249 | } | ||
250 | return (0); | ||
251 | } | ||
252 | |||
253 | static int | ||
254 | x509_opt_digest(int argc, char **argv, int *argsused) | ||
255 | { | ||
256 | char *name = argv[0]; | ||
257 | |||
258 | if (*name++ != '-') | ||
259 | return (1); | ||
260 | |||
261 | if ((cfg.md_alg = EVP_get_digestbyname(name)) != NULL) { | ||
262 | cfg.digest = cfg.md_alg; | ||
263 | } else { | ||
264 | BIO_printf(bio_err, "unknown option %s\n", *argv); | ||
265 | cfg.badops = 1; | ||
266 | return (1); | ||
267 | } | ||
268 | |||
269 | *argsused = 1; | ||
270 | return (0); | ||
271 | } | ||
272 | |||
273 | static int | ||
274 | x509_opt_nameopt(char *arg) | ||
275 | { | ||
276 | if (!set_name_ex(&cfg.nmflag, arg)) | ||
277 | return (1); | ||
278 | |||
279 | return (0); | ||
280 | } | ||
281 | |||
282 | static int | ||
283 | x509_opt_set_serial(char *arg) | ||
284 | { | ||
285 | ASN1_INTEGER_free(cfg.sno); | ||
286 | if ((cfg.sno = s2i_ASN1_INTEGER(NULL, arg)) == NULL) | ||
287 | return (1); | ||
288 | |||
289 | return (0); | ||
290 | } | ||
291 | |||
292 | static int | ||
293 | x509_opt_setalias(char *arg) | ||
294 | { | ||
295 | cfg.alias = arg; | ||
296 | cfg.trustout = 1; | ||
297 | return (0); | ||
298 | } | ||
299 | |||
300 | static int | ||
301 | x509_opt_signkey(char *arg) | ||
302 | { | ||
303 | cfg.keyfile = arg; | ||
304 | cfg.sign_flag = ++cfg.num; | ||
305 | return (0); | ||
306 | } | ||
307 | |||
308 | static int | ||
309 | x509_opt_sigopt(char *arg) | ||
310 | { | ||
311 | if (cfg.sigopts == NULL && | ||
312 | (cfg.sigopts = sk_OPENSSL_STRING_new_null()) == NULL) | ||
313 | return (1); | ||
314 | |||
315 | if (!sk_OPENSSL_STRING_push(cfg.sigopts, arg)) | ||
316 | return (1); | ||
317 | |||
318 | return (0); | ||
319 | } | ||
320 | |||
321 | static int | ||
322 | x509_opt_utf8(void) | ||
323 | { | ||
324 | cfg.chtype = MBSTRING_UTF8; | ||
325 | return (0); | ||
326 | } | ||
327 | |||
328 | static const struct option x509_options[] = { | ||
329 | { | ||
330 | .name = "addreject", | ||
331 | .argname = "arg", | ||
332 | .desc = "Reject certificate for a given purpose", | ||
333 | .type = OPTION_ARG_FUNC, | ||
334 | .opt.argfunc = x509_opt_addreject, | ||
335 | }, | ||
336 | { | ||
337 | .name = "addtrust", | ||
338 | .argname = "arg", | ||
339 | .desc = "Trust certificate for a given purpose", | ||
340 | .type = OPTION_ARG_FUNC, | ||
341 | .opt.argfunc = x509_opt_addtrust, | ||
342 | }, | ||
343 | { | ||
344 | .name = "alias", | ||
345 | .desc = "Output certificate alias", | ||
346 | .type = OPTION_ORDER, | ||
347 | .opt.order = &cfg.aliasout, | ||
348 | .order = &cfg.num, | ||
349 | }, | ||
350 | { | ||
351 | .name = "CA", | ||
352 | .argname = "file", | ||
353 | .desc = "CA certificate in PEM format unless -CAform is specified", | ||
354 | .type = OPTION_ARG_FUNC, | ||
355 | .opt.argfunc = x509_opt_ca, | ||
356 | }, | ||
357 | { | ||
358 | .name = "CAcreateserial", | ||
359 | .desc = "Create serial number file if it does not exist", | ||
360 | .type = OPTION_ORDER, | ||
361 | .opt.order = &cfg.CA_createserial, | ||
362 | .order = &cfg.num, | ||
363 | }, | ||
364 | { | ||
365 | .name = "CAform", | ||
366 | .argname = "fmt", | ||
367 | .desc = "CA format - default PEM", | ||
368 | .type = OPTION_ARG_FORMAT, | ||
369 | .opt.value = &cfg.CAformat, | ||
370 | }, | ||
371 | { | ||
372 | .name = "CAkey", | ||
373 | .argname = "file", | ||
374 | .desc = "CA key in PEM format unless -CAkeyform is specified\n" | ||
375 | "if omitted, the key is assumed to be in the CA file", | ||
376 | .type = OPTION_ARG, | ||
377 | .opt.arg = &cfg.CAkeyfile, | ||
378 | }, | ||
379 | { | ||
380 | .name = "CAkeyform", | ||
381 | .argname = "fmt", | ||
382 | .desc = "CA key format - default PEM", | ||
383 | .type = OPTION_ARG_FORMAT, | ||
384 | .opt.value = &cfg.CAkeyformat, | ||
385 | }, | ||
386 | { | ||
387 | .name = "CAserial", | ||
388 | .argname = "file", | ||
389 | .desc = "Serial file", | ||
390 | .type = OPTION_ARG, | ||
391 | .opt.arg = &cfg.CAserial, | ||
392 | }, | ||
393 | { | ||
394 | .name = "certopt", | ||
395 | .argname = "option", | ||
396 | .desc = "Various certificate text options", | ||
397 | .type = OPTION_ARG_FUNC, | ||
398 | .opt.argfunc = x509_opt_certopt, | ||
399 | }, | ||
400 | { | ||
401 | .name = "checkend", | ||
402 | .argname = "arg", | ||
403 | .desc = "Check whether the cert expires in the next arg seconds\n" | ||
404 | "exit 1 if so, 0 if not", | ||
405 | .type = OPTION_ARG_FUNC, | ||
406 | .opt.argfunc = x509_opt_checkend, | ||
407 | }, | ||
408 | { | ||
409 | .name = "clrext", | ||
410 | .desc = "Clear all extensions", | ||
411 | .type = OPTION_FLAG, | ||
412 | .opt.flag = &cfg.clrext, | ||
413 | }, | ||
414 | { | ||
415 | .name = "clrreject", | ||
416 | .desc = "Clear all rejected purposes", | ||
417 | .type = OPTION_ORDER, | ||
418 | .opt.order = &cfg.clrreject, | ||
419 | .order = &cfg.num, | ||
420 | }, | ||
421 | { | ||
422 | .name = "clrtrust", | ||
423 | .desc = "Clear all trusted purposes", | ||
424 | .type = OPTION_ORDER, | ||
425 | .opt.order = &cfg.clrtrust, | ||
426 | .order = &cfg.num, | ||
427 | }, | ||
428 | { | ||
429 | .name = "dates", | ||
430 | .desc = "Both Before and After dates", | ||
431 | .type = OPTION_FUNC, | ||
432 | .opt.func = x509_opt_dates, | ||
433 | }, | ||
434 | { | ||
435 | .name = "days", | ||
436 | .argname = "arg", | ||
437 | .desc = "How long till expiry of a signed certificate - def 30 days", | ||
438 | .type = OPTION_ARG_FUNC, | ||
439 | .opt.argfunc = x509_opt_days, | ||
440 | }, | ||
441 | { | ||
442 | .name = "email", | ||
443 | .desc = "Print email address(es)", | ||
444 | .type = OPTION_ORDER, | ||
445 | .opt.order = &cfg.email, | ||
446 | .order = &cfg.num, | ||
447 | }, | ||
448 | { | ||
449 | .name = "enddate", | ||
450 | .desc = "Print notAfter field", | ||
451 | .type = OPTION_ORDER, | ||
452 | .opt.order = &cfg.enddate, | ||
453 | .order = &cfg.num, | ||
454 | }, | ||
455 | { | ||
456 | .name = "extensions", | ||
457 | .argname = "section", | ||
458 | .desc = "Section from config file with X509V3 extensions to add", | ||
459 | .type = OPTION_ARG, | ||
460 | .opt.arg = &cfg.extsect, | ||
461 | }, | ||
462 | { | ||
463 | .name = "extfile", | ||
464 | .argname = "file", | ||
465 | .desc = "Configuration file with X509V3 extensions to add", | ||
466 | .type = OPTION_ARG, | ||
467 | .opt.arg = &cfg.extfile, | ||
468 | }, | ||
469 | { | ||
470 | .name = "fingerprint", | ||
471 | .desc = "Print the certificate fingerprint", | ||
472 | .type = OPTION_ORDER, | ||
473 | .opt.order = &cfg.fingerprint, | ||
474 | .order = &cfg.num, | ||
475 | }, | ||
476 | { | ||
477 | .name = "force_pubkey", | ||
478 | .argname = "key", | ||
479 | .desc = "Force the public key to be put in the certificate", | ||
480 | .type = OPTION_ARG, | ||
481 | .opt.arg = &cfg.force_pubkey, | ||
482 | }, | ||
483 | { | ||
484 | .name = "hash", | ||
485 | .desc = "Synonym for -subject_hash", | ||
486 | .type = OPTION_ORDER, | ||
487 | .opt.order = &cfg.subject_hash, | ||
488 | .order = &cfg.num, | ||
489 | }, | ||
490 | { | ||
491 | .name = "in", | ||
492 | .argname = "file", | ||
493 | .desc = "Input file - default stdin", | ||
494 | .type = OPTION_ARG, | ||
495 | .opt.arg = &cfg.infile, | ||
496 | }, | ||
497 | { | ||
498 | .name = "inform", | ||
499 | .argname = "fmt", | ||
500 | .desc = "Input format - default PEM (one of DER, NET or PEM)", | ||
501 | .type = OPTION_ARG_FORMAT, | ||
502 | .opt.value = &cfg.informat, | ||
503 | }, | ||
504 | { | ||
505 | .name = "issuer", | ||
506 | .desc = "Print issuer name", | ||
507 | .type = OPTION_ORDER, | ||
508 | .opt.order = &cfg.issuer, | ||
509 | .order = &cfg.num, | ||
510 | }, | ||
511 | { | ||
512 | .name = "issuer_hash", | ||
513 | .desc = "Print issuer hash value", | ||
514 | .type = OPTION_ORDER, | ||
515 | .opt.order = &cfg.issuer_hash, | ||
516 | .order = &cfg.num, | ||
517 | }, | ||
518 | #ifndef OPENSSL_NO_MD5 | ||
519 | { | ||
520 | .name = "issuer_hash_old", | ||
521 | .desc = "Print old-style (MD5) issuer hash value", | ||
522 | .type = OPTION_ORDER, | ||
523 | .opt.order = &cfg.issuer_hash_old, | ||
524 | .order = &cfg.num, | ||
525 | }, | ||
526 | #endif | ||
527 | { | ||
528 | .name = "key", | ||
529 | .argname = "file", | ||
530 | .type = OPTION_ARG_FUNC, | ||
531 | .opt.argfunc = x509_opt_signkey, | ||
532 | }, | ||
533 | { | ||
534 | .name = "keyform", | ||
535 | .argname = "fmt", | ||
536 | .desc = "Private key format - default PEM", | ||
537 | .type = OPTION_ARG_FORMAT, | ||
538 | .opt.value = &cfg.keyformat, | ||
539 | }, | ||
540 | { | ||
541 | .name = "modulus", | ||
542 | .desc = "Print the RSA key modulus", | ||
543 | .type = OPTION_ORDER, | ||
544 | .opt.order = &cfg.modulus, | ||
545 | .order = &cfg.num, | ||
546 | }, | ||
547 | { | ||
548 | .name = "multivalue-rdn", | ||
549 | .desc = "Enable support for multivalued RDNs", | ||
550 | .type = OPTION_FLAG, | ||
551 | .opt.flag = &cfg.multirdn, | ||
552 | }, | ||
553 | { | ||
554 | .name = "nameopt", | ||
555 | .argname = "option", | ||
556 | .desc = "Various certificate name options", | ||
557 | .type = OPTION_ARG_FUNC, | ||
558 | .opt.argfunc = x509_opt_nameopt, | ||
559 | }, | ||
560 | { | ||
561 | .name = "new", | ||
562 | .desc = "Generate a new certificate", | ||
563 | .type = OPTION_FLAG, | ||
564 | .opt.flag = &cfg.new, | ||
565 | }, | ||
566 | { | ||
567 | .name = "next_serial", | ||
568 | .desc = "Print the next serial number", | ||
569 | .type = OPTION_ORDER, | ||
570 | .opt.order = &cfg.next_serial, | ||
571 | .order = &cfg.num, | ||
572 | }, | ||
573 | { | ||
574 | .name = "noout", | ||
575 | .desc = "No certificate output", | ||
576 | .type = OPTION_ORDER, | ||
577 | .opt.order = &cfg.noout, | ||
578 | .order = &cfg.num, | ||
579 | }, | ||
580 | { | ||
581 | .name = "ocsp_uri", | ||
582 | .desc = "Print OCSP Responder URL(s)", | ||
583 | .type = OPTION_ORDER, | ||
584 | .opt.order = &cfg.ocsp_uri, | ||
585 | .order = &cfg.num, | ||
586 | }, | ||
587 | { | ||
588 | .name = "ocspid", | ||
589 | .desc = "Print OCSP hash values for the subject name and public key", | ||
590 | .type = OPTION_ORDER, | ||
591 | .opt.order = &cfg.ocspid, | ||
592 | .order = &cfg.num, | ||
593 | }, | ||
594 | { | ||
595 | .name = "out", | ||
596 | .argname = "file", | ||
597 | .desc = "Output file - default stdout", | ||
598 | .type = OPTION_ARG, | ||
599 | .opt.arg = &cfg.outfile, | ||
600 | }, | ||
601 | { | ||
602 | .name = "outform", | ||
603 | .argname = "fmt", | ||
604 | .desc = "Output format - default PEM (one of DER, NET or PEM)", | ||
605 | .type = OPTION_ARG_FORMAT, | ||
606 | .opt.value = &cfg.outformat, | ||
607 | }, | ||
608 | { | ||
609 | .name = "passin", | ||
610 | .argname = "src", | ||
611 | .desc = "Private key password source", | ||
612 | .type = OPTION_ARG, | ||
613 | .opt.arg = &cfg.passargin, | ||
614 | }, | ||
615 | { | ||
616 | .name = "pubkey", | ||
617 | .desc = "Output the public key", | ||
618 | .type = OPTION_ORDER, | ||
619 | .opt.order = &cfg.pubkey, | ||
620 | .order = &cfg.num, | ||
621 | }, | ||
622 | { | ||
623 | .name = "purpose", | ||
624 | .desc = "Print out certificate purposes", | ||
625 | .type = OPTION_ORDER, | ||
626 | .opt.order = &cfg.pprint, | ||
627 | .order = &cfg.num, | ||
628 | }, | ||
629 | { | ||
630 | .name = "req", | ||
631 | .desc = "Input is a certificate request, sign and output", | ||
632 | .type = OPTION_FLAG, | ||
633 | .opt.flag = &cfg.reqfile, | ||
634 | }, | ||
635 | { | ||
636 | .name = "serial", | ||
637 | .desc = "Print serial number value", | ||
638 | .type = OPTION_ORDER, | ||
639 | .opt.order = &cfg.serial, | ||
640 | .order = &cfg.num, | ||
641 | }, | ||
642 | { | ||
643 | .name = "set_issuer", | ||
644 | .argname = "name", | ||
645 | .desc = "Set the issuer name", | ||
646 | .type = OPTION_ARG, | ||
647 | .opt.arg = &cfg.set_issuer, | ||
648 | }, | ||
649 | { | ||
650 | .name = "set_serial", | ||
651 | .argname = "n", | ||
652 | .desc = "Serial number to use", | ||
653 | .type = OPTION_ARG_FUNC, | ||
654 | .opt.argfunc = x509_opt_set_serial, | ||
655 | }, | ||
656 | { | ||
657 | .name = "set_subject", | ||
658 | .argname = "name", | ||
659 | .desc = "Set the subject name", | ||
660 | .type = OPTION_ARG, | ||
661 | .opt.arg = &cfg.set_subject, | ||
662 | }, | ||
663 | { | ||
664 | .name = "setalias", | ||
665 | .argname = "arg", | ||
666 | .desc = "Set certificate alias", | ||
667 | .type = OPTION_ARG_FUNC, | ||
668 | .opt.argfunc = x509_opt_setalias, | ||
669 | }, | ||
670 | { | ||
671 | .name = "signkey", | ||
672 | .argname = "file", | ||
673 | .desc = "Self sign cert with arg", | ||
674 | .type = OPTION_ARG_FUNC, | ||
675 | .opt.argfunc = x509_opt_signkey, | ||
676 | }, | ||
677 | { | ||
678 | .name = "sigopt", | ||
679 | .argname = "nm:v", | ||
680 | .desc = "Various signature algorithm options", | ||
681 | .type = OPTION_ARG_FUNC, | ||
682 | .opt.argfunc = x509_opt_sigopt, | ||
683 | }, | ||
684 | { | ||
685 | .name = "startdate", | ||
686 | .desc = "Print notBefore field", | ||
687 | .type = OPTION_ORDER, | ||
688 | .opt.order = &cfg.startdate, | ||
689 | .order = &cfg.num, | ||
690 | }, | ||
691 | { | ||
692 | .name = "subj", | ||
693 | .type = OPTION_ARG, | ||
694 | .opt.arg = &cfg.set_subject, | ||
695 | }, | ||
696 | { | ||
697 | .name = "subject", | ||
698 | .desc = "Print subject name", | ||
699 | .type = OPTION_ORDER, | ||
700 | .opt.order = &cfg.subject, | ||
701 | .order = &cfg.num, | ||
702 | }, | ||
703 | { | ||
704 | .name = "subject_hash", | ||
705 | .desc = "Print subject hash value", | ||
706 | .type = OPTION_ORDER, | ||
707 | .opt.order = &cfg.subject_hash, | ||
708 | .order = &cfg.num, | ||
709 | }, | ||
710 | #ifndef OPENSSL_NO_MD5 | ||
711 | { | ||
712 | .name = "subject_hash_old", | ||
713 | .desc = "Print old-style (MD5) subject hash value", | ||
714 | .type = OPTION_ORDER, | ||
715 | .opt.order = &cfg.subject_hash_old, | ||
716 | .order = &cfg.num, | ||
717 | }, | ||
718 | #endif | ||
719 | { | ||
720 | .name = "text", | ||
721 | .desc = "Print the certificate in text form", | ||
722 | .type = OPTION_ORDER, | ||
723 | .opt.order = &cfg.text, | ||
724 | .order = &cfg.num, | ||
725 | }, | ||
726 | { | ||
727 | .name = "trustout", | ||
728 | .desc = "Output a trusted certificate", | ||
729 | .type = OPTION_FLAG, | ||
730 | .opt.flag = &cfg.trustout, | ||
731 | }, | ||
732 | { | ||
733 | .name = "utf8", | ||
734 | .desc = "Input characters are in UTF-8 (default ASCII)", | ||
735 | .type = OPTION_FUNC, | ||
736 | .opt.func = x509_opt_utf8, | ||
737 | }, | ||
738 | { | ||
739 | .name = "x509toreq", | ||
740 | .desc = "Output a certification request object", | ||
741 | .type = OPTION_ORDER, | ||
742 | .opt.order = &cfg.x509req, | ||
743 | .order = &cfg.num, | ||
744 | }, | ||
745 | { | ||
746 | .name = NULL, | ||
747 | .desc = "", | ||
748 | .type = OPTION_ARGV_FUNC, | ||
749 | .opt.argvfunc = x509_opt_digest, | ||
750 | }, | ||
751 | { NULL }, | ||
752 | }; | ||
753 | |||
754 | static void | ||
755 | x509_usage(void) | ||
756 | { | ||
757 | fprintf(stderr, "usage: x509 " | ||
758 | "[-addreject arg] [-addtrust arg] [-alias] [-CA file]\n" | ||
759 | " [-CAcreateserial] [-CAform der | pem] [-CAkey file]\n" | ||
760 | " [-CAkeyform der | pem] [-CAserial file] [-certopt option]\n" | ||
761 | " [-checkend arg] [-clrext] [-clrreject] [-clrtrust] [-dates]\n" | ||
762 | " [-days arg] [-email] [-enddate] [-extensions section]\n" | ||
763 | " [-extfile file] [-fingerprint] [-force_pubkey key] [-hash]\n" | ||
764 | " [-in file] [-inform der | net | pem] [-issuer]\n" | ||
765 | " [-issuer_hash] [-issuer_hash_old] [-keyform der | pem]\n" | ||
766 | " [-md5 | -sha1] [-modulus] [-multivalue-rdn]\n" | ||
767 | " [-nameopt option] [-new] [-next_serial] [-noout] [-ocsp_uri]\n" | ||
768 | " [-ocspid] [-out file] [-outform der | net | pem]\n" | ||
769 | " [-passin arg] [-pubkey] [-purpose] [-req] [-serial]\n" | ||
770 | " [-set_issuer name] [-set_serial n] [-set_subject name]\n" | ||
771 | " [-setalias arg] [-signkey file] [-sigopt nm:v] [-startdate]\n" | ||
772 | " [-subject] [-subject_hash] [-subject_hash_old] [-text]\n" | ||
773 | " [-trustout] [-utf8] [-x509toreq]\n"); | ||
774 | fprintf(stderr, "\n"); | ||
775 | options_usage(x509_options); | ||
776 | fprintf(stderr, "\n"); | ||
777 | } | ||
778 | |||
779 | int | ||
780 | x509_main(int argc, char **argv) | ||
781 | { | ||
782 | int ret = 1; | ||
783 | X509_REQ *req = NULL; | ||
784 | X509 *x = NULL, *xca = NULL; | ||
785 | X509_NAME *iname = NULL, *sname = NULL; | ||
786 | EVP_PKEY *Fpkey = NULL, *Upkey = NULL, *CApkey = NULL; | ||
787 | EVP_PKEY *pkey; | ||
788 | int i; | ||
789 | BIO *out = NULL; | ||
790 | BIO *STDout = NULL; | ||
791 | X509_STORE *ctx = NULL; | ||
792 | X509_REQ *rq = NULL; | ||
793 | CONF *extconf = NULL; | ||
794 | char *passin = NULL; | ||
795 | |||
796 | if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { | ||
797 | perror("pledge"); | ||
798 | exit(1); | ||
799 | } | ||
800 | |||
801 | memset(&cfg, 0, sizeof(cfg)); | ||
802 | cfg.chtype = MBSTRING_ASC; | ||
803 | cfg.days = DEF_DAYS; | ||
804 | cfg.informat = FORMAT_PEM; | ||
805 | cfg.outformat = FORMAT_PEM; | ||
806 | cfg.keyformat = FORMAT_PEM; | ||
807 | cfg.CAformat = FORMAT_PEM; | ||
808 | cfg.CAkeyformat = FORMAT_PEM; | ||
809 | |||
810 | STDout = BIO_new_fp(stdout, BIO_NOCLOSE); | ||
811 | |||
812 | ctx = X509_STORE_new(); | ||
813 | if (ctx == NULL) | ||
814 | goto end; | ||
815 | X509_STORE_set_verify_cb(ctx, callb); | ||
816 | |||
817 | if (options_parse(argc, argv, x509_options, NULL, NULL) != 0) | ||
818 | goto bad; | ||
819 | |||
820 | if (cfg.badops) { | ||
821 | bad: | ||
822 | x509_usage(); | ||
823 | goto end; | ||
824 | } | ||
825 | |||
826 | if (!app_passwd(bio_err, cfg.passargin, NULL, &passin, NULL)) { | ||
827 | BIO_printf(bio_err, "Error getting password\n"); | ||
828 | goto end; | ||
829 | } | ||
830 | if (!X509_STORE_set_default_paths(ctx)) { | ||
831 | ERR_print_errors(bio_err); | ||
832 | goto end; | ||
833 | } | ||
834 | if (cfg.CAkeyfile == NULL && cfg.CA_flag && cfg.CAformat == FORMAT_PEM) { | ||
835 | cfg.CAkeyfile = cfg.CAfile; | ||
836 | } else if (cfg.CA_flag && cfg.CAkeyfile == NULL) { | ||
837 | BIO_printf(bio_err, | ||
838 | "need to specify a CAkey if using the CA command\n"); | ||
839 | goto end; | ||
840 | } | ||
841 | if (cfg.extfile != NULL) { | ||
842 | long errorline = -1; | ||
843 | X509V3_CTX ctx2; | ||
844 | extconf = NCONF_new(NULL); | ||
845 | if (!NCONF_load(extconf, cfg.extfile, &errorline)) { | ||
846 | if (errorline <= 0) | ||
847 | BIO_printf(bio_err, | ||
848 | "error loading the config file '%s'\n", | ||
849 | cfg.extfile); | ||
850 | else | ||
851 | BIO_printf(bio_err, | ||
852 | "error on line %ld of config file '%s'\n", | ||
853 | errorline, cfg.extfile); | ||
854 | goto end; | ||
855 | } | ||
856 | if (cfg.extsect == NULL) { | ||
857 | cfg.extsect = NCONF_get_string(extconf, "default", | ||
858 | "extensions"); | ||
859 | if (cfg.extsect == NULL) { | ||
860 | ERR_clear_error(); | ||
861 | cfg.extsect = "default"; | ||
862 | } | ||
863 | } | ||
864 | X509V3_set_ctx_test(&ctx2); | ||
865 | X509V3_set_nconf(&ctx2, extconf); | ||
866 | if (!X509V3_EXT_add_nconf(extconf, &ctx2, cfg.extsect, NULL)) { | ||
867 | BIO_printf(bio_err, | ||
868 | "Error Loading extension section %s\n", cfg.extsect); | ||
869 | ERR_print_errors(bio_err); | ||
870 | goto end; | ||
871 | } | ||
872 | } | ||
873 | if (cfg.force_pubkey != NULL) { | ||
874 | if ((Fpkey = load_pubkey(bio_err, cfg.force_pubkey, | ||
875 | cfg.keyformat, 0, NULL, "Forced key")) == NULL) | ||
876 | goto end; | ||
877 | } | ||
878 | if (cfg.new) { | ||
879 | if (cfg.infile != NULL) { | ||
880 | BIO_printf(bio_err, "Can't combine -new and -in\n"); | ||
881 | goto end; | ||
882 | } | ||
883 | if (cfg.reqfile) { | ||
884 | BIO_printf(bio_err, "Can't combine -new and -req\n"); | ||
885 | goto end; | ||
886 | } | ||
887 | if (cfg.set_subject == NULL) { | ||
888 | BIO_printf(bio_err, "Must use -set_subject with -new\n"); | ||
889 | goto end; | ||
890 | } | ||
891 | if (cfg.keyfile == NULL) { | ||
892 | BIO_printf(bio_err, "Must use -signkey with -new\n"); | ||
893 | goto end; | ||
894 | } | ||
895 | if ((Upkey = load_key(bio_err, cfg.keyfile, cfg.keyformat, 0, | ||
896 | passin, "Private key")) == NULL) | ||
897 | goto end; | ||
898 | } | ||
899 | if (cfg.reqfile) { | ||
900 | BIO *in; | ||
901 | |||
902 | if (!cfg.sign_flag && !cfg.CA_flag) { | ||
903 | BIO_printf(bio_err, | ||
904 | "We need a private key to sign with\n"); | ||
905 | goto end; | ||
906 | } | ||
907 | in = BIO_new(BIO_s_file()); | ||
908 | if (in == NULL) { | ||
909 | ERR_print_errors(bio_err); | ||
910 | goto end; | ||
911 | } | ||
912 | if (cfg.infile == NULL) | ||
913 | BIO_set_fp(in, stdin, BIO_NOCLOSE | BIO_FP_TEXT); | ||
914 | else { | ||
915 | if (BIO_read_filename(in, cfg.infile) <= 0) { | ||
916 | perror(cfg.infile); | ||
917 | BIO_free(in); | ||
918 | goto end; | ||
919 | } | ||
920 | } | ||
921 | req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL); | ||
922 | BIO_free(in); | ||
923 | |||
924 | if (req == NULL) { | ||
925 | ERR_print_errors(bio_err); | ||
926 | goto end; | ||
927 | } | ||
928 | if ((pkey = X509_REQ_get0_pubkey(req)) == NULL) { | ||
929 | BIO_printf(bio_err, "error unpacking public key\n"); | ||
930 | goto end; | ||
931 | } | ||
932 | i = X509_REQ_verify(req, pkey); | ||
933 | if (i < 0) { | ||
934 | BIO_printf(bio_err, "Signature verification error\n"); | ||
935 | ERR_print_errors(bio_err); | ||
936 | goto end; | ||
937 | } | ||
938 | if (i == 0) { | ||
939 | BIO_printf(bio_err, | ||
940 | "Signature did not match the certificate request\n"); | ||
941 | goto end; | ||
942 | } else | ||
943 | BIO_printf(bio_err, "Signature ok\n"); | ||
944 | |||
945 | print_name(bio_err, "subject=", X509_REQ_get_subject_name(req), | ||
946 | cfg.nmflag); | ||
947 | |||
948 | } | ||
949 | if (cfg.reqfile || cfg.new) { | ||
950 | if ((x = X509_new()) == NULL) | ||
951 | goto end; | ||
952 | |||
953 | if (cfg.sno == NULL) { | ||
954 | cfg.sno = ASN1_INTEGER_new(); | ||
955 | if (cfg.sno == NULL || !rand_serial(NULL, cfg.sno)) | ||
956 | goto end; | ||
957 | if (!X509_set_serialNumber(x, cfg.sno)) | ||
958 | goto end; | ||
959 | ASN1_INTEGER_free(cfg.sno); | ||
960 | cfg.sno = NULL; | ||
961 | } else if (!X509_set_serialNumber(x, cfg.sno)) | ||
962 | goto end; | ||
963 | |||
964 | if (cfg.set_issuer != NULL) { | ||
965 | iname = parse_name(cfg.set_issuer, cfg.chtype, | ||
966 | cfg.multirdn); | ||
967 | if (iname == NULL) | ||
968 | goto end; | ||
969 | } | ||
970 | |||
971 | if (cfg.set_subject != NULL) | ||
972 | sname = parse_name(cfg.set_subject, cfg.chtype, | ||
973 | cfg.multirdn); | ||
974 | else | ||
975 | sname = X509_NAME_dup(X509_REQ_get_subject_name(req)); | ||
976 | if (sname == NULL) | ||
977 | goto end; | ||
978 | if (!X509_set_subject_name(x, sname)) | ||
979 | goto end; | ||
980 | |||
981 | if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL) | ||
982 | goto end; | ||
983 | if (X509_time_adj_ex(X509_get_notAfter(x), cfg.days, 0, | ||
984 | NULL) == NULL) | ||
985 | goto end; | ||
986 | |||
987 | if ((pkey = Fpkey) == NULL) | ||
988 | pkey = X509_REQ_get0_pubkey(req); | ||
989 | if (pkey == NULL) | ||
990 | pkey = Upkey; | ||
991 | if (pkey == NULL) | ||
992 | goto end; | ||
993 | if (!X509_set_pubkey(x, pkey)) | ||
994 | goto end; | ||
995 | } else { | ||
996 | x = load_cert(bio_err, cfg.infile, cfg.informat, NULL, | ||
997 | "Certificate"); | ||
998 | } | ||
999 | if (x == NULL) | ||
1000 | goto end; | ||
1001 | |||
1002 | if (cfg.CA_flag) { | ||
1003 | xca = load_cert(bio_err, cfg.CAfile, cfg.CAformat, NULL, | ||
1004 | "CA Certificate"); | ||
1005 | if (xca == NULL) | ||
1006 | goto end; | ||
1007 | } | ||
1008 | if (!cfg.noout || cfg.text || cfg.next_serial) { | ||
1009 | OBJ_create("2.99999.3", "SET.ex3", "SET x509v3 extension 3"); | ||
1010 | |||
1011 | out = BIO_new(BIO_s_file()); | ||
1012 | if (out == NULL) { | ||
1013 | ERR_print_errors(bio_err); | ||
1014 | goto end; | ||
1015 | } | ||
1016 | if (cfg.outfile == NULL) { | ||
1017 | BIO_set_fp(out, stdout, BIO_NOCLOSE); | ||
1018 | } else { | ||
1019 | if (BIO_write_filename(out, cfg.outfile) <= 0) { | ||
1020 | perror(cfg.outfile); | ||
1021 | goto end; | ||
1022 | } | ||
1023 | } | ||
1024 | } | ||
1025 | if (cfg.alias != NULL) { | ||
1026 | if (!X509_alias_set1(x, (unsigned char *)cfg.alias, -1)) | ||
1027 | goto end; | ||
1028 | } | ||
1029 | |||
1030 | if (cfg.clrtrust) | ||
1031 | X509_trust_clear(x); | ||
1032 | if (cfg.clrreject) | ||
1033 | X509_reject_clear(x); | ||
1034 | |||
1035 | if (cfg.trust != NULL) { | ||
1036 | for (i = 0; i < sk_ASN1_OBJECT_num(cfg.trust); i++) { | ||
1037 | cfg.objtmp = sk_ASN1_OBJECT_value(cfg.trust, i); | ||
1038 | if (!X509_add1_trust_object(x, cfg.objtmp)) | ||
1039 | goto end; | ||
1040 | } | ||
1041 | } | ||
1042 | if (cfg.reject != NULL) { | ||
1043 | for (i = 0; i < sk_ASN1_OBJECT_num(cfg.reject); i++) { | ||
1044 | cfg.objtmp = sk_ASN1_OBJECT_value(cfg.reject, i); | ||
1045 | if (!X509_add1_reject_object(x, cfg.objtmp)) | ||
1046 | goto end; | ||
1047 | } | ||
1048 | } | ||
1049 | if (cfg.num) { | ||
1050 | for (i = 1; i <= cfg.num; i++) { | ||
1051 | if (cfg.issuer == i) { | ||
1052 | print_name(STDout, "issuer= ", | ||
1053 | X509_get_issuer_name(x), cfg.nmflag); | ||
1054 | } else if (cfg.subject == i) { | ||
1055 | print_name(STDout, "subject= ", | ||
1056 | X509_get_subject_name(x), cfg.nmflag); | ||
1057 | } else if (cfg.serial == i) { | ||
1058 | BIO_printf(STDout, "serial="); | ||
1059 | i2a_ASN1_INTEGER(STDout, | ||
1060 | X509_get_serialNumber(x)); | ||
1061 | BIO_printf(STDout, "\n"); | ||
1062 | } else if (cfg.next_serial == i) { | ||
1063 | BIGNUM *bnser; | ||
1064 | ASN1_INTEGER *ser; | ||
1065 | |||
1066 | ser = X509_get_serialNumber(x); | ||
1067 | if (ser == NULL) | ||
1068 | goto end; | ||
1069 | bnser = ASN1_INTEGER_to_BN(ser, NULL); | ||
1070 | if (bnser == NULL) | ||
1071 | goto end; | ||
1072 | if (!BN_add_word(bnser, 1)) { | ||
1073 | BN_free(bnser); | ||
1074 | goto end; | ||
1075 | } | ||
1076 | ser = BN_to_ASN1_INTEGER(bnser, NULL); | ||
1077 | if (ser == NULL) { | ||
1078 | BN_free(bnser); | ||
1079 | goto end; | ||
1080 | } | ||
1081 | BN_free(bnser); | ||
1082 | i2a_ASN1_INTEGER(out, ser); | ||
1083 | ASN1_INTEGER_free(ser); | ||
1084 | BIO_puts(out, "\n"); | ||
1085 | } else if (cfg.email == i || cfg.ocsp_uri == i) { | ||
1086 | STACK_OF(OPENSSL_STRING) *emlst; | ||
1087 | int j; | ||
1088 | |||
1089 | if (cfg.email == i) | ||
1090 | emlst = X509_get1_email(x); | ||
1091 | else | ||
1092 | emlst = X509_get1_ocsp(x); | ||
1093 | for (j = 0; j < sk_OPENSSL_STRING_num(emlst); j++) | ||
1094 | BIO_printf(STDout, "%s\n", | ||
1095 | sk_OPENSSL_STRING_value(emlst, j)); | ||
1096 | X509_email_free(emlst); | ||
1097 | } else if (cfg.aliasout == i) { | ||
1098 | unsigned char *albuf; | ||
1099 | int buflen; | ||
1100 | albuf = X509_alias_get0(x, &buflen); | ||
1101 | if (albuf != NULL) | ||
1102 | BIO_printf(STDout, "%.*s\n", | ||
1103 | buflen, albuf); | ||
1104 | else | ||
1105 | BIO_puts(STDout, "<No Alias>\n"); | ||
1106 | } else if (cfg.subject_hash == i) { | ||
1107 | BIO_printf(STDout, "%08lx\n", | ||
1108 | X509_subject_name_hash(x)); | ||
1109 | } | ||
1110 | #ifndef OPENSSL_NO_MD5 | ||
1111 | else if (cfg.subject_hash_old == i) { | ||
1112 | BIO_printf(STDout, "%08lx\n", | ||
1113 | X509_subject_name_hash_old(x)); | ||
1114 | } | ||
1115 | #endif | ||
1116 | else if (cfg.issuer_hash == i) { | ||
1117 | BIO_printf(STDout, "%08lx\n", | ||
1118 | X509_issuer_name_hash(x)); | ||
1119 | } | ||
1120 | #ifndef OPENSSL_NO_MD5 | ||
1121 | else if (cfg.issuer_hash_old == i) { | ||
1122 | BIO_printf(STDout, "%08lx\n", | ||
1123 | X509_issuer_name_hash_old(x)); | ||
1124 | } | ||
1125 | #endif | ||
1126 | else if (cfg.pprint == i) { | ||
1127 | const X509_PURPOSE *ptmp; | ||
1128 | int j; | ||
1129 | |||
1130 | BIO_printf(STDout, "Certificate purposes:\n"); | ||
1131 | for (j = 0; j < X509_PURPOSE_get_count(); j++) { | ||
1132 | ptmp = X509_PURPOSE_get0(j); | ||
1133 | purpose_print(STDout, x, ptmp); | ||
1134 | } | ||
1135 | } else if (cfg.modulus == i) { | ||
1136 | EVP_PKEY *pubkey; | ||
1137 | |||
1138 | if ((pubkey = X509_get0_pubkey(x)) == NULL) { | ||
1139 | BIO_printf(bio_err, | ||
1140 | "Modulus=unavailable\n"); | ||
1141 | ERR_print_errors(bio_err); | ||
1142 | goto end; | ||
1143 | } | ||
1144 | BIO_printf(STDout, "Modulus="); | ||
1145 | if (EVP_PKEY_id(pubkey) == EVP_PKEY_RSA) { | ||
1146 | RSA *rsa = EVP_PKEY_get0_RSA(pubkey); | ||
1147 | const BIGNUM *n = NULL; | ||
1148 | |||
1149 | RSA_get0_key(rsa, &n, NULL, NULL); | ||
1150 | BN_print(STDout, n); | ||
1151 | } else if (EVP_PKEY_id(pubkey) == EVP_PKEY_DSA) { | ||
1152 | DSA *dsa = EVP_PKEY_get0_DSA(pubkey); | ||
1153 | const BIGNUM *dsa_pub_key = NULL; | ||
1154 | |||
1155 | DSA_get0_key(dsa, &dsa_pub_key, NULL); | ||
1156 | |||
1157 | BN_print(STDout, dsa_pub_key); | ||
1158 | } else | ||
1159 | BIO_printf(STDout, | ||
1160 | "Wrong Algorithm type"); | ||
1161 | BIO_printf(STDout, "\n"); | ||
1162 | } else if (cfg.pubkey == i) { | ||
1163 | EVP_PKEY *pubkey; | ||
1164 | |||
1165 | if ((pubkey = X509_get0_pubkey(x)) == NULL) { | ||
1166 | BIO_printf(bio_err, | ||
1167 | "Error getting public key\n"); | ||
1168 | ERR_print_errors(bio_err); | ||
1169 | goto end; | ||
1170 | } | ||
1171 | PEM_write_bio_PUBKEY(STDout, pubkey); | ||
1172 | } else if (cfg.text == i) { | ||
1173 | if(!X509_print_ex(STDout, x, cfg.nmflag, | ||
1174 | cfg.certflag)) | ||
1175 | goto end; | ||
1176 | } else if (cfg.startdate == i) { | ||
1177 | ASN1_TIME *nB = X509_get_notBefore(x); | ||
1178 | |||
1179 | BIO_puts(STDout, "notBefore="); | ||
1180 | if (!ASN1_TIME_to_tm(nB, NULL)) | ||
1181 | BIO_puts(STDout, | ||
1182 | "INVALID RFC5280 TIME"); | ||
1183 | else | ||
1184 | ASN1_TIME_print(STDout, nB); | ||
1185 | BIO_puts(STDout, "\n"); | ||
1186 | } else if (cfg.enddate == i) { | ||
1187 | ASN1_TIME *nA = X509_get_notAfter(x); | ||
1188 | |||
1189 | BIO_puts(STDout, "notAfter="); | ||
1190 | if (!ASN1_TIME_to_tm(nA, NULL)) | ||
1191 | BIO_puts(STDout, | ||
1192 | "INVALID RFC5280 TIME"); | ||
1193 | else | ||
1194 | ASN1_TIME_print(STDout, nA); | ||
1195 | BIO_puts(STDout, "\n"); | ||
1196 | } else if (cfg.fingerprint == i) { | ||
1197 | int j; | ||
1198 | unsigned int n; | ||
1199 | unsigned char md[EVP_MAX_MD_SIZE]; | ||
1200 | const EVP_MD *fdig = cfg.digest; | ||
1201 | |||
1202 | if (fdig == NULL) | ||
1203 | fdig = EVP_sha256(); | ||
1204 | |||
1205 | if (!X509_digest(x, fdig, md, &n)) { | ||
1206 | BIO_printf(bio_err, "out of memory\n"); | ||
1207 | goto end; | ||
1208 | } | ||
1209 | BIO_printf(STDout, "%s Fingerprint=", | ||
1210 | OBJ_nid2sn(EVP_MD_type(fdig))); | ||
1211 | for (j = 0; j < (int) n; j++) { | ||
1212 | BIO_printf(STDout, "%02X%c", md[j], | ||
1213 | (j + 1 == (int)n) ? '\n' : ':'); | ||
1214 | } | ||
1215 | } else if (cfg.sign_flag == i && cfg.x509req == 0) { | ||
1216 | if (Upkey == NULL) { | ||
1217 | Upkey = load_key(bio_err, cfg.keyfile, | ||
1218 | cfg.keyformat, 0, passin, | ||
1219 | "Private key"); | ||
1220 | if (Upkey == NULL) | ||
1221 | goto end; | ||
1222 | } | ||
1223 | if (!sign(x, Upkey, cfg.days, | ||
1224 | cfg.clrext, cfg.digest, | ||
1225 | extconf, cfg.extsect, iname, | ||
1226 | cfg.force_pubkey)) | ||
1227 | goto end; | ||
1228 | } else if (cfg.CA_flag == i) { | ||
1229 | if (cfg.CAkeyfile != NULL) { | ||
1230 | CApkey = load_key(bio_err, cfg.CAkeyfile, | ||
1231 | cfg.CAkeyformat, 0, passin, | ||
1232 | "CA Private Key"); | ||
1233 | if (CApkey == NULL) | ||
1234 | goto end; | ||
1235 | } | ||
1236 | if (!x509_certify(ctx, cfg.CAfile, cfg.digest, | ||
1237 | x, xca, CApkey, cfg.sigopts, cfg.CAserial, | ||
1238 | cfg.CA_createserial, cfg.days, cfg.clrext, | ||
1239 | extconf, cfg.extsect, cfg.sno, iname)) | ||
1240 | goto end; | ||
1241 | } else if (cfg.x509req == i) { | ||
1242 | EVP_PKEY *pk; | ||
1243 | |||
1244 | BIO_printf(bio_err, | ||
1245 | "Getting request Private Key\n"); | ||
1246 | if (cfg.keyfile == NULL) { | ||
1247 | BIO_printf(bio_err, | ||
1248 | "no request key file specified\n"); | ||
1249 | goto end; | ||
1250 | } else { | ||
1251 | pk = load_key(bio_err, cfg.keyfile, | ||
1252 | cfg.keyformat, 0, passin, | ||
1253 | "request key"); | ||
1254 | if (pk == NULL) | ||
1255 | goto end; | ||
1256 | } | ||
1257 | |||
1258 | BIO_printf(bio_err, | ||
1259 | "Generating certificate request\n"); | ||
1260 | |||
1261 | rq = X509_to_X509_REQ(x, pk, cfg.digest); | ||
1262 | EVP_PKEY_free(pk); | ||
1263 | if (rq == NULL) { | ||
1264 | ERR_print_errors(bio_err); | ||
1265 | goto end; | ||
1266 | } | ||
1267 | if (!cfg.noout) { | ||
1268 | if (!X509_REQ_print(out, rq)) | ||
1269 | goto end; | ||
1270 | if (!PEM_write_bio_X509_REQ(out, rq)) | ||
1271 | goto end; | ||
1272 | } | ||
1273 | cfg.noout = 1; | ||
1274 | } else if (cfg.ocspid == i) { | ||
1275 | if (!X509_ocspid_print(out, x)) | ||
1276 | goto end; | ||
1277 | } | ||
1278 | } | ||
1279 | } | ||
1280 | if (cfg.checkend) { | ||
1281 | time_t tcheck = time(NULL) + cfg.checkoffset; | ||
1282 | int timecheck = X509_cmp_time(X509_get_notAfter(x), &tcheck); | ||
1283 | if (timecheck == 0) { | ||
1284 | BIO_printf(out, "Certificate expiry time is invalid\n"); | ||
1285 | ret = 1; | ||
1286 | } else if (timecheck < 0) { | ||
1287 | BIO_printf(out, "Certificate will expire\n"); | ||
1288 | ret = 1; | ||
1289 | } else { | ||
1290 | BIO_printf(out, "Certificate will not expire\n"); | ||
1291 | ret = 0; | ||
1292 | } | ||
1293 | goto end; | ||
1294 | } | ||
1295 | if (cfg.noout) { | ||
1296 | ret = 0; | ||
1297 | goto end; | ||
1298 | } | ||
1299 | if (cfg.outformat == FORMAT_ASN1) | ||
1300 | i = i2d_X509_bio(out, x); | ||
1301 | else if (cfg.outformat == FORMAT_PEM) { | ||
1302 | if (cfg.trustout) | ||
1303 | i = PEM_write_bio_X509_AUX(out, x); | ||
1304 | else | ||
1305 | i = PEM_write_bio_X509(out, x); | ||
1306 | } else { | ||
1307 | BIO_printf(bio_err, | ||
1308 | "bad output format specified for outfile\n"); | ||
1309 | goto end; | ||
1310 | } | ||
1311 | if (!i) { | ||
1312 | BIO_printf(bio_err, "unable to write certificate\n"); | ||
1313 | ERR_print_errors(bio_err); | ||
1314 | goto end; | ||
1315 | } | ||
1316 | ret = 0; | ||
1317 | |||
1318 | end: | ||
1319 | OBJ_cleanup(); | ||
1320 | NCONF_free(extconf); | ||
1321 | BIO_free_all(out); | ||
1322 | BIO_free_all(STDout); | ||
1323 | X509_NAME_free(iname); | ||
1324 | X509_NAME_free(sname); | ||
1325 | X509_STORE_free(ctx); | ||
1326 | X509_REQ_free(req); | ||
1327 | X509_free(x); | ||
1328 | X509_free(xca); | ||
1329 | EVP_PKEY_free(Fpkey); | ||
1330 | EVP_PKEY_free(Upkey); | ||
1331 | EVP_PKEY_free(CApkey); | ||
1332 | sk_OPENSSL_STRING_free(cfg.sigopts); | ||
1333 | X509_REQ_free(rq); | ||
1334 | ASN1_INTEGER_free(cfg.sno); | ||
1335 | sk_ASN1_OBJECT_pop_free(cfg.trust, ASN1_OBJECT_free); | ||
1336 | sk_ASN1_OBJECT_pop_free(cfg.reject, ASN1_OBJECT_free); | ||
1337 | free(passin); | ||
1338 | |||
1339 | return (ret); | ||
1340 | } | ||
1341 | |||
1342 | static ASN1_INTEGER * | ||
1343 | x509_load_serial(char *CAfile, char *serialfile, int create) | ||
1344 | { | ||
1345 | char *buf = NULL, *p; | ||
1346 | ASN1_INTEGER *bs = NULL; | ||
1347 | BIGNUM *serial = NULL; | ||
1348 | size_t len; | ||
1349 | |||
1350 | len = ((serialfile == NULL) ? (strlen(CAfile) + strlen(POSTFIX) + 1) : | ||
1351 | (strlen(serialfile))) + 1; | ||
1352 | buf = malloc(len); | ||
1353 | if (buf == NULL) { | ||
1354 | BIO_printf(bio_err, "out of mem\n"); | ||
1355 | goto end; | ||
1356 | } | ||
1357 | if (serialfile == NULL) { | ||
1358 | strlcpy(buf, CAfile, len); | ||
1359 | for (p = buf; *p; p++) | ||
1360 | if (*p == '.') { | ||
1361 | *p = '\0'; | ||
1362 | break; | ||
1363 | } | ||
1364 | strlcat(buf, POSTFIX, len); | ||
1365 | } else | ||
1366 | strlcpy(buf, serialfile, len); | ||
1367 | |||
1368 | serial = load_serial(buf, create, NULL); | ||
1369 | if (serial == NULL) | ||
1370 | goto end; | ||
1371 | |||
1372 | if (!BN_add_word(serial, 1)) { | ||
1373 | BIO_printf(bio_err, "add_word failure\n"); | ||
1374 | goto end; | ||
1375 | } | ||
1376 | if (!save_serial(buf, NULL, serial, &bs)) | ||
1377 | goto end; | ||
1378 | |||
1379 | end: | ||
1380 | free(buf); | ||
1381 | BN_free(serial); | ||
1382 | |||
1383 | return bs; | ||
1384 | } | ||
1385 | |||
1386 | static int | ||
1387 | x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, X509 *x, | ||
1388 | X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts, | ||
1389 | char *serialfile, int create, int days, int clrext, CONF *conf, | ||
1390 | char *section, ASN1_INTEGER *sno, X509_NAME *issuer) | ||
1391 | { | ||
1392 | int ret = 0; | ||
1393 | ASN1_INTEGER *bs = NULL; | ||
1394 | X509_STORE_CTX *xsc = NULL; | ||
1395 | EVP_PKEY *upkey; | ||
1396 | |||
1397 | upkey = X509_get0_pubkey(xca); | ||
1398 | if (upkey == NULL) | ||
1399 | goto end; | ||
1400 | EVP_PKEY_copy_parameters(upkey, pkey); | ||
1401 | |||
1402 | if ((xsc = X509_STORE_CTX_new()) == NULL) | ||
1403 | goto end; | ||
1404 | if (!X509_STORE_CTX_init(xsc, ctx, x, NULL)) { | ||
1405 | BIO_printf(bio_err, "Error initialising X509 store\n"); | ||
1406 | goto end; | ||
1407 | } | ||
1408 | if (sno != NULL) | ||
1409 | bs = sno; | ||
1410 | else if ((bs = x509_load_serial(CAfile, serialfile, create)) == NULL) | ||
1411 | goto end; | ||
1412 | |||
1413 | /* if (!X509_STORE_add_cert(ctx,x)) goto end;*/ | ||
1414 | |||
1415 | /* | ||
1416 | * NOTE: this certificate can/should be self signed, unless it was a | ||
1417 | * certificate request in which case it is not. | ||
1418 | */ | ||
1419 | X509_STORE_CTX_set_cert(xsc, x); | ||
1420 | X509_STORE_CTX_set_flags(xsc, X509_V_FLAG_CHECK_SS_SIGNATURE); | ||
1421 | if (!cfg.reqfile && X509_verify_cert(xsc) <= 0) | ||
1422 | goto end; | ||
1423 | |||
1424 | if (!X509_check_private_key(xca, pkey)) { | ||
1425 | BIO_printf(bio_err, | ||
1426 | "CA certificate and CA private key do not match\n"); | ||
1427 | goto end; | ||
1428 | } | ||
1429 | |||
1430 | if (issuer == NULL) | ||
1431 | issuer = X509_get_subject_name(xca); | ||
1432 | if (issuer == NULL) | ||
1433 | goto end; | ||
1434 | if (!X509_set_issuer_name(x, issuer)) | ||
1435 | goto end; | ||
1436 | |||
1437 | if (!X509_set_serialNumber(x, bs)) | ||
1438 | goto end; | ||
1439 | |||
1440 | if (X509_gmtime_adj(X509_get_notBefore(x), 0L) == NULL) | ||
1441 | goto end; | ||
1442 | |||
1443 | /* hardwired expired */ | ||
1444 | if (X509_time_adj_ex(X509_get_notAfter(x), days, 0, NULL) == NULL) | ||
1445 | goto end; | ||
1446 | |||
1447 | if (clrext) { | ||
1448 | while (X509_get_ext_count(x) > 0) { | ||
1449 | if (X509_delete_ext(x, 0) == NULL) | ||
1450 | goto end; | ||
1451 | } | ||
1452 | } | ||
1453 | if (conf != NULL) { | ||
1454 | X509V3_CTX ctx2; | ||
1455 | if (!X509_set_version(x, 2)) /* version 3 certificate */ | ||
1456 | goto end; | ||
1457 | X509V3_set_ctx(&ctx2, xca, x, NULL, NULL, 0); | ||
1458 | X509V3_set_nconf(&ctx2, conf); | ||
1459 | if (!X509V3_EXT_add_nconf(conf, &ctx2, section, x)) | ||
1460 | goto end; | ||
1461 | } | ||
1462 | if (!do_X509_sign(bio_err, x, pkey, digest, sigopts)) | ||
1463 | goto end; | ||
1464 | |||
1465 | ret = 1; | ||
1466 | end: | ||
1467 | X509_STORE_CTX_free(xsc); | ||
1468 | if (!ret) | ||
1469 | ERR_print_errors(bio_err); | ||
1470 | if (sno == NULL) | ||
1471 | ASN1_INTEGER_free(bs); | ||
1472 | return ret; | ||
1473 | } | ||
1474 | |||
1475 | static int | ||
1476 | callb(int ok, X509_STORE_CTX *ctx) | ||
1477 | { | ||
1478 | int err; | ||
1479 | X509 *err_cert; | ||
1480 | |||
1481 | /* | ||
1482 | * it is ok to use a self signed certificate This case will catch | ||
1483 | * both the initial ok == 0 and the final ok == 1 calls to this | ||
1484 | * function | ||
1485 | */ | ||
1486 | err = X509_STORE_CTX_get_error(ctx); | ||
1487 | if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) | ||
1488 | return 1; | ||
1489 | |||
1490 | /* | ||
1491 | * BAD we should have gotten an error. Normally if everything worked | ||
1492 | * X509_STORE_CTX_get_error(ctx) will still be set to | ||
1493 | * DEPTH_ZERO_SELF_.... | ||
1494 | */ | ||
1495 | if (ok) { | ||
1496 | BIO_printf(bio_err, | ||
1497 | "error with certificate to be certified - should be self signed\n"); | ||
1498 | return 0; | ||
1499 | } else { | ||
1500 | err_cert = X509_STORE_CTX_get_current_cert(ctx); | ||
1501 | print_name(bio_err, NULL, X509_get_subject_name(err_cert), 0); | ||
1502 | BIO_printf(bio_err, | ||
1503 | "error with certificate - error %d at depth %d\n%s\n", | ||
1504 | err, X509_STORE_CTX_get_error_depth(ctx), | ||
1505 | X509_verify_cert_error_string(err)); | ||
1506 | return 1; | ||
1507 | } | ||
1508 | } | ||
1509 | |||
1510 | static int | ||
1511 | key_identifier_hash(EVP_PKEY *pkey, unsigned char *md, unsigned int *md_len) | ||
1512 | { | ||
1513 | X509_PUBKEY *x509_pubkey = NULL; | ||
1514 | const unsigned char *der; | ||
1515 | int der_len; | ||
1516 | int ret = 0; | ||
1517 | |||
1518 | if (*md_len < SHA_DIGEST_LENGTH) | ||
1519 | goto err; | ||
1520 | |||
1521 | if (!X509_PUBKEY_set(&x509_pubkey, pkey)) | ||
1522 | goto err; | ||
1523 | if (!X509_PUBKEY_get0_param(NULL, &der, &der_len, NULL, x509_pubkey)) | ||
1524 | goto err; | ||
1525 | if (!EVP_Digest(der, der_len, md, md_len, EVP_sha1(), NULL)) | ||
1526 | goto err; | ||
1527 | |||
1528 | ret = 1; | ||
1529 | |||
1530 | err: | ||
1531 | X509_PUBKEY_free(x509_pubkey); | ||
1532 | |||
1533 | return ret; | ||
1534 | } | ||
1535 | |||
1536 | static ASN1_OCTET_STRING * | ||
1537 | compute_key_identifier(EVP_PKEY *pkey) | ||
1538 | { | ||
1539 | ASN1_OCTET_STRING *ki = NULL; | ||
1540 | unsigned char md[EVP_MAX_MD_SIZE]; | ||
1541 | unsigned int md_len = EVP_MAX_MD_SIZE; | ||
1542 | |||
1543 | if (!key_identifier_hash(pkey, md, &md_len)) | ||
1544 | goto err; | ||
1545 | |||
1546 | if ((ki = ASN1_OCTET_STRING_new()) == NULL) | ||
1547 | goto err; | ||
1548 | if (!ASN1_STRING_set(ki, md, md_len)) | ||
1549 | goto err; | ||
1550 | |||
1551 | return ki; | ||
1552 | |||
1553 | err: | ||
1554 | ASN1_OCTET_STRING_free(ki); | ||
1555 | |||
1556 | return NULL; | ||
1557 | } | ||
1558 | |||
1559 | static ASN1_OCTET_STRING * | ||
1560 | compute_subject_key_identifier(EVP_PKEY *subject_key) | ||
1561 | { | ||
1562 | return compute_key_identifier(subject_key); | ||
1563 | } | ||
1564 | |||
1565 | static AUTHORITY_KEYID * | ||
1566 | compute_authority_key_identifier(EVP_PKEY *issuer_key) | ||
1567 | { | ||
1568 | AUTHORITY_KEYID *aki = NULL; | ||
1569 | |||
1570 | if ((aki = AUTHORITY_KEYID_new()) == NULL) | ||
1571 | goto err; | ||
1572 | if ((aki->keyid = compute_key_identifier(issuer_key)) == NULL) | ||
1573 | goto err; | ||
1574 | |||
1575 | return aki; | ||
1576 | |||
1577 | err: | ||
1578 | AUTHORITY_KEYID_free(aki); | ||
1579 | |||
1580 | return NULL; | ||
1581 | } | ||
1582 | |||
1583 | static int | ||
1584 | set_key_identifiers(X509 *cert, EVP_PKEY *issuer_key) | ||
1585 | { | ||
1586 | EVP_PKEY *subject_key; | ||
1587 | ASN1_OCTET_STRING *ski = NULL; | ||
1588 | AUTHORITY_KEYID *aki = NULL; | ||
1589 | int ret = 0; | ||
1590 | |||
1591 | if ((subject_key = X509_get0_pubkey(cert)) == NULL) | ||
1592 | goto err; | ||
1593 | |||
1594 | if ((ski = compute_subject_key_identifier(subject_key)) == NULL) | ||
1595 | goto err; | ||
1596 | if (!X509_add1_ext_i2d(cert, NID_subject_key_identifier, ski, 0, | ||
1597 | X509V3_ADD_REPLACE)) | ||
1598 | goto err; | ||
1599 | |||
1600 | /* | ||
1601 | * Historical OpenSSL behavior: don't set AKI if we're self-signing. | ||
1602 | * RFC 5280 says we MAY omit it, so this is ok. | ||
1603 | */ | ||
1604 | if (EVP_PKEY_cmp(subject_key, issuer_key) == 1) | ||
1605 | goto done; | ||
1606 | |||
1607 | if ((aki = compute_authority_key_identifier(issuer_key)) == NULL) | ||
1608 | goto err; | ||
1609 | if (!X509_add1_ext_i2d(cert, NID_authority_key_identifier, aki, 0, | ||
1610 | X509V3_ADD_REPLACE)) | ||
1611 | goto err; | ||
1612 | |||
1613 | done: | ||
1614 | ret = 1; | ||
1615 | |||
1616 | err: | ||
1617 | ASN1_OCTET_STRING_free(ski); | ||
1618 | AUTHORITY_KEYID_free(aki); | ||
1619 | |||
1620 | return ret; | ||
1621 | } | ||
1622 | |||
1623 | static int | ||
1624 | sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *digest, | ||
1625 | CONF *conf, char *section, X509_NAME *issuer, char *force_pubkey) | ||
1626 | { | ||
1627 | EVP_PKEY *pktmp; | ||
1628 | |||
1629 | pktmp = X509_get0_pubkey(x); | ||
1630 | if (pktmp == NULL) | ||
1631 | goto err; | ||
1632 | EVP_PKEY_copy_parameters(pktmp, pkey); | ||
1633 | EVP_PKEY_save_parameters(pktmp, 1); | ||
1634 | |||
1635 | if (issuer == NULL) | ||
1636 | issuer = X509_get_subject_name(x); | ||
1637 | if (issuer == NULL) | ||
1638 | goto err; | ||
1639 | if (!X509_set_issuer_name(x, issuer)) | ||
1640 | goto err; | ||
1641 | if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL) | ||
1642 | goto err; | ||
1643 | |||
1644 | if (X509_gmtime_adj(X509_get_notAfter(x), 60L * 60 * 24 * days) == NULL) | ||
1645 | goto err; | ||
1646 | |||
1647 | if (force_pubkey == NULL) { | ||
1648 | if (!X509_set_pubkey(x, pkey)) | ||
1649 | goto err; | ||
1650 | } | ||
1651 | if (clrext) { | ||
1652 | while (X509_get_ext_count(x) > 0) { | ||
1653 | if (X509_delete_ext(x, 0) == NULL) | ||
1654 | goto err; | ||
1655 | } | ||
1656 | } | ||
1657 | if (conf != NULL) { | ||
1658 | X509V3_CTX ctx; | ||
1659 | |||
1660 | if (!X509_set_version(x, 2)) /* version 3 certificate */ | ||
1661 | goto err; | ||
1662 | X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0); | ||
1663 | X509V3_set_nconf(&ctx, conf); | ||
1664 | if (!X509V3_EXT_add_nconf(conf, &ctx, section, x)) | ||
1665 | goto err; | ||
1666 | if (force_pubkey != NULL) { | ||
1667 | /* | ||
1668 | * Set or fix up SKI and AKI. | ||
1669 | * | ||
1670 | * XXX - Doing this in a fully OpenSSL 3 compatible way | ||
1671 | * is extremely nasty: they hang an issuer_pubkey off | ||
1672 | * the X509V3_CTX and adjusted v2i_AUTHORITY_KEYID(). | ||
1673 | * Punt on this and make things work in the specific | ||
1674 | * situation we're interested in. Like OpenSSL, we only | ||
1675 | * support the keyid form of the AKI, which is what | ||
1676 | * RFC 5280 recommends, but unlike OpenSSL we replace | ||
1677 | * existing SKI and AKI rather than honoring the most | ||
1678 | * likely outdated ones already present in the cert. | ||
1679 | */ | ||
1680 | if (!set_key_identifiers(x, pkey)) | ||
1681 | goto err; | ||
1682 | } | ||
1683 | } | ||
1684 | if (!X509_sign(x, pkey, digest)) | ||
1685 | goto err; | ||
1686 | |||
1687 | return 1; | ||
1688 | |||
1689 | err: | ||
1690 | ERR_print_errors(bio_err); | ||
1691 | return 0; | ||
1692 | } | ||
1693 | |||
1694 | static int | ||
1695 | purpose_print(BIO *bio, X509 *cert, const X509_PURPOSE *pt) | ||
1696 | { | ||
1697 | int id, i, idret; | ||
1698 | const char *pname; | ||
1699 | |||
1700 | id = X509_PURPOSE_get_id(pt); | ||
1701 | pname = X509_PURPOSE_get0_name(pt); | ||
1702 | for (i = 0; i < 2; i++) { | ||
1703 | idret = X509_check_purpose(cert, id, i); | ||
1704 | BIO_printf(bio, "%s%s : ", pname, i ? " CA" : ""); | ||
1705 | if (idret == 1) | ||
1706 | BIO_printf(bio, "Yes\n"); | ||
1707 | else if (idret == 0) | ||
1708 | BIO_printf(bio, "No\n"); | ||
1709 | else | ||
1710 | BIO_printf(bio, "Yes (WARNING code=%d)\n", idret); | ||
1711 | } | ||
1712 | return 1; | ||
1713 | } | ||