Annotation of src/usr.bin/openssl/rsautl.c, Revision 1.17
1.17 ! tb 1: /* $OpenBSD: rsautl.c,v 1.16 2019/02/03 15:40:32 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.15 jsing 78: 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: } rsautl_config;
91:
92: struct option rsautl_options[] = {
93: {
94: .name = "asn1parse",
95: .desc = "ASN.1 parse the output data",
96: .type = OPTION_FLAG,
97: .opt.flag = &rsautl_config.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 = &rsautl_config.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 = &rsautl_config.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 = &rsautl_config.rsa_mode,
119: },
120: {
121: .name = "hexdump",
122: .desc = "Hex dump the output data",
123: .type = OPTION_FLAG,
124: .opt.flag = &rsautl_config.hexdump,
125: },
126: {
127: .name = "in",
128: .argname = "file",
129: .desc = "Input file (default stdin)",
130: .type = OPTION_ARG,
131: .opt.arg = &rsautl_config.infile,
132: },
133: {
134: .name = "inkey",
135: .argname = "file",
136: .desc = "Input key file",
137: .type = OPTION_ARG,
138: .opt.arg = &rsautl_config.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 = &rsautl_config.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 = &rsautl_config.pad,
153: },
154: {
155: .name = "out",
156: .argname = "file",
157: .desc = "Output file (default stdout)",
158: .type = OPTION_ARG,
159: .opt.arg = &rsautl_config.outfile,
160: },
161: {
162: .name = "passin",
163: .argname = "arg",
164: .desc = "Key password source",
165: .type = OPTION_ARG,
166: .opt.arg = &rsautl_config.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 = &rsautl_config.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 = &rsautl_config.key_type,
181: },
182: {
183: .name = "raw",
184: .desc = "Use no padding",
185: .type = OPTION_VALUE,
186: .value = RSA_NO_PADDING,
187: .opt.value = &rsautl_config.pad,
188: },
189: {
190: .name = "rev",
191: .desc = "Reverse the input data",
192: .type = OPTION_FLAG,
193: .opt.flag = &rsautl_config.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 = &rsautl_config.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 = &rsautl_config.rsa_mode,
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,
214: .opt.value = &rsautl_config.pad,
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:
247: if (single_execution) {
1.11 deraadt 248: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
1.8 doug 249: perror("pledge");
1.10 doug 250: exit(1);
251: }
1.8 doug 252: }
1.1 jsing 253:
1.15 jsing 254: memset(&rsautl_config, 0, sizeof(rsautl_config));
255: rsautl_config.keyform = FORMAT_PEM;
256: rsautl_config.key_type = KEY_PRIVKEY;
257: rsautl_config.pad = RSA_PKCS1_PADDING;
258: rsautl_config.rsa_mode = RSA_VERIFY;
259:
260: if (options_parse(argc, argv, rsautl_options, NULL, NULL) != 0) {
261: rsautl_usage();
262: return (1);
263: }
264:
265: if (rsautl_config.rsa_mode == RSA_SIGN ||
266: rsautl_config.rsa_mode == RSA_DECRYPT)
267: need_priv = 1;
1.1 jsing 268:
1.15 jsing 269: if (need_priv && rsautl_config.key_type != KEY_PRIVKEY) {
1.1 jsing 270: BIO_printf(bio_err, "A private key is needed for this operation\n");
271: goto end;
272: }
1.15 jsing 273: if (!app_passwd(bio_err, rsautl_config.passargin, NULL, &passin, NULL)) {
1.1 jsing 274: BIO_printf(bio_err, "Error getting password\n");
275: goto end;
276: }
277:
1.15 jsing 278: switch (rsautl_config.key_type) {
1.1 jsing 279: case KEY_PRIVKEY:
1.15 jsing 280: pkey = load_key(bio_err, rsautl_config.keyfile,
281: rsautl_config.keyform, 0, passin, "Private Key");
1.1 jsing 282: break;
283:
284: case KEY_PUBKEY:
1.15 jsing 285: pkey = load_pubkey(bio_err, rsautl_config.keyfile,
286: rsautl_config.keyform, 0, NULL, "Public Key");
1.1 jsing 287: break;
288:
289: case KEY_CERT:
1.15 jsing 290: x = load_cert(bio_err, rsautl_config.keyfile,
291: rsautl_config.keyform, NULL, "Certificate");
1.1 jsing 292: if (x) {
293: pkey = X509_get_pubkey(x);
294: X509_free(x);
295: }
296: break;
297: }
298:
1.5 doug 299: if (!pkey)
300: goto end;
301:
1.1 jsing 302: rsa = EVP_PKEY_get1_RSA(pkey);
303: EVP_PKEY_free(pkey);
304:
305: if (!rsa) {
306: BIO_printf(bio_err, "Error getting RSA key\n");
307: ERR_print_errors(bio_err);
308: goto end;
309: }
1.15 jsing 310: if (rsautl_config.infile) {
311: if (!(in = BIO_new_file(rsautl_config.infile, "rb"))) {
1.1 jsing 312: BIO_printf(bio_err, "Error Reading Input File\n");
313: ERR_print_errors(bio_err);
314: goto end;
315: }
316: } else
317: in = BIO_new_fp(stdin, BIO_NOCLOSE);
318:
1.15 jsing 319: if (rsautl_config.outfile) {
320: if (!(out = BIO_new_file(rsautl_config.outfile, "wb"))) {
1.1 jsing 321: BIO_printf(bio_err, "Error Reading Output File\n");
322: ERR_print_errors(bio_err);
323: goto end;
324: }
325: } else {
326: out = BIO_new_fp(stdout, BIO_NOCLOSE);
327: }
328:
329: keysize = RSA_size(rsa);
330:
331: rsa_in = reallocarray(NULL, keysize, 2);
1.4 lteo 332: if (rsa_in == NULL) {
333: BIO_printf(bio_err, "Error allocating memory for input data\n");
334: exit(1);
335: }
1.1 jsing 336: rsa_out = malloc(keysize);
1.4 lteo 337: if (rsa_out == NULL) {
338: BIO_printf(bio_err, "Error allocating memory for output data\n");
339: exit(1);
340: }
1.1 jsing 341:
342: /* Read the input data */
343: rsa_inlen = BIO_read(in, rsa_in, keysize * 2);
344: if (rsa_inlen <= 0) {
345: BIO_printf(bio_err, "Error reading input Data\n");
346: exit(1);
347: }
1.15 jsing 348: if (rsautl_config.rev) {
1.1 jsing 349: int i;
350: unsigned char ctmp;
351: for (i = 0; i < rsa_inlen / 2; i++) {
352: ctmp = rsa_in[i];
353: rsa_in[i] = rsa_in[rsa_inlen - 1 - i];
354: rsa_in[rsa_inlen - 1 - i] = ctmp;
355: }
356: }
357:
1.15 jsing 358: switch (rsautl_config.rsa_mode) {
1.1 jsing 359: case RSA_VERIFY:
1.15 jsing 360: rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out,
361: rsa, rsautl_config.pad);
1.1 jsing 362: break;
363:
364: case RSA_SIGN:
1.15 jsing 365: rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out,
366: rsa, rsautl_config.pad);
1.1 jsing 367: break;
368:
369: case RSA_ENCRYPT:
1.15 jsing 370: rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out,
371: rsa, rsautl_config.pad);
1.1 jsing 372: break;
373:
374: case RSA_DECRYPT:
1.15 jsing 375: rsa_outlen = RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out,
376: rsa, rsautl_config.pad);
1.1 jsing 377: break;
378: }
379:
380: if (rsa_outlen <= 0) {
381: BIO_printf(bio_err, "RSA operation error\n");
382: ERR_print_errors(bio_err);
383: goto end;
384: }
385: ret = 0;
1.15 jsing 386: if (rsautl_config.asn1parse) {
1.1 jsing 387: if (!ASN1_parse_dump(out, rsa_out, rsa_outlen, 1, -1)) {
388: ERR_print_errors(bio_err);
389: }
1.15 jsing 390: } else if (rsautl_config.hexdump)
1.1 jsing 391: BIO_dump(out, (char *) rsa_out, rsa_outlen);
392: else
393: BIO_write(out, rsa_out, rsa_outlen);
394:
1.13 jsing 395: end:
1.1 jsing 396: RSA_free(rsa);
397: BIO_free(in);
398: BIO_free_all(out);
399: free(rsa_in);
400: free(rsa_out);
401: free(passin);
402:
403: return ret;
404: }