1 /* 2 * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 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 8 */ 9 10 #include <openssl/opensslconf.h> 11 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> 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 34 35 typedef enum OPTION_choice { 36 OPT_COMMON, 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, 41 OPT_PUBOUT, OPT_CIPHER, OPT_PASSIN, OPT_PASSOUT, 42 OPT_PROV_ENUM 43 } OPTION_CHOICE; 44 45 const OPTIONS dsa_options[] = { 46 OPT_SECTION("General"), 47 {"help", OPT_HELP, '-', "Display this summary"}, 48 {"", OPT_CIPHER, '-', "Any supported cipher"}, 49 #ifndef OPENSSL_NO_RC4 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"}, 53 #endif 54 #ifndef OPENSSL_NO_ENGINE 55 {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, 56 #endif 57 58 OPT_SECTION("Input"), 59 {"in", OPT_IN, 's', "Input key"}, 60 {"inform", OPT_INFORM, 'f', "Input format (DER/PEM/PVK); has no effect"}, 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 73 OPT_PROV_OPTIONS, 74 {NULL} 75 }; 76 77 int dsa_main(int argc, char **argv) 78 { 79 BIO *out = NULL; 80 ENGINE *e = NULL; 81 EVP_PKEY *pkey = NULL; 82 EVP_CIPHER *enc = NULL; 83 char *infile = NULL, *outfile = NULL, *prog; 84 char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; 85 OPTION_CHOICE o; 86 int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, noout = 0; 87 int modulus = 0, pubin = 0, pubout = 0, ret = 1; 88 int pvk_encr = DEFAULT_PVK_ENCR_STRENGTH; 89 int private = 0; 90 const char *output_type = NULL, *ciphername = NULL; 91 const char *output_structure = NULL; 92 int selection = 0; 93 OSSL_ENCODER_CTX *ectx = NULL; 94 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: 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: 109 if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) 110 goto opthelp; 111 break; 112 case OPT_IN: 113 infile = opt_arg(); 114 break; 115 case OPT_OUTFORM: 116 if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat)) 117 goto opthelp; 118 break; 119 case OPT_OUT: 120 outfile = opt_arg(); 121 break; 122 case OPT_ENGINE: 123 e = setup_engine(opt_arg(), 0); 124 break; 125 case OPT_PASSIN: 126 passinarg = opt_arg(); 127 break; 128 case OPT_PASSOUT: 129 passoutarg = opt_arg(); 130 break; 131 case OPT_PVK_STRONG: /* pvk_encr:= 2 */ 132 case OPT_PVK_WEAK: /* pvk_encr:= 1 */ 133 case OPT_PVK_NONE: /* pvk_encr:= 0 */ 134 #ifndef OPENSSL_NO_RC4 135 pvk_encr = (o - OPT_PVK_NONE); 136 #endif 137 break; 138 case OPT_NOOUT: 139 noout = 1; 140 break; 141 case OPT_TEXT: 142 text = 1; 143 break; 144 case OPT_MODULUS: 145 modulus = 1; 146 break; 147 case OPT_PUBIN: 148 pubin = 1; 149 break; 150 case OPT_PUBOUT: 151 pubout = 1; 152 break; 153 case OPT_CIPHER: 154 ciphername = opt_unknown(); 155 break; 156 case OPT_PROV_CASES: 157 if (!opt_provider(o)) 158 goto end; 159 break; 160 } 161 } 162 163 /* No extra args. */ 164 argc = opt_num_rest(); 165 if (argc != 0) 166 goto opthelp; 167 168 if (ciphername != NULL) { 169 if (!opt_cipher(ciphername, &enc)) 170 goto end; 171 } 172 private = pubin || pubout ? 0 : 1; 173 if (text && !pubin) 174 private = 1; 175 176 if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { 177 BIO_printf(bio_err, "Error getting passwords\n"); 178 goto end; 179 } 180 181 BIO_printf(bio_err, "read DSA key\n"); 182 if (pubin) 183 pkey = load_pubkey(infile, informat, 1, passin, e, "public key"); 184 else 185 pkey = load_key(infile, informat, 1, passin, e, "private key"); 186 187 if (pkey == NULL) { 188 BIO_printf(bio_err, "unable to load Key\n"); 189 ERR_print_errors(bio_err); 190 goto end; 191 } 192 if (!EVP_PKEY_is_a(pkey, "DSA")) { 193 BIO_printf(bio_err, "Not a DSA key\n"); 194 goto end; 195 } 196 197 out = bio_open_owner(outfile, outformat, private); 198 if (out == NULL) 199 goto end; 200 201 if (text) { 202 assert(pubin || private); 203 if ((pubin && EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0) 204 || (!pubin && EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0)) { 205 perror(outfile); 206 ERR_print_errors(bio_err); 207 goto end; 208 } 209 } 210 211 if (modulus) { 212 BIGNUM *pub_key = NULL; 213 214 if (!EVP_PKEY_get_bn_param(pkey, "pub", &pub_key)) { 215 ERR_print_errors(bio_err); 216 goto end; 217 } 218 BIO_printf(out, "Public Key="); 219 BN_print(out, pub_key); 220 BIO_printf(out, "\n"); 221 BN_free(pub_key); 222 } 223 224 if (noout) { 225 ret = 0; 226 goto end; 227 } 228 BIO_printf(bio_err, "writing DSA key\n"); 229 if (outformat == FORMAT_ASN1) { 230 output_type = "DER"; 231 } else if (outformat == FORMAT_PEM) { 232 output_type = "PEM"; 233 } else if (outformat == FORMAT_MSBLOB) { 234 output_type = "MSBLOB"; 235 } else if (outformat == FORMAT_PVK) { 236 if (pubin) { 237 BIO_printf(bio_err, "PVK form impossible with public key input\n"); 238 goto end; 239 } 240 output_type = "PVK"; 241 } else { 242 BIO_printf(bio_err, "bad output format specified for outfile\n"); 243 goto end; 244 } 245 246 if (outformat == FORMAT_ASN1 || outformat == FORMAT_PEM) { 247 if (pubout || pubin) 248 output_structure = "SubjectPublicKeyInfo"; 249 else 250 output_structure = "type-specific"; 251 } 252 253 /* Select what you want in the output */ 254 if (pubout || pubin) { 255 selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY; 256 } else { 257 assert(private); 258 selection = (OSSL_KEYMGMT_SELECT_KEYPAIR 259 | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS); 260 } 261 262 /* Perform the encoding */ 263 ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, output_type, 264 output_structure, NULL); 265 if (OSSL_ENCODER_CTX_get_num_encoders(ectx) == 0) { 266 BIO_printf(bio_err, "%s format not supported\n", output_type); 267 goto end; 268 } 269 270 /* Passphrase setup */ 271 if (enc != NULL) 272 OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL); 273 274 /* Default passphrase prompter */ 275 if (enc != NULL || outformat == FORMAT_PVK) { 276 OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL); 277 if (passout != NULL) 278 /* When passout given, override the passphrase prompter */ 279 OSSL_ENCODER_CTX_set_passphrase(ectx, 280 (const unsigned char *)passout, 281 strlen(passout)); 282 } 283 284 /* PVK requires a bit more */ 285 if (outformat == FORMAT_PVK) { 286 OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; 287 288 params[0] = OSSL_PARAM_construct_int("encrypt-level", &pvk_encr); 289 if (!OSSL_ENCODER_CTX_set_params(ectx, params)) { 290 BIO_printf(bio_err, "invalid PVK encryption level\n"); 291 goto end; 292 } 293 } 294 295 if (!OSSL_ENCODER_to_bio(ectx, out)) { 296 BIO_printf(bio_err, "unable to write key\n"); 297 goto end; 298 } 299 ret = 0; 300 end: 301 if (ret != 0) 302 ERR_print_errors(bio_err); 303 OSSL_ENCODER_CTX_free(ectx); 304 BIO_free_all(out); 305 EVP_PKEY_free(pkey); 306 EVP_CIPHER_free(enc); 307 release_engine(e); 308 OPENSSL_free(passin); 309 OPENSSL_free(passout); 310 return ret; 311 } 312