]>
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 | 172 | argc = opt_num_rest(); |
03358517 KR |
173 | if (argc != 0) |
174 | goto opthelp; | |
175 | ||
3b061a00 | 176 | private = do_param ? 0 : 1; |
0f113f3e | 177 | |
7e1b7485 RS |
178 | if (ctx == NULL) |
179 | goto opthelp; | |
0f113f3e | 180 | |
7e1b7485 | 181 | if (!app_passwd(passarg, NULL, &pass, NULL)) { |
0f113f3e MC |
182 | BIO_puts(bio_err, "Error getting password\n"); |
183 | goto end; | |
184 | } | |
185 | ||
bdd58d98 | 186 | out = bio_open_owner(outfile, outformat, private); |
7e1b7485 RS |
187 | if (out == NULL) |
188 | goto end; | |
0f113f3e MC |
189 | |
190 | EVP_PKEY_CTX_set_cb(ctx, genpkey_cb); | |
191 | EVP_PKEY_CTX_set_app_data(ctx, bio_err); | |
192 | ||
193 | if (do_param) { | |
194 | if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) { | |
195 | BIO_puts(bio_err, "Error generating parameters\n"); | |
196 | ERR_print_errors(bio_err); | |
197 | goto end; | |
198 | } | |
199 | } else { | |
200 | if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { | |
201 | BIO_puts(bio_err, "Error generating key\n"); | |
202 | ERR_print_errors(bio_err); | |
203 | goto end; | |
204 | } | |
205 | } | |
206 | ||
207 | if (do_param) | |
208 | rv = PEM_write_bio_Parameters(out, pkey); | |
3b061a00 RS |
209 | else if (outformat == FORMAT_PEM) { |
210 | assert(private); | |
0f113f3e | 211 | rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass); |
3b061a00 RS |
212 | } else if (outformat == FORMAT_ASN1) { |
213 | assert(private); | |
0f113f3e | 214 | rv = i2d_PrivateKey_bio(out, pkey); |
3b061a00 | 215 | } else { |
0f113f3e MC |
216 | BIO_printf(bio_err, "Bad format specified for key\n"); |
217 | goto end; | |
218 | } | |
219 | ||
220 | if (rv <= 0) { | |
221 | BIO_puts(bio_err, "Error writing key\n"); | |
222 | ERR_print_errors(bio_err); | |
223 | } | |
224 | ||
225 | if (text) { | |
226 | if (do_param) | |
227 | rv = EVP_PKEY_print_params(out, pkey, 0, NULL); | |
228 | else | |
229 | rv = EVP_PKEY_print_private(out, pkey, 0, NULL); | |
230 | ||
231 | if (rv <= 0) { | |
232 | BIO_puts(bio_err, "Error printing key\n"); | |
233 | ERR_print_errors(bio_err); | |
234 | } | |
235 | } | |
236 | ||
237 | ret = 0; | |
238 | ||
239 | end: | |
c5ba2d99 RS |
240 | EVP_PKEY_free(pkey); |
241 | EVP_PKEY_CTX_free(ctx); | |
ca3a82c3 | 242 | BIO_free_all(out); |
0f113f3e | 243 | BIO_free(in); |
b548a1f1 | 244 | OPENSSL_free(pass); |
0f113f3e MC |
245 | |
246 | return ret; | |
247 | } | |
f5cda4cb | 248 | |
7e1b7485 | 249 | static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e) |
0f113f3e MC |
250 | { |
251 | BIO *pbio; | |
252 | EVP_PKEY *pkey = NULL; | |
253 | EVP_PKEY_CTX *ctx = NULL; | |
254 | if (*pctx) { | |
7e1b7485 | 255 | BIO_puts(bio_err, "Parameters already set!\n"); |
0f113f3e MC |
256 | return 0; |
257 | } | |
258 | ||
259 | pbio = BIO_new_file(file, "r"); | |
260 | if (!pbio) { | |
7e1b7485 | 261 | BIO_printf(bio_err, "Can't open parameter file %s\n", file); |
0f113f3e MC |
262 | return 0; |
263 | } | |
264 | ||
265 | pkey = PEM_read_bio_Parameters(pbio, NULL); | |
266 | BIO_free(pbio); | |
267 | ||
268 | if (!pkey) { | |
269 | BIO_printf(bio_err, "Error reading parameter file %s\n", file); | |
270 | return 0; | |
271 | } | |
272 | ||
273 | ctx = EVP_PKEY_CTX_new(pkey, e); | |
96487cdd | 274 | if (ctx == NULL) |
0f113f3e MC |
275 | goto err; |
276 | if (EVP_PKEY_keygen_init(ctx) <= 0) | |
277 | goto err; | |
278 | EVP_PKEY_free(pkey); | |
279 | *pctx = ctx; | |
280 | return 1; | |
281 | ||
282 | err: | |
7e1b7485 RS |
283 | BIO_puts(bio_err, "Error initializing context\n"); |
284 | ERR_print_errors(bio_err); | |
c5ba2d99 RS |
285 | EVP_PKEY_CTX_free(ctx); |
286 | EVP_PKEY_free(pkey); | |
0f113f3e MC |
287 | return 0; |
288 | ||
289 | } | |
f5cda4cb | 290 | |
7e1b7485 | 291 | int init_gen_str(EVP_PKEY_CTX **pctx, |
0f113f3e MC |
292 | const char *algname, ENGINE *e, int do_param) |
293 | { | |
294 | EVP_PKEY_CTX *ctx = NULL; | |
295 | const EVP_PKEY_ASN1_METHOD *ameth; | |
296 | ENGINE *tmpeng = NULL; | |
297 | int pkey_id; | |
01b8b3c7 | 298 | |
0f113f3e | 299 | if (*pctx) { |
7e1b7485 | 300 | BIO_puts(bio_err, "Algorithm already set!\n"); |
0f113f3e MC |
301 | return 0; |
302 | } | |
b3c6a331 | 303 | |
0f113f3e | 304 | ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1); |
f5cda4cb | 305 | |
70531c14 | 306 | #ifndef OPENSSL_NO_ENGINE |
0f113f3e MC |
307 | if (!ameth && e) |
308 | ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1); | |
70531c14 | 309 | #endif |
b3c6a331 | 310 | |
0f113f3e MC |
311 | if (!ameth) { |
312 | BIO_printf(bio_err, "Algorithm %s not found\n", algname); | |
313 | return 0; | |
314 | } | |
f5cda4cb | 315 | |
0f113f3e | 316 | ERR_clear_error(); |
b3c6a331 | 317 | |
0f113f3e | 318 | EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); |
01b8b3c7 | 319 | #ifndef OPENSSL_NO_ENGINE |
7c96dbcd | 320 | ENGINE_finish(tmpeng); |
01b8b3c7 | 321 | #endif |
0f113f3e MC |
322 | ctx = EVP_PKEY_CTX_new_id(pkey_id, e); |
323 | ||
324 | if (!ctx) | |
325 | goto err; | |
326 | if (do_param) { | |
327 | if (EVP_PKEY_paramgen_init(ctx) <= 0) | |
328 | goto err; | |
329 | } else { | |
330 | if (EVP_PKEY_keygen_init(ctx) <= 0) | |
331 | goto err; | |
332 | } | |
333 | ||
334 | *pctx = ctx; | |
335 | return 1; | |
336 | ||
337 | err: | |
7e1b7485 RS |
338 | BIO_printf(bio_err, "Error initializing %s context\n", algname); |
339 | ERR_print_errors(bio_err); | |
c5ba2d99 | 340 | EVP_PKEY_CTX_free(ctx); |
0f113f3e MC |
341 | return 0; |
342 | ||
343 | } | |
f5cda4cb DSH |
344 | |
345 | static int genpkey_cb(EVP_PKEY_CTX *ctx) | |
0f113f3e MC |
346 | { |
347 | char c = '*'; | |
348 | BIO *b = EVP_PKEY_CTX_get_app_data(ctx); | |
349 | int p; | |
350 | p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); | |
351 | if (p == 0) | |
352 | c = '.'; | |
353 | if (p == 1) | |
354 | c = '+'; | |
355 | if (p == 2) | |
356 | c = '*'; | |
357 | if (p == 3) | |
358 | c = '\n'; | |
359 | BIO_write(b, &c, 1); | |
360 | (void)BIO_flush(b); | |
361 | return 1; | |
362 | } |