1*b0100c00Stb /* $OpenBSD: rsa.c,v 1.20 2025/01/02 12:31:44 tb Exp $ */ 2dab3f910Sjsing /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3dab3f910Sjsing * All rights reserved. 4dab3f910Sjsing * 5dab3f910Sjsing * This package is an SSL implementation written 6dab3f910Sjsing * by Eric Young (eay@cryptsoft.com). 7dab3f910Sjsing * The implementation was written so as to conform with Netscapes SSL. 8dab3f910Sjsing * 9dab3f910Sjsing * This library is free for commercial and non-commercial use as long as 10dab3f910Sjsing * the following conditions are aheared to. The following conditions 11dab3f910Sjsing * apply to all code found in this distribution, be it the RC4, RSA, 12dab3f910Sjsing * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13dab3f910Sjsing * included with this distribution is covered by the same copyright terms 14dab3f910Sjsing * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15dab3f910Sjsing * 16dab3f910Sjsing * Copyright remains Eric Young's, and as such any Copyright notices in 17dab3f910Sjsing * the code are not to be removed. 18dab3f910Sjsing * If this package is used in a product, Eric Young should be given attribution 19dab3f910Sjsing * as the author of the parts of the library used. 20dab3f910Sjsing * This can be in the form of a textual message at program startup or 21dab3f910Sjsing * in documentation (online or textual) provided with the package. 22dab3f910Sjsing * 23dab3f910Sjsing * Redistribution and use in source and binary forms, with or without 24dab3f910Sjsing * modification, are permitted provided that the following conditions 25dab3f910Sjsing * are met: 26dab3f910Sjsing * 1. Redistributions of source code must retain the copyright 27dab3f910Sjsing * notice, this list of conditions and the following disclaimer. 28dab3f910Sjsing * 2. Redistributions in binary form must reproduce the above copyright 29dab3f910Sjsing * notice, this list of conditions and the following disclaimer in the 30dab3f910Sjsing * documentation and/or other materials provided with the distribution. 31dab3f910Sjsing * 3. All advertising materials mentioning features or use of this software 32dab3f910Sjsing * must display the following acknowledgement: 33dab3f910Sjsing * "This product includes cryptographic software written by 34dab3f910Sjsing * Eric Young (eay@cryptsoft.com)" 35dab3f910Sjsing * The word 'cryptographic' can be left out if the rouines from the library 36dab3f910Sjsing * being used are not cryptographic related :-). 37dab3f910Sjsing * 4. If you include any Windows specific code (or a derivative thereof) from 38dab3f910Sjsing * the apps directory (application code) you must include an acknowledgement: 39dab3f910Sjsing * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40dab3f910Sjsing * 41dab3f910Sjsing * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42dab3f910Sjsing * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43dab3f910Sjsing * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44dab3f910Sjsing * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45dab3f910Sjsing * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46dab3f910Sjsing * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47dab3f910Sjsing * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48dab3f910Sjsing * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49dab3f910Sjsing * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50dab3f910Sjsing * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51dab3f910Sjsing * SUCH DAMAGE. 52dab3f910Sjsing * 53dab3f910Sjsing * The licence and distribution terms for any publically available version or 54dab3f910Sjsing * derivative of this code cannot be changed. i.e. this code cannot simply be 55dab3f910Sjsing * copied and put under another distribution licence 56dab3f910Sjsing * [including the GNU Public Licence.] 57dab3f910Sjsing */ 58dab3f910Sjsing 59dab3f910Sjsing #include <openssl/opensslconf.h> 60dab3f910Sjsing 61dab3f910Sjsing #include <stdio.h> 62dab3f910Sjsing #include <stdlib.h> 63dab3f910Sjsing #include <string.h> 64dab3f910Sjsing #include <time.h> 65dab3f910Sjsing 66dab3f910Sjsing #include "apps.h" 67dab3f910Sjsing 68dab3f910Sjsing #include <openssl/bio.h> 69dab3f910Sjsing #include <openssl/bn.h> 70dab3f910Sjsing #include <openssl/err.h> 71dab3f910Sjsing #include <openssl/evp.h> 72dab3f910Sjsing #include <openssl/pem.h> 73dab3f910Sjsing #include <openssl/rsa.h> 74dab3f910Sjsing #include <openssl/x509.h> 75dab3f910Sjsing 7671636f46Sdoug static struct { 7771636f46Sdoug int check; 7871636f46Sdoug const EVP_CIPHER *enc; 7971636f46Sdoug char *infile; 8071636f46Sdoug int informat; 8171636f46Sdoug int modulus; 8271636f46Sdoug int noout; 8371636f46Sdoug char *outfile; 8471636f46Sdoug int outformat; 8571636f46Sdoug char *passargin; 8671636f46Sdoug char *passargout; 8771636f46Sdoug int pubin; 8871636f46Sdoug int pubout; 8971636f46Sdoug int pvk_encr; 9071636f46Sdoug int text; 91e7718adaStb } cfg; 92dab3f910Sjsing 9371636f46Sdoug static int 9471636f46Sdoug rsa_opt_cipher(int argc, char **argv, int *argsused) 9571636f46Sdoug { 9671636f46Sdoug char *name = argv[0]; 9771636f46Sdoug 9871636f46Sdoug if (*name++ != '-') 9971636f46Sdoug return (1); 10071636f46Sdoug 101e7718adaStb if ((cfg.enc = EVP_get_cipherbyname(name)) == NULL) { 10271636f46Sdoug fprintf(stderr, "Invalid cipher '%s'\n", name); 10371636f46Sdoug return (1); 10471636f46Sdoug } 10571636f46Sdoug 10671636f46Sdoug *argsused = 1; 10771636f46Sdoug return (0); 10871636f46Sdoug } 10971636f46Sdoug 110ea149709Sguenther static const struct option rsa_options[] = { 11171636f46Sdoug { 11271636f46Sdoug .name = "check", 11371636f46Sdoug .desc = "Check consistency of RSA private key", 11471636f46Sdoug .type = OPTION_FLAG, 115e7718adaStb .opt.flag = &cfg.check, 11671636f46Sdoug }, 11771636f46Sdoug { 11871636f46Sdoug .name = "in", 11971636f46Sdoug .argname = "file", 12071636f46Sdoug .desc = "Input file (default stdin)", 12171636f46Sdoug .type = OPTION_ARG, 122e7718adaStb .opt.arg = &cfg.infile, 12371636f46Sdoug }, 12471636f46Sdoug { 12571636f46Sdoug .name = "inform", 12671636f46Sdoug .argname = "format", 12771636f46Sdoug .desc = "Input format (DER, NET or PEM (default))", 12871636f46Sdoug .type = OPTION_ARG_FORMAT, 129e7718adaStb .opt.value = &cfg.informat, 13071636f46Sdoug }, 13171636f46Sdoug { 13271636f46Sdoug .name = "modulus", 13371636f46Sdoug .desc = "Print the RSA key modulus", 13471636f46Sdoug .type = OPTION_FLAG, 135e7718adaStb .opt.flag = &cfg.modulus, 13671636f46Sdoug }, 13771636f46Sdoug { 13871636f46Sdoug .name = "noout", 13971636f46Sdoug .desc = "Do not print encoded version of the key", 14071636f46Sdoug .type = OPTION_FLAG, 141e7718adaStb .opt.flag = &cfg.noout, 14271636f46Sdoug }, 14371636f46Sdoug { 14471636f46Sdoug .name = "out", 14571636f46Sdoug .argname = "file", 14671636f46Sdoug .desc = "Output file (default stdout)", 14771636f46Sdoug .type = OPTION_ARG, 148e7718adaStb .opt.arg = &cfg.outfile, 14971636f46Sdoug }, 15071636f46Sdoug { 15171636f46Sdoug .name = "outform", 15271636f46Sdoug .argname = "format", 15371636f46Sdoug .desc = "Output format (DER, NET or PEM (default PEM))", 15471636f46Sdoug .type = OPTION_ARG_FORMAT, 155e7718adaStb .opt.value = &cfg.outformat, 15671636f46Sdoug }, 15771636f46Sdoug { 15871636f46Sdoug .name = "passin", 15971636f46Sdoug .argname = "src", 16071636f46Sdoug .desc = "Input file passphrase source", 16171636f46Sdoug .type = OPTION_ARG, 162e7718adaStb .opt.arg = &cfg.passargin, 16371636f46Sdoug }, 16471636f46Sdoug { 16571636f46Sdoug .name = "passout", 16671636f46Sdoug .argname = "src", 16771636f46Sdoug .desc = "Output file passphrase source", 16871636f46Sdoug .type = OPTION_ARG, 169e7718adaStb .opt.arg = &cfg.passargout, 17071636f46Sdoug }, 17171636f46Sdoug { 17271636f46Sdoug .name = "pubin", 17371636f46Sdoug .desc = "Expect a public key (default private key)", 17471636f46Sdoug .type = OPTION_VALUE, 17571636f46Sdoug .value = 1, 176e7718adaStb .opt.value = &cfg.pubin, 17771636f46Sdoug }, 17871636f46Sdoug { 17971636f46Sdoug .name = "pubout", 18071636f46Sdoug .desc = "Output a public key (default private key)", 18171636f46Sdoug .type = OPTION_VALUE, 18271636f46Sdoug .value = 1, 183e7718adaStb .opt.value = &cfg.pubout, 18471636f46Sdoug }, 18571636f46Sdoug { 18671636f46Sdoug .name = "pvk-none", 18771636f46Sdoug .type = OPTION_VALUE, 18871636f46Sdoug .value = 0, 189e7718adaStb .opt.value = &cfg.pvk_encr, 19071636f46Sdoug }, 19171636f46Sdoug { 19271636f46Sdoug .name = "pvk-strong", 19371636f46Sdoug .type = OPTION_VALUE, 19471636f46Sdoug .value = 2, 195e7718adaStb .opt.value = &cfg.pvk_encr, 19671636f46Sdoug }, 19771636f46Sdoug { 19871636f46Sdoug .name = "pvk-weak", 19971636f46Sdoug .type = OPTION_VALUE, 20071636f46Sdoug .value = 1, 201e7718adaStb .opt.value = &cfg.pvk_encr, 20271636f46Sdoug }, 20371636f46Sdoug { 20471636f46Sdoug .name = "RSAPublicKey_in", 20571636f46Sdoug .type = OPTION_VALUE, 20671636f46Sdoug .value = 2, 207e7718adaStb .opt.value = &cfg.pubin, 20871636f46Sdoug }, 20971636f46Sdoug { 21071636f46Sdoug .name = "RSAPublicKey_out", 21171636f46Sdoug .type = OPTION_VALUE, 21271636f46Sdoug .value = 2, 213e7718adaStb .opt.value = &cfg.pubout, 21471636f46Sdoug }, 21571636f46Sdoug { 21671636f46Sdoug .name = "text", 21771636f46Sdoug .desc = "Print in plain text in addition to encoded", 21871636f46Sdoug .type = OPTION_FLAG, 219e7718adaStb .opt.flag = &cfg.text, 22071636f46Sdoug }, 22171636f46Sdoug { 22271636f46Sdoug .name = NULL, 22371636f46Sdoug .type = OPTION_ARGV_FUNC, 22471636f46Sdoug .opt.argvfunc = rsa_opt_cipher, 22571636f46Sdoug }, 22671636f46Sdoug { NULL } 22771636f46Sdoug }; 22871636f46Sdoug 22971636f46Sdoug static void 230440d1414Stb rsa_usage(void) 23171636f46Sdoug { 2326685372aSinoguchi int n = 0; 2336685372aSinoguchi 23471636f46Sdoug fprintf(stderr, 2355284dfeaSbcook "usage: rsa [-ciphername] [-check] [-in file] " 23671636f46Sdoug "[-inform fmt]\n" 23771636f46Sdoug " [-modulus] [-noout] [-out file] [-outform fmt] " 23871636f46Sdoug "[-passin src]\n" 239b1044e52Stb " [-passout src] [-pubin] [-pubout] [-text]\n\n"); 24071636f46Sdoug options_usage(rsa_options); 24171636f46Sdoug fprintf(stderr, "\n"); 24271636f46Sdoug 24371636f46Sdoug fprintf(stderr, "Valid ciphername values:\n\n"); 2446685372aSinoguchi OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_cipher, &n); 24571636f46Sdoug fprintf(stderr, "\n"); 24671636f46Sdoug } 247dab3f910Sjsing 248dab3f910Sjsing int 249dab3f910Sjsing rsa_main(int argc, char **argv) 250dab3f910Sjsing { 251dab3f910Sjsing int ret = 1; 252dab3f910Sjsing RSA *rsa = NULL; 25371636f46Sdoug int i; 254dab3f910Sjsing BIO *out = NULL; 255dab3f910Sjsing char *passin = NULL, *passout = NULL; 256dab3f910Sjsing 25751811eadSderaadt if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 2589bc487adSdoug perror("pledge"); 259e370f0eeSdoug exit(1); 260e370f0eeSdoug } 2619bc487adSdoug 262e7718adaStb memset(&cfg, 0, sizeof(cfg)); 263e7718adaStb cfg.pvk_encr = 2; 264e7718adaStb cfg.informat = FORMAT_PEM; 265e7718adaStb cfg.outformat = FORMAT_PEM; 266dab3f910Sjsing 26771636f46Sdoug if (options_parse(argc, argv, rsa_options, NULL, NULL) != 0) { 26871636f46Sdoug rsa_usage(); 269dab3f910Sjsing goto end; 270dab3f910Sjsing } 271dab3f910Sjsing 272e7718adaStb if (!app_passwd(bio_err, cfg.passargin, cfg.passargout, 27371636f46Sdoug &passin, &passout)) { 274dab3f910Sjsing BIO_printf(bio_err, "Error getting passwords\n"); 275dab3f910Sjsing goto end; 276dab3f910Sjsing } 277e7718adaStb if (cfg.check && cfg.pubin) { 278dab3f910Sjsing BIO_printf(bio_err, "Only private keys can be checked\n"); 279dab3f910Sjsing goto end; 280dab3f910Sjsing } 281dab3f910Sjsing out = BIO_new(BIO_s_file()); 282dab3f910Sjsing 283dab3f910Sjsing { 284dab3f910Sjsing EVP_PKEY *pkey; 285dab3f910Sjsing 286e7718adaStb if (cfg.pubin) { 287dab3f910Sjsing int tmpformat = -1; 288e7718adaStb if (cfg.pubin == 2) { 289e7718adaStb if (cfg.informat == FORMAT_PEM) 290dab3f910Sjsing tmpformat = FORMAT_PEMRSA; 291e7718adaStb else if (cfg.informat == FORMAT_ASN1) 292dab3f910Sjsing tmpformat = FORMAT_ASN1RSA; 293b1044e52Stb } else 294e7718adaStb tmpformat = cfg.informat; 295dab3f910Sjsing 296e7718adaStb pkey = load_pubkey(bio_err, cfg.infile, 2975284dfeaSbcook tmpformat, 1, passin, "Public Key"); 298dab3f910Sjsing } else 299e7718adaStb pkey = load_key(bio_err, cfg.infile, 300e7718adaStb cfg.informat, 1, passin, "Private Key"); 301dab3f910Sjsing 302dab3f910Sjsing if (pkey != NULL) 303dab3f910Sjsing rsa = EVP_PKEY_get1_RSA(pkey); 304dab3f910Sjsing EVP_PKEY_free(pkey); 305dab3f910Sjsing } 306dab3f910Sjsing 307dab3f910Sjsing if (rsa == NULL) { 308dab3f910Sjsing ERR_print_errors(bio_err); 309dab3f910Sjsing goto end; 310dab3f910Sjsing } 311e7718adaStb if (cfg.outfile == NULL) { 312dab3f910Sjsing BIO_set_fp(out, stdout, BIO_NOCLOSE); 313dab3f910Sjsing } else { 314e7718adaStb if (BIO_write_filename(out, cfg.outfile) <= 0) { 315e7718adaStb perror(cfg.outfile); 316dab3f910Sjsing goto end; 317dab3f910Sjsing } 318dab3f910Sjsing } 319dab3f910Sjsing 320e7718adaStb if (cfg.text) 321dab3f910Sjsing if (!RSA_print(out, rsa, 0)) { 322e7718adaStb perror(cfg.outfile); 323dab3f910Sjsing ERR_print_errors(bio_err); 324dab3f910Sjsing goto end; 325dab3f910Sjsing } 326e7718adaStb if (cfg.modulus) { 327dab3f910Sjsing BIO_printf(out, "Modulus="); 3282de05b95Stb BN_print(out, RSA_get0_n(rsa)); 329dab3f910Sjsing BIO_printf(out, "\n"); 330dab3f910Sjsing } 331e7718adaStb if (cfg.check) { 332dab3f910Sjsing int r = RSA_check_key(rsa); 333dab3f910Sjsing 334dab3f910Sjsing if (r == 1) 335dab3f910Sjsing BIO_printf(out, "RSA key ok\n"); 336dab3f910Sjsing else if (r == 0) { 337dab3f910Sjsing unsigned long err; 338dab3f910Sjsing 339dab3f910Sjsing while ((err = ERR_peek_error()) != 0 && 340dab3f910Sjsing ERR_GET_LIB(err) == ERR_LIB_RSA && 341dab3f910Sjsing ERR_GET_FUNC(err) == RSA_F_RSA_CHECK_KEY && 342dab3f910Sjsing ERR_GET_REASON(err) != ERR_R_MALLOC_FAILURE) { 34371636f46Sdoug BIO_printf(out, "RSA key error: %s\n", 34471636f46Sdoug ERR_reason_error_string(err)); 345dab3f910Sjsing ERR_get_error(); /* remove e from error 346dab3f910Sjsing * stack */ 347dab3f910Sjsing } 348dab3f910Sjsing } 349dab3f910Sjsing if (r == -1 || ERR_peek_error() != 0) { /* should happen only if 350dab3f910Sjsing * r == -1 */ 351dab3f910Sjsing ERR_print_errors(bio_err); 352dab3f910Sjsing goto end; 353dab3f910Sjsing } 354dab3f910Sjsing } 355e7718adaStb if (cfg.noout) { 356dab3f910Sjsing ret = 0; 357dab3f910Sjsing goto end; 358dab3f910Sjsing } 359dab3f910Sjsing BIO_printf(bio_err, "writing RSA key\n"); 360e7718adaStb if (cfg.outformat == FORMAT_ASN1) { 361e7718adaStb if (cfg.pubout || cfg.pubin) { 362e7718adaStb if (cfg.pubout == 2) 363dab3f910Sjsing i = i2d_RSAPublicKey_bio(out, rsa); 364dab3f910Sjsing else 365dab3f910Sjsing i = i2d_RSA_PUBKEY_bio(out, rsa); 366dab3f910Sjsing } else 367dab3f910Sjsing i = i2d_RSAPrivateKey_bio(out, rsa); 368e7718adaStb } else if (cfg.outformat == FORMAT_PEM) { 369e7718adaStb if (cfg.pubout || cfg.pubin) { 370e7718adaStb if (cfg.pubout == 2) 371dab3f910Sjsing i = PEM_write_bio_RSAPublicKey(out, rsa); 372dab3f910Sjsing else 373dab3f910Sjsing i = PEM_write_bio_RSA_PUBKEY(out, rsa); 374dab3f910Sjsing } else 375dab3f910Sjsing i = PEM_write_bio_RSAPrivateKey(out, rsa, 376e7718adaStb cfg.enc, NULL, 0, NULL, passout); 377dab3f910Sjsing #if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) 378e7718adaStb } else if (cfg.outformat == FORMAT_MSBLOB || 379e7718adaStb cfg.outformat == FORMAT_PVK) { 380dab3f910Sjsing EVP_PKEY *pk; 381dab3f910Sjsing pk = EVP_PKEY_new(); 382dab3f910Sjsing EVP_PKEY_set1_RSA(pk, rsa); 383e7718adaStb if (cfg.outformat == FORMAT_PVK) 384e7718adaStb i = i2b_PVK_bio(out, pk, cfg.pvk_encr, 0, 38571636f46Sdoug passout); 386e7718adaStb else if (cfg.pubin || cfg.pubout) 387dab3f910Sjsing i = i2b_PublicKey_bio(out, pk); 388dab3f910Sjsing else 389dab3f910Sjsing i = i2b_PrivateKey_bio(out, pk); 390dab3f910Sjsing EVP_PKEY_free(pk); 391dab3f910Sjsing #endif 392dab3f910Sjsing } else { 39371636f46Sdoug BIO_printf(bio_err, 39471636f46Sdoug "bad output format specified for outfile\n"); 395dab3f910Sjsing goto end; 396dab3f910Sjsing } 397dab3f910Sjsing if (i <= 0) { 398dab3f910Sjsing BIO_printf(bio_err, "unable to write key\n"); 399dab3f910Sjsing ERR_print_errors(bio_err); 400dab3f910Sjsing } else 401dab3f910Sjsing ret = 0; 40271636f46Sdoug 403dab3f910Sjsing end: 404dab3f910Sjsing BIO_free_all(out); 405dab3f910Sjsing RSA_free(rsa); 406dab3f910Sjsing free(passin); 407dab3f910Sjsing free(passout); 408dab3f910Sjsing 409dab3f910Sjsing return (ret); 410dab3f910Sjsing } 411