1*ea149709Sguenther /* $OpenBSD: rsautl.c,v 1.18 2019/07/14 03:30:46 guenther Exp $ */ 2dab3f910Sjsing /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3dab3f910Sjsing * project 2000. 4dab3f910Sjsing */ 5dab3f910Sjsing /* ==================================================================== 6dab3f910Sjsing * Copyright (c) 2000 The OpenSSL Project. All rights reserved. 7dab3f910Sjsing * 8dab3f910Sjsing * Redistribution and use in source and binary forms, with or without 9dab3f910Sjsing * modification, are permitted provided that the following conditions 10dab3f910Sjsing * are met: 11dab3f910Sjsing * 12dab3f910Sjsing * 1. Redistributions of source code must retain the above copyright 13dab3f910Sjsing * notice, this list of conditions and the following disclaimer. 14dab3f910Sjsing * 15dab3f910Sjsing * 2. Redistributions in binary form must reproduce the above copyright 16dab3f910Sjsing * notice, this list of conditions and the following disclaimer in 17dab3f910Sjsing * the documentation and/or other materials provided with the 18dab3f910Sjsing * distribution. 19dab3f910Sjsing * 20dab3f910Sjsing * 3. All advertising materials mentioning features or use of this 21dab3f910Sjsing * software must display the following acknowledgment: 22dab3f910Sjsing * "This product includes software developed by the OpenSSL Project 23dab3f910Sjsing * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24dab3f910Sjsing * 25dab3f910Sjsing * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26dab3f910Sjsing * endorse or promote products derived from this software without 27dab3f910Sjsing * prior written permission. For written permission, please contact 28dab3f910Sjsing * licensing@OpenSSL.org. 29dab3f910Sjsing * 30dab3f910Sjsing * 5. Products derived from this software may not be called "OpenSSL" 31dab3f910Sjsing * nor may "OpenSSL" appear in their names without prior written 32dab3f910Sjsing * permission of the OpenSSL Project. 33dab3f910Sjsing * 34dab3f910Sjsing * 6. Redistributions of any form whatsoever must retain the following 35dab3f910Sjsing * acknowledgment: 36dab3f910Sjsing * "This product includes software developed by the OpenSSL Project 37dab3f910Sjsing * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38dab3f910Sjsing * 39dab3f910Sjsing * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40dab3f910Sjsing * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41dab3f910Sjsing * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42dab3f910Sjsing * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43dab3f910Sjsing * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44dab3f910Sjsing * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45dab3f910Sjsing * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46dab3f910Sjsing * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47dab3f910Sjsing * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48dab3f910Sjsing * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49dab3f910Sjsing * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50dab3f910Sjsing * OF THE POSSIBILITY OF SUCH DAMAGE. 51dab3f910Sjsing * ==================================================================== 52dab3f910Sjsing * 53dab3f910Sjsing * This product includes cryptographic software written by Eric Young 54dab3f910Sjsing * (eay@cryptsoft.com). This product includes software written by Tim 55dab3f910Sjsing * Hudson (tjh@cryptsoft.com). 56dab3f910Sjsing * 57dab3f910Sjsing */ 58dab3f910Sjsing 59dab3f910Sjsing #include <openssl/opensslconf.h> 60dab3f910Sjsing 61dab3f910Sjsing #include <string.h> 62dab3f910Sjsing 63dab3f910Sjsing #include "apps.h" 64dab3f910Sjsing 65dab3f910Sjsing #include <openssl/err.h> 66dab3f910Sjsing #include <openssl/pem.h> 67dab3f910Sjsing #include <openssl/rsa.h> 68dab3f910Sjsing 69dab3f910Sjsing #define RSA_SIGN 1 70dab3f910Sjsing #define RSA_VERIFY 2 71dab3f910Sjsing #define RSA_ENCRYPT 3 72dab3f910Sjsing #define RSA_DECRYPT 4 73dab3f910Sjsing 74dab3f910Sjsing #define KEY_PRIVKEY 1 75dab3f910Sjsing #define KEY_PUBKEY 2 76dab3f910Sjsing #define KEY_CERT 3 77dab3f910Sjsing 7894e38b1eSjsing struct { 7994e38b1eSjsing int asn1parse; 8094e38b1eSjsing int hexdump; 8194e38b1eSjsing char *infile; 8294e38b1eSjsing char *keyfile; 8394e38b1eSjsing int keyform; 8494e38b1eSjsing int key_type; 8594e38b1eSjsing char *outfile; 8694e38b1eSjsing int pad; 8794e38b1eSjsing char *passargin; 8894e38b1eSjsing int rev; 8994e38b1eSjsing int rsa_mode; 9094e38b1eSjsing } rsautl_config; 9194e38b1eSjsing 92*ea149709Sguenther static const struct option rsautl_options[] = { 9394e38b1eSjsing { 9494e38b1eSjsing .name = "asn1parse", 9594e38b1eSjsing .desc = "ASN.1 parse the output data", 9694e38b1eSjsing .type = OPTION_FLAG, 9794e38b1eSjsing .opt.flag = &rsautl_config.asn1parse, 9894e38b1eSjsing }, 9994e38b1eSjsing { 10094e38b1eSjsing .name = "certin", 10194e38b1eSjsing .desc = "Input is a certificate containing an RSA public key", 10294e38b1eSjsing .type = OPTION_VALUE, 10394e38b1eSjsing .value = KEY_CERT, 10494e38b1eSjsing .opt.value = &rsautl_config.key_type, 10594e38b1eSjsing }, 10694e38b1eSjsing { 10794e38b1eSjsing .name = "decrypt", 10894e38b1eSjsing .desc = "Decrypt the input data using RSA private key", 10994e38b1eSjsing .type = OPTION_VALUE, 11094e38b1eSjsing .value = RSA_DECRYPT, 11194e38b1eSjsing .opt.value = &rsautl_config.rsa_mode, 11294e38b1eSjsing }, 11394e38b1eSjsing { 11494e38b1eSjsing .name = "encrypt", 11594e38b1eSjsing .desc = "Encrypt the input data using RSA public key", 11694e38b1eSjsing .type = OPTION_VALUE, 11794e38b1eSjsing .value = RSA_ENCRYPT, 11894e38b1eSjsing .opt.value = &rsautl_config.rsa_mode, 11994e38b1eSjsing }, 12094e38b1eSjsing { 12194e38b1eSjsing .name = "hexdump", 12294e38b1eSjsing .desc = "Hex dump the output data", 12394e38b1eSjsing .type = OPTION_FLAG, 12494e38b1eSjsing .opt.flag = &rsautl_config.hexdump, 12594e38b1eSjsing }, 12694e38b1eSjsing { 12794e38b1eSjsing .name = "in", 12894e38b1eSjsing .argname = "file", 12994e38b1eSjsing .desc = "Input file (default stdin)", 13094e38b1eSjsing .type = OPTION_ARG, 13194e38b1eSjsing .opt.arg = &rsautl_config.infile, 13294e38b1eSjsing }, 13394e38b1eSjsing { 13494e38b1eSjsing .name = "inkey", 13594e38b1eSjsing .argname = "file", 13694e38b1eSjsing .desc = "Input key file", 13794e38b1eSjsing .type = OPTION_ARG, 13894e38b1eSjsing .opt.arg = &rsautl_config.keyfile, 13994e38b1eSjsing }, 14094e38b1eSjsing { 14194e38b1eSjsing .name = "keyform", 14294e38b1eSjsing .argname = "fmt", 14394e38b1eSjsing .desc = "Input key format (DER, TXT or PEM (default))", 14494e38b1eSjsing .type = OPTION_ARG_FORMAT, 14594e38b1eSjsing .opt.value = &rsautl_config.keyform, 14694e38b1eSjsing }, 14794e38b1eSjsing { 14894e38b1eSjsing .name = "oaep", 14994e38b1eSjsing .desc = "Use PKCS#1 OAEP padding", 15094e38b1eSjsing .type = OPTION_VALUE, 15194e38b1eSjsing .value = RSA_PKCS1_OAEP_PADDING, 15294e38b1eSjsing .opt.value = &rsautl_config.pad, 15394e38b1eSjsing }, 15494e38b1eSjsing { 15594e38b1eSjsing .name = "out", 15694e38b1eSjsing .argname = "file", 15794e38b1eSjsing .desc = "Output file (default stdout)", 15894e38b1eSjsing .type = OPTION_ARG, 15994e38b1eSjsing .opt.arg = &rsautl_config.outfile, 16094e38b1eSjsing }, 16194e38b1eSjsing { 16294e38b1eSjsing .name = "passin", 16394e38b1eSjsing .argname = "arg", 16494e38b1eSjsing .desc = "Key password source", 16594e38b1eSjsing .type = OPTION_ARG, 16694e38b1eSjsing .opt.arg = &rsautl_config.passargin, 16794e38b1eSjsing }, 16894e38b1eSjsing { 16994e38b1eSjsing .name = "pkcs", 17094e38b1eSjsing .desc = "Use PKCS#1 v1.5 padding (default)", 17194e38b1eSjsing .type = OPTION_VALUE, 17294e38b1eSjsing .value = RSA_PKCS1_PADDING, 17394e38b1eSjsing .opt.value = &rsautl_config.pad, 17494e38b1eSjsing }, 17594e38b1eSjsing { 17694e38b1eSjsing .name = "pubin", 17794e38b1eSjsing .desc = "Input is an RSA public key", 17894e38b1eSjsing .type = OPTION_VALUE, 17994e38b1eSjsing .value = KEY_PUBKEY, 18094e38b1eSjsing .opt.value = &rsautl_config.key_type, 18194e38b1eSjsing }, 18294e38b1eSjsing { 18394e38b1eSjsing .name = "raw", 18494e38b1eSjsing .desc = "Use no padding", 18594e38b1eSjsing .type = OPTION_VALUE, 18694e38b1eSjsing .value = RSA_NO_PADDING, 18794e38b1eSjsing .opt.value = &rsautl_config.pad, 18894e38b1eSjsing }, 18994e38b1eSjsing { 19094e38b1eSjsing .name = "rev", 19194e38b1eSjsing .desc = "Reverse the input data", 19294e38b1eSjsing .type = OPTION_FLAG, 19394e38b1eSjsing .opt.flag = &rsautl_config.rev, 19494e38b1eSjsing }, 19594e38b1eSjsing { 19694e38b1eSjsing .name = "sign", 19794e38b1eSjsing .desc = "Sign the input data using RSA private key", 19894e38b1eSjsing .type = OPTION_VALUE, 19994e38b1eSjsing .value = RSA_SIGN, 20094e38b1eSjsing .opt.value = &rsautl_config.rsa_mode, 20194e38b1eSjsing }, 20294e38b1eSjsing { 20394e38b1eSjsing .name = "verify", 20494e38b1eSjsing .desc = "Verify the input data using RSA public key", 20594e38b1eSjsing .type = OPTION_VALUE, 20694e38b1eSjsing .value = RSA_VERIFY, 20794e38b1eSjsing .opt.value = &rsautl_config.rsa_mode, 20894e38b1eSjsing }, 20994e38b1eSjsing { 21094e38b1eSjsing .name = "x931", 211ce730975Stb .desc = "Use ANSI X9.31 padding", 21294e38b1eSjsing .type = OPTION_VALUE, 21394e38b1eSjsing .value = RSA_X931_PADDING, 21494e38b1eSjsing .opt.value = &rsautl_config.pad, 21594e38b1eSjsing }, 21694e38b1eSjsing 21794e38b1eSjsing {NULL}, 21894e38b1eSjsing }; 21994e38b1eSjsing 22094e38b1eSjsing static void 22194e38b1eSjsing rsautl_usage() 22294e38b1eSjsing { 22394e38b1eSjsing fprintf(stderr, 22494e38b1eSjsing "usage: rsautl [-asn1parse] [-certin] [-decrypt] [-encrypt] " 22594e38b1eSjsing "[-hexdump]\n" 22694e38b1eSjsing " [-in file] [-inkey file] [-keyform der | pem]\n" 227ce730975Stb " [-oaep | -pkcs | -raw | -x931] [-out file] [-passin arg]\n" 228ce730975Stb " [-pubin] [-rev] [-sign] [-verify]\n\n"); 22994e38b1eSjsing 23094e38b1eSjsing options_usage(rsautl_options); 23194e38b1eSjsing } 232dab3f910Sjsing 233dab3f910Sjsing int 234dab3f910Sjsing rsautl_main(int argc, char **argv) 235dab3f910Sjsing { 236dab3f910Sjsing BIO *in = NULL, *out = NULL; 237dab3f910Sjsing X509 *x; 238dab3f910Sjsing EVP_PKEY *pkey = NULL; 239dab3f910Sjsing RSA *rsa = NULL; 24094e38b1eSjsing unsigned char *rsa_in = NULL, *rsa_out = NULL; 24194e38b1eSjsing char *passin = NULL; 242dab3f910Sjsing int rsa_inlen, rsa_outlen = 0; 24394e38b1eSjsing int need_priv = 0; 244dab3f910Sjsing int keysize; 245dab3f910Sjsing int ret = 1; 246dab3f910Sjsing 2479bc487adSdoug if (single_execution) { 24851811eadSderaadt if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 2499bc487adSdoug perror("pledge"); 250e370f0eeSdoug exit(1); 251e370f0eeSdoug } 2529bc487adSdoug } 2539bc487adSdoug 25494e38b1eSjsing memset(&rsautl_config, 0, sizeof(rsautl_config)); 25594e38b1eSjsing rsautl_config.keyform = FORMAT_PEM; 25694e38b1eSjsing rsautl_config.key_type = KEY_PRIVKEY; 25794e38b1eSjsing rsautl_config.pad = RSA_PKCS1_PADDING; 25894e38b1eSjsing rsautl_config.rsa_mode = RSA_VERIFY; 259dab3f910Sjsing 26094e38b1eSjsing if (options_parse(argc, argv, rsautl_options, NULL, NULL) != 0) { 26194e38b1eSjsing rsautl_usage(); 26294e38b1eSjsing return (1); 263dab3f910Sjsing } 264dab3f910Sjsing 26594e38b1eSjsing if (rsautl_config.rsa_mode == RSA_SIGN || 26694e38b1eSjsing rsautl_config.rsa_mode == RSA_DECRYPT) 26794e38b1eSjsing need_priv = 1; 26894e38b1eSjsing 26994e38b1eSjsing if (need_priv && rsautl_config.key_type != KEY_PRIVKEY) { 270dab3f910Sjsing BIO_printf(bio_err, "A private key is needed for this operation\n"); 271dab3f910Sjsing goto end; 272dab3f910Sjsing } 27394e38b1eSjsing if (!app_passwd(bio_err, rsautl_config.passargin, NULL, &passin, NULL)) { 274dab3f910Sjsing BIO_printf(bio_err, "Error getting password\n"); 275dab3f910Sjsing goto end; 276dab3f910Sjsing } 277dab3f910Sjsing 27894e38b1eSjsing switch (rsautl_config.key_type) { 279dab3f910Sjsing case KEY_PRIVKEY: 28094e38b1eSjsing pkey = load_key(bio_err, rsautl_config.keyfile, 28194e38b1eSjsing rsautl_config.keyform, 0, passin, "Private Key"); 282dab3f910Sjsing break; 283dab3f910Sjsing 284dab3f910Sjsing case KEY_PUBKEY: 28594e38b1eSjsing pkey = load_pubkey(bio_err, rsautl_config.keyfile, 28694e38b1eSjsing rsautl_config.keyform, 0, NULL, "Public Key"); 287dab3f910Sjsing break; 288dab3f910Sjsing 289dab3f910Sjsing case KEY_CERT: 29094e38b1eSjsing x = load_cert(bio_err, rsautl_config.keyfile, 29194e38b1eSjsing rsautl_config.keyform, NULL, "Certificate"); 292dab3f910Sjsing if (x) { 293dab3f910Sjsing pkey = X509_get_pubkey(x); 294dab3f910Sjsing X509_free(x); 295dab3f910Sjsing } 296dab3f910Sjsing break; 297dab3f910Sjsing } 298dab3f910Sjsing 29999e8894fSdoug if (!pkey) 30099e8894fSdoug goto end; 30199e8894fSdoug 302dab3f910Sjsing rsa = EVP_PKEY_get1_RSA(pkey); 303dab3f910Sjsing EVP_PKEY_free(pkey); 304dab3f910Sjsing 305dab3f910Sjsing if (!rsa) { 306dab3f910Sjsing BIO_printf(bio_err, "Error getting RSA key\n"); 307dab3f910Sjsing ERR_print_errors(bio_err); 308dab3f910Sjsing goto end; 309dab3f910Sjsing } 31094e38b1eSjsing if (rsautl_config.infile) { 31194e38b1eSjsing if (!(in = BIO_new_file(rsautl_config.infile, "rb"))) { 312dab3f910Sjsing BIO_printf(bio_err, "Error Reading Input File\n"); 313dab3f910Sjsing ERR_print_errors(bio_err); 314dab3f910Sjsing goto end; 315dab3f910Sjsing } 316dab3f910Sjsing } else 317dab3f910Sjsing in = BIO_new_fp(stdin, BIO_NOCLOSE); 318dab3f910Sjsing 31994e38b1eSjsing if (rsautl_config.outfile) { 32094e38b1eSjsing if (!(out = BIO_new_file(rsautl_config.outfile, "wb"))) { 321dab3f910Sjsing BIO_printf(bio_err, "Error Reading Output File\n"); 322dab3f910Sjsing ERR_print_errors(bio_err); 323dab3f910Sjsing goto end; 324dab3f910Sjsing } 325dab3f910Sjsing } else { 326dab3f910Sjsing out = BIO_new_fp(stdout, BIO_NOCLOSE); 327dab3f910Sjsing } 328dab3f910Sjsing 329dab3f910Sjsing keysize = RSA_size(rsa); 330dab3f910Sjsing 331dab3f910Sjsing rsa_in = reallocarray(NULL, keysize, 2); 33240b191f1Slteo if (rsa_in == NULL) { 33340b191f1Slteo BIO_printf(bio_err, "Error allocating memory for input data\n"); 33440b191f1Slteo exit(1); 33540b191f1Slteo } 336dab3f910Sjsing rsa_out = malloc(keysize); 33740b191f1Slteo if (rsa_out == NULL) { 33840b191f1Slteo BIO_printf(bio_err, "Error allocating memory for output data\n"); 33940b191f1Slteo exit(1); 34040b191f1Slteo } 341dab3f910Sjsing 342dab3f910Sjsing /* Read the input data */ 343dab3f910Sjsing rsa_inlen = BIO_read(in, rsa_in, keysize * 2); 344dab3f910Sjsing if (rsa_inlen <= 0) { 345dab3f910Sjsing BIO_printf(bio_err, "Error reading input Data\n"); 346dab3f910Sjsing exit(1); 347dab3f910Sjsing } 34894e38b1eSjsing if (rsautl_config.rev) { 349dab3f910Sjsing int i; 350dab3f910Sjsing unsigned char ctmp; 351dab3f910Sjsing for (i = 0; i < rsa_inlen / 2; i++) { 352dab3f910Sjsing ctmp = rsa_in[i]; 353dab3f910Sjsing rsa_in[i] = rsa_in[rsa_inlen - 1 - i]; 354dab3f910Sjsing rsa_in[rsa_inlen - 1 - i] = ctmp; 355dab3f910Sjsing } 356dab3f910Sjsing } 357dab3f910Sjsing 35894e38b1eSjsing switch (rsautl_config.rsa_mode) { 359dab3f910Sjsing case RSA_VERIFY: 36094e38b1eSjsing rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out, 36194e38b1eSjsing rsa, rsautl_config.pad); 362dab3f910Sjsing break; 363dab3f910Sjsing 364dab3f910Sjsing case RSA_SIGN: 36594e38b1eSjsing rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out, 36694e38b1eSjsing rsa, rsautl_config.pad); 367dab3f910Sjsing break; 368dab3f910Sjsing 369dab3f910Sjsing case RSA_ENCRYPT: 37094e38b1eSjsing rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out, 37194e38b1eSjsing rsa, rsautl_config.pad); 372dab3f910Sjsing break; 373dab3f910Sjsing 374dab3f910Sjsing case RSA_DECRYPT: 37594e38b1eSjsing rsa_outlen = RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out, 37694e38b1eSjsing rsa, rsautl_config.pad); 377dab3f910Sjsing break; 378dab3f910Sjsing } 379dab3f910Sjsing 380dab3f910Sjsing if (rsa_outlen <= 0) { 381dab3f910Sjsing BIO_printf(bio_err, "RSA operation error\n"); 382dab3f910Sjsing ERR_print_errors(bio_err); 383dab3f910Sjsing goto end; 384dab3f910Sjsing } 385dab3f910Sjsing ret = 0; 38694e38b1eSjsing if (rsautl_config.asn1parse) { 387dab3f910Sjsing if (!ASN1_parse_dump(out, rsa_out, rsa_outlen, 1, -1)) { 388dab3f910Sjsing ERR_print_errors(bio_err); 389dab3f910Sjsing } 39094e38b1eSjsing } else if (rsautl_config.hexdump) 391dab3f910Sjsing BIO_dump(out, (char *) rsa_out, rsa_outlen); 392dab3f910Sjsing else 393dab3f910Sjsing BIO_write(out, rsa_out, rsa_outlen); 394dab3f910Sjsing 395dab3f910Sjsing end: 396dab3f910Sjsing RSA_free(rsa); 397dab3f910Sjsing BIO_free(in); 398dab3f910Sjsing BIO_free_all(out); 399dab3f910Sjsing free(rsa_in); 400dab3f910Sjsing free(rsa_out); 401dab3f910Sjsing free(passin); 402dab3f910Sjsing 403dab3f910Sjsing return ret; 404dab3f910Sjsing } 405