Annotation of src/usr.bin/openssl/rsautl.c, Revision 1.22
1.22 ! tb 1: /* $OpenBSD: rsautl.c,v 1.21 2023/03/06 14:32:06 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: {NULL},
211: };
212:
213: static void
214: rsautl_usage()
215: {
216: fprintf(stderr,
217: "usage: rsautl [-asn1parse] [-certin] [-decrypt] [-encrypt] "
218: "[-hexdump]\n"
219: " [-in file] [-inkey file] [-keyform der | pem]\n"
1.22 ! tb 220: " [-oaep | -pkcs | -raw] [-out file] [-passin arg]\n"
1.17 tb 221: " [-pubin] [-rev] [-sign] [-verify]\n\n");
1.15 jsing 222:
223: options_usage(rsautl_options);
224: }
1.1 jsing 225:
226: int
227: rsautl_main(int argc, char **argv)
228: {
229: BIO *in = NULL, *out = NULL;
230: X509 *x;
231: EVP_PKEY *pkey = NULL;
232: RSA *rsa = NULL;
1.15 jsing 233: unsigned char *rsa_in = NULL, *rsa_out = NULL;
234: char *passin = NULL;
1.1 jsing 235: int rsa_inlen, rsa_outlen = 0;
1.15 jsing 236: int need_priv = 0;
1.1 jsing 237: int keysize;
238: int ret = 1;
1.8 doug 239:
1.19 joshua 240: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
241: perror("pledge");
242: exit(1);
1.8 doug 243: }
1.1 jsing 244:
1.21 tb 245: memset(&cfg, 0, sizeof(cfg));
246: cfg.keyform = FORMAT_PEM;
247: cfg.key_type = KEY_PRIVKEY;
248: cfg.pad = RSA_PKCS1_PADDING;
249: cfg.rsa_mode = RSA_VERIFY;
1.15 jsing 250:
251: if (options_parse(argc, argv, rsautl_options, NULL, NULL) != 0) {
252: rsautl_usage();
253: return (1);
254: }
255:
1.21 tb 256: if (cfg.rsa_mode == RSA_SIGN ||
257: cfg.rsa_mode == RSA_DECRYPT)
1.15 jsing 258: need_priv = 1;
1.1 jsing 259:
1.21 tb 260: if (need_priv && cfg.key_type != KEY_PRIVKEY) {
1.1 jsing 261: BIO_printf(bio_err, "A private key is needed for this operation\n");
262: goto end;
263: }
1.21 tb 264: if (!app_passwd(bio_err, cfg.passargin, NULL, &passin, NULL)) {
1.1 jsing 265: BIO_printf(bio_err, "Error getting password\n");
266: goto end;
267: }
268:
1.21 tb 269: switch (cfg.key_type) {
1.1 jsing 270: case KEY_PRIVKEY:
1.21 tb 271: pkey = load_key(bio_err, cfg.keyfile,
272: cfg.keyform, 0, passin, "Private Key");
1.1 jsing 273: break;
274:
275: case KEY_PUBKEY:
1.21 tb 276: pkey = load_pubkey(bio_err, cfg.keyfile,
277: cfg.keyform, 0, NULL, "Public Key");
1.1 jsing 278: break;
279:
280: case KEY_CERT:
1.21 tb 281: x = load_cert(bio_err, cfg.keyfile,
282: cfg.keyform, NULL, "Certificate");
1.1 jsing 283: if (x) {
284: pkey = X509_get_pubkey(x);
285: X509_free(x);
286: }
287: break;
288: }
289:
1.5 doug 290: if (!pkey)
291: goto end;
292:
1.1 jsing 293: rsa = EVP_PKEY_get1_RSA(pkey);
294: EVP_PKEY_free(pkey);
295:
296: if (!rsa) {
297: BIO_printf(bio_err, "Error getting RSA key\n");
298: ERR_print_errors(bio_err);
299: goto end;
300: }
1.21 tb 301: if (cfg.infile) {
302: if (!(in = BIO_new_file(cfg.infile, "rb"))) {
1.1 jsing 303: BIO_printf(bio_err, "Error Reading Input File\n");
304: ERR_print_errors(bio_err);
305: goto end;
306: }
307: } else
308: in = BIO_new_fp(stdin, BIO_NOCLOSE);
309:
1.21 tb 310: if (cfg.outfile) {
311: if (!(out = BIO_new_file(cfg.outfile, "wb"))) {
1.1 jsing 312: BIO_printf(bio_err, "Error Reading Output File\n");
313: ERR_print_errors(bio_err);
314: goto end;
315: }
316: } else {
317: out = BIO_new_fp(stdout, BIO_NOCLOSE);
318: }
319:
320: keysize = RSA_size(rsa);
321:
322: rsa_in = reallocarray(NULL, keysize, 2);
1.4 lteo 323: if (rsa_in == NULL) {
324: BIO_printf(bio_err, "Error allocating memory for input data\n");
325: exit(1);
326: }
1.1 jsing 327: rsa_out = malloc(keysize);
1.4 lteo 328: if (rsa_out == NULL) {
329: BIO_printf(bio_err, "Error allocating memory for output data\n");
330: exit(1);
331: }
1.1 jsing 332:
333: /* Read the input data */
334: rsa_inlen = BIO_read(in, rsa_in, keysize * 2);
335: if (rsa_inlen <= 0) {
336: BIO_printf(bio_err, "Error reading input Data\n");
337: exit(1);
338: }
1.21 tb 339: if (cfg.rev) {
1.1 jsing 340: int i;
341: unsigned char ctmp;
342: for (i = 0; i < rsa_inlen / 2; i++) {
343: ctmp = rsa_in[i];
344: rsa_in[i] = rsa_in[rsa_inlen - 1 - i];
345: rsa_in[rsa_inlen - 1 - i] = ctmp;
346: }
347: }
348:
1.21 tb 349: switch (cfg.rsa_mode) {
1.1 jsing 350: case RSA_VERIFY:
1.15 jsing 351: rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out,
1.21 tb 352: rsa, cfg.pad);
1.1 jsing 353: break;
354:
355: case RSA_SIGN:
1.15 jsing 356: rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out,
1.21 tb 357: rsa, cfg.pad);
1.1 jsing 358: break;
359:
360: case RSA_ENCRYPT:
1.15 jsing 361: rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out,
1.21 tb 362: rsa, cfg.pad);
1.1 jsing 363: break;
364:
365: case RSA_DECRYPT:
1.15 jsing 366: rsa_outlen = RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out,
1.21 tb 367: rsa, cfg.pad);
1.1 jsing 368: break;
369: }
370:
371: if (rsa_outlen <= 0) {
372: BIO_printf(bio_err, "RSA operation error\n");
373: ERR_print_errors(bio_err);
374: goto end;
375: }
376: ret = 0;
1.21 tb 377: if (cfg.asn1parse) {
1.1 jsing 378: if (!ASN1_parse_dump(out, rsa_out, rsa_outlen, 1, -1)) {
379: ERR_print_errors(bio_err);
380: }
1.21 tb 381: } else if (cfg.hexdump)
1.1 jsing 382: BIO_dump(out, (char *) rsa_out, rsa_outlen);
383: else
384: BIO_write(out, rsa_out, rsa_outlen);
385:
1.13 jsing 386: end:
1.1 jsing 387: RSA_free(rsa);
388: BIO_free(in);
389: BIO_free_all(out);
390: free(rsa_in);
391: free(rsa_out);
392: free(passin);
393:
394: return ret;
395: }