1 /* 2 * Copyright 1995-2023 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 opt_set_unknown_name("cipher"); 96 prog = opt_init(argc, argv, dsa_options); 97 while ((o = opt_next()) != OPT_EOF) { 98 switch (o) { 99 case OPT_EOF: 100 case OPT_ERR: 101 opthelp: 102 ret = 0; 103 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 104 goto end; 105 case OPT_HELP: 106 opt_help(dsa_options); 107 ret = 0; 108 goto end; 109 case OPT_INFORM: 110 if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) 111 goto opthelp; 112 break; 113 case OPT_IN: 114 infile = opt_arg(); 115 break; 116 case OPT_OUTFORM: 117 if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat)) 118 goto opthelp; 119 break; 120 case OPT_OUT: 121 outfile = opt_arg(); 122 break; 123 case OPT_ENGINE: 124 e = setup_engine(opt_arg(), 0); 125 break; 126 case OPT_PASSIN: 127 passinarg = opt_arg(); 128 break; 129 case OPT_PASSOUT: 130 passoutarg = opt_arg(); 131 break; 132 case OPT_PVK_STRONG: /* pvk_encr:= 2 */ 133 case OPT_PVK_WEAK: /* pvk_encr:= 1 */ 134 case OPT_PVK_NONE: /* pvk_encr:= 0 */ 135 #ifndef OPENSSL_NO_RC4 136 pvk_encr = (o - OPT_PVK_NONE); 137 #endif 138 break; 139 case OPT_NOOUT: 140 noout = 1; 141 break; 142 case OPT_TEXT: 143 text = 1; 144 break; 145 case OPT_MODULUS: 146 modulus = 1; 147 break; 148 case OPT_PUBIN: 149 pubin = 1; 150 break; 151 case OPT_PUBOUT: 152 pubout = 1; 153 break; 154 case OPT_CIPHER: 155 ciphername = opt_unknown(); 156 break; 157 case OPT_PROV_CASES: 158 if (!opt_provider(o)) 159 goto end; 160 break; 161 } 162 } 163 164 /* No extra args. */ 165 if (!opt_check_rest_arg(NULL)) 166 goto opthelp; 167 168 if (!opt_cipher(ciphername, &enc)) 169 goto end; 170 private = !pubin && (!pubout || text); 171 172 if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { 173 BIO_printf(bio_err, "Error getting passwords\n"); 174 goto end; 175 } 176 177 BIO_printf(bio_err, "read DSA key\n"); 178 if (pubin) 179 pkey = load_pubkey(infile, informat, 1, passin, e, "public key"); 180 else 181 pkey = load_key(infile, informat, 1, passin, e, "private key"); 182 183 if (pkey == NULL) { 184 BIO_printf(bio_err, "unable to load Key\n"); 185 ERR_print_errors(bio_err); 186 goto end; 187 } 188 if (!EVP_PKEY_is_a(pkey, "DSA")) { 189 BIO_printf(bio_err, "Not a DSA key\n"); 190 goto end; 191 } 192 193 out = bio_open_owner(outfile, outformat, private); 194 if (out == NULL) 195 goto end; 196 197 if (text) { 198 assert(pubin || private); 199 if ((pubin && EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0) 200 || (!pubin && EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0)) { 201 perror(outfile); 202 ERR_print_errors(bio_err); 203 goto end; 204 } 205 } 206 207 if (modulus) { 208 BIGNUM *pub_key = NULL; 209 210 if (!EVP_PKEY_get_bn_param(pkey, "pub", &pub_key)) { 211 ERR_print_errors(bio_err); 212 goto end; 213 } 214 BIO_printf(out, "Public Key="); 215 BN_print(out, pub_key); 216 BIO_printf(out, "\n"); 217 BN_free(pub_key); 218 } 219 220 if (noout) { 221 ret = 0; 222 goto end; 223 } 224 BIO_printf(bio_err, "writing DSA key\n"); 225 if (outformat == FORMAT_ASN1) { 226 output_type = "DER"; 227 } else if (outformat == FORMAT_PEM) { 228 output_type = "PEM"; 229 } else if (outformat == FORMAT_MSBLOB) { 230 output_type = "MSBLOB"; 231 } else if (outformat == FORMAT_PVK) { 232 if (pubin) { 233 BIO_printf(bio_err, "PVK form impossible with public key input\n"); 234 goto end; 235 } 236 output_type = "PVK"; 237 } else { 238 BIO_printf(bio_err, "bad output format specified for outfile\n"); 239 goto end; 240 } 241 242 if (outformat == FORMAT_ASN1 || outformat == FORMAT_PEM) { 243 if (pubout || pubin) 244 output_structure = "SubjectPublicKeyInfo"; 245 else 246 output_structure = "type-specific"; 247 } 248 249 /* Select what you want in the output */ 250 if (pubout || pubin) { 251 selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY; 252 } else { 253 assert(private); 254 selection = (OSSL_KEYMGMT_SELECT_KEYPAIR 255 | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS); 256 } 257 258 /* Perform the encoding */ 259 ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, output_type, 260 output_structure, NULL); 261 if (OSSL_ENCODER_CTX_get_num_encoders(ectx) == 0) { 262 BIO_printf(bio_err, "%s format not supported\n", output_type); 263 goto end; 264 } 265 266 /* Passphrase setup */ 267 if (enc != NULL) 268 OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL); 269 270 /* Default passphrase prompter */ 271 if (enc != NULL || outformat == FORMAT_PVK) { 272 OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL); 273 if (passout != NULL) 274 /* When passout given, override the passphrase prompter */ 275 OSSL_ENCODER_CTX_set_passphrase(ectx, 276 (const unsigned char *)passout, 277 strlen(passout)); 278 } 279 280 /* PVK requires a bit more */ 281 if (outformat == FORMAT_PVK) { 282 OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; 283 284 params[0] = OSSL_PARAM_construct_int("encrypt-level", &pvk_encr); 285 if (!OSSL_ENCODER_CTX_set_params(ectx, params)) { 286 BIO_printf(bio_err, "invalid PVK encryption level\n"); 287 goto end; 288 } 289 } 290 291 if (!OSSL_ENCODER_to_bio(ectx, out)) { 292 BIO_printf(bio_err, "unable to write key\n"); 293 goto end; 294 } 295 ret = 0; 296 end: 297 if (ret != 0) 298 ERR_print_errors(bio_err); 299 OSSL_ENCODER_CTX_free(ectx); 300 BIO_free_all(out); 301 EVP_PKEY_free(pkey); 302 EVP_CIPHER_free(enc); 303 release_engine(e); 304 OPENSSL_free(passin); 305 OPENSSL_free(passout); 306 return ret; 307 } 308