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 <time.h> 15 #include <string.h> 16 #include "apps.h" 17 #include "progs.h" 18 #include <openssl/bio.h> 19 #include <openssl/err.h> 20 #include <openssl/bn.h> 21 #include <openssl/dsa.h> 22 #include <openssl/x509.h> 23 #include <openssl/pem.h> 24 25 static int verbose = 0; 26 27 typedef enum OPTION_choice { 28 OPT_COMMON, 29 OPT_INFORM, 30 OPT_OUTFORM, 31 OPT_IN, 32 OPT_OUT, 33 OPT_TEXT, 34 OPT_NOOUT, 35 OPT_GENKEY, 36 OPT_ENGINE, 37 OPT_VERBOSE, 38 OPT_QUIET, 39 OPT_R_ENUM, 40 OPT_PROV_ENUM 41 } OPTION_CHOICE; 42 43 const OPTIONS dsaparam_options[] = { 44 { OPT_HELP_STR, 1, '-', "Usage: %s [options] [numbits] [numqbits]\n" }, 45 46 OPT_SECTION("General"), 47 { "help", OPT_HELP, '-', "Display this summary" }, 48 #ifndef OPENSSL_NO_ENGINE 49 { "engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device" }, 50 #endif 51 52 OPT_SECTION("Input"), 53 { "in", OPT_IN, '<', "Input file" }, 54 { "inform", OPT_INFORM, 'F', "Input format - DER or PEM" }, 55 56 OPT_SECTION("Output"), 57 { "out", OPT_OUT, '>', "Output file" }, 58 { "outform", OPT_OUTFORM, 'F', "Output format - DER or PEM" }, 59 { "text", OPT_TEXT, '-', "Print as text" }, 60 { "noout", OPT_NOOUT, '-', "No output" }, 61 { "verbose", OPT_VERBOSE, '-', "Verbose output" }, 62 { "quiet", OPT_QUIET, '-', "Terse output" }, 63 { "genkey", OPT_GENKEY, '-', "Generate a DSA key" }, 64 65 OPT_R_OPTIONS, 66 OPT_PROV_OPTIONS, 67 68 OPT_PARAMETERS(), 69 { "numbits", 0, 0, "Number of bits if generating parameters or key (optional)" }, 70 { "numqbits", 0, 0, "Number of bits in the subprime parameter q if generating parameters or key (optional)" }, 71 { NULL } 72 }; 73 74 int dsaparam_main(int argc, char **argv) 75 { 76 ENGINE *e = NULL; 77 BIO *out = NULL; 78 EVP_PKEY *params = NULL, *pkey = NULL; 79 EVP_PKEY_CTX *ctx = NULL; 80 int numbits = -1, numqbits = -1, num = 0, genkey = 0; 81 int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, noout = 0; 82 int ret = 1, i, text = 0, private = 0; 83 char *infile = NULL, *outfile = NULL, *prog; 84 OPTION_CHOICE o; 85 86 prog = opt_init(argc, argv, dsaparam_options); 87 while ((o = opt_next()) != OPT_EOF) { 88 switch (o) { 89 case OPT_EOF: 90 case OPT_ERR: 91 opthelp: 92 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 93 goto end; 94 case OPT_HELP: 95 opt_help(dsaparam_options); 96 ret = 0; 97 goto end; 98 case OPT_INFORM: 99 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) 100 goto opthelp; 101 break; 102 case OPT_IN: 103 infile = opt_arg(); 104 break; 105 case OPT_OUTFORM: 106 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) 107 goto opthelp; 108 break; 109 case OPT_OUT: 110 outfile = opt_arg(); 111 break; 112 case OPT_ENGINE: 113 e = setup_engine(opt_arg(), 0); 114 break; 115 case OPT_TEXT: 116 text = 1; 117 break; 118 case OPT_GENKEY: 119 genkey = 1; 120 break; 121 case OPT_R_CASES: 122 if (!opt_rand(o)) 123 goto end; 124 break; 125 case OPT_PROV_CASES: 126 if (!opt_provider(o)) 127 goto end; 128 break; 129 case OPT_NOOUT: 130 noout = 1; 131 break; 132 case OPT_VERBOSE: 133 verbose = 1; 134 break; 135 case OPT_QUIET: 136 verbose = 0; 137 break; 138 } 139 } 140 141 /* Optional args are bitsize and q bitsize. */ 142 argc = opt_num_rest(); 143 argv = opt_rest(); 144 if (argc == 2) { 145 if (!opt_int(argv[0], &num) || num < 0) 146 goto opthelp; 147 if (!opt_int(argv[1], &numqbits) || numqbits < 0) 148 goto opthelp; 149 } else if (argc == 1) { 150 if (!opt_int(argv[0], &num) || num < 0) 151 goto opthelp; 152 } else if (!opt_check_rest_arg(NULL)) { 153 goto opthelp; 154 } 155 if (!app_RAND_load()) 156 goto end; 157 158 /* generate a key */ 159 numbits = num; 160 private = genkey ? 1 : 0; 161 162 ctx = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), "DSA", app_get0_propq()); 163 if (ctx == NULL) { 164 BIO_printf(bio_err, 165 "Error, DSA parameter generation context allocation failed\n"); 166 goto end; 167 } 168 if (numbits > 0) { 169 if (numbits > OPENSSL_DSA_MAX_MODULUS_BITS) 170 BIO_printf(bio_err, 171 "Warning: It is not recommended to use more than %d bit for DSA keys.\n" 172 " Your key size is %d! Larger key size may behave not as expected.\n", 173 OPENSSL_DSA_MAX_MODULUS_BITS, numbits); 174 175 EVP_PKEY_CTX_set_app_data(ctx, bio_err); 176 if (verbose) { 177 EVP_PKEY_CTX_set_cb(ctx, progress_cb); 178 BIO_printf(bio_err, "Generating DSA parameters, %d bit long prime\n", 179 num); 180 BIO_printf(bio_err, "This could take some time\n"); 181 } 182 if (EVP_PKEY_paramgen_init(ctx) <= 0) { 183 BIO_printf(bio_err, 184 "Error, DSA key generation paramgen init failed\n"); 185 goto end; 186 } 187 if (EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, num) <= 0) { 188 BIO_printf(bio_err, 189 "Error, DSA key generation setting bit length failed\n"); 190 goto end; 191 } 192 if (numqbits > 0) { 193 if (EVP_PKEY_CTX_set_dsa_paramgen_q_bits(ctx, numqbits) <= 0) { 194 BIO_printf(bio_err, 195 "Error, DSA key generation setting subprime bit length failed\n"); 196 goto end; 197 } 198 } 199 params = app_paramgen(ctx, "DSA"); 200 } else { 201 params = load_keyparams(infile, informat, 1, "DSA", "DSA parameters"); 202 } 203 if (params == NULL) { 204 /* Error message should already have been displayed */ 205 goto end; 206 } 207 208 out = bio_open_owner(outfile, outformat, private); 209 if (out == NULL) 210 goto end; 211 212 if (text) { 213 EVP_PKEY_print_params(out, params, 0, NULL); 214 } 215 216 if (outformat == FORMAT_ASN1 && genkey) 217 noout = 1; 218 219 if (!noout) { 220 if (outformat == FORMAT_ASN1) 221 i = i2d_KeyParams_bio(out, params); 222 else 223 i = PEM_write_bio_Parameters(out, params); 224 if (!i) { 225 BIO_printf(bio_err, "Error, unable to write DSA parameters\n"); 226 goto end; 227 } 228 } 229 if (genkey) { 230 EVP_PKEY_CTX_free(ctx); 231 ctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), params, 232 app_get0_propq()); 233 if (ctx == NULL) { 234 BIO_printf(bio_err, 235 "Error, DSA key generation context allocation failed\n"); 236 goto end; 237 } 238 if (EVP_PKEY_keygen_init(ctx) <= 0) { 239 BIO_printf(bio_err, 240 "Error, unable to initialise for key generation\n"); 241 goto end; 242 } 243 pkey = app_keygen(ctx, "DSA", numbits, verbose); 244 if (pkey == NULL) 245 goto end; 246 assert(private); 247 if (outformat == FORMAT_ASN1) 248 i = i2d_PrivateKey_bio(out, pkey); 249 else 250 i = PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, NULL); 251 } 252 ret = 0; 253 end: 254 if (ret != 0) 255 ERR_print_errors(bio_err); 256 BIO_free_all(out); 257 EVP_PKEY_CTX_free(ctx); 258 EVP_PKEY_free(pkey); 259 EVP_PKEY_free(params); 260 release_engine(e); 261 return ret; 262 } 263