1 /* $OpenBSD: rsautl.c,v 1.17 2019/02/04 11:21:05 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 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",
211 		.desc = "Use ANSI X9.31 padding",
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"
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 (single_execution) {
248 		if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
249 			perror("pledge");
250 			exit(1);
251 		}
252 	}
253 
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;
268 
269 	if (need_priv && rsautl_config.key_type != KEY_PRIVKEY) {
270 		BIO_printf(bio_err, "A private key is needed for this operation\n");
271 		goto end;
272 	}
273 	if (!app_passwd(bio_err, rsautl_config.passargin, NULL, &passin, NULL)) {
274 		BIO_printf(bio_err, "Error getting password\n");
275 		goto end;
276 	}
277 
278 	switch (rsautl_config.key_type) {
279 	case KEY_PRIVKEY:
280 		pkey = load_key(bio_err, rsautl_config.keyfile,
281 		    rsautl_config.keyform, 0, passin, "Private Key");
282 		break;
283 
284 	case KEY_PUBKEY:
285 		pkey = load_pubkey(bio_err, rsautl_config.keyfile,
286 		    rsautl_config.keyform, 0, NULL, "Public Key");
287 		break;
288 
289 	case KEY_CERT:
290 		x = load_cert(bio_err, rsautl_config.keyfile,
291 		    rsautl_config.keyform, NULL, "Certificate");
292 		if (x) {
293 			pkey = X509_get_pubkey(x);
294 			X509_free(x);
295 		}
296 		break;
297 	}
298 
299 	if (!pkey)
300 		goto end;
301 
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 	}
310 	if (rsautl_config.infile) {
311 		if (!(in = BIO_new_file(rsautl_config.infile, "rb"))) {
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 
319 	if (rsautl_config.outfile) {
320 		if (!(out = BIO_new_file(rsautl_config.outfile, "wb"))) {
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);
332 	if (rsa_in == NULL) {
333 		BIO_printf(bio_err, "Error allocating memory for input data\n");
334 		exit(1);
335 	}
336 	rsa_out = malloc(keysize);
337 	if (rsa_out == NULL) {
338 		BIO_printf(bio_err, "Error allocating memory for output data\n");
339 		exit(1);
340 	}
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 	}
348 	if (rsautl_config.rev) {
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 
358 	switch (rsautl_config.rsa_mode) {
359 	case RSA_VERIFY:
360 		rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out,
361 		    rsa, rsautl_config.pad);
362 		break;
363 
364 	case RSA_SIGN:
365 		rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out,
366 		    rsa, rsautl_config.pad);
367 		break;
368 
369 	case RSA_ENCRYPT:
370 		rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out,
371 		    rsa, rsautl_config.pad);
372 		break;
373 
374 	case RSA_DECRYPT:
375 		rsa_outlen = RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out,
376 		    rsa, rsautl_config.pad);
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;
386 	if (rsautl_config.asn1parse) {
387 		if (!ASN1_parse_dump(out, rsa_out, rsa_outlen, 1, -1)) {
388 			ERR_print_errors(bio_err);
389 		}
390 	} else if (rsautl_config.hexdump)
391 		BIO_dump(out, (char *) rsa_out, rsa_outlen);
392 	else
393 		BIO_write(out, rsa_out, rsa_outlen);
394 
395  end:
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 }
405