Annotation of src/usr.bin/openssl/rsautl.c, Revision 1.21
1.21 ! tb 1: /* $OpenBSD: rsautl.c,v 1.20 2023/03/05 13:12:53 tb Exp $ */
1.1 jsing 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:
1.16 tb 69: #define RSA_SIGN 1
70: #define RSA_VERIFY 2
71: #define RSA_ENCRYPT 3
72: #define RSA_DECRYPT 4
1.1 jsing 73:
74: #define KEY_PRIVKEY 1
75: #define KEY_PUBKEY 2
76: #define KEY_CERT 3
77:
1.20 tb 78: static struct {
1.15 jsing 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;
1.21 ! tb 90: } cfg;
1.15 jsing 91:
1.18 guenther 92: static const struct option rsautl_options[] = {
1.15 jsing 93: {
94: .name = "asn1parse",
95: .desc = "ASN.1 parse the output data",
96: .type = OPTION_FLAG,
1.21 ! tb 97: .opt.flag = &cfg.asn1parse,
1.15 jsing 98: },
99: {
100: .name = "certin",
101: .desc = "Input is a certificate containing an RSA public key",
102: .type = OPTION_VALUE,
103: .value = KEY_CERT,
1.21 ! tb 104: .opt.value = &cfg.key_type,
1.15 jsing 105: },
106: {
107: .name = "decrypt",
108: .desc = "Decrypt the input data using RSA private key",
109: .type = OPTION_VALUE,
110: .value = RSA_DECRYPT,
1.21 ! tb 111: .opt.value = &cfg.rsa_mode,
1.15 jsing 112: },
113: {
114: .name = "encrypt",
115: .desc = "Encrypt the input data using RSA public key",
116: .type = OPTION_VALUE,
117: .value = RSA_ENCRYPT,
1.21 ! tb 118: .opt.value = &cfg.rsa_mode,
1.15 jsing 119: },
120: {
121: .name = "hexdump",
122: .desc = "Hex dump the output data",
123: .type = OPTION_FLAG,
1.21 ! tb 124: .opt.flag = &cfg.hexdump,
1.15 jsing 125: },
126: {
127: .name = "in",
128: .argname = "file",
129: .desc = "Input file (default stdin)",
130: .type = OPTION_ARG,
1.21 ! tb 131: .opt.arg = &cfg.infile,
1.15 jsing 132: },
133: {
134: .name = "inkey",
135: .argname = "file",
136: .desc = "Input key file",
137: .type = OPTION_ARG,
1.21 ! tb 138: .opt.arg = &cfg.keyfile,
1.15 jsing 139: },
140: {
141: .name = "keyform",
142: .argname = "fmt",
143: .desc = "Input key format (DER, TXT or PEM (default))",
144: .type = OPTION_ARG_FORMAT,
1.21 ! tb 145: .opt.value = &cfg.keyform,
1.15 jsing 146: },
147: {
148: .name = "oaep",
149: .desc = "Use PKCS#1 OAEP padding",
150: .type = OPTION_VALUE,
151: .value = RSA_PKCS1_OAEP_PADDING,
1.21 ! tb 152: .opt.value = &cfg.pad,
1.15 jsing 153: },
154: {
155: .name = "out",
156: .argname = "file",
157: .desc = "Output file (default stdout)",
158: .type = OPTION_ARG,
1.21 ! tb 159: .opt.arg = &cfg.outfile,
1.15 jsing 160: },
161: {
162: .name = "passin",
163: .argname = "arg",
164: .desc = "Key password source",
165: .type = OPTION_ARG,
1.21 ! tb 166: .opt.arg = &cfg.passargin,
1.15 jsing 167: },
168: {
169: .name = "pkcs",
170: .desc = "Use PKCS#1 v1.5 padding (default)",
171: .type = OPTION_VALUE,
172: .value = RSA_PKCS1_PADDING,
1.21 ! tb 173: .opt.value = &cfg.pad,
1.15 jsing 174: },
175: {
176: .name = "pubin",
177: .desc = "Input is an RSA public key",
178: .type = OPTION_VALUE,
179: .value = KEY_PUBKEY,
1.21 ! tb 180: .opt.value = &cfg.key_type,
1.15 jsing 181: },
182: {
183: .name = "raw",
184: .desc = "Use no padding",
185: .type = OPTION_VALUE,
186: .value = RSA_NO_PADDING,
1.21 ! tb 187: .opt.value = &cfg.pad,
1.15 jsing 188: },
189: {
190: .name = "rev",
191: .desc = "Reverse the input data",
192: .type = OPTION_FLAG,
1.21 ! tb 193: .opt.flag = &cfg.rev,
1.15 jsing 194: },
195: {
196: .name = "sign",
197: .desc = "Sign the input data using RSA private key",
198: .type = OPTION_VALUE,
199: .value = RSA_SIGN,
1.21 ! tb 200: .opt.value = &cfg.rsa_mode,
1.15 jsing 201: },
202: {
203: .name = "verify",
204: .desc = "Verify the input data using RSA public key",
205: .type = OPTION_VALUE,
206: .value = RSA_VERIFY,
1.21 ! tb 207: .opt.value = &cfg.rsa_mode,
1.15 jsing 208: },
209: {
210: .name = "x931",
1.17 tb 211: .desc = "Use ANSI X9.31 padding",
1.15 jsing 212: .type = OPTION_VALUE,
213: .value = RSA_X931_PADDING,
1.21 ! tb 214: .opt.value = &cfg.pad,
1.15 jsing 215: },
216:
217: {NULL},
218: };
219:
220: static void
221: rsautl_usage()
222: {
223: fprintf(stderr,
224: "usage: rsautl [-asn1parse] [-certin] [-decrypt] [-encrypt] "
225: "[-hexdump]\n"
226: " [-in file] [-inkey file] [-keyform der | pem]\n"
1.17 tb 227: " [-oaep | -pkcs | -raw | -x931] [-out file] [-passin arg]\n"
228: " [-pubin] [-rev] [-sign] [-verify]\n\n");
1.15 jsing 229:
230: options_usage(rsautl_options);
231: }
1.1 jsing 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;
1.15 jsing 240: unsigned char *rsa_in = NULL, *rsa_out = NULL;
241: char *passin = NULL;
1.1 jsing 242: int rsa_inlen, rsa_outlen = 0;
1.15 jsing 243: int need_priv = 0;
1.1 jsing 244: int keysize;
245: int ret = 1;
1.8 doug 246:
1.19 joshua 247: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
248: perror("pledge");
249: exit(1);
1.8 doug 250: }
1.1 jsing 251:
1.21 ! tb 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;
1.15 jsing 257:
258: if (options_parse(argc, argv, rsautl_options, NULL, NULL) != 0) {
259: rsautl_usage();
260: return (1);
261: }
262:
1.21 ! tb 263: if (cfg.rsa_mode == RSA_SIGN ||
! 264: cfg.rsa_mode == RSA_DECRYPT)
1.15 jsing 265: need_priv = 1;
1.1 jsing 266:
1.21 ! tb 267: if (need_priv && cfg.key_type != KEY_PRIVKEY) {
1.1 jsing 268: BIO_printf(bio_err, "A private key is needed for this operation\n");
269: goto end;
270: }
1.21 ! tb 271: if (!app_passwd(bio_err, cfg.passargin, NULL, &passin, NULL)) {
1.1 jsing 272: BIO_printf(bio_err, "Error getting password\n");
273: goto end;
274: }
275:
1.21 ! tb 276: switch (cfg.key_type) {
1.1 jsing 277: case KEY_PRIVKEY:
1.21 ! tb 278: pkey = load_key(bio_err, cfg.keyfile,
! 279: cfg.keyform, 0, passin, "Private Key");
1.1 jsing 280: break;
281:
282: case KEY_PUBKEY:
1.21 ! tb 283: pkey = load_pubkey(bio_err, cfg.keyfile,
! 284: cfg.keyform, 0, NULL, "Public Key");
1.1 jsing 285: break;
286:
287: case KEY_CERT:
1.21 ! tb 288: x = load_cert(bio_err, cfg.keyfile,
! 289: cfg.keyform, NULL, "Certificate");
1.1 jsing 290: if (x) {
291: pkey = X509_get_pubkey(x);
292: X509_free(x);
293: }
294: break;
295: }
296:
1.5 doug 297: if (!pkey)
298: goto end;
299:
1.1 jsing 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: }
1.21 ! tb 308: if (cfg.infile) {
! 309: if (!(in = BIO_new_file(cfg.infile, "rb"))) {
1.1 jsing 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:
1.21 ! tb 317: if (cfg.outfile) {
! 318: if (!(out = BIO_new_file(cfg.outfile, "wb"))) {
1.1 jsing 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);
1.4 lteo 330: if (rsa_in == NULL) {
331: BIO_printf(bio_err, "Error allocating memory for input data\n");
332: exit(1);
333: }
1.1 jsing 334: rsa_out = malloc(keysize);
1.4 lteo 335: if (rsa_out == NULL) {
336: BIO_printf(bio_err, "Error allocating memory for output data\n");
337: exit(1);
338: }
1.1 jsing 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: }
1.21 ! tb 346: if (cfg.rev) {
1.1 jsing 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:
1.21 ! tb 356: switch (cfg.rsa_mode) {
1.1 jsing 357: case RSA_VERIFY:
1.15 jsing 358: rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out,
1.21 ! tb 359: rsa, cfg.pad);
1.1 jsing 360: break;
361:
362: case RSA_SIGN:
1.15 jsing 363: rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out,
1.21 ! tb 364: rsa, cfg.pad);
1.1 jsing 365: break;
366:
367: case RSA_ENCRYPT:
1.15 jsing 368: rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out,
1.21 ! tb 369: rsa, cfg.pad);
1.1 jsing 370: break;
371:
372: case RSA_DECRYPT:
1.15 jsing 373: rsa_outlen = RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out,
1.21 ! tb 374: rsa, cfg.pad);
1.1 jsing 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;
1.21 ! tb 384: if (cfg.asn1parse) {
1.1 jsing 385: if (!ASN1_parse_dump(out, rsa_out, rsa_outlen, 1, -1)) {
386: ERR_print_errors(bio_err);
387: }
1.21 ! tb 388: } else if (cfg.hexdump)
1.1 jsing 389: BIO_dump(out, (char *) rsa_out, rsa_outlen);
390: else
391: BIO_write(out, rsa_out, rsa_outlen);
392:
1.13 jsing 393: end:
1.1 jsing 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: }