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