1e71b7053SJung-uk Kim /* 2e71b7053SJung-uk Kim * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. 374664626SKris Kennaway * 4e71b7053SJung-uk Kim * Licensed under the OpenSSL license (the "License"). You may not use 5e71b7053SJung-uk Kim * this file except in compliance with the License. You can obtain a copy 6e71b7053SJung-uk Kim * in the file LICENSE in the source distribution or at 7e71b7053SJung-uk Kim * https://www.openssl.org/source/license.html 874664626SKris Kennaway */ 974664626SKris Kennaway 103b4e3dcbSSimon L. B. Nielsen #include <openssl/opensslconf.h> 11e71b7053SJung-uk Kim #ifdef OPENSSL_NO_RSA 12e71b7053SJung-uk Kim NON_EMPTY_TRANSLATION_UNIT 13e71b7053SJung-uk Kim #else 14e71b7053SJung-uk Kim 1574664626SKris Kennaway # include <stdio.h> 1674664626SKris Kennaway # include <stdlib.h> 1774664626SKris Kennaway # include <string.h> 1874664626SKris Kennaway # include <time.h> 1974664626SKris Kennaway # include "apps.h" 20e71b7053SJung-uk Kim # include "progs.h" 2174664626SKris Kennaway # include <openssl/bio.h> 2274664626SKris Kennaway # include <openssl/err.h> 2374664626SKris Kennaway # include <openssl/rsa.h> 2474664626SKris Kennaway # include <openssl/evp.h> 2574664626SKris Kennaway # include <openssl/x509.h> 2674664626SKris Kennaway # include <openssl/pem.h> 273b4e3dcbSSimon L. B. Nielsen # include <openssl/bn.h> 2874664626SKris Kennaway 29e71b7053SJung-uk Kim typedef enum OPTION_choice { 30e71b7053SJung-uk Kim OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, 31e71b7053SJung-uk Kim OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT, 32e71b7053SJung-uk Kim OPT_PUBIN, OPT_PUBOUT, OPT_PASSOUT, OPT_PASSIN, 33e71b7053SJung-uk Kim OPT_RSAPUBKEY_IN, OPT_RSAPUBKEY_OUT, 34e71b7053SJung-uk Kim /* Do not change the order here; see case statements below */ 35e71b7053SJung-uk Kim OPT_PVK_NONE, OPT_PVK_WEAK, OPT_PVK_STRONG, 36e71b7053SJung-uk Kim OPT_NOOUT, OPT_TEXT, OPT_MODULUS, OPT_CHECK, OPT_CIPHER 37e71b7053SJung-uk Kim } OPTION_CHOICE; 3874664626SKris Kennaway 39e71b7053SJung-uk Kim const OPTIONS rsa_options[] = { 40e71b7053SJung-uk Kim {"help", OPT_HELP, '-', "Display this summary"}, 41*c9cf7b5cSJung-uk Kim {"inform", OPT_INFORM, 'f', "Input format, one of DER PEM"}, 42*c9cf7b5cSJung-uk Kim {"outform", OPT_OUTFORM, 'f', "Output format, one of DER PEM PVK"}, 43e71b7053SJung-uk Kim {"in", OPT_IN, 's', "Input file"}, 44e71b7053SJung-uk Kim {"out", OPT_OUT, '>', "Output file"}, 45e71b7053SJung-uk Kim {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, 46e71b7053SJung-uk Kim {"pubout", OPT_PUBOUT, '-', "Output a public key"}, 47e71b7053SJung-uk Kim {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, 48e71b7053SJung-uk Kim {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, 49e71b7053SJung-uk Kim {"RSAPublicKey_in", OPT_RSAPUBKEY_IN, '-', "Input is an RSAPublicKey"}, 50e71b7053SJung-uk Kim {"RSAPublicKey_out", OPT_RSAPUBKEY_OUT, '-', "Output is an RSAPublicKey"}, 51e71b7053SJung-uk Kim {"noout", OPT_NOOUT, '-', "Don't print key out"}, 52e71b7053SJung-uk Kim {"text", OPT_TEXT, '-', "Print the key in text"}, 53e71b7053SJung-uk Kim {"modulus", OPT_MODULUS, '-', "Print the RSA key modulus"}, 54e71b7053SJung-uk Kim {"check", OPT_CHECK, '-', "Verify key consistency"}, 55e71b7053SJung-uk Kim {"", OPT_CIPHER, '-', "Any supported cipher"}, 56e71b7053SJung-uk Kim # if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) 57e71b7053SJung-uk Kim {"pvk-strong", OPT_PVK_STRONG, '-', "Enable 'Strong' PVK encoding level (default)"}, 58e71b7053SJung-uk Kim {"pvk-weak", OPT_PVK_WEAK, '-', "Enable 'Weak' PVK encoding level"}, 59e71b7053SJung-uk Kim {"pvk-none", OPT_PVK_NONE, '-', "Don't enforce PVK encoding"}, 60e71b7053SJung-uk Kim # endif 61e71b7053SJung-uk Kim # ifndef OPENSSL_NO_ENGINE 62e71b7053SJung-uk Kim {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, 63e71b7053SJung-uk Kim # endif 64e71b7053SJung-uk Kim {NULL} 65e71b7053SJung-uk Kim }; 6674664626SKris Kennaway 67e71b7053SJung-uk Kim int rsa_main(int argc, char **argv) 6874664626SKris Kennaway { 695c87c606SMark Murray ENGINE *e = NULL; 705c87c606SMark Murray BIO *out = NULL; 71e71b7053SJung-uk Kim RSA *rsa = NULL; 72e71b7053SJung-uk Kim const EVP_CIPHER *enc = NULL; 73e71b7053SJung-uk Kim char *infile = NULL, *outfile = NULL, *prog; 74e71b7053SJung-uk Kim char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; 75e71b7053SJung-uk Kim int i, private = 0; 76e71b7053SJung-uk Kim int informat = FORMAT_PEM, outformat = FORMAT_PEM, text = 0, check = 0; 77e71b7053SJung-uk Kim int noout = 0, modulus = 0, pubin = 0, pubout = 0, ret = 1; 78e71b7053SJung-uk Kim # if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) 791f13597dSJung-uk Kim int pvk_encr = 2; 80fceca8a3SJacques Vidrine # endif 81e71b7053SJung-uk Kim OPTION_CHOICE o; 82e71b7053SJung-uk Kim 83e71b7053SJung-uk Kim prog = opt_init(argc, argv, rsa_options); 84e71b7053SJung-uk Kim while ((o = opt_next()) != OPT_EOF) { 85e71b7053SJung-uk Kim switch (o) { 86e71b7053SJung-uk Kim case OPT_EOF: 87e71b7053SJung-uk Kim case OPT_ERR: 88e71b7053SJung-uk Kim opthelp: 89e71b7053SJung-uk Kim BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 90e71b7053SJung-uk Kim goto end; 91e71b7053SJung-uk Kim case OPT_HELP: 92e71b7053SJung-uk Kim opt_help(rsa_options); 93e71b7053SJung-uk Kim ret = 0; 94e71b7053SJung-uk Kim goto end; 95e71b7053SJung-uk Kim case OPT_INFORM: 96e71b7053SJung-uk Kim if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) 97e71b7053SJung-uk Kim goto opthelp; 98e71b7053SJung-uk Kim break; 99e71b7053SJung-uk Kim case OPT_IN: 100e71b7053SJung-uk Kim infile = opt_arg(); 101e71b7053SJung-uk Kim break; 102e71b7053SJung-uk Kim case OPT_OUTFORM: 103e71b7053SJung-uk Kim if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat)) 104e71b7053SJung-uk Kim goto opthelp; 105e71b7053SJung-uk Kim break; 106e71b7053SJung-uk Kim case OPT_OUT: 107e71b7053SJung-uk Kim outfile = opt_arg(); 108e71b7053SJung-uk Kim break; 109e71b7053SJung-uk Kim case OPT_PASSIN: 110e71b7053SJung-uk Kim passinarg = opt_arg(); 111e71b7053SJung-uk Kim break; 112e71b7053SJung-uk Kim case OPT_PASSOUT: 113e71b7053SJung-uk Kim passoutarg = opt_arg(); 114e71b7053SJung-uk Kim break; 115e71b7053SJung-uk Kim case OPT_ENGINE: 116e71b7053SJung-uk Kim e = setup_engine(opt_arg(), 0); 117e71b7053SJung-uk Kim break; 118e71b7053SJung-uk Kim case OPT_PUBIN: 119f579bf8eSKris Kennaway pubin = 1; 120e71b7053SJung-uk Kim break; 121e71b7053SJung-uk Kim case OPT_PUBOUT: 122f579bf8eSKris Kennaway pubout = 1; 123e71b7053SJung-uk Kim break; 124e71b7053SJung-uk Kim case OPT_RSAPUBKEY_IN: 1251f13597dSJung-uk Kim pubin = 2; 126e71b7053SJung-uk Kim break; 127e71b7053SJung-uk Kim case OPT_RSAPUBKEY_OUT: 1281f13597dSJung-uk Kim pubout = 2; 129e71b7053SJung-uk Kim break; 130e71b7053SJung-uk Kim case OPT_PVK_STRONG: /* pvk_encr:= 2 */ 131e71b7053SJung-uk Kim case OPT_PVK_WEAK: /* pvk_encr:= 1 */ 132e71b7053SJung-uk Kim case OPT_PVK_NONE: /* pvk_encr:= 0 */ 133e71b7053SJung-uk Kim # if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) 134e71b7053SJung-uk Kim pvk_encr = (o - OPT_PVK_NONE); 135e71b7053SJung-uk Kim # endif 136e71b7053SJung-uk Kim break; 137e71b7053SJung-uk Kim case OPT_NOOUT: 13874664626SKris Kennaway noout = 1; 139e71b7053SJung-uk Kim break; 140e71b7053SJung-uk Kim case OPT_TEXT: 14174664626SKris Kennaway text = 1; 142e71b7053SJung-uk Kim break; 143e71b7053SJung-uk Kim case OPT_MODULUS: 14474664626SKris Kennaway modulus = 1; 145e71b7053SJung-uk Kim break; 146e71b7053SJung-uk Kim case OPT_CHECK: 14774664626SKris Kennaway check = 1; 148e71b7053SJung-uk Kim break; 149e71b7053SJung-uk Kim case OPT_CIPHER: 150e71b7053SJung-uk Kim if (!opt_cipher(opt_unknown(), &enc)) 151e71b7053SJung-uk Kim goto opthelp; 15274664626SKris Kennaway break; 15374664626SKris Kennaway } 15474664626SKris Kennaway } 155e71b7053SJung-uk Kim argc = opt_num_rest(); 156e71b7053SJung-uk Kim if (argc != 0) 157e71b7053SJung-uk Kim goto opthelp; 15874664626SKris Kennaway 159e71b7053SJung-uk Kim private = (text && !pubin) || (!pubout && !noout) ? 1 : 0; 16074664626SKris Kennaway 161e71b7053SJung-uk Kim if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { 162f579bf8eSKris Kennaway BIO_printf(bio_err, "Error getting passwords\n"); 163f579bf8eSKris Kennaway goto end; 164f579bf8eSKris Kennaway } 165f579bf8eSKris Kennaway if (check && pubin) { 166f579bf8eSKris Kennaway BIO_printf(bio_err, "Only private keys can be checked\n"); 167f579bf8eSKris Kennaway goto end; 168f579bf8eSKris Kennaway } 169f579bf8eSKris Kennaway 1705c87c606SMark Murray { 1715c87c606SMark Murray EVP_PKEY *pkey; 1725c87c606SMark Murray 1736f9291ceSJung-uk Kim if (pubin) { 1741f13597dSJung-uk Kim int tmpformat = -1; 1756f9291ceSJung-uk Kim if (pubin == 2) { 1761f13597dSJung-uk Kim if (informat == FORMAT_PEM) 1771f13597dSJung-uk Kim tmpformat = FORMAT_PEMRSA; 1781f13597dSJung-uk Kim else if (informat == FORMAT_ASN1) 1791f13597dSJung-uk Kim tmpformat = FORMAT_ASN1RSA; 180e71b7053SJung-uk Kim } else { 1811f13597dSJung-uk Kim tmpformat = informat; 182e71b7053SJung-uk Kim } 1831f13597dSJung-uk Kim 184e71b7053SJung-uk Kim pkey = load_pubkey(infile, tmpformat, 1, passin, e, "Public Key"); 185e71b7053SJung-uk Kim } else { 186e71b7053SJung-uk Kim pkey = load_key(infile, informat, 1, passin, e, "Private Key"); 187e71b7053SJung-uk Kim } 1885c87c606SMark Murray 1895c87c606SMark Murray if (pkey != NULL) 1901f13597dSJung-uk Kim rsa = EVP_PKEY_get1_RSA(pkey); 1915c87c606SMark Murray EVP_PKEY_free(pkey); 19274664626SKris Kennaway } 19374664626SKris Kennaway 1946f9291ceSJung-uk Kim if (rsa == NULL) { 19574664626SKris Kennaway ERR_print_errors(bio_err); 19674664626SKris Kennaway goto end; 19774664626SKris Kennaway } 19874664626SKris Kennaway 199e71b7053SJung-uk Kim out = bio_open_owner(outfile, outformat, private); 200e71b7053SJung-uk Kim if (out == NULL) 20174664626SKris Kennaway goto end; 20274664626SKris Kennaway 203e71b7053SJung-uk Kim if (text) { 204e71b7053SJung-uk Kim assert(pubin || private); 2056f9291ceSJung-uk Kim if (!RSA_print(out, rsa, 0)) { 20674664626SKris Kennaway perror(outfile); 20774664626SKris Kennaway ERR_print_errors(bio_err); 20874664626SKris Kennaway goto end; 20974664626SKris Kennaway } 210e71b7053SJung-uk Kim } 21174664626SKris Kennaway 2126f9291ceSJung-uk Kim if (modulus) { 213e71b7053SJung-uk Kim const BIGNUM *n; 214e71b7053SJung-uk Kim RSA_get0_key(rsa, &n, NULL, NULL); 215f579bf8eSKris Kennaway BIO_printf(out, "Modulus="); 216e71b7053SJung-uk Kim BN_print(out, n); 217f579bf8eSKris Kennaway BIO_printf(out, "\n"); 21874664626SKris Kennaway } 21974664626SKris Kennaway 2206f9291ceSJung-uk Kim if (check) { 221e71b7053SJung-uk Kim int r = RSA_check_key_ex(rsa, NULL); 22274664626SKris Kennaway 223e71b7053SJung-uk Kim if (r == 1) { 22474664626SKris Kennaway BIO_printf(out, "RSA key ok\n"); 225e71b7053SJung-uk Kim } else if (r == 0) { 2263b4e3dcbSSimon L. B. Nielsen unsigned long err; 22774664626SKris Kennaway 2285c87c606SMark Murray while ((err = ERR_peek_error()) != 0 && 2295c87c606SMark Murray ERR_GET_LIB(err) == ERR_LIB_RSA && 230e71b7053SJung-uk Kim ERR_GET_FUNC(err) == RSA_F_RSA_CHECK_KEY_EX && 2316f9291ceSJung-uk Kim ERR_GET_REASON(err) != ERR_R_MALLOC_FAILURE) { 2326f9291ceSJung-uk Kim BIO_printf(out, "RSA key error: %s\n", 2336f9291ceSJung-uk Kim ERR_reason_error_string(err)); 234e71b7053SJung-uk Kim ERR_get_error(); /* remove err from error stack */ 23574664626SKris Kennaway } 236e71b7053SJung-uk Kim } else if (r == -1) { 23774664626SKris Kennaway ERR_print_errors(bio_err); 23874664626SKris Kennaway goto end; 23974664626SKris Kennaway } 24074664626SKris Kennaway } 24174664626SKris Kennaway 2426f9291ceSJung-uk Kim if (noout) { 243f579bf8eSKris Kennaway ret = 0; 244f579bf8eSKris Kennaway goto end; 245f579bf8eSKris Kennaway } 246f579bf8eSKris Kennaway BIO_printf(bio_err, "writing RSA key\n"); 247f579bf8eSKris Kennaway if (outformat == FORMAT_ASN1) { 2486f9291ceSJung-uk Kim if (pubout || pubin) { 2491f13597dSJung-uk Kim if (pubout == 2) 2501f13597dSJung-uk Kim i = i2d_RSAPublicKey_bio(out, rsa); 2511f13597dSJung-uk Kim else 2521f13597dSJung-uk Kim i = i2d_RSA_PUBKEY_bio(out, rsa); 253e71b7053SJung-uk Kim } else { 254e71b7053SJung-uk Kim assert(private); 2556f9291ceSJung-uk Kim i = i2d_RSAPrivateKey_bio(out, rsa); 256f579bf8eSKris Kennaway } 257e71b7053SJung-uk Kim } else if (outformat == FORMAT_PEM) { 2586f9291ceSJung-uk Kim if (pubout || pubin) { 2591f13597dSJung-uk Kim if (pubout == 2) 2601f13597dSJung-uk Kim i = PEM_write_bio_RSAPublicKey(out, rsa); 2611f13597dSJung-uk Kim else 262f579bf8eSKris Kennaway i = PEM_write_bio_RSA_PUBKEY(out, rsa); 263e71b7053SJung-uk Kim } else { 264e71b7053SJung-uk Kim assert(private); 2656f9291ceSJung-uk Kim i = PEM_write_bio_RSAPrivateKey(out, rsa, 266f579bf8eSKris Kennaway enc, NULL, 0, NULL, passout); 267e71b7053SJung-uk Kim } 268e71b7053SJung-uk Kim # ifndef OPENSSL_NO_DSA 2691f13597dSJung-uk Kim } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { 2701f13597dSJung-uk Kim EVP_PKEY *pk; 2711f13597dSJung-uk Kim pk = EVP_PKEY_new(); 272*c9cf7b5cSJung-uk Kim if (pk == NULL) 273*c9cf7b5cSJung-uk Kim goto end; 274*c9cf7b5cSJung-uk Kim 2751f13597dSJung-uk Kim EVP_PKEY_set1_RSA(pk, rsa); 276e71b7053SJung-uk Kim if (outformat == FORMAT_PVK) { 277e71b7053SJung-uk Kim if (pubin) { 278e71b7053SJung-uk Kim BIO_printf(bio_err, "PVK form impossible with public key input\n"); 279e71b7053SJung-uk Kim EVP_PKEY_free(pk); 280e71b7053SJung-uk Kim goto end; 281e71b7053SJung-uk Kim } 282e71b7053SJung-uk Kim assert(private); 283e71b7053SJung-uk Kim # ifdef OPENSSL_NO_RC4 284e71b7053SJung-uk Kim BIO_printf(bio_err, "PVK format not supported\n"); 285e71b7053SJung-uk Kim EVP_PKEY_free(pk); 286e71b7053SJung-uk Kim goto end; 287e71b7053SJung-uk Kim # else 2881f13597dSJung-uk Kim i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout); 289e71b7053SJung-uk Kim # endif 290e71b7053SJung-uk Kim } else if (pubin || pubout) { 2911f13597dSJung-uk Kim i = i2b_PublicKey_bio(out, pk); 292e71b7053SJung-uk Kim } else { 293e71b7053SJung-uk Kim assert(private); 2941f13597dSJung-uk Kim i = i2b_PrivateKey_bio(out, pk); 295e71b7053SJung-uk Kim } 2961f13597dSJung-uk Kim EVP_PKEY_free(pk); 2971f13597dSJung-uk Kim # endif 298f579bf8eSKris Kennaway } else { 29974664626SKris Kennaway BIO_printf(bio_err, "bad output format specified for outfile\n"); 30074664626SKris Kennaway goto end; 30174664626SKris Kennaway } 3026f9291ceSJung-uk Kim if (i <= 0) { 303f579bf8eSKris Kennaway BIO_printf(bio_err, "unable to write key\n"); 30474664626SKris Kennaway ERR_print_errors(bio_err); 305e71b7053SJung-uk Kim } else { 30674664626SKris Kennaway ret = 0; 307e71b7053SJung-uk Kim } 30874664626SKris Kennaway end: 3096cf8931aSJung-uk Kim release_engine(e); 3106f9291ceSJung-uk Kim BIO_free_all(out); 3116f9291ceSJung-uk Kim RSA_free(rsa); 3126f9291ceSJung-uk Kim OPENSSL_free(passin); 3136f9291ceSJung-uk Kim OPENSSL_free(passout); 314e71b7053SJung-uk Kim return ret; 31574664626SKris Kennaway } 31674664626SKris Kennaway #endif 317