]>
Commit | Line | Data |
---|---|---|
0f113f3e MC |
1 | /* |
2 | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project | |
3 | * 2006 | |
f5cda4cb DSH |
4 | */ |
5 | /* ==================================================================== | |
6 | * Copyright (c) 2006 The OpenSSL Project. All rights reserved. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * 1. Redistributions of source code must retain the above copyright | |
0f113f3e | 13 | * notice, this list of conditions and the following disclaimer. |
f5cda4cb DSH |
14 | * |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in | |
17 | * the documentation and/or other materials provided with the | |
18 | * distribution. | |
19 | * | |
20 | * 3. All advertising materials mentioning features or use of this | |
21 | * software must display the following acknowledgment: | |
22 | * "This product includes software developed by the OpenSSL Project | |
23 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | |
24 | * | |
25 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
26 | * endorse or promote products derived from this software without | |
27 | * prior written permission. For written permission, please contact | |
28 | * licensing@OpenSSL.org. | |
29 | * | |
30 | * 5. Products derived from this software may not be called "OpenSSL" | |
31 | * nor may "OpenSSL" appear in their names without prior written | |
32 | * permission of the OpenSSL Project. | |
33 | * | |
34 | * 6. Redistributions of any form whatsoever must retain the following | |
35 | * acknowledgment: | |
36 | * "This product includes software developed by the OpenSSL Project | |
37 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | |
38 | * | |
39 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
40 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
42 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
43 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
44 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
45 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
46 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
48 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
49 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
50 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
51 | * ==================================================================== | |
52 | * | |
53 | * This product includes cryptographic software written by Eric Young | |
54 | * (eay@cryptsoft.com). This product includes software written by Tim | |
55 | * Hudson (tjh@cryptsoft.com). | |
56 | * | |
57 | */ | |
58 | #include <stdio.h> | |
59 | #include <string.h> | |
60 | #include "apps.h" | |
61 | #include <openssl/pem.h> | |
62 | #include <openssl/err.h> | |
63 | #include <openssl/evp.h> | |
01b8b3c7 | 64 | #ifndef OPENSSL_NO_ENGINE |
0f113f3e | 65 | # include <openssl/engine.h> |
01b8b3c7 | 66 | #endif |
f5cda4cb | 67 | |
7e1b7485 | 68 | static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e); |
f5cda4cb DSH |
69 | static int genpkey_cb(EVP_PKEY_CTX *ctx); |
70 | ||
7e1b7485 RS |
71 | typedef enum OPTION_choice { |
72 | OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, | |
73 | OPT_ENGINE, OPT_OUTFORM, OPT_OUT, OPT_PASS, OPT_PARAMFILE, | |
74 | OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER | |
75 | } OPTION_CHOICE; | |
76 | ||
77 | OPTIONS genpkey_options[] = { | |
78 | {"help", OPT_HELP, '-', "Display this summary"}, | |
79 | {"out", OPT_OUT, '>', "Output file"}, | |
80 | {"outform", OPT_OUTFORM, 'F', "output format (DER or PEM)"}, | |
81 | {"pass", OPT_PASS, 's', "Output file pass phrase source"}, | |
82 | {"paramfile", OPT_PARAMFILE, '<', "Parameters file"}, | |
83 | {"algorithm", OPT_ALGORITHM, 's', "The public key algorithm"}, | |
84 | {"pkeyopt", OPT_PKEYOPT, 's', | |
85 | "Set the public key algorithm option as opt:value"}, | |
86 | {"genparam", OPT_GENPARAM, '-', "Generate parameters, not key"}, | |
87 | {"text", OPT_TEXT, '-', "Print the in text"}, | |
88 | {"", OPT_CIPHER, '-', "Cipher to use to encrypt the key"}, | |
89 | #ifndef OPENSSL_NO_ENGINE | |
90 | {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, | |
91 | #endif | |
9c3bcfa0 | 92 | /* This is deliberately last. */ |
7e1b7485 RS |
93 | {OPT_HELP_STR, 1, 1, |
94 | "Order of options may be important! See the documentation.\n"}, | |
95 | {NULL} | |
96 | }; | |
f5cda4cb | 97 | |
7e1b7485 | 98 | int genpkey_main(int argc, char **argv) |
0f113f3e | 99 | { |
0f113f3e | 100 | BIO *in = NULL, *out = NULL; |
7e1b7485 | 101 | ENGINE *e = NULL; |
0f113f3e MC |
102 | EVP_PKEY *pkey = NULL; |
103 | EVP_PKEY_CTX *ctx = NULL; | |
7e1b7485 RS |
104 | char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog; |
105 | const EVP_CIPHER *cipher = NULL; | |
106 | OPTION_CHOICE o; | |
107 | int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0; | |
3b061a00 | 108 | int private = 0; |
7e1b7485 RS |
109 | |
110 | prog = opt_init(argc, argv, genpkey_options); | |
111 | while ((o = opt_next()) != OPT_EOF) { | |
112 | switch (o) { | |
113 | case OPT_EOF: | |
114 | case OPT_ERR: | |
115 | opthelp: | |
116 | BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); | |
117 | goto end; | |
118 | case OPT_HELP: | |
119 | ret = 0; | |
120 | opt_help(genpkey_options); | |
121 | goto end; | |
122 | case OPT_OUTFORM: | |
123 | if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) | |
124 | goto opthelp; | |
125 | break; | |
126 | case OPT_OUT: | |
127 | outfile = opt_arg(); | |
128 | break; | |
7e1b7485 RS |
129 | case OPT_PASS: |
130 | passarg = opt_arg(); | |
131 | break; | |
7e1b7485 RS |
132 | case OPT_ENGINE: |
133 | e = setup_engine(opt_arg(), 0); | |
134 | break; | |
7e1b7485 | 135 | case OPT_PARAMFILE: |
0f113f3e | 136 | if (do_param == 1) |
7e1b7485 RS |
137 | goto opthelp; |
138 | if (!init_keygen_file(&ctx, opt_arg(), e)) | |
0f113f3e | 139 | goto end; |
7e1b7485 RS |
140 | break; |
141 | case OPT_ALGORITHM: | |
142 | if (!init_gen_str(&ctx, opt_arg(), e, do_param)) | |
0f113f3e | 143 | goto end; |
7e1b7485 RS |
144 | break; |
145 | case OPT_PKEYOPT: | |
146 | if (ctx == NULL) { | |
147 | BIO_printf(bio_err, "%s: No keytype specified.\n", prog); | |
148 | goto opthelp; | |
149 | } | |
150 | if (pkey_ctrl_string(ctx, opt_arg()) <= 0) { | |
151 | BIO_printf(bio_err, | |
152 | "%s: Error setting %s parameter:\n", | |
153 | prog, opt_arg()); | |
0f113f3e MC |
154 | ERR_print_errors(bio_err); |
155 | goto end; | |
156 | } | |
7e1b7485 RS |
157 | break; |
158 | case OPT_GENPARAM: | |
159 | if (ctx != NULL) | |
160 | goto opthelp; | |
0f113f3e | 161 | do_param = 1; |
7e1b7485 RS |
162 | break; |
163 | case OPT_TEXT: | |
0f113f3e | 164 | text = 1; |
7e1b7485 RS |
165 | break; |
166 | case OPT_CIPHER: | |
167 | if (!opt_cipher(opt_unknown(), &cipher) | |
168 | || do_param == 1) | |
169 | goto opthelp; | |
0f113f3e | 170 | } |
0f113f3e | 171 | } |
7e1b7485 RS |
172 | argc = opt_num_rest(); |
173 | argv = opt_rest(); | |
3b061a00 | 174 | private = do_param ? 0 : 1; |
0f113f3e | 175 | |
7e1b7485 RS |
176 | if (ctx == NULL) |
177 | goto opthelp; | |
0f113f3e | 178 | |
7e1b7485 | 179 | if (!app_passwd(passarg, NULL, &pass, NULL)) { |
0f113f3e MC |
180 | BIO_puts(bio_err, "Error getting password\n"); |
181 | goto end; | |
182 | } | |
183 | ||
bdd58d98 | 184 | out = bio_open_owner(outfile, outformat, private); |
7e1b7485 RS |
185 | if (out == NULL) |
186 | goto end; | |
0f113f3e MC |
187 | |
188 | EVP_PKEY_CTX_set_cb(ctx, genpkey_cb); | |
189 | EVP_PKEY_CTX_set_app_data(ctx, bio_err); | |
190 | ||
191 | if (do_param) { | |
192 | if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) { | |
193 | BIO_puts(bio_err, "Error generating parameters\n"); | |
194 | ERR_print_errors(bio_err); | |
195 | goto end; | |
196 | } | |
197 | } else { | |
198 | if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { | |
199 | BIO_puts(bio_err, "Error generating key\n"); | |
200 | ERR_print_errors(bio_err); | |
201 | goto end; | |
202 | } | |
203 | } | |
204 | ||
205 | if (do_param) | |
206 | rv = PEM_write_bio_Parameters(out, pkey); | |
3b061a00 RS |
207 | else if (outformat == FORMAT_PEM) { |
208 | assert(private); | |
0f113f3e | 209 | rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass); |
3b061a00 RS |
210 | } else if (outformat == FORMAT_ASN1) { |
211 | assert(private); | |
0f113f3e | 212 | rv = i2d_PrivateKey_bio(out, pkey); |
3b061a00 | 213 | } else { |
0f113f3e MC |
214 | BIO_printf(bio_err, "Bad format specified for key\n"); |
215 | goto end; | |
216 | } | |
217 | ||
218 | if (rv <= 0) { | |
219 | BIO_puts(bio_err, "Error writing key\n"); | |
220 | ERR_print_errors(bio_err); | |
221 | } | |
222 | ||
223 | if (text) { | |
224 | if (do_param) | |
225 | rv = EVP_PKEY_print_params(out, pkey, 0, NULL); | |
226 | else | |
227 | rv = EVP_PKEY_print_private(out, pkey, 0, NULL); | |
228 | ||
229 | if (rv <= 0) { | |
230 | BIO_puts(bio_err, "Error printing key\n"); | |
231 | ERR_print_errors(bio_err); | |
232 | } | |
233 | } | |
234 | ||
235 | ret = 0; | |
236 | ||
237 | end: | |
c5ba2d99 RS |
238 | EVP_PKEY_free(pkey); |
239 | EVP_PKEY_CTX_free(ctx); | |
ca3a82c3 | 240 | BIO_free_all(out); |
0f113f3e | 241 | BIO_free(in); |
b548a1f1 | 242 | OPENSSL_free(pass); |
0f113f3e MC |
243 | |
244 | return ret; | |
245 | } | |
f5cda4cb | 246 | |
7e1b7485 | 247 | static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e) |
0f113f3e MC |
248 | { |
249 | BIO *pbio; | |
250 | EVP_PKEY *pkey = NULL; | |
251 | EVP_PKEY_CTX *ctx = NULL; | |
252 | if (*pctx) { | |
7e1b7485 | 253 | BIO_puts(bio_err, "Parameters already set!\n"); |
0f113f3e MC |
254 | return 0; |
255 | } | |
256 | ||
257 | pbio = BIO_new_file(file, "r"); | |
258 | if (!pbio) { | |
7e1b7485 | 259 | BIO_printf(bio_err, "Can't open parameter file %s\n", file); |
0f113f3e MC |
260 | return 0; |
261 | } | |
262 | ||
263 | pkey = PEM_read_bio_Parameters(pbio, NULL); | |
264 | BIO_free(pbio); | |
265 | ||
266 | if (!pkey) { | |
267 | BIO_printf(bio_err, "Error reading parameter file %s\n", file); | |
268 | return 0; | |
269 | } | |
270 | ||
271 | ctx = EVP_PKEY_CTX_new(pkey, e); | |
96487cdd | 272 | if (ctx == NULL) |
0f113f3e MC |
273 | goto err; |
274 | if (EVP_PKEY_keygen_init(ctx) <= 0) | |
275 | goto err; | |
276 | EVP_PKEY_free(pkey); | |
277 | *pctx = ctx; | |
278 | return 1; | |
279 | ||
280 | err: | |
7e1b7485 RS |
281 | BIO_puts(bio_err, "Error initializing context\n"); |
282 | ERR_print_errors(bio_err); | |
c5ba2d99 RS |
283 | EVP_PKEY_CTX_free(ctx); |
284 | EVP_PKEY_free(pkey); | |
0f113f3e MC |
285 | return 0; |
286 | ||
287 | } | |
f5cda4cb | 288 | |
7e1b7485 | 289 | int init_gen_str(EVP_PKEY_CTX **pctx, |
0f113f3e MC |
290 | const char *algname, ENGINE *e, int do_param) |
291 | { | |
292 | EVP_PKEY_CTX *ctx = NULL; | |
293 | const EVP_PKEY_ASN1_METHOD *ameth; | |
294 | ENGINE *tmpeng = NULL; | |
295 | int pkey_id; | |
01b8b3c7 | 296 | |
0f113f3e | 297 | if (*pctx) { |
7e1b7485 | 298 | BIO_puts(bio_err, "Algorithm already set!\n"); |
0f113f3e MC |
299 | return 0; |
300 | } | |
b3c6a331 | 301 | |
0f113f3e | 302 | ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1); |
f5cda4cb | 303 | |
70531c14 | 304 | #ifndef OPENSSL_NO_ENGINE |
0f113f3e MC |
305 | if (!ameth && e) |
306 | ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1); | |
70531c14 | 307 | #endif |
b3c6a331 | 308 | |
0f113f3e MC |
309 | if (!ameth) { |
310 | BIO_printf(bio_err, "Algorithm %s not found\n", algname); | |
311 | return 0; | |
312 | } | |
f5cda4cb | 313 | |
0f113f3e | 314 | ERR_clear_error(); |
b3c6a331 | 315 | |
0f113f3e | 316 | EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); |
01b8b3c7 | 317 | #ifndef OPENSSL_NO_ENGINE |
0f113f3e MC |
318 | if (tmpeng) |
319 | ENGINE_finish(tmpeng); | |
01b8b3c7 | 320 | #endif |
0f113f3e MC |
321 | ctx = EVP_PKEY_CTX_new_id(pkey_id, e); |
322 | ||
323 | if (!ctx) | |
324 | goto err; | |
325 | if (do_param) { | |
326 | if (EVP_PKEY_paramgen_init(ctx) <= 0) | |
327 | goto err; | |
328 | } else { | |
329 | if (EVP_PKEY_keygen_init(ctx) <= 0) | |
330 | goto err; | |
331 | } | |
332 | ||
333 | *pctx = ctx; | |
334 | return 1; | |
335 | ||
336 | err: | |
7e1b7485 RS |
337 | BIO_printf(bio_err, "Error initializing %s context\n", algname); |
338 | ERR_print_errors(bio_err); | |
c5ba2d99 | 339 | EVP_PKEY_CTX_free(ctx); |
0f113f3e MC |
340 | return 0; |
341 | ||
342 | } | |
f5cda4cb DSH |
343 | |
344 | static int genpkey_cb(EVP_PKEY_CTX *ctx) | |
0f113f3e MC |
345 | { |
346 | char c = '*'; | |
347 | BIO *b = EVP_PKEY_CTX_get_app_data(ctx); | |
348 | int p; | |
349 | p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); | |
350 | if (p == 0) | |
351 | c = '.'; | |
352 | if (p == 1) | |
353 | c = '+'; | |
354 | if (p == 2) | |
355 | c = '*'; | |
356 | if (p == 3) | |
357 | c = '\n'; | |
358 | BIO_write(b, &c, 1); | |
359 | (void)BIO_flush(b); | |
360 | return 1; | |
361 | } |