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