]>
Commit | Line | Data |
---|---|---|
846e33c7 | 1 | /* |
a28d06f3 | 2 | * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. |
d02b48c6 | 3 | * |
dffa7520 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
846e33c7 RS |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
d02b48c6 RE |
8 | */ |
9 | ||
effaf4de | 10 | #include <openssl/opensslconf.h> |
effaf4de | 11 | |
1ae56f2f RS |
12 | #include <stdio.h> |
13 | #include <stdlib.h> | |
14 | #include <string.h> | |
15 | #include <time.h> | |
16 | #include "apps.h" | |
17 | #include "progs.h" | |
18 | #include <openssl/bio.h> | |
19 | #include <openssl/err.h> | |
20 | #include <openssl/dsa.h> | |
21 | #include <openssl/evp.h> | |
22 | #include <openssl/x509.h> | |
23 | #include <openssl/pem.h> | |
24 | #include <openssl/bn.h> | |
47422549 P |
25 | #include <openssl/encoder.h> |
26 | #include <openssl/core_names.h> | |
27 | #include <openssl/core_dispatch.h> | |
28 | ||
29 | #ifndef OPENSSL_NO_RC4 | |
30 | # define DEFAULT_PVK_ENCR_STRENGTH 2 | |
31 | #else | |
32 | # define DEFAULT_PVK_ENCR_STRENGTH 0 | |
33 | #endif | |
d02b48c6 | 34 | |
7e1b7485 | 35 | typedef enum OPTION_choice { |
b0f96018 | 36 | OPT_COMMON, |
e7917e38 F |
37 | OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_ENGINE, |
38 | /* Do not change the order here; see case statements below */ | |
39 | OPT_PVK_NONE, OPT_PVK_WEAK, OPT_PVK_STRONG, | |
40 | OPT_NOOUT, OPT_TEXT, OPT_MODULUS, OPT_PUBIN, | |
6bd4e3f2 P |
41 | OPT_PUBOUT, OPT_CIPHER, OPT_PASSIN, OPT_PASSOUT, |
42 | OPT_PROV_ENUM | |
7e1b7485 | 43 | } OPTION_CHOICE; |
d02b48c6 | 44 | |
44c83ebd | 45 | const OPTIONS dsa_options[] = { |
5388f986 | 46 | OPT_SECTION("General"), |
7e1b7485 | 47 | {"help", OPT_HELP, '-', "Display this summary"}, |
7e1b7485 | 48 | {"", OPT_CIPHER, '-', "Any supported cipher"}, |
1ae56f2f | 49 | #ifndef OPENSSL_NO_RC4 |
e7917e38 F |
50 | {"pvk-strong", OPT_PVK_STRONG, '-', "Enable 'Strong' PVK encoding level (default)"}, |
51 | {"pvk-weak", OPT_PVK_WEAK, '-', "Enable 'Weak' PVK encoding level"}, | |
52 | {"pvk-none", OPT_PVK_NONE, '-', "Don't enforce PVK encoding"}, | |
1ae56f2f RS |
53 | #endif |
54 | #ifndef OPENSSL_NO_ENGINE | |
9c3bcfa0 | 55 | {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, |
1ae56f2f | 56 | #endif |
5388f986 RS |
57 | |
58 | OPT_SECTION("Input"), | |
59 | {"in", OPT_IN, 's', "Input key"}, | |
6d382c74 | 60 | {"inform", OPT_INFORM, 'f', "Input format (DER/PEM/PVK); has no effect"}, |
5388f986 RS |
61 | {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, |
62 | {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, | |
63 | ||
64 | OPT_SECTION("Output"), | |
65 | {"out", OPT_OUT, '>', "Output file"}, | |
66 | {"outform", OPT_OUTFORM, 'f', "Output format, DER PEM PVK"}, | |
67 | {"noout", OPT_NOOUT, '-', "Don't print key out"}, | |
68 | {"text", OPT_TEXT, '-', "Print the key in text"}, | |
69 | {"modulus", OPT_MODULUS, '-', "Print the DSA public value"}, | |
70 | {"pubout", OPT_PUBOUT, '-', "Output public key, not private"}, | |
71 | {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, | |
72 | ||
6bd4e3f2 | 73 | OPT_PROV_OPTIONS, |
7e1b7485 RS |
74 | {NULL} |
75 | }; | |
667ac4ec | 76 | |
7e1b7485 | 77 | int dsa_main(int argc, char **argv) |
0f113f3e | 78 | { |
7e1b7485 | 79 | BIO *out = NULL; |
7e1b7485 | 80 | ENGINE *e = NULL; |
b940349d | 81 | EVP_PKEY *pkey = NULL; |
606a417f | 82 | EVP_CIPHER *enc = NULL; |
333b070e RS |
83 | char *infile = NULL, *outfile = NULL, *prog; |
84 | char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; | |
7e1b7485 | 85 | OPTION_CHOICE o; |
d382e796 | 86 | int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, noout = 0; |
47422549 P |
87 | int modulus = 0, pubin = 0, pubout = 0, ret = 1; |
88 | int pvk_encr = DEFAULT_PVK_ENCR_STRENGTH; | |
3b061a00 | 89 | int private = 0; |
03bbd346 | 90 | const char *output_type = NULL, *ciphername = NULL; |
47422549 P |
91 | const char *output_structure = NULL; |
92 | int selection = 0; | |
93 | OSSL_ENCODER_CTX *ectx = NULL; | |
d02b48c6 | 94 | |
7e1b7485 RS |
95 | prog = opt_init(argc, argv, dsa_options); |
96 | while ((o = opt_next()) != OPT_EOF) { | |
97 | switch (o) { | |
98 | case OPT_EOF: | |
99 | case OPT_ERR: | |
7e1b7485 RS |
100 | opthelp: |
101 | ret = 0; | |
102 | BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); | |
103 | goto end; | |
104 | case OPT_HELP: | |
105 | opt_help(dsa_options); | |
106 | ret = 0; | |
107 | goto end; | |
108 | case OPT_INFORM: | |
dd958974 | 109 | if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) |
7e1b7485 RS |
110 | goto opthelp; |
111 | break; | |
112 | case OPT_IN: | |
113 | infile = opt_arg(); | |
114 | break; | |
115 | case OPT_OUTFORM: | |
b3795987 | 116 | if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat)) |
7e1b7485 RS |
117 | goto opthelp; |
118 | break; | |
119 | case OPT_OUT: | |
120 | outfile = opt_arg(); | |
121 | break; | |
122 | case OPT_ENGINE: | |
333b070e | 123 | e = setup_engine(opt_arg(), 0); |
7e1b7485 RS |
124 | break; |
125 | case OPT_PASSIN: | |
126 | passinarg = opt_arg(); | |
127 | break; | |
128 | case OPT_PASSOUT: | |
129 | passoutarg = opt_arg(); | |
130 | break; | |
e7917e38 F |
131 | case OPT_PVK_STRONG: /* pvk_encr:= 2 */ |
132 | case OPT_PVK_WEAK: /* pvk_encr:= 1 */ | |
133 | case OPT_PVK_NONE: /* pvk_encr:= 0 */ | |
35313768 | 134 | #ifndef OPENSSL_NO_RC4 |
e7917e38 | 135 | pvk_encr = (o - OPT_PVK_NONE); |
35313768 | 136 | #endif |
e7917e38 | 137 | break; |
7e1b7485 | 138 | case OPT_NOOUT: |
0f113f3e | 139 | noout = 1; |
7e1b7485 RS |
140 | break; |
141 | case OPT_TEXT: | |
0f113f3e | 142 | text = 1; |
7e1b7485 RS |
143 | break; |
144 | case OPT_MODULUS: | |
0f113f3e | 145 | modulus = 1; |
7e1b7485 RS |
146 | break; |
147 | case OPT_PUBIN: | |
0f113f3e | 148 | pubin = 1; |
7e1b7485 RS |
149 | break; |
150 | case OPT_PUBOUT: | |
0f113f3e | 151 | pubout = 1; |
7e1b7485 RS |
152 | break; |
153 | case OPT_CIPHER: | |
03bbd346 | 154 | ciphername = opt_unknown(); |
0f113f3e | 155 | break; |
6bd4e3f2 P |
156 | case OPT_PROV_CASES: |
157 | if (!opt_provider(o)) | |
158 | goto end; | |
159 | break; | |
0f113f3e | 160 | } |
0f113f3e | 161 | } |
021410ea RS |
162 | |
163 | /* No extra args. */ | |
d9f07357 | 164 | if (!opt_check_rest_arg(NULL)) |
03358517 KR |
165 | goto opthelp; |
166 | ||
d9f07357 DDO |
167 | if (!opt_cipher(ciphername, &enc)) |
168 | goto end; | |
3b061a00 | 169 | private = pubin || pubout ? 0 : 1; |
7eff6aa0 | 170 | if (text && !pubin) |
3b061a00 | 171 | private = 1; |
d02b48c6 | 172 | |
7e1b7485 | 173 | if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { |
0f113f3e MC |
174 | BIO_printf(bio_err, "Error getting passwords\n"); |
175 | goto end; | |
176 | } | |
a3fe382e | 177 | |
0f113f3e | 178 | BIO_printf(bio_err, "read DSA key\n"); |
b940349d | 179 | if (pubin) |
50eb2a50 | 180 | pkey = load_pubkey(infile, informat, 1, passin, e, "public key"); |
b940349d | 181 | else |
50eb2a50 | 182 | pkey = load_key(infile, informat, 1, passin, e, "private key"); |
a0156a92 | 183 | |
47422549 | 184 | if (pkey == NULL) { |
0f113f3e MC |
185 | BIO_printf(bio_err, "unable to load Key\n"); |
186 | ERR_print_errors(bio_err); | |
187 | goto end; | |
188 | } | |
47422549 P |
189 | if (!EVP_PKEY_is_a(pkey, "DSA")) { |
190 | BIO_printf(bio_err, "Not a DSA key\n"); | |
191 | goto end; | |
192 | } | |
d02b48c6 | 193 | |
bdd58d98 | 194 | out = bio_open_owner(outfile, outformat, private); |
7e1b7485 RS |
195 | if (out == NULL) |
196 | goto end; | |
d02b48c6 | 197 | |
3b061a00 | 198 | if (text) { |
7eff6aa0 | 199 | assert(pubin || private); |
b940349d P |
200 | if ((pubin && EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0) |
201 | || (!pubin && EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0)) { | |
0f113f3e MC |
202 | perror(outfile); |
203 | ERR_print_errors(bio_err); | |
204 | goto end; | |
205 | } | |
3b061a00 | 206 | } |
d02b48c6 | 207 | |
0f113f3e | 208 | if (modulus) { |
47422549 P |
209 | BIGNUM *pub_key = NULL; |
210 | ||
211 | if (!EVP_PKEY_get_bn_param(pkey, "pub", &pub_key)) { | |
212 | ERR_print_errors(bio_err); | |
213 | goto end; | |
214 | } | |
7e1b7485 | 215 | BIO_printf(out, "Public Key="); |
6e9fa57c | 216 | BN_print(out, pub_key); |
7e1b7485 | 217 | BIO_printf(out, "\n"); |
47422549 | 218 | BN_free(pub_key); |
0f113f3e | 219 | } |
d02b48c6 | 220 | |
7e1b7485 RS |
221 | if (noout) { |
222 | ret = 0; | |
0f113f3e | 223 | goto end; |
7e1b7485 | 224 | } |
0f113f3e MC |
225 | BIO_printf(bio_err, "writing DSA key\n"); |
226 | if (outformat == FORMAT_ASN1) { | |
47422549 | 227 | output_type = "DER"; |
0f113f3e | 228 | } else if (outformat == FORMAT_PEM) { |
47422549 P |
229 | output_type = "PEM"; |
230 | } else if (outformat == FORMAT_MSBLOB) { | |
231 | output_type = "MSBLOB"; | |
232 | } else if (outformat == FORMAT_PVK) { | |
233 | if (pubin) { | |
234 | BIO_printf(bio_err, "PVK form impossible with public key input\n"); | |
b6c68982 | 235 | goto end; |
3b061a00 | 236 | } |
47422549 | 237 | output_type = "PVK"; |
0f113f3e MC |
238 | } else { |
239 | BIO_printf(bio_err, "bad output format specified for outfile\n"); | |
240 | goto end; | |
241 | } | |
47422549 P |
242 | |
243 | if (outformat == FORMAT_ASN1 || outformat == FORMAT_PEM) { | |
244 | if (pubout || pubin) | |
245 | output_structure = "SubjectPublicKeyInfo"; | |
246 | else | |
247 | output_structure = "type-specific"; | |
248 | } | |
249 | ||
250 | /* Select what you want in the output */ | |
251 | if (pubout || pubin) { | |
252 | selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY; | |
253 | } else { | |
254 | assert(private); | |
255 | selection = (OSSL_KEYMGMT_SELECT_KEYPAIR | |
256 | | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS); | |
257 | } | |
258 | ||
259 | /* Perform the encoding */ | |
fe75766c TM |
260 | ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, output_type, |
261 | output_structure, NULL); | |
47422549 P |
262 | if (OSSL_ENCODER_CTX_get_num_encoders(ectx) == 0) { |
263 | BIO_printf(bio_err, "%s format not supported\n", output_type); | |
264 | goto end; | |
265 | } | |
266 | ||
5432d827 RL |
267 | /* Passphrase setup */ |
268 | if (enc != NULL) | |
ed576acd | 269 | OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL); |
5432d827 RL |
270 | |
271 | /* Default passphrase prompter */ | |
272 | if (enc != NULL || outformat == FORMAT_PVK) { | |
273 | OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL); | |
274 | if (passout != NULL) | |
275 | /* When passout given, override the passphrase prompter */ | |
276 | OSSL_ENCODER_CTX_set_passphrase(ectx, | |
277 | (const unsigned char *)passout, | |
278 | strlen(passout)); | |
279 | } | |
280 | ||
47422549 P |
281 | /* PVK requires a bit more */ |
282 | if (outformat == FORMAT_PVK) { | |
283 | OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
284 | ||
285 | params[0] = OSSL_PARAM_construct_int("encrypt-level", &pvk_encr); | |
286 | if (!OSSL_ENCODER_CTX_set_params(ectx, params)) { | |
287 | BIO_printf(bio_err, "invalid PVK encryption level\n"); | |
288 | goto end; | |
289 | } | |
290 | } | |
291 | ||
292 | if (!OSSL_ENCODER_to_bio(ectx, out)) { | |
293 | BIO_printf(bio_err, "unable to write key\n"); | |
7e1b7485 RS |
294 | goto end; |
295 | } | |
296 | ret = 0; | |
0f113f3e | 297 | end: |
47422549 P |
298 | if (ret != 0) |
299 | ERR_print_errors(bio_err); | |
300 | OSSL_ENCODER_CTX_free(ectx); | |
ca3a82c3 | 301 | BIO_free_all(out); |
b940349d | 302 | EVP_PKEY_free(pkey); |
606a417f | 303 | EVP_CIPHER_free(enc); |
dd1abd44 | 304 | release_engine(e); |
b548a1f1 RS |
305 | OPENSSL_free(passin); |
306 | OPENSSL_free(passout); | |
26a7d938 | 307 | return ret; |
0f113f3e | 308 | } |