diff options
Diffstat (limited to 'src/usr.bin/openssl/req.c')
-rw-r--r-- | src/usr.bin/openssl/req.c | 1879 |
1 files changed, 0 insertions, 1879 deletions
diff --git a/src/usr.bin/openssl/req.c b/src/usr.bin/openssl/req.c deleted file mode 100644 index 1044f145ab..0000000000 --- a/src/usr.bin/openssl/req.c +++ /dev/null | |||
@@ -1,1879 +0,0 @@ | |||
1 | /* $OpenBSD: req.c,v 1.29 2024/04/17 01:24:43 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 | /* Until the key-gen callbacks are modified to use newer prototypes, we allow | ||
60 | * deprecated functions for openssl-internal code */ | ||
61 | #ifdef OPENSSL_NO_DEPRECATED | ||
62 | #undef OPENSSL_NO_DEPRECATED | ||
63 | #endif | ||
64 | |||
65 | #include <ctype.h> | ||
66 | #include <limits.h> | ||
67 | #include <stdio.h> | ||
68 | #include <stdlib.h> | ||
69 | #include <string.h> | ||
70 | #include <time.h> | ||
71 | |||
72 | #include "apps.h" | ||
73 | |||
74 | #include <openssl/asn1.h> | ||
75 | #include <openssl/bio.h> | ||
76 | #include <openssl/bn.h> | ||
77 | #include <openssl/conf.h> | ||
78 | #include <openssl/err.h> | ||
79 | #include <openssl/evp.h> | ||
80 | #include <openssl/objects.h> | ||
81 | #include <openssl/pem.h> | ||
82 | #include <openssl/x509.h> | ||
83 | #include <openssl/x509v3.h> | ||
84 | |||
85 | #include <openssl/dsa.h> | ||
86 | |||
87 | #include <openssl/rsa.h> | ||
88 | |||
89 | #define SECTION "req" | ||
90 | |||
91 | #define BITS "default_bits" | ||
92 | #define KEYFILE "default_keyfile" | ||
93 | #define PROMPT "prompt" | ||
94 | #define DISTINGUISHED_NAME "distinguished_name" | ||
95 | #define ATTRIBUTES "attributes" | ||
96 | #define V3_EXTENSIONS "x509_extensions" | ||
97 | #define REQ_EXTENSIONS "req_extensions" | ||
98 | #define STRING_MASK "string_mask" | ||
99 | #define UTF8_IN "utf8" | ||
100 | |||
101 | #define DEFAULT_KEY_LENGTH 2048 | ||
102 | #define MIN_KEY_LENGTH 384 | ||
103 | |||
104 | static int make_REQ(X509_REQ * req, EVP_PKEY * pkey, char *dn, int multirdn, | ||
105 | int attribs, unsigned long chtype); | ||
106 | static int build_subject(X509_REQ * req, char *subj, unsigned long chtype, | ||
107 | int multirdn); | ||
108 | static int prompt_info(X509_REQ * req, | ||
109 | STACK_OF(CONF_VALUE) * dn_sk, char *dn_sect, | ||
110 | STACK_OF(CONF_VALUE) * attr_sk, char *attr_sect, int attribs, | ||
111 | unsigned long chtype); | ||
112 | static int auto_info(X509_REQ * req, STACK_OF(CONF_VALUE) * sk, | ||
113 | STACK_OF(CONF_VALUE) * attr, int attribs, | ||
114 | unsigned long chtype); | ||
115 | static int add_attribute_object(X509_REQ * req, char *text, const char *def, | ||
116 | char *value, int nid, int n_min, | ||
117 | int n_max, unsigned long chtype); | ||
118 | static int add_DN_object(X509_NAME * n, char *text, const char *def, char *value, | ||
119 | int nid, int n_min, int n_max, unsigned long chtype, int mval); | ||
120 | static int genpkey_cb(EVP_PKEY_CTX * ctx); | ||
121 | static int req_check_len(int len, int n_min, int n_max); | ||
122 | static int check_end(const char *str, const char *end); | ||
123 | static EVP_PKEY_CTX *set_keygen_ctx(BIO * err, const char *gstr, int *pkey_type, | ||
124 | long *pkeylen, char **palgnam); | ||
125 | static unsigned long ext_name_hash(const OPENSSL_STRING *a); | ||
126 | static int ext_name_cmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b); | ||
127 | static void exts_cleanup(OPENSSL_STRING *x); | ||
128 | static int duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv); | ||
129 | static CONF *req_conf = NULL; | ||
130 | static CONF *addext_conf = NULL; | ||
131 | |||
132 | static struct { | ||
133 | LHASH_OF(OPENSSL_STRING) *addexts; | ||
134 | BIO *addext_bio; | ||
135 | int batch; | ||
136 | unsigned long chtype; | ||
137 | int days; | ||
138 | const EVP_MD *digest; | ||
139 | char *extensions; | ||
140 | char *infile; | ||
141 | int informat; | ||
142 | char *keyalg; | ||
143 | char *keyfile; | ||
144 | int keyform; | ||
145 | char *keyout; | ||
146 | int modulus; | ||
147 | int multirdn; | ||
148 | int newhdr; | ||
149 | long newkey; | ||
150 | int newreq; | ||
151 | unsigned long nmflag; | ||
152 | int nodes; | ||
153 | int noout; | ||
154 | char *outfile; | ||
155 | int outformat; | ||
156 | char *passargin; | ||
157 | char *passargout; | ||
158 | STACK_OF(OPENSSL_STRING) *pkeyopts; | ||
159 | int pubkey; | ||
160 | char *req_exts; | ||
161 | unsigned long reqflag; | ||
162 | ASN1_INTEGER *serial; | ||
163 | STACK_OF(OPENSSL_STRING) *sigopts; | ||
164 | char *subj; | ||
165 | int subject; | ||
166 | char *template; | ||
167 | int text; | ||
168 | int verbose; | ||
169 | int verify; | ||
170 | int x509; | ||
171 | } cfg; | ||
172 | |||
173 | static int | ||
174 | req_opt_addext(char *arg) | ||
175 | { | ||
176 | int i; | ||
177 | |||
178 | if (cfg.addexts == NULL) { | ||
179 | cfg.addexts = (LHASH_OF(OPENSSL_STRING) *)lh_new( | ||
180 | (LHASH_HASH_FN_TYPE)ext_name_hash, | ||
181 | (LHASH_COMP_FN_TYPE)ext_name_cmp); | ||
182 | cfg.addext_bio = BIO_new(BIO_s_mem()); | ||
183 | if (cfg.addexts == NULL || | ||
184 | cfg.addext_bio == NULL) | ||
185 | return (1); | ||
186 | } | ||
187 | i = duplicated(cfg.addexts, arg); | ||
188 | if (i == 1) | ||
189 | return (1); | ||
190 | if (i < 0 || BIO_printf(cfg.addext_bio, "%s\n", arg) < 0) | ||
191 | return (1); | ||
192 | |||
193 | return (0); | ||
194 | } | ||
195 | |||
196 | static int | ||
197 | req_opt_days(char *arg) | ||
198 | { | ||
199 | const char *errstr; | ||
200 | |||
201 | cfg.days = strtonum(arg, 1, INT_MAX, &errstr); | ||
202 | if (errstr != NULL) { | ||
203 | BIO_printf(bio_err, "bad -days %s, using 0: %s\n", | ||
204 | arg, errstr); | ||
205 | cfg.days = 30; | ||
206 | } | ||
207 | return (0); | ||
208 | } | ||
209 | |||
210 | static int | ||
211 | req_opt_digest(int argc, char **argv, int *argsused) | ||
212 | { | ||
213 | char *name = argv[0]; | ||
214 | |||
215 | if (*name++ != '-') | ||
216 | return (1); | ||
217 | |||
218 | if ((cfg.digest = EVP_get_digestbyname(name)) == NULL) | ||
219 | return (1); | ||
220 | |||
221 | *argsused = 1; | ||
222 | return (0); | ||
223 | } | ||
224 | |||
225 | static int | ||
226 | req_opt_newkey(char *arg) | ||
227 | { | ||
228 | cfg.keyalg = arg; | ||
229 | cfg.newreq = 1; | ||
230 | return (0); | ||
231 | } | ||
232 | |||
233 | static int | ||
234 | req_opt_nameopt(char *arg) | ||
235 | { | ||
236 | if (!set_name_ex(&cfg.nmflag, arg)) | ||
237 | return (1); | ||
238 | return (0); | ||
239 | } | ||
240 | |||
241 | static int | ||
242 | req_opt_pkeyopt(char *arg) | ||
243 | { | ||
244 | if (cfg.pkeyopts == NULL) | ||
245 | cfg.pkeyopts = sk_OPENSSL_STRING_new_null(); | ||
246 | if (cfg.pkeyopts == NULL) | ||
247 | return (1); | ||
248 | if (!sk_OPENSSL_STRING_push(cfg.pkeyopts, arg)) | ||
249 | return (1); | ||
250 | return (0); | ||
251 | } | ||
252 | |||
253 | static int | ||
254 | req_opt_reqopt(char *arg) | ||
255 | { | ||
256 | if (!set_cert_ex(&cfg.reqflag, arg)) | ||
257 | return (1); | ||
258 | return (0); | ||
259 | } | ||
260 | |||
261 | static int | ||
262 | req_opt_set_serial(char *arg) | ||
263 | { | ||
264 | cfg.serial = s2i_ASN1_INTEGER(NULL, arg); | ||
265 | if (cfg.serial == NULL) | ||
266 | return (1); | ||
267 | return (0); | ||
268 | } | ||
269 | |||
270 | static int | ||
271 | req_opt_sigopt(char *arg) | ||
272 | { | ||
273 | if (cfg.sigopts == NULL) | ||
274 | cfg.sigopts = sk_OPENSSL_STRING_new_null(); | ||
275 | if (cfg.sigopts == NULL) | ||
276 | return (1); | ||
277 | if (!sk_OPENSSL_STRING_push(cfg.sigopts, arg)) | ||
278 | return (1); | ||
279 | return (0); | ||
280 | } | ||
281 | |||
282 | static int | ||
283 | req_opt_utf8(void) | ||
284 | { | ||
285 | cfg.chtype = MBSTRING_UTF8; | ||
286 | return (0); | ||
287 | } | ||
288 | |||
289 | static const struct option req_options[] = { | ||
290 | { | ||
291 | .name = "addext", | ||
292 | .argname = "key=value", | ||
293 | .desc = "Additional certificate extension (may be repeated)", | ||
294 | .type = OPTION_ARG_FUNC, | ||
295 | .opt.argfunc = req_opt_addext, | ||
296 | }, | ||
297 | { | ||
298 | .name = "batch", | ||
299 | .desc = "Operate in batch mode", | ||
300 | .type = OPTION_FLAG, | ||
301 | .opt.flag = &cfg.batch, | ||
302 | }, | ||
303 | { | ||
304 | .name = "config", | ||
305 | .argname = "file", | ||
306 | .desc = "Configuration file to use as request template", | ||
307 | .type = OPTION_ARG, | ||
308 | .opt.arg = &cfg.template, | ||
309 | }, | ||
310 | { | ||
311 | .name = "days", | ||
312 | .argname = "number", | ||
313 | .desc = "Number of days generated certificate is valid for", | ||
314 | .type = OPTION_ARG_FUNC, | ||
315 | .opt.argfunc = req_opt_days, | ||
316 | }, | ||
317 | { | ||
318 | .name = "extensions", | ||
319 | .argname = "section", | ||
320 | .desc = "Config section to use for certificate extensions", | ||
321 | .type = OPTION_ARG, | ||
322 | .opt.arg = &cfg.extensions, | ||
323 | }, | ||
324 | { | ||
325 | .name = "in", | ||
326 | .argname = "file", | ||
327 | .desc = "Input file (default stdin)", | ||
328 | .type = OPTION_ARG, | ||
329 | .opt.arg = &cfg.infile, | ||
330 | }, | ||
331 | { | ||
332 | .name = "inform", | ||
333 | .argname = "format", | ||
334 | .desc = "Input format (DER or PEM (default))", | ||
335 | .type = OPTION_ARG_FORMAT, | ||
336 | .opt.value = &cfg.informat, | ||
337 | }, | ||
338 | { | ||
339 | .name = "key", | ||
340 | .argname = "file", | ||
341 | .desc = "Private key file", | ||
342 | .type = OPTION_ARG, | ||
343 | .opt.arg = &cfg.keyfile, | ||
344 | }, | ||
345 | { | ||
346 | .name = "keyform", | ||
347 | .argname = "format", | ||
348 | .desc = "Private key format (DER or PEM (default))", | ||
349 | .type = OPTION_ARG_FORMAT, | ||
350 | .opt.value = &cfg.keyform, | ||
351 | }, | ||
352 | { | ||
353 | .name = "keyout", | ||
354 | .argname = "file", | ||
355 | .desc = "Private key output file", | ||
356 | .type = OPTION_ARG, | ||
357 | .opt.arg = &cfg.keyout, | ||
358 | }, | ||
359 | { | ||
360 | .name = "modulus", | ||
361 | .desc = "Print RSA modulus", | ||
362 | .type = OPTION_FLAG, | ||
363 | .opt.flag = &cfg.modulus, | ||
364 | }, | ||
365 | { | ||
366 | .name = "multivalue-rdn", | ||
367 | .desc = "Enable support for multivalued RDNs", | ||
368 | .type = OPTION_FLAG, | ||
369 | .opt.flag = &cfg.multirdn, | ||
370 | }, | ||
371 | { | ||
372 | .name = "nameopt", | ||
373 | .argname = "arg", | ||
374 | .desc = "Certificate name options", | ||
375 | .type = OPTION_ARG_FUNC, | ||
376 | .opt.argfunc = req_opt_nameopt, | ||
377 | }, | ||
378 | { | ||
379 | .name = "new", | ||
380 | .desc = "New request", | ||
381 | .type = OPTION_FLAG, | ||
382 | .opt.flag = &cfg.newreq, | ||
383 | }, | ||
384 | { | ||
385 | .name = "newhdr", | ||
386 | .desc = "Include 'NEW' in header lines", | ||
387 | .type = OPTION_FLAG, | ||
388 | .opt.flag = &cfg.newhdr, | ||
389 | }, | ||
390 | { | ||
391 | .name = "newkey", | ||
392 | .argname = "param", | ||
393 | .desc = "Generate a new key using given parameters", | ||
394 | .type = OPTION_ARG_FUNC, | ||
395 | .opt.argfunc = req_opt_newkey, | ||
396 | }, | ||
397 | { | ||
398 | .name = "nodes", | ||
399 | .desc = "Do not encrypt output private key", | ||
400 | .type = OPTION_FLAG, | ||
401 | .opt.flag = &cfg.nodes, | ||
402 | }, | ||
403 | { | ||
404 | .name = "noout", | ||
405 | .desc = "Do not output request", | ||
406 | .type = OPTION_FLAG, | ||
407 | .opt.flag = &cfg.noout, | ||
408 | }, | ||
409 | { | ||
410 | .name = "out", | ||
411 | .argname = "file", | ||
412 | .desc = "Output file (default stdout)", | ||
413 | .type = OPTION_ARG, | ||
414 | .opt.arg = &cfg.outfile, | ||
415 | }, | ||
416 | { | ||
417 | .name = "outform", | ||
418 | .argname = "format", | ||
419 | .desc = "Output format (DER or PEM (default))", | ||
420 | .type = OPTION_ARG_FORMAT, | ||
421 | .opt.value = &cfg.outformat, | ||
422 | }, | ||
423 | { | ||
424 | .name = "passin", | ||
425 | .argname = "source", | ||
426 | .desc = "Private key input password source", | ||
427 | .type = OPTION_ARG, | ||
428 | .opt.arg = &cfg.passargin, | ||
429 | }, | ||
430 | { | ||
431 | .name = "passout", | ||
432 | .argname = "source", | ||
433 | .desc = "Private key output password source", | ||
434 | .type = OPTION_ARG, | ||
435 | .opt.arg = &cfg.passargout, | ||
436 | }, | ||
437 | { | ||
438 | .name = "pkeyopt", | ||
439 | .argname = "opt:val", | ||
440 | .desc = "Set the public key algorithm option opt to val", | ||
441 | .type = OPTION_ARG_FUNC, | ||
442 | .opt.argfunc = req_opt_pkeyopt, | ||
443 | }, | ||
444 | { | ||
445 | .name = "pubkey", | ||
446 | .desc = "Output the public key", | ||
447 | .type = OPTION_FLAG, | ||
448 | .opt.flag = &cfg.pubkey, | ||
449 | }, | ||
450 | { | ||
451 | .name = "reqexts", | ||
452 | .argname = "section", | ||
453 | .desc = "Config section to use for request extensions", | ||
454 | .type = OPTION_ARG, | ||
455 | .opt.arg = &cfg.req_exts, | ||
456 | }, | ||
457 | { | ||
458 | .name = "reqopt", | ||
459 | .argname = "option", | ||
460 | .desc = "Request text options", | ||
461 | .type = OPTION_ARG_FUNC, | ||
462 | .opt.argfunc = req_opt_reqopt, | ||
463 | }, | ||
464 | { | ||
465 | .name = "set_serial", | ||
466 | .argname = "serial", | ||
467 | .desc = "Serial number to use for generated certificate", | ||
468 | .type = OPTION_ARG_FUNC, | ||
469 | .opt.argfunc = req_opt_set_serial, | ||
470 | }, | ||
471 | { | ||
472 | .name = "sigopt", | ||
473 | .argname = "name:val", | ||
474 | .desc = "Signature options", | ||
475 | .type = OPTION_ARG_FUNC, | ||
476 | .opt.argfunc = req_opt_sigopt, | ||
477 | }, | ||
478 | { | ||
479 | .name = "subj", | ||
480 | .argname = "name", | ||
481 | .desc = "Set or modify the request subject", | ||
482 | .type = OPTION_ARG, | ||
483 | .opt.arg = &cfg.subj, | ||
484 | }, | ||
485 | { | ||
486 | .name = "subject", | ||
487 | .desc = "Output the subject of the request", | ||
488 | .type = OPTION_FLAG, | ||
489 | .opt.flag = &cfg.subject, | ||
490 | }, | ||
491 | { | ||
492 | .name = "text", | ||
493 | .desc = "Print request in text form", | ||
494 | .type = OPTION_FLAG, | ||
495 | .opt.flag = &cfg.text, | ||
496 | }, | ||
497 | { | ||
498 | .name = "utf8", | ||
499 | .desc = "Input characters are in UTF-8 (default ASCII)", | ||
500 | .type = OPTION_FUNC, | ||
501 | .opt.func = req_opt_utf8, | ||
502 | }, | ||
503 | { | ||
504 | .name = "verbose", | ||
505 | .desc = "Verbose", | ||
506 | .type = OPTION_FLAG, | ||
507 | .opt.flag = &cfg.verbose, | ||
508 | }, | ||
509 | { | ||
510 | .name = "verify", | ||
511 | .desc = "Verify signature on request", | ||
512 | .type = OPTION_FLAG, | ||
513 | .opt.flag = &cfg.verify, | ||
514 | }, | ||
515 | { | ||
516 | .name = "x509", | ||
517 | .desc = "Output an X.509 structure instead of a certificate request", | ||
518 | .type = OPTION_FLAG, | ||
519 | .opt.flag = &cfg.x509, | ||
520 | }, | ||
521 | { | ||
522 | .name = NULL, | ||
523 | .desc = "", | ||
524 | .type = OPTION_ARGV_FUNC, | ||
525 | .opt.argvfunc = req_opt_digest, | ||
526 | }, | ||
527 | { NULL }, | ||
528 | }; | ||
529 | |||
530 | static void | ||
531 | req_usage(void) | ||
532 | { | ||
533 | fprintf(stderr, | ||
534 | "usage: req [-addext ext] [-batch] [-config file]\n" | ||
535 | " [-days n] [-extensions section] [-in file]\n" | ||
536 | " [-inform der | pem] [-key keyfile] [-keyform der | pem]\n" | ||
537 | " [-keyout file] [-md4 | -md5 | -sha1] [-modulus]\n" | ||
538 | " [-multivalue-rdn] [-nameopt option] [-new] [-newhdr]\n" | ||
539 | " [-newkey arg] [-nodes] [-noout]\n" | ||
540 | " [-out file] [-outform der | pem] [-passin arg]\n" | ||
541 | " [-passout arg] [-pkeyopt opt:value] [-pubkey]\n" | ||
542 | " [-reqexts section] [-reqopt option] [-set_serial n]\n" | ||
543 | " [-sigopt nm:v] [-subj arg] [-subject] [-text] [-utf8]\n" | ||
544 | " [-verbose] [-verify] [-x509]\n\n"); | ||
545 | |||
546 | options_usage(req_options); | ||
547 | fprintf(stderr, "\n"); | ||
548 | } | ||
549 | |||
550 | int | ||
551 | req_main(int argc, char **argv) | ||
552 | { | ||
553 | int ex = 1; | ||
554 | X509 *x509ss = NULL; | ||
555 | X509_REQ *req = NULL; | ||
556 | EVP_PKEY_CTX *genctx = NULL; | ||
557 | char *keyalgstr = NULL; | ||
558 | const EVP_CIPHER *cipher = NULL; | ||
559 | EVP_PKEY *pkey = NULL; | ||
560 | int i = 0, pkey_type = -1; | ||
561 | BIO *in = NULL, *out = NULL; | ||
562 | char *passin = NULL, *passout = NULL; | ||
563 | const EVP_MD *md_alg = NULL; | ||
564 | char *p; | ||
565 | |||
566 | if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { | ||
567 | perror("pledge"); | ||
568 | exit(1); | ||
569 | } | ||
570 | |||
571 | memset(&cfg, 0, sizeof(cfg)); | ||
572 | |||
573 | cfg.chtype = MBSTRING_ASC; | ||
574 | cfg.days = 30; | ||
575 | cfg.digest = EVP_sha256(); | ||
576 | cfg.newkey = -1; | ||
577 | cfg.informat = FORMAT_PEM; | ||
578 | cfg.keyform = FORMAT_PEM; | ||
579 | cfg.outformat = FORMAT_PEM; | ||
580 | |||
581 | if (options_parse(argc, argv, req_options, NULL, NULL) != 0) { | ||
582 | req_usage(); | ||
583 | return (1); | ||
584 | } | ||
585 | |||
586 | req_conf = NULL; | ||
587 | cipher = EVP_aes_256_cbc(); | ||
588 | |||
589 | if (!app_passwd(bio_err, cfg.passargin, cfg.passargout, &passin, &passout)) { | ||
590 | BIO_printf(bio_err, "Error getting passwords\n"); | ||
591 | goto end; | ||
592 | } | ||
593 | if (cfg.template != NULL) { | ||
594 | long errline = -1; | ||
595 | |||
596 | if (cfg.verbose) | ||
597 | BIO_printf(bio_err, "Using configuration from %s\n", cfg.template); | ||
598 | if ((req_conf = NCONF_new(NULL)) == NULL) | ||
599 | goto end; | ||
600 | if(!NCONF_load(req_conf, cfg.template, &errline)) { | ||
601 | BIO_printf(bio_err, "error on line %ld of %s\n", errline, cfg.template); | ||
602 | goto end; | ||
603 | } | ||
604 | } else { | ||
605 | req_conf = config; | ||
606 | |||
607 | if (req_conf == NULL) { | ||
608 | BIO_printf(bio_err, "Unable to load config info from %s\n", default_config_file); | ||
609 | if (cfg.newreq) | ||
610 | goto end; | ||
611 | } else if (cfg.verbose) | ||
612 | BIO_printf(bio_err, "Using configuration from %s\n", | ||
613 | default_config_file); | ||
614 | } | ||
615 | |||
616 | if (cfg.addext_bio != NULL) { | ||
617 | long errline = -1; | ||
618 | if (cfg.verbose) | ||
619 | BIO_printf(bio_err, | ||
620 | "Using additional configuration from command line\n"); | ||
621 | if ((addext_conf = NCONF_new(NULL)) == NULL) | ||
622 | goto end; | ||
623 | if (!NCONF_load_bio(addext_conf, cfg.addext_bio, &errline)) { | ||
624 | BIO_printf(bio_err, | ||
625 | "req: Error on line %ld of config input\n", | ||
626 | errline); | ||
627 | goto end; | ||
628 | } | ||
629 | } | ||
630 | |||
631 | if (req_conf != NULL) { | ||
632 | if (!load_config(bio_err, req_conf)) | ||
633 | goto end; | ||
634 | p = NCONF_get_string(req_conf, NULL, "oid_file"); | ||
635 | if (p == NULL) | ||
636 | ERR_clear_error(); | ||
637 | if (p != NULL) { | ||
638 | BIO *oid_bio; | ||
639 | |||
640 | oid_bio = BIO_new_file(p, "r"); | ||
641 | if (oid_bio == NULL) { | ||
642 | /* | ||
643 | BIO_printf(bio_err,"problems opening %s for extra oid's\n",p); | ||
644 | ERR_print_errors(bio_err); | ||
645 | */ | ||
646 | } else { | ||
647 | OBJ_create_objects(oid_bio); | ||
648 | BIO_free(oid_bio); | ||
649 | } | ||
650 | } | ||
651 | } | ||
652 | if (!add_oid_section(bio_err, req_conf)) | ||
653 | goto end; | ||
654 | |||
655 | if (md_alg == NULL) { | ||
656 | p = NCONF_get_string(req_conf, SECTION, "default_md"); | ||
657 | if (p == NULL) | ||
658 | ERR_clear_error(); | ||
659 | if (p != NULL) { | ||
660 | if ((md_alg = EVP_get_digestbyname(p)) != NULL) | ||
661 | cfg.digest = md_alg; | ||
662 | } | ||
663 | } | ||
664 | if (!cfg.extensions) { | ||
665 | cfg.extensions = NCONF_get_string(req_conf, SECTION, V3_EXTENSIONS); | ||
666 | if (!cfg.extensions) | ||
667 | ERR_clear_error(); | ||
668 | } | ||
669 | if (cfg.extensions) { | ||
670 | /* Check syntax of file */ | ||
671 | X509V3_CTX ctx; | ||
672 | X509V3_set_ctx_test(&ctx); | ||
673 | X509V3_set_nconf(&ctx, req_conf); | ||
674 | if (!X509V3_EXT_add_nconf(req_conf, &ctx, cfg.extensions, NULL)) { | ||
675 | BIO_printf(bio_err, | ||
676 | "Error Loading extension section %s\n", cfg.extensions); | ||
677 | goto end; | ||
678 | } | ||
679 | } | ||
680 | if (addext_conf != NULL) { | ||
681 | /* Check syntax of command line extensions */ | ||
682 | X509V3_CTX ctx; | ||
683 | X509V3_set_ctx_test(&ctx); | ||
684 | X509V3_set_nconf(&ctx, addext_conf); | ||
685 | if (!X509V3_EXT_add_nconf(addext_conf, &ctx, "default", NULL)) { | ||
686 | BIO_printf(bio_err, | ||
687 | "Error Loading command line extensions\n"); | ||
688 | goto end; | ||
689 | } | ||
690 | } | ||
691 | if (!passin) { | ||
692 | passin = NCONF_get_string(req_conf, SECTION, "input_password"); | ||
693 | if (!passin) | ||
694 | ERR_clear_error(); | ||
695 | } | ||
696 | if (!passout) { | ||
697 | passout = NCONF_get_string(req_conf, SECTION, "output_password"); | ||
698 | if (!passout) | ||
699 | ERR_clear_error(); | ||
700 | } | ||
701 | p = NCONF_get_string(req_conf, SECTION, STRING_MASK); | ||
702 | if (!p) | ||
703 | ERR_clear_error(); | ||
704 | |||
705 | if (p && !ASN1_STRING_set_default_mask_asc(p)) { | ||
706 | BIO_printf(bio_err, "Invalid global string mask setting %s\n", p); | ||
707 | goto end; | ||
708 | } | ||
709 | if (cfg.chtype != MBSTRING_UTF8) { | ||
710 | p = NCONF_get_string(req_conf, SECTION, UTF8_IN); | ||
711 | if (!p) | ||
712 | ERR_clear_error(); | ||
713 | else if (!strcmp(p, "yes")) | ||
714 | cfg.chtype = MBSTRING_UTF8; | ||
715 | } | ||
716 | if (!cfg.req_exts) { | ||
717 | cfg.req_exts = NCONF_get_string(req_conf, SECTION, REQ_EXTENSIONS); | ||
718 | if (!cfg.req_exts) | ||
719 | ERR_clear_error(); | ||
720 | } | ||
721 | if (cfg.req_exts) { | ||
722 | /* Check syntax of file */ | ||
723 | X509V3_CTX ctx; | ||
724 | X509V3_set_ctx_test(&ctx); | ||
725 | X509V3_set_nconf(&ctx, req_conf); | ||
726 | if (!X509V3_EXT_add_nconf(req_conf, &ctx, cfg.req_exts, NULL)) { | ||
727 | BIO_printf(bio_err, | ||
728 | "Error Loading request extension section %s\n", | ||
729 | cfg.req_exts); | ||
730 | goto end; | ||
731 | } | ||
732 | } | ||
733 | in = BIO_new(BIO_s_file()); | ||
734 | out = BIO_new(BIO_s_file()); | ||
735 | if ((in == NULL) || (out == NULL)) | ||
736 | goto end; | ||
737 | |||
738 | if (cfg.keyfile != NULL) { | ||
739 | pkey = load_key(bio_err, cfg.keyfile, cfg.keyform, 0, passin, | ||
740 | "Private Key"); | ||
741 | if (!pkey) { | ||
742 | /* | ||
743 | * load_key() has already printed an appropriate | ||
744 | * message | ||
745 | */ | ||
746 | goto end; | ||
747 | } | ||
748 | } | ||
749 | if (cfg.newreq && (pkey == NULL)) { | ||
750 | if (!NCONF_get_number(req_conf, SECTION, BITS, &cfg.newkey)) { | ||
751 | cfg.newkey = DEFAULT_KEY_LENGTH; | ||
752 | } | ||
753 | if (cfg.keyalg) { | ||
754 | genctx = set_keygen_ctx(bio_err, cfg.keyalg, &pkey_type, &cfg.newkey, | ||
755 | &keyalgstr); | ||
756 | if (!genctx) | ||
757 | goto end; | ||
758 | } | ||
759 | if (cfg.newkey < MIN_KEY_LENGTH && (pkey_type == EVP_PKEY_RSA || pkey_type == EVP_PKEY_DSA)) { | ||
760 | BIO_printf(bio_err, "private key length is too short,\n"); | ||
761 | BIO_printf(bio_err, "it needs to be at least %d bits, not %ld\n", MIN_KEY_LENGTH, cfg.newkey); | ||
762 | goto end; | ||
763 | } | ||
764 | if (!genctx) { | ||
765 | genctx = set_keygen_ctx(bio_err, NULL, &pkey_type, &cfg.newkey, | ||
766 | &keyalgstr); | ||
767 | if (!genctx) | ||
768 | goto end; | ||
769 | } | ||
770 | if (cfg.pkeyopts) { | ||
771 | char *genopt; | ||
772 | for (i = 0; i < sk_OPENSSL_STRING_num(cfg.pkeyopts); i++) { | ||
773 | genopt = sk_OPENSSL_STRING_value(cfg.pkeyopts, i); | ||
774 | if (pkey_ctrl_string(genctx, genopt) <= 0) { | ||
775 | BIO_printf(bio_err, | ||
776 | "parameter error \"%s\"\n", | ||
777 | genopt); | ||
778 | ERR_print_errors(bio_err); | ||
779 | goto end; | ||
780 | } | ||
781 | } | ||
782 | } | ||
783 | BIO_printf(bio_err, "Generating a %ld bit %s private key\n", | ||
784 | cfg.newkey, keyalgstr); | ||
785 | |||
786 | EVP_PKEY_CTX_set_cb(genctx, genpkey_cb); | ||
787 | EVP_PKEY_CTX_set_app_data(genctx, bio_err); | ||
788 | |||
789 | if (EVP_PKEY_keygen(genctx, &pkey) <= 0) { | ||
790 | BIO_puts(bio_err, "Error Generating Key\n"); | ||
791 | goto end; | ||
792 | } | ||
793 | EVP_PKEY_CTX_free(genctx); | ||
794 | genctx = NULL; | ||
795 | |||
796 | if (cfg.keyout == NULL) { | ||
797 | cfg.keyout = NCONF_get_string(req_conf, SECTION, KEYFILE); | ||
798 | if (cfg.keyout == NULL) | ||
799 | ERR_clear_error(); | ||
800 | } | ||
801 | if (cfg.keyout == NULL) { | ||
802 | BIO_printf(bio_err, "writing new private key to stdout\n"); | ||
803 | BIO_set_fp(out, stdout, BIO_NOCLOSE); | ||
804 | } else { | ||
805 | BIO_printf(bio_err, "writing new private key to '%s'\n", cfg.keyout); | ||
806 | if (BIO_write_filename(out, cfg.keyout) <= 0) { | ||
807 | perror(cfg.keyout); | ||
808 | goto end; | ||
809 | } | ||
810 | } | ||
811 | |||
812 | p = NCONF_get_string(req_conf, SECTION, "encrypt_rsa_key"); | ||
813 | if (p == NULL) { | ||
814 | ERR_clear_error(); | ||
815 | p = NCONF_get_string(req_conf, SECTION, "encrypt_key"); | ||
816 | if (p == NULL) | ||
817 | ERR_clear_error(); | ||
818 | } | ||
819 | if ((p != NULL) && (strcmp(p, "no") == 0)) | ||
820 | cipher = NULL; | ||
821 | if (cfg.nodes) | ||
822 | cipher = NULL; | ||
823 | |||
824 | i = 0; | ||
825 | loop: | ||
826 | if (!PEM_write_bio_PrivateKey(out, pkey, cipher, | ||
827 | NULL, 0, NULL, passout)) { | ||
828 | if ((ERR_GET_REASON(ERR_peek_error()) == | ||
829 | PEM_R_PROBLEMS_GETTING_PASSWORD) && (i < 3)) { | ||
830 | ERR_clear_error(); | ||
831 | i++; | ||
832 | goto loop; | ||
833 | } | ||
834 | goto end; | ||
835 | } | ||
836 | BIO_printf(bio_err, "-----\n"); | ||
837 | } | ||
838 | if (!cfg.newreq) { | ||
839 | if (cfg.infile == NULL) | ||
840 | BIO_set_fp(in, stdin, BIO_NOCLOSE); | ||
841 | else { | ||
842 | if (BIO_read_filename(in, cfg.infile) <= 0) { | ||
843 | perror(cfg.infile); | ||
844 | goto end; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | if (cfg.informat == FORMAT_ASN1) | ||
849 | req = d2i_X509_REQ_bio(in, NULL); | ||
850 | else if (cfg.informat == FORMAT_PEM) | ||
851 | req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL); | ||
852 | else { | ||
853 | BIO_printf(bio_err, "bad input format specified for X509 request\n"); | ||
854 | goto end; | ||
855 | } | ||
856 | if (req == NULL) { | ||
857 | BIO_printf(bio_err, "unable to load X509 request\n"); | ||
858 | goto end; | ||
859 | } | ||
860 | } | ||
861 | if (cfg.newreq || cfg.x509) { | ||
862 | if (pkey == NULL) { | ||
863 | BIO_printf(bio_err, "you need to specify a private key\n"); | ||
864 | goto end; | ||
865 | } | ||
866 | if (req == NULL) { | ||
867 | req = X509_REQ_new(); | ||
868 | if (req == NULL) { | ||
869 | goto end; | ||
870 | } | ||
871 | i = make_REQ(req, pkey, cfg.subj, cfg.multirdn, !cfg.x509, cfg.chtype); | ||
872 | cfg.subj = NULL; /* done processing '-subj' option */ | ||
873 | if (!i) { | ||
874 | BIO_printf(bio_err, "problems making Certificate Request\n"); | ||
875 | goto end; | ||
876 | } | ||
877 | } | ||
878 | if (cfg.x509) { | ||
879 | EVP_PKEY *tmppkey; | ||
880 | |||
881 | X509V3_CTX ext_ctx; | ||
882 | if ((x509ss = X509_new()) == NULL) | ||
883 | goto end; | ||
884 | |||
885 | /* Set version to V3 */ | ||
886 | if ((cfg.extensions != NULL || addext_conf != NULL) && | ||
887 | !X509_set_version(x509ss, 2)) | ||
888 | goto end; | ||
889 | if (cfg.serial) { | ||
890 | if (!X509_set_serialNumber(x509ss, cfg.serial)) | ||
891 | goto end; | ||
892 | } else { | ||
893 | if (!rand_serial(NULL, | ||
894 | X509_get_serialNumber(x509ss))) | ||
895 | goto end; | ||
896 | } | ||
897 | |||
898 | if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req))) | ||
899 | goto end; | ||
900 | if (!X509_gmtime_adj(X509_get_notBefore(x509ss), 0)) | ||
901 | goto end; | ||
902 | if (!X509_time_adj_ex(X509_get_notAfter(x509ss), cfg.days, 0, NULL)) | ||
903 | goto end; | ||
904 | if (!X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req))) | ||
905 | goto end; | ||
906 | if ((tmppkey = X509_REQ_get0_pubkey(req)) == NULL) | ||
907 | goto end; | ||
908 | if (!X509_set_pubkey(x509ss, tmppkey)) | ||
909 | goto end; | ||
910 | |||
911 | /* Set up V3 context struct */ | ||
912 | |||
913 | X509V3_set_ctx(&ext_ctx, x509ss, x509ss, NULL, NULL, 0); | ||
914 | X509V3_set_nconf(&ext_ctx, req_conf); | ||
915 | |||
916 | /* Add extensions */ | ||
917 | if (cfg.extensions && !X509V3_EXT_add_nconf(req_conf, | ||
918 | &ext_ctx, cfg.extensions, x509ss)) { | ||
919 | BIO_printf(bio_err, | ||
920 | "Error Loading extension section %s\n", | ||
921 | cfg.extensions); | ||
922 | goto end; | ||
923 | } | ||
924 | if (addext_conf != NULL && | ||
925 | !X509V3_EXT_add_nconf(addext_conf, &ext_ctx, | ||
926 | "default", x509ss)) { | ||
927 | BIO_printf(bio_err, | ||
928 | "Error Loading command line extensions\n"); | ||
929 | goto end; | ||
930 | } | ||
931 | i = do_X509_sign(bio_err, x509ss, pkey, cfg.digest, cfg.sigopts); | ||
932 | if (!i) { | ||
933 | ERR_print_errors(bio_err); | ||
934 | goto end; | ||
935 | } | ||
936 | } else { | ||
937 | X509V3_CTX ext_ctx; | ||
938 | |||
939 | /* Set up V3 context struct */ | ||
940 | |||
941 | X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0); | ||
942 | X509V3_set_nconf(&ext_ctx, req_conf); | ||
943 | |||
944 | /* Add extensions */ | ||
945 | if (cfg.req_exts && !X509V3_EXT_REQ_add_nconf(req_conf, | ||
946 | &ext_ctx, cfg.req_exts, req)) { | ||
947 | BIO_printf(bio_err, | ||
948 | "Error Loading extension section %s\n", | ||
949 | cfg.req_exts); | ||
950 | goto end; | ||
951 | } | ||
952 | if (addext_conf != NULL && | ||
953 | !X509V3_EXT_REQ_add_nconf(addext_conf, &ext_ctx, | ||
954 | "default", req)) { | ||
955 | BIO_printf(bio_err, | ||
956 | "Error Loading command line extensions\n"); | ||
957 | goto end; | ||
958 | } | ||
959 | i = do_X509_REQ_sign(bio_err, req, pkey, cfg.digest, cfg.sigopts); | ||
960 | if (!i) { | ||
961 | ERR_print_errors(bio_err); | ||
962 | goto end; | ||
963 | } | ||
964 | } | ||
965 | } | ||
966 | if (cfg.subj && cfg.x509) { | ||
967 | BIO_printf(bio_err, "Cannot modify certificate subject\n"); | ||
968 | goto end; | ||
969 | } | ||
970 | if (cfg.subj && !cfg.x509) { | ||
971 | if (cfg.verbose) { | ||
972 | BIO_printf(bio_err, "Modifying Request's Subject\n"); | ||
973 | print_name(bio_err, "old subject=", X509_REQ_get_subject_name(req), cfg.nmflag); | ||
974 | } | ||
975 | if (build_subject(req, cfg.subj, cfg.chtype, cfg.multirdn) == 0) { | ||
976 | BIO_printf(bio_err, "ERROR: cannot modify subject\n"); | ||
977 | ex = 1; | ||
978 | goto end; | ||
979 | } | ||
980 | |||
981 | if (cfg.verbose) { | ||
982 | print_name(bio_err, "new subject=", X509_REQ_get_subject_name(req), cfg.nmflag); | ||
983 | } | ||
984 | } | ||
985 | if (cfg.verify && !cfg.x509) { | ||
986 | EVP_PKEY *pubkey = pkey; | ||
987 | |||
988 | if (pubkey == NULL) | ||
989 | pubkey = X509_REQ_get0_pubkey(req); | ||
990 | if (pubkey == NULL) | ||
991 | goto end; | ||
992 | i = X509_REQ_verify(req, pubkey); | ||
993 | if (i < 0) { | ||
994 | goto end; | ||
995 | } else if (i == 0) { | ||
996 | BIO_printf(bio_err, "verify failure\n"); | ||
997 | ERR_print_errors(bio_err); | ||
998 | } else /* if (i > 0) */ | ||
999 | BIO_printf(bio_err, "verify OK\n"); | ||
1000 | } | ||
1001 | if (cfg.noout && !cfg.text && !cfg.modulus && !cfg.subject && !cfg.pubkey) { | ||
1002 | ex = 0; | ||
1003 | goto end; | ||
1004 | } | ||
1005 | if (cfg.outfile == NULL) { | ||
1006 | BIO_set_fp(out, stdout, BIO_NOCLOSE); | ||
1007 | } else { | ||
1008 | if ((cfg.keyout != NULL) && (strcmp(cfg.outfile, cfg.keyout) == 0)) | ||
1009 | i = (int) BIO_append_filename(out, cfg.outfile); | ||
1010 | else | ||
1011 | i = (int) BIO_write_filename(out, cfg.outfile); | ||
1012 | if (!i) { | ||
1013 | perror(cfg.outfile); | ||
1014 | goto end; | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | if (cfg.pubkey) { | ||
1019 | EVP_PKEY *tpubkey; | ||
1020 | |||
1021 | if ((tpubkey = X509_REQ_get0_pubkey(req)) == NULL) { | ||
1022 | BIO_printf(bio_err, "Error getting public key\n"); | ||
1023 | ERR_print_errors(bio_err); | ||
1024 | goto end; | ||
1025 | } | ||
1026 | PEM_write_bio_PUBKEY(out, tpubkey); | ||
1027 | } | ||
1028 | if (cfg.text) { | ||
1029 | if (cfg.x509) | ||
1030 | X509_print_ex(out, x509ss, cfg.nmflag, cfg.reqflag); | ||
1031 | else | ||
1032 | X509_REQ_print_ex(out, req, cfg.nmflag, cfg.reqflag); | ||
1033 | } | ||
1034 | if (cfg.subject) { | ||
1035 | if (cfg.x509) | ||
1036 | print_name(out, "subject=", X509_get_subject_name(x509ss), cfg.nmflag); | ||
1037 | else | ||
1038 | print_name(out, "subject=", X509_REQ_get_subject_name(req), cfg.nmflag); | ||
1039 | } | ||
1040 | if (cfg.modulus) { | ||
1041 | EVP_PKEY *tpubkey; | ||
1042 | |||
1043 | if (cfg.x509) | ||
1044 | tpubkey = X509_get0_pubkey(x509ss); | ||
1045 | else | ||
1046 | tpubkey = X509_REQ_get0_pubkey(req); | ||
1047 | if (tpubkey == NULL) { | ||
1048 | fprintf(stdout, "Modulus=unavailable\n"); | ||
1049 | goto end; | ||
1050 | } | ||
1051 | fprintf(stdout, "Modulus="); | ||
1052 | if (EVP_PKEY_base_id(tpubkey) == EVP_PKEY_RSA) { | ||
1053 | const BIGNUM *n = NULL; | ||
1054 | |||
1055 | RSA_get0_key(EVP_PKEY_get0_RSA(tpubkey), &n, NULL, NULL); | ||
1056 | |||
1057 | BN_print(out, n); | ||
1058 | } else | ||
1059 | fprintf(stdout, "Wrong Algorithm type"); | ||
1060 | fprintf(stdout, "\n"); | ||
1061 | } | ||
1062 | if (!cfg.noout && !cfg.x509) { | ||
1063 | if (cfg.outformat == FORMAT_ASN1) | ||
1064 | i = i2d_X509_REQ_bio(out, req); | ||
1065 | else if (cfg.outformat == FORMAT_PEM) { | ||
1066 | if (cfg.newhdr) | ||
1067 | i = PEM_write_bio_X509_REQ_NEW(out, req); | ||
1068 | else | ||
1069 | i = PEM_write_bio_X509_REQ(out, req); | ||
1070 | } else { | ||
1071 | BIO_printf(bio_err, "bad output format specified for outfile\n"); | ||
1072 | goto end; | ||
1073 | } | ||
1074 | if (!i) { | ||
1075 | BIO_printf(bio_err, "unable to write X509 request\n"); | ||
1076 | goto end; | ||
1077 | } | ||
1078 | } | ||
1079 | if (!cfg.noout && cfg.x509 && (x509ss != NULL)) { | ||
1080 | if (cfg.outformat == FORMAT_ASN1) | ||
1081 | i = i2d_X509_bio(out, x509ss); | ||
1082 | else if (cfg.outformat == FORMAT_PEM) | ||
1083 | i = PEM_write_bio_X509(out, x509ss); | ||
1084 | else { | ||
1085 | BIO_printf(bio_err, "bad output format specified for outfile\n"); | ||
1086 | goto end; | ||
1087 | } | ||
1088 | if (!i) { | ||
1089 | BIO_printf(bio_err, "unable to write X509 certificate\n"); | ||
1090 | goto end; | ||
1091 | } | ||
1092 | } | ||
1093 | ex = 0; | ||
1094 | end: | ||
1095 | if (ex) { | ||
1096 | ERR_print_errors(bio_err); | ||
1097 | } | ||
1098 | if ((req_conf != NULL) && (req_conf != config)) | ||
1099 | NCONF_free(req_conf); | ||
1100 | NCONF_free(addext_conf); | ||
1101 | BIO_free(cfg.addext_bio); | ||
1102 | BIO_free(in); | ||
1103 | BIO_free_all(out); | ||
1104 | EVP_PKEY_free(pkey); | ||
1105 | if (genctx) | ||
1106 | EVP_PKEY_CTX_free(genctx); | ||
1107 | if (cfg.pkeyopts) | ||
1108 | sk_OPENSSL_STRING_free(cfg.pkeyopts); | ||
1109 | if (cfg.sigopts) | ||
1110 | sk_OPENSSL_STRING_free(cfg.sigopts); | ||
1111 | lh_OPENSSL_STRING_doall(cfg.addexts, (LHASH_DOALL_FN_TYPE)exts_cleanup); | ||
1112 | lh_OPENSSL_STRING_free(cfg.addexts); | ||
1113 | free(keyalgstr); | ||
1114 | X509_REQ_free(req); | ||
1115 | X509_free(x509ss); | ||
1116 | ASN1_INTEGER_free(cfg.serial); | ||
1117 | if (cfg.passargin && passin) | ||
1118 | free(passin); | ||
1119 | if (cfg.passargout && passout) | ||
1120 | free(passout); | ||
1121 | OBJ_cleanup(); | ||
1122 | |||
1123 | return (ex); | ||
1124 | } | ||
1125 | |||
1126 | static int | ||
1127 | make_REQ(X509_REQ * req, EVP_PKEY * pkey, char *subj, int multirdn, | ||
1128 | int attribs, unsigned long chtype) | ||
1129 | { | ||
1130 | int ret = 0, i; | ||
1131 | char no_prompt = 0; | ||
1132 | STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL; | ||
1133 | char *tmp, *dn_sect, *attr_sect; | ||
1134 | |||
1135 | tmp = NCONF_get_string(req_conf, SECTION, PROMPT); | ||
1136 | if (tmp == NULL) | ||
1137 | ERR_clear_error(); | ||
1138 | if ((tmp != NULL) && !strcmp(tmp, "no")) | ||
1139 | no_prompt = 1; | ||
1140 | |||
1141 | dn_sect = NCONF_get_string(req_conf, SECTION, DISTINGUISHED_NAME); | ||
1142 | if (dn_sect == NULL) { | ||
1143 | BIO_printf(bio_err, "unable to find '%s' in config\n", | ||
1144 | DISTINGUISHED_NAME); | ||
1145 | goto err; | ||
1146 | } | ||
1147 | dn_sk = NCONF_get_section(req_conf, dn_sect); | ||
1148 | if (dn_sk == NULL) { | ||
1149 | BIO_printf(bio_err, "unable to get '%s' section\n", dn_sect); | ||
1150 | goto err; | ||
1151 | } | ||
1152 | attr_sect = NCONF_get_string(req_conf, SECTION, ATTRIBUTES); | ||
1153 | if (attr_sect == NULL) { | ||
1154 | ERR_clear_error(); | ||
1155 | attr_sk = NULL; | ||
1156 | } else { | ||
1157 | attr_sk = NCONF_get_section(req_conf, attr_sect); | ||
1158 | if (attr_sk == NULL) { | ||
1159 | BIO_printf(bio_err, "unable to get '%s' section\n", attr_sect); | ||
1160 | goto err; | ||
1161 | } | ||
1162 | } | ||
1163 | |||
1164 | /* setup version number */ | ||
1165 | if (!X509_REQ_set_version(req, 0L)) | ||
1166 | goto err; /* version 1 */ | ||
1167 | |||
1168 | if (no_prompt) | ||
1169 | i = auto_info(req, dn_sk, attr_sk, attribs, chtype); | ||
1170 | else { | ||
1171 | if (subj) | ||
1172 | i = build_subject(req, subj, chtype, multirdn); | ||
1173 | else | ||
1174 | i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs, chtype); | ||
1175 | } | ||
1176 | if (!i) | ||
1177 | goto err; | ||
1178 | |||
1179 | if (!X509_REQ_set_pubkey(req, pkey)) | ||
1180 | goto err; | ||
1181 | |||
1182 | ret = 1; | ||
1183 | err: | ||
1184 | return (ret); | ||
1185 | } | ||
1186 | |||
1187 | /* | ||
1188 | * subject is expected to be in the format /type0=value0/type1=value1/type2=... | ||
1189 | * where characters may be escaped by \ | ||
1190 | */ | ||
1191 | static int | ||
1192 | build_subject(X509_REQ * req, char *subject, unsigned long chtype, int multirdn) | ||
1193 | { | ||
1194 | X509_NAME *n; | ||
1195 | |||
1196 | if (!(n = parse_name(subject, chtype, multirdn))) | ||
1197 | return 0; | ||
1198 | |||
1199 | if (!X509_REQ_set_subject_name(req, n)) { | ||
1200 | X509_NAME_free(n); | ||
1201 | return 0; | ||
1202 | } | ||
1203 | X509_NAME_free(n); | ||
1204 | return 1; | ||
1205 | } | ||
1206 | |||
1207 | |||
1208 | static int | ||
1209 | prompt_info(X509_REQ * req, | ||
1210 | STACK_OF(CONF_VALUE) * dn_sk, char *dn_sect, | ||
1211 | STACK_OF(CONF_VALUE) * attr_sk, char *attr_sect, int attribs, | ||
1212 | unsigned long chtype) | ||
1213 | { | ||
1214 | int i; | ||
1215 | char *p, *q; | ||
1216 | char buf[100]; | ||
1217 | int nid, mval; | ||
1218 | long n_min, n_max; | ||
1219 | char *type, *value; | ||
1220 | const char *def; | ||
1221 | CONF_VALUE *v; | ||
1222 | X509_NAME *subj; | ||
1223 | subj = X509_REQ_get_subject_name(req); | ||
1224 | |||
1225 | if (!cfg.batch) { | ||
1226 | BIO_printf(bio_err, "You are about to be asked to enter information that will be incorporated\n"); | ||
1227 | BIO_printf(bio_err, "into your certificate request.\n"); | ||
1228 | BIO_printf(bio_err, "What you are about to enter is what is called a Distinguished Name or a DN.\n"); | ||
1229 | BIO_printf(bio_err, "There are quite a few fields but you can leave some blank\n"); | ||
1230 | BIO_printf(bio_err, "For some fields there will be a default value,\n"); | ||
1231 | BIO_printf(bio_err, "If you enter '.', the field will be left blank.\n"); | ||
1232 | BIO_printf(bio_err, "-----\n"); | ||
1233 | } | ||
1234 | if (sk_CONF_VALUE_num(dn_sk)) { | ||
1235 | i = -1; | ||
1236 | start: for (;;) { | ||
1237 | int ret; | ||
1238 | i++; | ||
1239 | if (sk_CONF_VALUE_num(dn_sk) <= i) | ||
1240 | break; | ||
1241 | |||
1242 | v = sk_CONF_VALUE_value(dn_sk, i); | ||
1243 | p = q = NULL; | ||
1244 | type = v->name; | ||
1245 | if (!check_end(type, "_min") || !check_end(type, "_max") || | ||
1246 | !check_end(type, "_default") || | ||
1247 | !check_end(type, "_value")) | ||
1248 | continue; | ||
1249 | /* | ||
1250 | * Skip past any leading X. X: X, etc to allow for | ||
1251 | * multiple instances | ||
1252 | */ | ||
1253 | for (p = v->name; *p; p++) | ||
1254 | if ((*p == ':') || (*p == ',') || | ||
1255 | (*p == '.')) { | ||
1256 | p++; | ||
1257 | if (*p) | ||
1258 | type = p; | ||
1259 | break; | ||
1260 | } | ||
1261 | if (*type == '+') { | ||
1262 | mval = -1; | ||
1263 | type++; | ||
1264 | } else | ||
1265 | mval = 0; | ||
1266 | /* If OBJ not recognised ignore it */ | ||
1267 | if ((nid = OBJ_txt2nid(type)) == NID_undef) | ||
1268 | goto start; | ||
1269 | ret = snprintf(buf, sizeof buf, "%s_default", v->name); | ||
1270 | if (ret < 0 || ret >= sizeof(buf)) { | ||
1271 | BIO_printf(bio_err, "Name '%s' too long for default\n", | ||
1272 | v->name); | ||
1273 | return 0; | ||
1274 | } | ||
1275 | if ((def = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) { | ||
1276 | ERR_clear_error(); | ||
1277 | def = ""; | ||
1278 | } | ||
1279 | ret = snprintf(buf, sizeof buf, "%s_value", v->name); | ||
1280 | if (ret < 0 || ret >= sizeof(buf)) { | ||
1281 | BIO_printf(bio_err, "Name '%s' too long for value\n", | ||
1282 | v->name); | ||
1283 | return 0; | ||
1284 | } | ||
1285 | if ((value = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) { | ||
1286 | ERR_clear_error(); | ||
1287 | value = NULL; | ||
1288 | } | ||
1289 | ret = snprintf(buf, sizeof buf, "%s_min", v->name); | ||
1290 | if (ret < 0 || ret >= sizeof(buf)) { | ||
1291 | BIO_printf(bio_err, "Name '%s' too long for min\n", | ||
1292 | v->name); | ||
1293 | return 0; | ||
1294 | } | ||
1295 | if (!NCONF_get_number(req_conf, dn_sect, buf, &n_min)) { | ||
1296 | ERR_clear_error(); | ||
1297 | n_min = -1; | ||
1298 | } | ||
1299 | ret = snprintf(buf, sizeof buf, "%s_max", v->name); | ||
1300 | if (ret < 0 || ret >= sizeof(buf)) { | ||
1301 | BIO_printf(bio_err, "Name '%s' too long for max\n", | ||
1302 | v->name); | ||
1303 | return 0; | ||
1304 | } | ||
1305 | if (!NCONF_get_number(req_conf, dn_sect, buf, &n_max)) { | ||
1306 | ERR_clear_error(); | ||
1307 | n_max = -1; | ||
1308 | } | ||
1309 | if (!add_DN_object(subj, v->value, def, value, nid, | ||
1310 | n_min, n_max, chtype, mval)) | ||
1311 | return 0; | ||
1312 | } | ||
1313 | if (X509_NAME_entry_count(subj) == 0) { | ||
1314 | BIO_printf(bio_err, "error, no objects specified in config file\n"); | ||
1315 | return 0; | ||
1316 | } | ||
1317 | if (attribs) { | ||
1318 | if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0) && | ||
1319 | (!cfg.batch)) { | ||
1320 | BIO_printf(bio_err, | ||
1321 | "\nPlease enter the following 'extra' attributes\n"); | ||
1322 | BIO_printf(bio_err, | ||
1323 | "to be sent with your certificate request\n"); | ||
1324 | } | ||
1325 | i = -1; | ||
1326 | start2: for (;;) { | ||
1327 | int ret; | ||
1328 | i++; | ||
1329 | if ((attr_sk == NULL) || | ||
1330 | (sk_CONF_VALUE_num(attr_sk) <= i)) | ||
1331 | break; | ||
1332 | |||
1333 | v = sk_CONF_VALUE_value(attr_sk, i); | ||
1334 | type = v->name; | ||
1335 | if ((nid = OBJ_txt2nid(type)) == NID_undef) | ||
1336 | goto start2; | ||
1337 | ret = snprintf(buf, sizeof buf, "%s_default", type); | ||
1338 | if (ret < 0 || ret >= sizeof(buf)) { | ||
1339 | BIO_printf(bio_err, "Name '%s' too long for default\n", | ||
1340 | v->name); | ||
1341 | return 0; | ||
1342 | } | ||
1343 | if ((def = NCONF_get_string(req_conf, attr_sect, buf)) | ||
1344 | == NULL) { | ||
1345 | ERR_clear_error(); | ||
1346 | def = ""; | ||
1347 | } | ||
1348 | ret = snprintf(buf, sizeof buf, "%s_value", type); | ||
1349 | if (ret < 0 || ret >= sizeof(buf)) { | ||
1350 | BIO_printf(bio_err, "Name '%s' too long for value\n", | ||
1351 | v->name); | ||
1352 | return 0; | ||
1353 | } | ||
1354 | if ((value = NCONF_get_string(req_conf, attr_sect, buf)) | ||
1355 | == NULL) { | ||
1356 | ERR_clear_error(); | ||
1357 | value = NULL; | ||
1358 | } | ||
1359 | ret = snprintf(buf, sizeof buf, "%s_min", type); | ||
1360 | if (ret < 0 || ret >= sizeof(buf)) { | ||
1361 | BIO_printf(bio_err, "Name '%s' too long for min\n", | ||
1362 | v->name); | ||
1363 | return 0; | ||
1364 | } | ||
1365 | if (!NCONF_get_number(req_conf, attr_sect, buf, &n_min)) { | ||
1366 | ERR_clear_error(); | ||
1367 | n_min = -1; | ||
1368 | } | ||
1369 | ret = snprintf(buf, sizeof buf, "%s_max", type); | ||
1370 | if (ret < 0 || ret >= sizeof(buf)) { | ||
1371 | BIO_printf(bio_err, "Name '%s' too long for max\n", | ||
1372 | v->name); | ||
1373 | return 0; | ||
1374 | } | ||
1375 | if (!NCONF_get_number(req_conf, attr_sect, buf, &n_max)) { | ||
1376 | ERR_clear_error(); | ||
1377 | n_max = -1; | ||
1378 | } | ||
1379 | if (!add_attribute_object(req, | ||
1380 | v->value, def, value, nid, n_min, n_max, chtype)) | ||
1381 | return 0; | ||
1382 | } | ||
1383 | } | ||
1384 | } else { | ||
1385 | BIO_printf(bio_err, "No template, please set one up.\n"); | ||
1386 | return 0; | ||
1387 | } | ||
1388 | |||
1389 | return 1; | ||
1390 | |||
1391 | } | ||
1392 | |||
1393 | static int | ||
1394 | auto_info(X509_REQ * req, STACK_OF(CONF_VALUE) * dn_sk, | ||
1395 | STACK_OF(CONF_VALUE) * attr_sk, int attribs, unsigned long chtype) | ||
1396 | { | ||
1397 | int i; | ||
1398 | char *p, *q; | ||
1399 | char *type; | ||
1400 | CONF_VALUE *v; | ||
1401 | X509_NAME *subj; | ||
1402 | |||
1403 | subj = X509_REQ_get_subject_name(req); | ||
1404 | |||
1405 | for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) { | ||
1406 | int mval; | ||
1407 | v = sk_CONF_VALUE_value(dn_sk, i); | ||
1408 | p = q = NULL; | ||
1409 | type = v->name; | ||
1410 | /* | ||
1411 | * Skip past any leading X. X: X, etc to allow for multiple | ||
1412 | * instances | ||
1413 | */ | ||
1414 | for (p = v->name; *p; p++) | ||
1415 | if ((*p == ':') || (*p == ',') || (*p == '.')) { | ||
1416 | p++; | ||
1417 | if (*p) | ||
1418 | type = p; | ||
1419 | break; | ||
1420 | } | ||
1421 | if (*p == '+') { | ||
1422 | p++; | ||
1423 | mval = -1; | ||
1424 | } else | ||
1425 | mval = 0; | ||
1426 | if (!X509_NAME_add_entry_by_txt(subj, type, chtype, | ||
1427 | (unsigned char *) v->value, -1, -1, mval)) | ||
1428 | return 0; | ||
1429 | |||
1430 | } | ||
1431 | |||
1432 | if (!X509_NAME_entry_count(subj)) { | ||
1433 | BIO_printf(bio_err, "error, no objects specified in config file\n"); | ||
1434 | return 0; | ||
1435 | } | ||
1436 | if (attribs) { | ||
1437 | for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) { | ||
1438 | v = sk_CONF_VALUE_value(attr_sk, i); | ||
1439 | if (!X509_REQ_add1_attr_by_txt(req, v->name, chtype, | ||
1440 | (unsigned char *) v->value, -1)) | ||
1441 | return 0; | ||
1442 | } | ||
1443 | } | ||
1444 | return 1; | ||
1445 | } | ||
1446 | |||
1447 | |||
1448 | static int | ||
1449 | add_DN_object(X509_NAME * n, char *text, const char *def, char *value, | ||
1450 | int nid, int n_min, int n_max, unsigned long chtype, int mval) | ||
1451 | { | ||
1452 | int i, ret = 0; | ||
1453 | char buf[1024]; | ||
1454 | start: | ||
1455 | if (!cfg.batch) | ||
1456 | BIO_printf(bio_err, "%s [%s]:", text, def); | ||
1457 | (void) BIO_flush(bio_err); | ||
1458 | if (value != NULL) { | ||
1459 | strlcpy(buf, value, sizeof buf); | ||
1460 | strlcat(buf, "\n", sizeof buf); | ||
1461 | BIO_printf(bio_err, "%s\n", value); | ||
1462 | } else { | ||
1463 | buf[0] = '\0'; | ||
1464 | if (!cfg.batch) { | ||
1465 | if (!fgets(buf, sizeof buf, stdin)) | ||
1466 | return 0; | ||
1467 | } else { | ||
1468 | buf[0] = '\n'; | ||
1469 | buf[1] = '\0'; | ||
1470 | } | ||
1471 | } | ||
1472 | |||
1473 | if (buf[0] == '\0') | ||
1474 | return (0); | ||
1475 | else if (buf[0] == '\n') { | ||
1476 | if ((def == NULL) || (def[0] == '\0')) | ||
1477 | return (1); | ||
1478 | strlcpy(buf, def, sizeof buf); | ||
1479 | strlcat(buf, "\n", sizeof buf); | ||
1480 | } else if ((buf[0] == '.') && (buf[1] == '\n')) | ||
1481 | return (1); | ||
1482 | |||
1483 | i = strlen(buf); | ||
1484 | if (buf[i - 1] != '\n') { | ||
1485 | BIO_printf(bio_err, "weird input :-(\n"); | ||
1486 | return (0); | ||
1487 | } | ||
1488 | buf[--i] = '\0'; | ||
1489 | if (!req_check_len(i, n_min, n_max)) | ||
1490 | goto start; | ||
1491 | if (!X509_NAME_add_entry_by_NID(n, nid, chtype, | ||
1492 | (unsigned char *) buf, -1, -1, mval)) | ||
1493 | goto err; | ||
1494 | ret = 1; | ||
1495 | err: | ||
1496 | return (ret); | ||
1497 | } | ||
1498 | |||
1499 | static int | ||
1500 | add_attribute_object(X509_REQ * req, char *text, const char *def, | ||
1501 | char *value, int nid, int n_min, | ||
1502 | int n_max, unsigned long chtype) | ||
1503 | { | ||
1504 | int i; | ||
1505 | static char buf[1024]; | ||
1506 | |||
1507 | start: | ||
1508 | if (!cfg.batch) | ||
1509 | BIO_printf(bio_err, "%s [%s]:", text, def); | ||
1510 | (void) BIO_flush(bio_err); | ||
1511 | if (value != NULL) { | ||
1512 | strlcpy(buf, value, sizeof buf); | ||
1513 | strlcat(buf, "\n", sizeof buf); | ||
1514 | BIO_printf(bio_err, "%s\n", value); | ||
1515 | } else { | ||
1516 | buf[0] = '\0'; | ||
1517 | if (!cfg.batch) { | ||
1518 | if (!fgets(buf, sizeof buf, stdin)) | ||
1519 | return 0; | ||
1520 | } else { | ||
1521 | buf[0] = '\n'; | ||
1522 | buf[1] = '\0'; | ||
1523 | } | ||
1524 | } | ||
1525 | |||
1526 | if (buf[0] == '\0') | ||
1527 | return (0); | ||
1528 | else if (buf[0] == '\n') { | ||
1529 | if ((def == NULL) || (def[0] == '\0')) | ||
1530 | return (1); | ||
1531 | strlcpy(buf, def, sizeof buf); | ||
1532 | strlcat(buf, "\n", sizeof buf); | ||
1533 | } else if ((buf[0] == '.') && (buf[1] == '\n')) | ||
1534 | return (1); | ||
1535 | |||
1536 | i = strlen(buf); | ||
1537 | if (buf[i - 1] != '\n') { | ||
1538 | BIO_printf(bio_err, "weird input :-(\n"); | ||
1539 | return (0); | ||
1540 | } | ||
1541 | buf[--i] = '\0'; | ||
1542 | if (!req_check_len(i, n_min, n_max)) | ||
1543 | goto start; | ||
1544 | |||
1545 | if (!X509_REQ_add1_attr_by_NID(req, nid, chtype, | ||
1546 | (unsigned char *) buf, -1)) { | ||
1547 | BIO_printf(bio_err, "Error adding attribute\n"); | ||
1548 | ERR_print_errors(bio_err); | ||
1549 | goto err; | ||
1550 | } | ||
1551 | return (1); | ||
1552 | err: | ||
1553 | return (0); | ||
1554 | } | ||
1555 | |||
1556 | static int | ||
1557 | req_check_len(int len, int n_min, int n_max) | ||
1558 | { | ||
1559 | if ((n_min > 0) && (len < n_min)) { | ||
1560 | BIO_printf(bio_err, "string is too short, it needs to be at least %d bytes long\n", n_min); | ||
1561 | return (0); | ||
1562 | } | ||
1563 | if ((n_max >= 0) && (len > n_max)) { | ||
1564 | BIO_printf(bio_err, "string is too long, it needs to be less than %d bytes long\n", n_max); | ||
1565 | return (0); | ||
1566 | } | ||
1567 | return (1); | ||
1568 | } | ||
1569 | |||
1570 | /* Check if the end of a string matches 'end' */ | ||
1571 | static int | ||
1572 | check_end(const char *str, const char *end) | ||
1573 | { | ||
1574 | int elen, slen; | ||
1575 | const char *tmp; | ||
1576 | elen = strlen(end); | ||
1577 | slen = strlen(str); | ||
1578 | if (elen > slen) | ||
1579 | return 1; | ||
1580 | tmp = str + slen - elen; | ||
1581 | return strcmp(tmp, end); | ||
1582 | } | ||
1583 | |||
1584 | static EVP_PKEY_CTX * | ||
1585 | set_keygen_ctx(BIO * err, const char *gstr, int *pkey_type, | ||
1586 | long *pkeylen, char **palgnam) | ||
1587 | { | ||
1588 | EVP_PKEY_CTX *gctx = NULL; | ||
1589 | EVP_PKEY *param = NULL; | ||
1590 | long keylen = -1; | ||
1591 | BIO *pbio = NULL; | ||
1592 | const char *paramfile = NULL; | ||
1593 | const char *errstr; | ||
1594 | |||
1595 | if (gstr == NULL) { | ||
1596 | *pkey_type = EVP_PKEY_RSA; | ||
1597 | keylen = *pkeylen; | ||
1598 | } else if (gstr[0] >= '0' && gstr[0] <= '9') { | ||
1599 | *pkey_type = EVP_PKEY_RSA; | ||
1600 | keylen = strtonum(gstr, 0, LONG_MAX, &errstr); | ||
1601 | if (errstr) { | ||
1602 | BIO_printf(err, "bad algorithm %s: %s\n", gstr, errstr); | ||
1603 | return NULL; | ||
1604 | } | ||
1605 | *pkeylen = keylen; | ||
1606 | } else if (!strncmp(gstr, "param:", 6)) | ||
1607 | paramfile = gstr + 6; | ||
1608 | else { | ||
1609 | const char *p = strchr(gstr, ':'); | ||
1610 | int len; | ||
1611 | const EVP_PKEY_ASN1_METHOD *ameth; | ||
1612 | |||
1613 | if (p) | ||
1614 | len = p - gstr; | ||
1615 | else | ||
1616 | len = strlen(gstr); | ||
1617 | |||
1618 | ameth = EVP_PKEY_asn1_find_str(NULL, gstr, len); | ||
1619 | |||
1620 | if (!ameth) { | ||
1621 | BIO_printf(err, "Unknown algorithm %.*s\n", len, gstr); | ||
1622 | return NULL; | ||
1623 | } | ||
1624 | EVP_PKEY_asn1_get0_info(NULL, pkey_type, NULL, NULL, NULL, | ||
1625 | ameth); | ||
1626 | if (*pkey_type == EVP_PKEY_RSA) { | ||
1627 | if (p) { | ||
1628 | keylen = strtonum(p + 1, 0, LONG_MAX, &errstr); | ||
1629 | if (errstr) { | ||
1630 | BIO_printf(err, "bad algorithm %s: %s\n", | ||
1631 | p + 1, errstr); | ||
1632 | return NULL; | ||
1633 | } | ||
1634 | *pkeylen = keylen; | ||
1635 | } else | ||
1636 | keylen = *pkeylen; | ||
1637 | } else if (p) | ||
1638 | paramfile = p + 1; | ||
1639 | } | ||
1640 | |||
1641 | if (paramfile) { | ||
1642 | pbio = BIO_new_file(paramfile, "r"); | ||
1643 | if (!pbio) { | ||
1644 | BIO_printf(err, "Can't open parameter file %s\n", | ||
1645 | paramfile); | ||
1646 | return NULL; | ||
1647 | } | ||
1648 | param = PEM_read_bio_Parameters(pbio, NULL); | ||
1649 | |||
1650 | if (!param) { | ||
1651 | X509 *x; | ||
1652 | (void) BIO_reset(pbio); | ||
1653 | x = PEM_read_bio_X509(pbio, NULL, NULL, NULL); | ||
1654 | if (x) { | ||
1655 | param = X509_get_pubkey(x); | ||
1656 | X509_free(x); | ||
1657 | } | ||
1658 | } | ||
1659 | BIO_free(pbio); | ||
1660 | |||
1661 | if (!param) { | ||
1662 | BIO_printf(err, "Error reading parameter file %s\n", | ||
1663 | paramfile); | ||
1664 | return NULL; | ||
1665 | } | ||
1666 | if (*pkey_type == -1) | ||
1667 | *pkey_type = EVP_PKEY_id(param); | ||
1668 | else if (*pkey_type != EVP_PKEY_base_id(param)) { | ||
1669 | BIO_printf(err, "Key Type does not match parameters\n"); | ||
1670 | EVP_PKEY_free(param); | ||
1671 | return NULL; | ||
1672 | } | ||
1673 | } | ||
1674 | if (palgnam) { | ||
1675 | const EVP_PKEY_ASN1_METHOD *ameth; | ||
1676 | const char *anam; | ||
1677 | ameth = EVP_PKEY_asn1_find(NULL, *pkey_type); | ||
1678 | if (!ameth) { | ||
1679 | BIO_puts(err, "Internal error: can't find key algorithm\n"); | ||
1680 | return NULL; | ||
1681 | } | ||
1682 | EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &anam, ameth); | ||
1683 | *palgnam = strdup(anam); | ||
1684 | } | ||
1685 | if (param) { | ||
1686 | gctx = EVP_PKEY_CTX_new(param, NULL); | ||
1687 | *pkeylen = EVP_PKEY_bits(param); | ||
1688 | EVP_PKEY_free(param); | ||
1689 | } else | ||
1690 | gctx = EVP_PKEY_CTX_new_id(*pkey_type, NULL); | ||
1691 | |||
1692 | if (!gctx) { | ||
1693 | BIO_puts(err, "Error allocating keygen context\n"); | ||
1694 | ERR_print_errors(err); | ||
1695 | return NULL; | ||
1696 | } | ||
1697 | if (EVP_PKEY_keygen_init(gctx) <= 0) { | ||
1698 | BIO_puts(err, "Error initializing keygen context\n"); | ||
1699 | ERR_print_errors(err); | ||
1700 | EVP_PKEY_CTX_free(gctx); | ||
1701 | return NULL; | ||
1702 | } | ||
1703 | if ((*pkey_type == EVP_PKEY_RSA) && (keylen != -1)) { | ||
1704 | if (EVP_PKEY_CTX_set_rsa_keygen_bits(gctx, keylen) <= 0) { | ||
1705 | BIO_puts(err, "Error setting RSA keysize\n"); | ||
1706 | ERR_print_errors(err); | ||
1707 | EVP_PKEY_CTX_free(gctx); | ||
1708 | return NULL; | ||
1709 | } | ||
1710 | } | ||
1711 | |||
1712 | return gctx; | ||
1713 | } | ||
1714 | |||
1715 | static int | ||
1716 | genpkey_cb(EVP_PKEY_CTX * ctx) | ||
1717 | { | ||
1718 | char c = '*'; | ||
1719 | BIO *b = EVP_PKEY_CTX_get_app_data(ctx); | ||
1720 | int p; | ||
1721 | p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); | ||
1722 | if (p == 0) | ||
1723 | c = '.'; | ||
1724 | if (p == 1) | ||
1725 | c = '+'; | ||
1726 | if (p == 2) | ||
1727 | c = '*'; | ||
1728 | if (p == 3) | ||
1729 | c = '\n'; | ||
1730 | BIO_write(b, &c, 1); | ||
1731 | (void) BIO_flush(b); | ||
1732 | return 1; | ||
1733 | } | ||
1734 | |||
1735 | static int | ||
1736 | do_sign_init(BIO * err, EVP_MD_CTX * ctx, EVP_PKEY * pkey, | ||
1737 | const EVP_MD * md, STACK_OF(OPENSSL_STRING) * sigopts) | ||
1738 | { | ||
1739 | EVP_PKEY_CTX *pkctx = NULL; | ||
1740 | int default_nid; | ||
1741 | int i; | ||
1742 | |||
1743 | if (EVP_PKEY_get_default_digest_nid(pkey, &default_nid) == 2 && | ||
1744 | default_nid == NID_undef) { | ||
1745 | /* The digest is required to be EVP_md_null() (EdDSA). */ | ||
1746 | md = EVP_md_null(); | ||
1747 | } | ||
1748 | |||
1749 | if (!EVP_DigestSignInit(ctx, &pkctx, md, NULL, pkey)) | ||
1750 | return 0; | ||
1751 | for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) { | ||
1752 | char *sigopt = sk_OPENSSL_STRING_value(sigopts, i); | ||
1753 | if (pkey_ctrl_string(pkctx, sigopt) <= 0) { | ||
1754 | BIO_printf(err, "parameter error \"%s\"\n", sigopt); | ||
1755 | ERR_print_errors(bio_err); | ||
1756 | return 0; | ||
1757 | } | ||
1758 | } | ||
1759 | return 1; | ||
1760 | } | ||
1761 | |||
1762 | int | ||
1763 | do_X509_sign(BIO * err, X509 * x, EVP_PKEY * pkey, const EVP_MD * md, | ||
1764 | STACK_OF(OPENSSL_STRING) * sigopts) | ||
1765 | { | ||
1766 | EVP_MD_CTX *mctx; | ||
1767 | int rv; | ||
1768 | |||
1769 | if ((mctx = EVP_MD_CTX_new()) == NULL) | ||
1770 | return 0; | ||
1771 | |||
1772 | rv = do_sign_init(err, mctx, pkey, md, sigopts); | ||
1773 | if (rv > 0) | ||
1774 | rv = X509_sign_ctx(x, mctx); | ||
1775 | |||
1776 | EVP_MD_CTX_free(mctx); | ||
1777 | |||
1778 | return rv > 0; | ||
1779 | } | ||
1780 | |||
1781 | |||
1782 | int | ||
1783 | do_X509_REQ_sign(BIO * err, X509_REQ * x, EVP_PKEY * pkey, const EVP_MD * md, | ||
1784 | STACK_OF(OPENSSL_STRING) * sigopts) | ||
1785 | { | ||
1786 | EVP_MD_CTX *mctx; | ||
1787 | int rv; | ||
1788 | |||
1789 | if ((mctx = EVP_MD_CTX_new()) == NULL) | ||
1790 | return 0; | ||
1791 | |||
1792 | rv = do_sign_init(err, mctx, pkey, md, sigopts); | ||
1793 | if (rv > 0) | ||
1794 | rv = X509_REQ_sign_ctx(x, mctx); | ||
1795 | |||
1796 | EVP_MD_CTX_free(mctx); | ||
1797 | |||
1798 | return rv > 0; | ||
1799 | } | ||
1800 | |||
1801 | |||
1802 | |||
1803 | int | ||
1804 | do_X509_CRL_sign(BIO * err, X509_CRL * x, EVP_PKEY * pkey, const EVP_MD * md, | ||
1805 | STACK_OF(OPENSSL_STRING) * sigopts) | ||
1806 | { | ||
1807 | int rv; | ||
1808 | EVP_MD_CTX *mctx; | ||
1809 | |||
1810 | if ((mctx = EVP_MD_CTX_new()) == NULL) | ||
1811 | return 0; | ||
1812 | |||
1813 | rv = do_sign_init(err, mctx, pkey, md, sigopts); | ||
1814 | if (rv > 0) | ||
1815 | rv = X509_CRL_sign_ctx(x, mctx); | ||
1816 | |||
1817 | EVP_MD_CTX_free(mctx); | ||
1818 | |||
1819 | return rv > 0; | ||
1820 | } | ||
1821 | |||
1822 | static unsigned long | ||
1823 | ext_name_hash(const OPENSSL_STRING *a) | ||
1824 | { | ||
1825 | return lh_strhash((const char *)a); | ||
1826 | } | ||
1827 | |||
1828 | static int | ||
1829 | ext_name_cmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b) | ||
1830 | { | ||
1831 | return strcmp((const char *)a, (const char *)b); | ||
1832 | } | ||
1833 | |||
1834 | static void | ||
1835 | exts_cleanup(OPENSSL_STRING *x) | ||
1836 | { | ||
1837 | free((char *)x); | ||
1838 | } | ||
1839 | |||
1840 | /* | ||
1841 | * Is the |kv| key already duplicated ? This is remarkably tricky to get right. | ||
1842 | * Return 0 if unique, -1 on runtime error; 1 if found or a syntax error. | ||
1843 | */ | ||
1844 | static int | ||
1845 | duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv) | ||
1846 | { | ||
1847 | char *p; | ||
1848 | size_t off; | ||
1849 | |||
1850 | /* Check syntax. */ | ||
1851 | /* Skip leading whitespace, make a copy. */ | ||
1852 | while (*kv && isspace(*kv)) | ||
1853 | if (*++kv == '\0') | ||
1854 | return 1; | ||
1855 | if ((p = strchr(kv, '=')) == NULL) | ||
1856 | return 1; | ||
1857 | off = p - kv; | ||
1858 | if ((kv = strdup(kv)) == NULL) | ||
1859 | return -1; | ||
1860 | |||
1861 | /* Skip trailing space before the equal sign. */ | ||
1862 | for (p = kv + off; p > kv; --p) | ||
1863 | if (!isspace(p[-1])) | ||
1864 | break; | ||
1865 | if (p == kv) { | ||
1866 | free(kv); | ||
1867 | return 1; | ||
1868 | } | ||
1869 | *p = '\0'; | ||
1870 | |||
1871 | /* See if "key" is there by attempting to add it. */ | ||
1872 | if ((p = (char *)lh_OPENSSL_STRING_insert(addexts, (OPENSSL_STRING*)kv)) | ||
1873 | != NULL || lh_OPENSSL_STRING_error(addexts)) { | ||
1874 | free(p != NULL ? p : kv); | ||
1875 | return -1; | ||
1876 | } | ||
1877 | |||
1878 | return 0; | ||
1879 | } | ||