1 /* $OpenBSD: pkeyutl.c,v 1.15 2019/02/17 15:01:08 inoguchi Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project 2006.
4  */
5 /* ====================================================================
6  * Copyright (c) 2006 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 <string.h>
60 
61 #include "apps.h"
62 
63 #include <openssl/err.h>
64 #include <openssl/evp.h>
65 #include <openssl/pem.h>
66 
67 #define KEY_PRIVKEY	1
68 #define KEY_PUBKEY	2
69 #define KEY_CERT	3
70 
71 struct {
72 	int asn1parse;
73 	EVP_PKEY_CTX *ctx;
74 	int hexdump;
75 	char *infile;
76 	int key_type;
77 	int keyform;
78 	int keysize;
79 	char *outfile;
80 	char *passargin;
81 	int peerform;
82 	int pkey_op;
83 	int rev;
84 	char *sigfile;
85 } pkeyutl_config;
86 
87 static void pkeyutl_usage(void);
88 
89 static int init_ctx(char *keyfile);
90 
91 static int setup_peer(char *file);
92 
93 static int pkeyutl_pkeyopt(char *pkeyopt);
94 
95 static int do_keyop(EVP_PKEY_CTX * ctx, int pkey_op,
96     unsigned char *out, size_t * poutlen,
97     unsigned char *in, size_t inlen);
98 
99 struct option pkeyutl_options[] = {
100 	{
101 		.name = "asn1parse",
102 		.desc = "ASN.1 parse the output data",
103 		.type = OPTION_FLAG,
104 		.opt.flag = &pkeyutl_config.asn1parse,
105 	},
106 	{
107 		.name = "certin",
108 		.desc = "Input is a certificate containing a public key",
109 		.type = OPTION_VALUE,
110 		.value = KEY_CERT,
111 		.opt.value = &pkeyutl_config.key_type,
112 	},
113 	{
114 		.name = "decrypt",
115 		.desc = "Decrypt the input data using a private key",
116 		.type = OPTION_VALUE,
117 		.value = EVP_PKEY_OP_DECRYPT,
118 		.opt.value = &pkeyutl_config.pkey_op,
119 	},
120 	{
121 		.name = "derive",
122 		.desc = "Derive a shared secret using the peer key",
123 		.type = OPTION_VALUE,
124 		.value = EVP_PKEY_OP_DERIVE,
125 		.opt.value = &pkeyutl_config.pkey_op,
126 	},
127 	{
128 		.name = "encrypt",
129 		.desc = "Encrypt the input data using a public key",
130 		.type = OPTION_VALUE,
131 		.value = EVP_PKEY_OP_ENCRYPT,
132 		.opt.value = &pkeyutl_config.pkey_op,
133 	},
134 	{
135 		.name = "hexdump",
136 		.desc = "Hex dump the output data",
137 		.type = OPTION_FLAG,
138 		.opt.flag = &pkeyutl_config.hexdump,
139 	},
140 	{
141 		.name = "in",
142 		.argname = "file",
143 		.desc = "Input file (default stdin)",
144 		.type = OPTION_ARG,
145 		.opt.arg = &pkeyutl_config.infile,
146 	},
147 	{
148 		.name = "inkey",
149 		.argname = "file",
150 		.desc = "Input key file",
151 		.type = OPTION_ARG_FUNC,
152 		.opt.argfunc = init_ctx,
153 	},
154 	{
155 		.name = "keyform",
156 		.argname = "fmt",
157 		.desc = "Input key format (DER or PEM (default))",
158 		.type = OPTION_ARG_FORMAT,
159 		.opt.value = &pkeyutl_config.keyform,
160 	},
161 	{
162 		.name = "out",
163 		.argname = "file",
164 		.desc = "Output file (default stdout)",
165 		.type = OPTION_ARG,
166 		.opt.arg = &pkeyutl_config.outfile,
167 	},
168 	{
169 		.name = "passin",
170 		.argname = "arg",
171 		.desc = "Key password source",
172 		.type = OPTION_ARG,
173 		.opt.arg = &pkeyutl_config.passargin,
174 	},
175 	{
176 		.name = "peerform",
177 		.argname = "fmt",
178 		.desc = "Input key format (DER or PEM (default))",
179 		.type = OPTION_ARG_FORMAT,
180 		.opt.value = &pkeyutl_config.peerform,
181 	},
182 	{
183 		.name = "peerkey",
184 		.argname = "file",
185 		.desc = "Peer key file",
186 		.type = OPTION_ARG_FUNC,
187 		.opt.argfunc = setup_peer,
188 	},
189 	{
190 		.name = "pkeyopt",
191 		.argname = "opt:value",
192 		.desc = "Public key options",
193 		.type = OPTION_ARG_FUNC,
194 		.opt.argfunc = pkeyutl_pkeyopt,
195 	},
196 	{
197 		.name = "pubin",
198 		.desc = "Input is a public key",
199 		.type = OPTION_VALUE,
200 		.value = KEY_PUBKEY,
201 		.opt.value = &pkeyutl_config.key_type,
202 	},
203 	{
204 		.name = "rev",
205 		.desc = "Reverse the input data",
206 		.type = OPTION_FLAG,
207 		.opt.flag = &pkeyutl_config.rev,
208 	},
209 	{
210 		.name = "sigfile",
211 		.argname = "file",
212 		.desc = "Signature file (verify operation only)",
213 		.type = OPTION_ARG,
214 		.opt.arg = &pkeyutl_config.sigfile,
215 	},
216 	{
217 		.name = "sign",
218 		.desc = "Sign the input data using private key",
219 		.type = OPTION_VALUE,
220 		.value = EVP_PKEY_OP_SIGN,
221 		.opt.value = &pkeyutl_config.pkey_op,
222 	},
223 	{
224 		.name = "verify",
225 		.desc = "Verify the input data using public key",
226 		.type = OPTION_VALUE,
227 		.value = EVP_PKEY_OP_VERIFY,
228 		.opt.value = &pkeyutl_config.pkey_op,
229 	},
230 	{
231 		.name = "verifyrecover",
232 		.desc = "Verify with public key, recover original data",
233 		.type = OPTION_VALUE,
234 		.value = EVP_PKEY_OP_VERIFYRECOVER,
235 		.opt.value = &pkeyutl_config.pkey_op,
236 	},
237 
238 	{NULL},
239 };
240 
241 static void
242 pkeyutl_usage()
243 {
244 	fprintf(stderr,
245 	    "usage: pkeyutl [-asn1parse] [-certin] [-decrypt] [-derive] "
246 	    "[-encrypt]\n"
247 	    "    [-hexdump] [-in file] [-inkey file] [-keyform fmt]\n"
248 	    "    [-out file] [-passin arg] [-peerform fmt]\n"
249 	    "    [-peerkey file] [-pkeyopt opt:value] [-pubin] [-rev]\n"
250 	    "    [-sigfile file] [-sign] [-verify] [-verifyrecover]\n\n");
251 	options_usage(pkeyutl_options);
252         fprintf(stderr, "\n");
253 }
254 
255 int
256 pkeyutl_main(int argc, char **argv)
257 {
258 	BIO *in = NULL, *out = NULL;
259 
260 	unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL;
261 	size_t buf_outlen = 0;
262 	int buf_inlen = 0, siglen = -1;
263 
264 	int ret = 1, rv = -1;
265 
266 	if (single_execution) {
267 		if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
268 			perror("pledge");
269 			exit(1);
270 		}
271 	}
272 
273 	memset(&pkeyutl_config, 0, sizeof(pkeyutl_config));
274 	pkeyutl_config.pkey_op = EVP_PKEY_OP_SIGN;
275 	pkeyutl_config.key_type = KEY_PRIVKEY;
276 	pkeyutl_config.keyform = FORMAT_PEM;
277 	pkeyutl_config.peerform = FORMAT_PEM;
278 	pkeyutl_config.keysize = -1;
279 
280 	if (options_parse(argc, argv, pkeyutl_options, NULL, NULL) != 0) {
281 		pkeyutl_usage();
282 		goto end;
283 	}
284 
285 	if (!pkeyutl_config.ctx) {
286 		pkeyutl_usage();
287 		goto end;
288 	}
289 	if (pkeyutl_config.sigfile &&
290 	    (pkeyutl_config.pkey_op != EVP_PKEY_OP_VERIFY)) {
291 		BIO_puts(bio_err, "Signature file specified for non verify\n");
292 		goto end;
293 	}
294 	if (!pkeyutl_config.sigfile &&
295 	    (pkeyutl_config.pkey_op == EVP_PKEY_OP_VERIFY)) {
296 		BIO_puts(bio_err, "No signature file specified for verify\n");
297 		goto end;
298 	}
299 
300 	if (pkeyutl_config.pkey_op != EVP_PKEY_OP_DERIVE) {
301 		if (pkeyutl_config.infile) {
302 			if (!(in = BIO_new_file(pkeyutl_config.infile, "rb"))) {
303 				BIO_puts(bio_err,
304 				    "Error Opening Input File\n");
305 				ERR_print_errors(bio_err);
306 				goto end;
307 			}
308 		} else
309 			in = BIO_new_fp(stdin, BIO_NOCLOSE);
310 	}
311 	if (pkeyutl_config.outfile) {
312 		if (!(out = BIO_new_file(pkeyutl_config.outfile, "wb"))) {
313 			BIO_printf(bio_err, "Error Creating Output File\n");
314 			ERR_print_errors(bio_err);
315 			goto end;
316 		}
317 	} else {
318 		out = BIO_new_fp(stdout, BIO_NOCLOSE);
319 	}
320 
321 	if (pkeyutl_config.sigfile) {
322 		BIO *sigbio = BIO_new_file(pkeyutl_config.sigfile, "rb");
323 		if (!sigbio) {
324 			BIO_printf(bio_err, "Can't open signature file %s\n",
325 			    pkeyutl_config.sigfile);
326 			goto end;
327 		}
328 		siglen = bio_to_mem(&sig, pkeyutl_config.keysize * 10, sigbio);
329 		BIO_free(sigbio);
330 		if (siglen <= 0) {
331 			BIO_printf(bio_err, "Error reading signature data\n");
332 			goto end;
333 		}
334 	}
335 	if (in) {
336 		/* Read the input data */
337 		buf_inlen = bio_to_mem(&buf_in, pkeyutl_config.keysize * 10, in);
338 		if (buf_inlen <= 0) {
339 			BIO_printf(bio_err, "Error reading input Data\n");
340 			exit(1);
341 		}
342 		if (pkeyutl_config.rev) {
343 			size_t i;
344 			unsigned char ctmp;
345 			size_t l = (size_t) buf_inlen;
346 			for (i = 0; i < l / 2; i++) {
347 				ctmp = buf_in[i];
348 				buf_in[i] = buf_in[l - 1 - i];
349 				buf_in[l - 1 - i] = ctmp;
350 			}
351 		}
352 	}
353 	if (pkeyutl_config.pkey_op == EVP_PKEY_OP_VERIFY) {
354 		rv = EVP_PKEY_verify(pkeyutl_config.ctx, sig, (size_t) siglen,
355 		    buf_in, (size_t) buf_inlen);
356 		if (rv == 1) {
357 			BIO_puts(out, "Signature Verified Successfully\n");
358 			ret = 0;
359 		} else
360 			BIO_puts(out, "Signature Verification Failure\n");
361 		if (rv >= 0)
362 			goto end;
363 	} else {
364 		rv = do_keyop(pkeyutl_config.ctx, pkeyutl_config.pkey_op, NULL,
365 		    (size_t *)&buf_outlen, buf_in, (size_t) buf_inlen);
366 		if (rv > 0) {
367 			buf_out = malloc(buf_outlen);
368 			if (!buf_out)
369 				rv = -1;
370 			else
371 				rv = do_keyop(pkeyutl_config.ctx,
372 				    pkeyutl_config.pkey_op,
373 				    buf_out, (size_t *) & buf_outlen,
374 				    buf_in, (size_t) buf_inlen);
375 		}
376 	}
377 
378 	if (rv <= 0) {
379 		BIO_printf(bio_err, "Public Key operation error\n");
380 		ERR_print_errors(bio_err);
381 		goto end;
382 	}
383 	ret = 0;
384 	if (pkeyutl_config.asn1parse) {
385 		if (!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1))
386 			ERR_print_errors(bio_err);
387 	} else if (pkeyutl_config.hexdump)
388 		BIO_dump(out, (char *) buf_out, buf_outlen);
389 	else
390 		BIO_write(out, buf_out, buf_outlen);
391 
392  end:
393 	EVP_PKEY_CTX_free(pkeyutl_config.ctx);
394 	BIO_free(in);
395 	BIO_free_all(out);
396 	free(buf_in);
397 	free(buf_out);
398 	free(sig);
399 
400 	return ret;
401 }
402 
403 static int
404 init_ctx(char *keyfile)
405 {
406 	EVP_PKEY *pkey = NULL;
407 	char *passin = NULL;
408 	int rv = -1;
409 	X509 *x;
410 
411 	if (((pkeyutl_config.pkey_op == EVP_PKEY_OP_SIGN)
412 		|| (pkeyutl_config.pkey_op == EVP_PKEY_OP_DECRYPT)
413 		|| (pkeyutl_config.pkey_op == EVP_PKEY_OP_DERIVE))
414 	    && (pkeyutl_config.key_type != KEY_PRIVKEY)) {
415 		BIO_printf(bio_err,
416 		    "A private key is needed for this operation\n");
417 		goto end;
418 	}
419 	if (!app_passwd(bio_err, pkeyutl_config.passargin, NULL, &passin,
420 	    NULL)) {
421 		BIO_printf(bio_err, "Error getting password\n");
422 		goto end;
423 	}
424 	switch (pkeyutl_config.key_type) {
425 	case KEY_PRIVKEY:
426 		pkey = load_key(bio_err, keyfile, pkeyutl_config.keyform, 0,
427 		    passin, "Private Key");
428 		break;
429 
430 	case KEY_PUBKEY:
431 		pkey = load_pubkey(bio_err, keyfile, pkeyutl_config.keyform, 0,
432 		    NULL, "Public Key");
433 		break;
434 
435 	case KEY_CERT:
436 		x = load_cert(bio_err, keyfile, pkeyutl_config.keyform,
437 		    NULL, "Certificate");
438 		if (x) {
439 			pkey = X509_get_pubkey(x);
440 			X509_free(x);
441 		}
442 		break;
443 	}
444 
445 	pkeyutl_config.keysize = EVP_PKEY_size(pkey);
446 
447 	if (!pkey)
448 		goto end;
449 
450 	pkeyutl_config.ctx = EVP_PKEY_CTX_new(pkey, NULL);
451 
452 	EVP_PKEY_free(pkey);
453 
454 	if (!pkeyutl_config.ctx)
455 		goto end;
456 
457 	switch (pkeyutl_config.pkey_op) {
458 	case EVP_PKEY_OP_SIGN:
459 		rv = EVP_PKEY_sign_init(pkeyutl_config.ctx);
460 		break;
461 
462 	case EVP_PKEY_OP_VERIFY:
463 		rv = EVP_PKEY_verify_init(pkeyutl_config.ctx);
464 		break;
465 
466 	case EVP_PKEY_OP_VERIFYRECOVER:
467 		rv = EVP_PKEY_verify_recover_init(pkeyutl_config.ctx);
468 		break;
469 
470 	case EVP_PKEY_OP_ENCRYPT:
471 		rv = EVP_PKEY_encrypt_init(pkeyutl_config.ctx);
472 		break;
473 
474 	case EVP_PKEY_OP_DECRYPT:
475 		rv = EVP_PKEY_decrypt_init(pkeyutl_config.ctx);
476 		break;
477 
478 	case EVP_PKEY_OP_DERIVE:
479 		rv = EVP_PKEY_derive_init(pkeyutl_config.ctx);
480 		break;
481 	}
482 
483 	if (rv <= 0) {
484 		EVP_PKEY_CTX_free(pkeyutl_config.ctx);
485 		pkeyutl_config.ctx = NULL;
486 	}
487 
488  end:
489 	free(passin);
490 
491 	if (!pkeyutl_config.ctx) {
492 		BIO_puts(bio_err, "Error initializing context\n");
493 		ERR_print_errors(bio_err);
494 		return (1);
495 	}
496 
497 	return (0);
498 }
499 
500 static int
501 setup_peer(char *file)
502 {
503 	EVP_PKEY *peer = NULL;
504 	int ret;
505 
506 	if (!pkeyutl_config.ctx) {
507 		BIO_puts(bio_err, "-peerkey command before -inkey\n");
508 		return (1);
509 	}
510 	peer = load_pubkey(bio_err, file, pkeyutl_config.peerform, 0, NULL,
511 	    "Peer Key");
512 
513 	if (!peer) {
514 		BIO_printf(bio_err, "Error reading peer key %s\n", file);
515 		ERR_print_errors(bio_err);
516 		return (1);
517 	}
518 	ret = EVP_PKEY_derive_set_peer(pkeyutl_config.ctx, peer);
519 
520 	EVP_PKEY_free(peer);
521 	if (ret <= 0) {
522 		ERR_print_errors(bio_err);
523 		return (1);
524 	}
525 
526 	return (0);
527 }
528 
529 static int
530 pkeyutl_pkeyopt(char *pkeyopt)
531 {
532 	if (!pkeyutl_config.ctx) {
533 		BIO_puts(bio_err, "-pkeyopt command before -inkey\n");
534 		return (1);
535 	} else if (pkey_ctrl_string(pkeyutl_config.ctx, pkeyopt) <= 0) {
536 		BIO_puts(bio_err, "parameter setting error\n");
537 		ERR_print_errors(bio_err);
538 		return (1);
539 	}
540 
541 	return (0);
542 }
543 
544 static int
545 do_keyop(EVP_PKEY_CTX * ctx, int pkey_op,
546     unsigned char *out, size_t * poutlen,
547     unsigned char *in, size_t inlen)
548 {
549 	int rv = 0;
550 	switch (pkey_op) {
551 	case EVP_PKEY_OP_VERIFYRECOVER:
552 		rv = EVP_PKEY_verify_recover(ctx, out, poutlen, in, inlen);
553 		break;
554 
555 	case EVP_PKEY_OP_SIGN:
556 		rv = EVP_PKEY_sign(ctx, out, poutlen, in, inlen);
557 		break;
558 
559 	case EVP_PKEY_OP_ENCRYPT:
560 		rv = EVP_PKEY_encrypt(ctx, out, poutlen, in, inlen);
561 		break;
562 
563 	case EVP_PKEY_OP_DECRYPT:
564 		rv = EVP_PKEY_decrypt(ctx, out, poutlen, in, inlen);
565 		break;
566 
567 	case EVP_PKEY_OP_DERIVE:
568 		rv = EVP_PKEY_derive(ctx, out, poutlen);
569 		break;
570 
571 	}
572 	return rv;
573 }
574