1 /* $OpenBSD: rsautl.c,v 1.24 2023/07/23 11:39:29 tb Exp $ */ 2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 * project 2000. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 2000 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * licensing@OpenSSL.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay@cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh@cryptsoft.com). 56 * 57 */ 58 59 #include <openssl/opensslconf.h> 60 61 #include <string.h> 62 63 #include "apps.h" 64 65 #include <openssl/err.h> 66 #include <openssl/pem.h> 67 #include <openssl/rsa.h> 68 69 #define RSA_SIGN 1 70 #define RSA_VERIFY 2 71 #define RSA_ENCRYPT 3 72 #define RSA_DECRYPT 4 73 74 #define KEY_PRIVKEY 1 75 #define KEY_PUBKEY 2 76 #define KEY_CERT 3 77 78 static struct { 79 int asn1parse; 80 int hexdump; 81 char *infile; 82 char *keyfile; 83 int keyform; 84 int key_type; 85 char *outfile; 86 int pad; 87 char *passargin; 88 int rev; 89 int rsa_mode; 90 } cfg; 91 92 static const struct option rsautl_options[] = { 93 { 94 .name = "asn1parse", 95 .desc = "ASN.1 parse the output data", 96 .type = OPTION_FLAG, 97 .opt.flag = &cfg.asn1parse, 98 }, 99 { 100 .name = "certin", 101 .desc = "Input is a certificate containing an RSA public key", 102 .type = OPTION_VALUE, 103 .value = KEY_CERT, 104 .opt.value = &cfg.key_type, 105 }, 106 { 107 .name = "decrypt", 108 .desc = "Decrypt the input data using RSA private key", 109 .type = OPTION_VALUE, 110 .value = RSA_DECRYPT, 111 .opt.value = &cfg.rsa_mode, 112 }, 113 { 114 .name = "encrypt", 115 .desc = "Encrypt the input data using RSA public key", 116 .type = OPTION_VALUE, 117 .value = RSA_ENCRYPT, 118 .opt.value = &cfg.rsa_mode, 119 }, 120 { 121 .name = "hexdump", 122 .desc = "Hex dump the output data", 123 .type = OPTION_FLAG, 124 .opt.flag = &cfg.hexdump, 125 }, 126 { 127 .name = "in", 128 .argname = "file", 129 .desc = "Input file (default stdin)", 130 .type = OPTION_ARG, 131 .opt.arg = &cfg.infile, 132 }, 133 { 134 .name = "inkey", 135 .argname = "file", 136 .desc = "Input key file", 137 .type = OPTION_ARG, 138 .opt.arg = &cfg.keyfile, 139 }, 140 { 141 .name = "keyform", 142 .argname = "fmt", 143 .desc = "Input key format (DER, TXT or PEM (default))", 144 .type = OPTION_ARG_FORMAT, 145 .opt.value = &cfg.keyform, 146 }, 147 { 148 .name = "oaep", 149 .desc = "Use PKCS#1 OAEP padding", 150 .type = OPTION_VALUE, 151 .value = RSA_PKCS1_OAEP_PADDING, 152 .opt.value = &cfg.pad, 153 }, 154 { 155 .name = "out", 156 .argname = "file", 157 .desc = "Output file (default stdout)", 158 .type = OPTION_ARG, 159 .opt.arg = &cfg.outfile, 160 }, 161 { 162 .name = "passin", 163 .argname = "arg", 164 .desc = "Key password source", 165 .type = OPTION_ARG, 166 .opt.arg = &cfg.passargin, 167 }, 168 { 169 .name = "pkcs", 170 .desc = "Use PKCS#1 v1.5 padding (default)", 171 .type = OPTION_VALUE, 172 .value = RSA_PKCS1_PADDING, 173 .opt.value = &cfg.pad, 174 }, 175 { 176 .name = "pubin", 177 .desc = "Input is an RSA public key", 178 .type = OPTION_VALUE, 179 .value = KEY_PUBKEY, 180 .opt.value = &cfg.key_type, 181 }, 182 { 183 .name = "raw", 184 .desc = "Use no padding", 185 .type = OPTION_VALUE, 186 .value = RSA_NO_PADDING, 187 .opt.value = &cfg.pad, 188 }, 189 { 190 .name = "rev", 191 .desc = "Reverse the input data", 192 .type = OPTION_FLAG, 193 .opt.flag = &cfg.rev, 194 }, 195 { 196 .name = "sign", 197 .desc = "Sign the input data using RSA private key", 198 .type = OPTION_VALUE, 199 .value = RSA_SIGN, 200 .opt.value = &cfg.rsa_mode, 201 }, 202 { 203 .name = "verify", 204 .desc = "Verify the input data using RSA public key", 205 .type = OPTION_VALUE, 206 .value = RSA_VERIFY, 207 .opt.value = &cfg.rsa_mode, 208 }, 209 { 210 .name = "x931", 211 .desc = "Use ANSI X9.31 padding", 212 .type = OPTION_VALUE, 213 .value = RSA_X931_PADDING, 214 .opt.value = &cfg.pad, 215 }, 216 217 {NULL}, 218 }; 219 220 static void 221 rsautl_usage(void) 222 { 223 fprintf(stderr, 224 "usage: rsautl [-asn1parse] [-certin] [-decrypt] [-encrypt] " 225 "[-hexdump]\n" 226 " [-in file] [-inkey file] [-keyform der | pem]\n" 227 " [-oaep | -pkcs | -raw | -x931] [-out file] [-passin arg]\n" 228 " [-pubin] [-rev] [-sign] [-verify]\n\n"); 229 230 options_usage(rsautl_options); 231 } 232 233 int 234 rsautl_main(int argc, char **argv) 235 { 236 BIO *in = NULL, *out = NULL; 237 X509 *x; 238 EVP_PKEY *pkey = NULL; 239 RSA *rsa = NULL; 240 unsigned char *rsa_in = NULL, *rsa_out = NULL; 241 char *passin = NULL; 242 int rsa_inlen, rsa_outlen = 0; 243 int need_priv = 0; 244 int keysize; 245 int ret = 1; 246 247 if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 248 perror("pledge"); 249 exit(1); 250 } 251 252 memset(&cfg, 0, sizeof(cfg)); 253 cfg.keyform = FORMAT_PEM; 254 cfg.key_type = KEY_PRIVKEY; 255 cfg.pad = RSA_PKCS1_PADDING; 256 cfg.rsa_mode = RSA_VERIFY; 257 258 if (options_parse(argc, argv, rsautl_options, NULL, NULL) != 0) { 259 rsautl_usage(); 260 return (1); 261 } 262 263 if (cfg.rsa_mode == RSA_SIGN || 264 cfg.rsa_mode == RSA_DECRYPT) 265 need_priv = 1; 266 267 if (need_priv && cfg.key_type != KEY_PRIVKEY) { 268 BIO_printf(bio_err, "A private key is needed for this operation\n"); 269 goto end; 270 } 271 if (!app_passwd(bio_err, cfg.passargin, NULL, &passin, NULL)) { 272 BIO_printf(bio_err, "Error getting password\n"); 273 goto end; 274 } 275 276 switch (cfg.key_type) { 277 case KEY_PRIVKEY: 278 pkey = load_key(bio_err, cfg.keyfile, 279 cfg.keyform, 0, passin, "Private Key"); 280 break; 281 282 case KEY_PUBKEY: 283 pkey = load_pubkey(bio_err, cfg.keyfile, 284 cfg.keyform, 0, NULL, "Public Key"); 285 break; 286 287 case KEY_CERT: 288 x = load_cert(bio_err, cfg.keyfile, 289 cfg.keyform, NULL, "Certificate"); 290 if (x) { 291 pkey = X509_get_pubkey(x); 292 X509_free(x); 293 } 294 break; 295 } 296 297 if (!pkey) 298 goto end; 299 300 rsa = EVP_PKEY_get1_RSA(pkey); 301 EVP_PKEY_free(pkey); 302 303 if (!rsa) { 304 BIO_printf(bio_err, "Error getting RSA key\n"); 305 ERR_print_errors(bio_err); 306 goto end; 307 } 308 if (cfg.infile) { 309 if (!(in = BIO_new_file(cfg.infile, "rb"))) { 310 BIO_printf(bio_err, "Error Reading Input File\n"); 311 ERR_print_errors(bio_err); 312 goto end; 313 } 314 } else 315 in = BIO_new_fp(stdin, BIO_NOCLOSE); 316 317 if (cfg.outfile) { 318 if (!(out = BIO_new_file(cfg.outfile, "wb"))) { 319 BIO_printf(bio_err, "Error Reading Output File\n"); 320 ERR_print_errors(bio_err); 321 goto end; 322 } 323 } else { 324 out = BIO_new_fp(stdout, BIO_NOCLOSE); 325 } 326 327 keysize = RSA_size(rsa); 328 329 rsa_in = reallocarray(NULL, keysize, 2); 330 if (rsa_in == NULL) { 331 BIO_printf(bio_err, "Error allocating memory for input data\n"); 332 exit(1); 333 } 334 rsa_out = malloc(keysize); 335 if (rsa_out == NULL) { 336 BIO_printf(bio_err, "Error allocating memory for output data\n"); 337 exit(1); 338 } 339 340 /* Read the input data */ 341 rsa_inlen = BIO_read(in, rsa_in, keysize * 2); 342 if (rsa_inlen <= 0) { 343 BIO_printf(bio_err, "Error reading input Data\n"); 344 exit(1); 345 } 346 if (cfg.rev) { 347 int i; 348 unsigned char ctmp; 349 for (i = 0; i < rsa_inlen / 2; i++) { 350 ctmp = rsa_in[i]; 351 rsa_in[i] = rsa_in[rsa_inlen - 1 - i]; 352 rsa_in[rsa_inlen - 1 - i] = ctmp; 353 } 354 } 355 356 switch (cfg.rsa_mode) { 357 case RSA_VERIFY: 358 rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out, 359 rsa, cfg.pad); 360 break; 361 362 case RSA_SIGN: 363 rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out, 364 rsa, cfg.pad); 365 break; 366 367 case RSA_ENCRYPT: 368 rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out, 369 rsa, cfg.pad); 370 break; 371 372 case RSA_DECRYPT: 373 rsa_outlen = RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out, 374 rsa, cfg.pad); 375 break; 376 } 377 378 if (rsa_outlen <= 0) { 379 BIO_printf(bio_err, "RSA operation error\n"); 380 ERR_print_errors(bio_err); 381 goto end; 382 } 383 ret = 0; 384 if (cfg.asn1parse) { 385 if (!ASN1_parse_dump(out, rsa_out, rsa_outlen, 1, -1)) { 386 ERR_print_errors(bio_err); 387 } 388 } else if (cfg.hexdump) 389 BIO_dump(out, (char *) rsa_out, rsa_outlen); 390 else 391 BIO_write(out, rsa_out, rsa_outlen); 392 393 end: 394 RSA_free(rsa); 395 BIO_free(in); 396 BIO_free_all(out); 397 free(rsa_in); 398 free(rsa_out); 399 free(passin); 400 401 return ret; 402 } 403