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 /* Necessary for legacy RSA public key export */ 11 #define OPENSSL_SUPPRESS_DEPRECATED 12 13 #include <openssl/opensslconf.h> 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <time.h> 19 #include "apps.h" 20 #include "progs.h" 21 #include <openssl/bio.h> 22 #include <openssl/err.h> 23 #include <openssl/rsa.h> 24 #include <openssl/evp.h> 25 #include <openssl/x509.h> 26 #include <openssl/pem.h> 27 #include <openssl/bn.h> 28 #include <openssl/encoder.h> 29 30 /* 31 * This include is to get OSSL_KEYMGMT_SELECT_*, which feels a bit 32 * much just for those macros... they might serve better as EVP macros. 33 */ 34 #include <openssl/core_dispatch.h> 35 36 #ifndef OPENSSL_NO_RC4 37 #define DEFAULT_PVK_ENCR_STRENGTH 2 38 #else 39 #define DEFAULT_PVK_ENCR_STRENGTH 0 40 #endif 41 42 typedef enum OPTION_choice { 43 OPT_COMMON, 44 OPT_INFORM, 45 OPT_OUTFORM, 46 OPT_ENGINE, 47 OPT_IN, 48 OPT_OUT, 49 OPT_PUBIN, 50 OPT_PUBOUT, 51 OPT_PASSOUT, 52 OPT_PASSIN, 53 OPT_RSAPUBKEY_IN, 54 OPT_RSAPUBKEY_OUT, 55 /* Do not change the order here; see case statements below */ 56 OPT_PVK_NONE, 57 OPT_PVK_WEAK, 58 OPT_PVK_STRONG, 59 OPT_NOOUT, 60 OPT_TEXT, 61 OPT_MODULUS, 62 OPT_CHECK, 63 OPT_CIPHER, 64 OPT_PROV_ENUM, 65 OPT_TRADITIONAL 66 } OPTION_CHOICE; 67 68 const OPTIONS rsa_options[] = { 69 OPT_SECTION("General"), 70 { "help", OPT_HELP, '-', "Display this summary" }, 71 { "check", OPT_CHECK, '-', "Verify key consistency" }, 72 { "", OPT_CIPHER, '-', "Any supported cipher" }, 73 #ifndef OPENSSL_NO_ENGINE 74 { "engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device" }, 75 #endif 76 77 OPT_SECTION("Input"), 78 { "in", OPT_IN, 's', "Input file" }, 79 { "inform", OPT_INFORM, 'f', "Input format (DER/PEM/P12/ENGINE)" }, 80 { "pubin", OPT_PUBIN, '-', "Expect a public key in input file" }, 81 { "RSAPublicKey_in", OPT_RSAPUBKEY_IN, '-', "Input is an RSAPublicKey" }, 82 { "passin", OPT_PASSIN, 's', "Input file pass phrase source" }, 83 84 OPT_SECTION("Output"), 85 { "out", OPT_OUT, '>', "Output file" }, 86 { "outform", OPT_OUTFORM, 'f', "Output format, one of DER PEM PVK" }, 87 { "pubout", OPT_PUBOUT, '-', "Output a public key" }, 88 { "RSAPublicKey_out", OPT_RSAPUBKEY_OUT, '-', "Output is an RSAPublicKey" }, 89 { "passout", OPT_PASSOUT, 's', "Output file pass phrase source" }, 90 { "noout", OPT_NOOUT, '-', "Don't print key out" }, 91 { "text", OPT_TEXT, '-', "Print the key in text" }, 92 { "modulus", OPT_MODULUS, '-', "Print the RSA key modulus" }, 93 { "traditional", OPT_TRADITIONAL, '-', 94 "Use traditional format for private keys" }, 95 96 #ifndef OPENSSL_NO_RC4 97 OPT_SECTION("PVK"), 98 { "pvk-strong", OPT_PVK_STRONG, '-', "Enable 'Strong' PVK encoding level (default)" }, 99 { "pvk-weak", OPT_PVK_WEAK, '-', "Enable 'Weak' PVK encoding level" }, 100 { "pvk-none", OPT_PVK_NONE, '-', "Don't enforce PVK encoding" }, 101 #endif 102 103 OPT_PROV_OPTIONS, 104 { NULL } 105 }; 106 107 static int try_legacy_encoding(EVP_PKEY *pkey, int outformat, int pubout, 108 BIO *out) 109 { 110 int ret = 0; 111 #ifndef OPENSSL_NO_DEPRECATED_3_0 112 const RSA *rsa = EVP_PKEY_get0_RSA(pkey); 113 114 if (rsa == NULL) 115 return 0; 116 117 if (outformat == FORMAT_ASN1) { 118 if (pubout == 2) 119 ret = i2d_RSAPublicKey_bio(out, rsa) > 0; 120 else 121 ret = i2d_RSA_PUBKEY_bio(out, rsa) > 0; 122 } else if (outformat == FORMAT_PEM) { 123 if (pubout == 2) 124 ret = PEM_write_bio_RSAPublicKey(out, rsa) > 0; 125 else 126 ret = PEM_write_bio_RSA_PUBKEY(out, rsa) > 0; 127 #ifndef OPENSSL_NO_DSA 128 } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { 129 ret = i2b_PublicKey_bio(out, pkey) > 0; 130 #endif 131 } 132 #endif 133 134 return ret; 135 } 136 137 int rsa_main(int argc, char **argv) 138 { 139 ENGINE *e = NULL; 140 BIO *out = NULL; 141 EVP_PKEY *pkey = NULL; 142 EVP_PKEY_CTX *pctx; 143 EVP_CIPHER *enc = NULL; 144 char *infile = NULL, *outfile = NULL, *ciphername = NULL, *prog; 145 char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; 146 int private = 0; 147 int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, check = 0; 148 int noout = 0, modulus = 0, pubin = 0, pubout = 0, ret = 1; 149 int pvk_encr = DEFAULT_PVK_ENCR_STRENGTH; 150 OPTION_CHOICE o; 151 int traditional = 0; 152 const char *output_type = NULL; 153 const char *output_structure = NULL; 154 int selection = 0; 155 OSSL_ENCODER_CTX *ectx = NULL; 156 157 opt_set_unknown_name("cipher"); 158 prog = opt_init(argc, argv, rsa_options); 159 while ((o = opt_next()) != OPT_EOF) { 160 switch (o) { 161 case OPT_EOF: 162 case OPT_ERR: 163 opthelp: 164 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 165 goto end; 166 case OPT_HELP: 167 opt_help(rsa_options); 168 ret = 0; 169 goto end; 170 case OPT_INFORM: 171 if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) 172 goto opthelp; 173 break; 174 case OPT_IN: 175 infile = opt_arg(); 176 break; 177 case OPT_OUTFORM: 178 if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat)) 179 goto opthelp; 180 break; 181 case OPT_OUT: 182 outfile = opt_arg(); 183 break; 184 case OPT_PASSIN: 185 passinarg = opt_arg(); 186 break; 187 case OPT_PASSOUT: 188 passoutarg = opt_arg(); 189 break; 190 case OPT_ENGINE: 191 e = setup_engine(opt_arg(), 0); 192 break; 193 case OPT_PUBIN: 194 pubin = 1; 195 break; 196 case OPT_PUBOUT: 197 pubout = 1; 198 break; 199 case OPT_RSAPUBKEY_IN: 200 pubin = 2; 201 break; 202 case OPT_RSAPUBKEY_OUT: 203 pubout = 2; 204 break; 205 case OPT_PVK_STRONG: /* pvk_encr:= 2 */ 206 case OPT_PVK_WEAK: /* pvk_encr:= 1 */ 207 case OPT_PVK_NONE: /* pvk_encr:= 0 */ 208 pvk_encr = (o - OPT_PVK_NONE); 209 break; 210 case OPT_NOOUT: 211 noout = 1; 212 break; 213 case OPT_TEXT: 214 text = 1; 215 break; 216 case OPT_MODULUS: 217 modulus = 1; 218 break; 219 case OPT_CHECK: 220 check = 1; 221 break; 222 case OPT_CIPHER: 223 ciphername = opt_unknown(); 224 break; 225 case OPT_PROV_CASES: 226 if (!opt_provider(o)) 227 goto end; 228 break; 229 case OPT_TRADITIONAL: 230 traditional = 1; 231 break; 232 } 233 } 234 235 /* No extra arguments. */ 236 if (!opt_check_rest_arg(NULL)) 237 goto opthelp; 238 239 if (!opt_cipher(ciphername, &enc)) 240 goto opthelp; 241 private = (text && !pubin) || (!pubout && !noout); 242 243 if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { 244 BIO_printf(bio_err, "Error getting passwords\n"); 245 goto end; 246 } 247 if (check && pubin) { 248 BIO_printf(bio_err, "Only private keys can be checked\n"); 249 goto end; 250 } 251 252 if (pubin) { 253 int tmpformat = FORMAT_UNDEF; 254 255 if (pubin == 2) { 256 if (informat == FORMAT_PEM) 257 tmpformat = FORMAT_PEMRSA; 258 else if (informat == FORMAT_ASN1) 259 tmpformat = FORMAT_ASN1RSA; 260 } else { 261 tmpformat = informat; 262 } 263 264 pkey = load_pubkey(infile, tmpformat, 1, passin, e, "public key"); 265 } else { 266 pkey = load_key(infile, informat, 1, passin, e, "private key"); 267 } 268 269 if (pkey == NULL) { 270 ERR_print_errors(bio_err); 271 goto end; 272 } 273 if (!EVP_PKEY_is_a(pkey, "RSA") && !EVP_PKEY_is_a(pkey, "RSA-PSS")) { 274 BIO_printf(bio_err, "Not an RSA key\n"); 275 goto end; 276 } 277 278 out = bio_open_owner(outfile, outformat, private); 279 if (out == NULL) 280 goto end; 281 282 if (text) { 283 assert(pubin || private); 284 if ((pubin && EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0) 285 || (!pubin && EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0)) { 286 perror(outfile); 287 ERR_print_errors(bio_err); 288 goto end; 289 } 290 } 291 292 if (modulus) { 293 BIGNUM *n = NULL; 294 295 /* Every RSA key has an 'n' */ 296 EVP_PKEY_get_bn_param(pkey, "n", &n); 297 BIO_printf(out, "Modulus="); 298 BN_print(out, n); 299 BIO_printf(out, "\n"); 300 BN_free(n); 301 } 302 303 if (check) { 304 int r; 305 306 pctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); 307 if (pctx == NULL) { 308 BIO_printf(bio_err, "RSA unable to create PKEY context\n"); 309 ERR_print_errors(bio_err); 310 goto end; 311 } 312 r = EVP_PKEY_check(pctx); 313 EVP_PKEY_CTX_free(pctx); 314 315 if (r == 1) { 316 BIO_printf(out, "RSA key ok\n"); 317 } else if (r == 0) { 318 BIO_printf(bio_err, "RSA key not ok\n"); 319 ERR_print_errors(bio_err); 320 } else if (r < 0) { 321 ERR_print_errors(bio_err); 322 goto end; 323 } 324 } 325 326 if (noout) { 327 ret = 0; 328 goto end; 329 } 330 BIO_printf(bio_err, "writing RSA key\n"); 331 332 /* Choose output type for the format */ 333 if (outformat == FORMAT_ASN1) { 334 output_type = "DER"; 335 } else if (outformat == FORMAT_PEM) { 336 output_type = "PEM"; 337 } else if (outformat == FORMAT_MSBLOB) { 338 output_type = "MSBLOB"; 339 } else if (outformat == FORMAT_PVK) { 340 if (pubin) { 341 BIO_printf(bio_err, "PVK form impossible with public key input\n"); 342 goto end; 343 } 344 output_type = "PVK"; 345 } else { 346 BIO_printf(bio_err, "bad output format specified for outfile\n"); 347 goto end; 348 } 349 350 /* Select what you want in the output */ 351 if (pubout || pubin) { 352 selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY; 353 } else { 354 assert(private); 355 selection = (OSSL_KEYMGMT_SELECT_KEYPAIR 356 | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS); 357 } 358 359 /* For DER based output, select the desired output structure */ 360 if (outformat == FORMAT_ASN1 || outformat == FORMAT_PEM) { 361 if (pubout || pubin) { 362 if (pubout == 2) 363 output_structure = "pkcs1"; /* "type-specific" would work too */ 364 else 365 output_structure = "SubjectPublicKeyInfo"; 366 } else { 367 assert(private); 368 if (traditional) 369 output_structure = "pkcs1"; /* "type-specific" would work too */ 370 else 371 output_structure = "PrivateKeyInfo"; 372 } 373 } 374 375 /* Now, perform the encoding */ 376 ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, 377 output_type, output_structure, 378 NULL); 379 if (OSSL_ENCODER_CTX_get_num_encoders(ectx) == 0) { 380 if ((!pubout && !pubin) 381 || !try_legacy_encoding(pkey, outformat, pubout, out)) 382 BIO_printf(bio_err, "%s format not supported\n", output_type); 383 else 384 ret = 0; 385 goto end; 386 } 387 388 /* Passphrase setup */ 389 if (enc != NULL) 390 OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL); 391 392 /* Default passphrase prompter */ 393 if (enc != NULL || outformat == FORMAT_PVK) { 394 OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL); 395 if (passout != NULL) 396 /* When passout given, override the passphrase prompter */ 397 OSSL_ENCODER_CTX_set_passphrase(ectx, 398 (const unsigned char *)passout, 399 strlen(passout)); 400 } 401 402 /* PVK is a bit special... */ 403 if (outformat == FORMAT_PVK) { 404 OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; 405 406 params[0] = OSSL_PARAM_construct_int("encrypt-level", &pvk_encr); 407 if (!OSSL_ENCODER_CTX_set_params(ectx, params)) { 408 BIO_printf(bio_err, "invalid PVK encryption level\n"); 409 goto end; 410 } 411 } 412 413 if (!OSSL_ENCODER_to_bio(ectx, out)) { 414 BIO_printf(bio_err, "unable to write key\n"); 415 ERR_print_errors(bio_err); 416 goto end; 417 } 418 ret = 0; 419 end: 420 OSSL_ENCODER_CTX_free(ectx); 421 release_engine(e); 422 BIO_free_all(out); 423 EVP_PKEY_free(pkey); 424 EVP_CIPHER_free(enc); 425 OPENSSL_free(passin); 426 OPENSSL_free(passout); 427 return ret; 428 } 429