xref: /dflybsd-src/crypto/libressl/apps/openssl/pkeyutl.c (revision cca6fc5243d2098262ea81f83ad5b28d3b800f4a)
1*cca6fc52SDaniel Fojt /* $OpenBSD: pkeyutl.c,v 1.16 2019/07/14 03:30:46 guenther Exp $ */
2f5b1c8a1SJohn Marino /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3f5b1c8a1SJohn Marino  * project 2006.
4f5b1c8a1SJohn Marino  */
5f5b1c8a1SJohn Marino /* ====================================================================
6f5b1c8a1SJohn Marino  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
7f5b1c8a1SJohn Marino  *
8f5b1c8a1SJohn Marino  * Redistribution and use in source and binary forms, with or without
9f5b1c8a1SJohn Marino  * modification, are permitted provided that the following conditions
10f5b1c8a1SJohn Marino  * are met:
11f5b1c8a1SJohn Marino  *
12f5b1c8a1SJohn Marino  * 1. Redistributions of source code must retain the above copyright
13f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer.
14f5b1c8a1SJohn Marino  *
15f5b1c8a1SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
16f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer in
17f5b1c8a1SJohn Marino  *    the documentation and/or other materials provided with the
18f5b1c8a1SJohn Marino  *    distribution.
19f5b1c8a1SJohn Marino  *
20f5b1c8a1SJohn Marino  * 3. All advertising materials mentioning features or use of this
21f5b1c8a1SJohn Marino  *    software must display the following acknowledgment:
22f5b1c8a1SJohn Marino  *    "This product includes software developed by the OpenSSL Project
23f5b1c8a1SJohn Marino  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24f5b1c8a1SJohn Marino  *
25f5b1c8a1SJohn Marino  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26f5b1c8a1SJohn Marino  *    endorse or promote products derived from this software without
27f5b1c8a1SJohn Marino  *    prior written permission. For written permission, please contact
28f5b1c8a1SJohn Marino  *    licensing@OpenSSL.org.
29f5b1c8a1SJohn Marino  *
30f5b1c8a1SJohn Marino  * 5. Products derived from this software may not be called "OpenSSL"
31f5b1c8a1SJohn Marino  *    nor may "OpenSSL" appear in their names without prior written
32f5b1c8a1SJohn Marino  *    permission of the OpenSSL Project.
33f5b1c8a1SJohn Marino  *
34f5b1c8a1SJohn Marino  * 6. Redistributions of any form whatsoever must retain the following
35f5b1c8a1SJohn Marino  *    acknowledgment:
36f5b1c8a1SJohn Marino  *    "This product includes software developed by the OpenSSL Project
37f5b1c8a1SJohn Marino  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38f5b1c8a1SJohn Marino  *
39f5b1c8a1SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40f5b1c8a1SJohn Marino  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41f5b1c8a1SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42f5b1c8a1SJohn Marino  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43f5b1c8a1SJohn Marino  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44f5b1c8a1SJohn Marino  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45f5b1c8a1SJohn Marino  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46f5b1c8a1SJohn Marino  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47f5b1c8a1SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48f5b1c8a1SJohn Marino  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49f5b1c8a1SJohn Marino  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50f5b1c8a1SJohn Marino  * OF THE POSSIBILITY OF SUCH DAMAGE.
51f5b1c8a1SJohn Marino  * ====================================================================
52f5b1c8a1SJohn Marino  *
53f5b1c8a1SJohn Marino  * This product includes cryptographic software written by Eric Young
54f5b1c8a1SJohn Marino  * (eay@cryptsoft.com).  This product includes software written by Tim
55f5b1c8a1SJohn Marino  * Hudson (tjh@cryptsoft.com).
56f5b1c8a1SJohn Marino  *
57f5b1c8a1SJohn Marino  */
58f5b1c8a1SJohn Marino 
59f5b1c8a1SJohn Marino #include <string.h>
60f5b1c8a1SJohn Marino 
61f5b1c8a1SJohn Marino #include "apps.h"
62f5b1c8a1SJohn Marino 
63f5b1c8a1SJohn Marino #include <openssl/err.h>
64f5b1c8a1SJohn Marino #include <openssl/evp.h>
65f5b1c8a1SJohn Marino #include <openssl/pem.h>
66f5b1c8a1SJohn Marino 
67f5b1c8a1SJohn Marino #define KEY_PRIVKEY	1
68f5b1c8a1SJohn Marino #define KEY_PUBKEY	2
69f5b1c8a1SJohn Marino #define KEY_CERT	3
70f5b1c8a1SJohn Marino 
7172c33676SMaxim Ag struct {
7272c33676SMaxim Ag 	int asn1parse;
7372c33676SMaxim Ag 	EVP_PKEY_CTX *ctx;
7472c33676SMaxim Ag 	int hexdump;
7572c33676SMaxim Ag 	char *infile;
7672c33676SMaxim Ag 	int key_type;
7772c33676SMaxim Ag 	int keyform;
7872c33676SMaxim Ag 	int keysize;
7972c33676SMaxim Ag 	char *outfile;
8072c33676SMaxim Ag 	char *passargin;
8172c33676SMaxim Ag 	int peerform;
8272c33676SMaxim Ag 	int pkey_op;
8372c33676SMaxim Ag 	int rev;
8472c33676SMaxim Ag 	char *sigfile;
8572c33676SMaxim Ag } pkeyutl_config;
86f5b1c8a1SJohn Marino 
8772c33676SMaxim Ag static void pkeyutl_usage(void);
88f5b1c8a1SJohn Marino 
8972c33676SMaxim Ag static int init_ctx(char *keyfile);
9072c33676SMaxim Ag 
9172c33676SMaxim Ag static int setup_peer(char *file);
9272c33676SMaxim Ag 
9372c33676SMaxim Ag static int pkeyutl_pkeyopt(char *pkeyopt);
94f5b1c8a1SJohn Marino 
95f5b1c8a1SJohn Marino static int do_keyop(EVP_PKEY_CTX * ctx, int pkey_op,
96f5b1c8a1SJohn Marino     unsigned char *out, size_t * poutlen,
97f5b1c8a1SJohn Marino     unsigned char *in, size_t inlen);
98f5b1c8a1SJohn Marino 
99*cca6fc52SDaniel Fojt static const struct option pkeyutl_options[] = {
10072c33676SMaxim Ag 	{
10172c33676SMaxim Ag 		.name = "asn1parse",
10272c33676SMaxim Ag 		.desc = "ASN.1 parse the output data",
10372c33676SMaxim Ag 		.type = OPTION_FLAG,
10472c33676SMaxim Ag 		.opt.flag = &pkeyutl_config.asn1parse,
10572c33676SMaxim Ag 	},
10672c33676SMaxim Ag 	{
10772c33676SMaxim Ag 		.name = "certin",
10872c33676SMaxim Ag 		.desc = "Input is a certificate containing a public key",
10972c33676SMaxim Ag 		.type = OPTION_VALUE,
11072c33676SMaxim Ag 		.value = KEY_CERT,
11172c33676SMaxim Ag 		.opt.value = &pkeyutl_config.key_type,
11272c33676SMaxim Ag 	},
11372c33676SMaxim Ag 	{
11472c33676SMaxim Ag 		.name = "decrypt",
11572c33676SMaxim Ag 		.desc = "Decrypt the input data using a private key",
11672c33676SMaxim Ag 		.type = OPTION_VALUE,
11772c33676SMaxim Ag 		.value = EVP_PKEY_OP_DECRYPT,
11872c33676SMaxim Ag 		.opt.value = &pkeyutl_config.pkey_op,
11972c33676SMaxim Ag 	},
12072c33676SMaxim Ag 	{
12172c33676SMaxim Ag 		.name = "derive",
12272c33676SMaxim Ag 		.desc = "Derive a shared secret using the peer key",
12372c33676SMaxim Ag 		.type = OPTION_VALUE,
12472c33676SMaxim Ag 		.value = EVP_PKEY_OP_DERIVE,
12572c33676SMaxim Ag 		.opt.value = &pkeyutl_config.pkey_op,
12672c33676SMaxim Ag 	},
12772c33676SMaxim Ag 	{
12872c33676SMaxim Ag 		.name = "encrypt",
12972c33676SMaxim Ag 		.desc = "Encrypt the input data using a public key",
13072c33676SMaxim Ag 		.type = OPTION_VALUE,
13172c33676SMaxim Ag 		.value = EVP_PKEY_OP_ENCRYPT,
13272c33676SMaxim Ag 		.opt.value = &pkeyutl_config.pkey_op,
13372c33676SMaxim Ag 	},
13472c33676SMaxim Ag 	{
13572c33676SMaxim Ag 		.name = "hexdump",
13672c33676SMaxim Ag 		.desc = "Hex dump the output data",
13772c33676SMaxim Ag 		.type = OPTION_FLAG,
13872c33676SMaxim Ag 		.opt.flag = &pkeyutl_config.hexdump,
13972c33676SMaxim Ag 	},
14072c33676SMaxim Ag 	{
14172c33676SMaxim Ag 		.name = "in",
14272c33676SMaxim Ag 		.argname = "file",
14372c33676SMaxim Ag 		.desc = "Input file (default stdin)",
14472c33676SMaxim Ag 		.type = OPTION_ARG,
14572c33676SMaxim Ag 		.opt.arg = &pkeyutl_config.infile,
14672c33676SMaxim Ag 	},
14772c33676SMaxim Ag 	{
14872c33676SMaxim Ag 		.name = "inkey",
14972c33676SMaxim Ag 		.argname = "file",
15072c33676SMaxim Ag 		.desc = "Input key file",
15172c33676SMaxim Ag 		.type = OPTION_ARG_FUNC,
15272c33676SMaxim Ag 		.opt.argfunc = init_ctx,
15372c33676SMaxim Ag 	},
15472c33676SMaxim Ag 	{
15572c33676SMaxim Ag 		.name = "keyform",
15672c33676SMaxim Ag 		.argname = "fmt",
15772c33676SMaxim Ag 		.desc = "Input key format (DER or PEM (default))",
15872c33676SMaxim Ag 		.type = OPTION_ARG_FORMAT,
15972c33676SMaxim Ag 		.opt.value = &pkeyutl_config.keyform,
16072c33676SMaxim Ag 	},
16172c33676SMaxim Ag 	{
16272c33676SMaxim Ag 		.name = "out",
16372c33676SMaxim Ag 		.argname = "file",
16472c33676SMaxim Ag 		.desc = "Output file (default stdout)",
16572c33676SMaxim Ag 		.type = OPTION_ARG,
16672c33676SMaxim Ag 		.opt.arg = &pkeyutl_config.outfile,
16772c33676SMaxim Ag 	},
16872c33676SMaxim Ag 	{
16972c33676SMaxim Ag 		.name = "passin",
17072c33676SMaxim Ag 		.argname = "arg",
17172c33676SMaxim Ag 		.desc = "Key password source",
17272c33676SMaxim Ag 		.type = OPTION_ARG,
17372c33676SMaxim Ag 		.opt.arg = &pkeyutl_config.passargin,
17472c33676SMaxim Ag 	},
17572c33676SMaxim Ag 	{
17672c33676SMaxim Ag 		.name = "peerform",
17772c33676SMaxim Ag 		.argname = "fmt",
17872c33676SMaxim Ag 		.desc = "Input key format (DER or PEM (default))",
17972c33676SMaxim Ag 		.type = OPTION_ARG_FORMAT,
18072c33676SMaxim Ag 		.opt.value = &pkeyutl_config.peerform,
18172c33676SMaxim Ag 	},
18272c33676SMaxim Ag 	{
18372c33676SMaxim Ag 		.name = "peerkey",
18472c33676SMaxim Ag 		.argname = "file",
18572c33676SMaxim Ag 		.desc = "Peer key file",
18672c33676SMaxim Ag 		.type = OPTION_ARG_FUNC,
18772c33676SMaxim Ag 		.opt.argfunc = setup_peer,
18872c33676SMaxim Ag 	},
18972c33676SMaxim Ag 	{
19072c33676SMaxim Ag 		.name = "pkeyopt",
19172c33676SMaxim Ag 		.argname = "opt:value",
19272c33676SMaxim Ag 		.desc = "Public key options",
19372c33676SMaxim Ag 		.type = OPTION_ARG_FUNC,
19472c33676SMaxim Ag 		.opt.argfunc = pkeyutl_pkeyopt,
19572c33676SMaxim Ag 	},
19672c33676SMaxim Ag 	{
19772c33676SMaxim Ag 		.name = "pubin",
19872c33676SMaxim Ag 		.desc = "Input is a public key",
19972c33676SMaxim Ag 		.type = OPTION_VALUE,
20072c33676SMaxim Ag 		.value = KEY_PUBKEY,
20172c33676SMaxim Ag 		.opt.value = &pkeyutl_config.key_type,
20272c33676SMaxim Ag 	},
20372c33676SMaxim Ag 	{
20472c33676SMaxim Ag 		.name = "rev",
20572c33676SMaxim Ag 		.desc = "Reverse the input data",
20672c33676SMaxim Ag 		.type = OPTION_FLAG,
20772c33676SMaxim Ag 		.opt.flag = &pkeyutl_config.rev,
20872c33676SMaxim Ag 	},
20972c33676SMaxim Ag 	{
21072c33676SMaxim Ag 		.name = "sigfile",
21172c33676SMaxim Ag 		.argname = "file",
21272c33676SMaxim Ag 		.desc = "Signature file (verify operation only)",
21372c33676SMaxim Ag 		.type = OPTION_ARG,
21472c33676SMaxim Ag 		.opt.arg = &pkeyutl_config.sigfile,
21572c33676SMaxim Ag 	},
21672c33676SMaxim Ag 	{
21772c33676SMaxim Ag 		.name = "sign",
21872c33676SMaxim Ag 		.desc = "Sign the input data using private key",
21972c33676SMaxim Ag 		.type = OPTION_VALUE,
22072c33676SMaxim Ag 		.value = EVP_PKEY_OP_SIGN,
22172c33676SMaxim Ag 		.opt.value = &pkeyutl_config.pkey_op,
22272c33676SMaxim Ag 	},
22372c33676SMaxim Ag 	{
22472c33676SMaxim Ag 		.name = "verify",
22572c33676SMaxim Ag 		.desc = "Verify the input data using public key",
22672c33676SMaxim Ag 		.type = OPTION_VALUE,
22772c33676SMaxim Ag 		.value = EVP_PKEY_OP_VERIFY,
22872c33676SMaxim Ag 		.opt.value = &pkeyutl_config.pkey_op,
22972c33676SMaxim Ag 	},
23072c33676SMaxim Ag 	{
23172c33676SMaxim Ag 		.name = "verifyrecover",
23272c33676SMaxim Ag 		.desc = "Verify with public key, recover original data",
23372c33676SMaxim Ag 		.type = OPTION_VALUE,
23472c33676SMaxim Ag 		.value = EVP_PKEY_OP_VERIFYRECOVER,
23572c33676SMaxim Ag 		.opt.value = &pkeyutl_config.pkey_op,
23672c33676SMaxim Ag 	},
23772c33676SMaxim Ag 
23872c33676SMaxim Ag 	{NULL},
23972c33676SMaxim Ag };
24072c33676SMaxim Ag 
24172c33676SMaxim Ag static void
pkeyutl_usage()24272c33676SMaxim Ag pkeyutl_usage()
24372c33676SMaxim Ag {
24472c33676SMaxim Ag 	fprintf(stderr,
24572c33676SMaxim Ag 	    "usage: pkeyutl [-asn1parse] [-certin] [-decrypt] [-derive] "
24672c33676SMaxim Ag 	    "[-encrypt]\n"
24772c33676SMaxim Ag 	    "    [-hexdump] [-in file] [-inkey file] [-keyform fmt]\n"
24872c33676SMaxim Ag 	    "    [-out file] [-passin arg] [-peerform fmt]\n"
24972c33676SMaxim Ag 	    "    [-peerkey file] [-pkeyopt opt:value] [-pubin] [-rev]\n"
25072c33676SMaxim Ag 	    "    [-sigfile file] [-sign] [-verify] [-verifyrecover]\n\n");
25172c33676SMaxim Ag 	options_usage(pkeyutl_options);
25272c33676SMaxim Ag         fprintf(stderr, "\n");
25372c33676SMaxim Ag }
25472c33676SMaxim Ag 
255f5b1c8a1SJohn Marino int
pkeyutl_main(int argc,char ** argv)256f5b1c8a1SJohn Marino pkeyutl_main(int argc, char **argv)
257f5b1c8a1SJohn Marino {
258f5b1c8a1SJohn Marino 	BIO *in = NULL, *out = NULL;
259f5b1c8a1SJohn Marino 
260f5b1c8a1SJohn Marino 	unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL;
26172c33676SMaxim Ag 	size_t buf_outlen = 0;
262f5b1c8a1SJohn Marino 	int buf_inlen = 0, siglen = -1;
263f5b1c8a1SJohn Marino 
264f5b1c8a1SJohn Marino 	int ret = 1, rv = -1;
265f5b1c8a1SJohn Marino 
266f5b1c8a1SJohn Marino 	if (single_execution) {
26772c33676SMaxim Ag 		if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
268f5b1c8a1SJohn Marino 			perror("pledge");
269f5b1c8a1SJohn Marino 			exit(1);
270f5b1c8a1SJohn Marino 		}
271f5b1c8a1SJohn Marino 	}
272f5b1c8a1SJohn Marino 
27372c33676SMaxim Ag 	memset(&pkeyutl_config, 0, sizeof(pkeyutl_config));
27472c33676SMaxim Ag 	pkeyutl_config.pkey_op = EVP_PKEY_OP_SIGN;
27572c33676SMaxim Ag 	pkeyutl_config.key_type = KEY_PRIVKEY;
27672c33676SMaxim Ag 	pkeyutl_config.keyform = FORMAT_PEM;
27772c33676SMaxim Ag 	pkeyutl_config.peerform = FORMAT_PEM;
27872c33676SMaxim Ag 	pkeyutl_config.keysize = -1;
279f5b1c8a1SJohn Marino 
28072c33676SMaxim Ag 	if (options_parse(argc, argv, pkeyutl_options, NULL, NULL) != 0) {
28172c33676SMaxim Ag 		pkeyutl_usage();
282f5b1c8a1SJohn Marino 		goto end;
283f5b1c8a1SJohn Marino 	}
284f5b1c8a1SJohn Marino 
28572c33676SMaxim Ag 	if (!pkeyutl_config.ctx) {
28672c33676SMaxim Ag 		pkeyutl_usage();
287f5b1c8a1SJohn Marino 		goto end;
288f5b1c8a1SJohn Marino 	}
28972c33676SMaxim Ag 	if (pkeyutl_config.sigfile &&
29072c33676SMaxim Ag 	    (pkeyutl_config.pkey_op != EVP_PKEY_OP_VERIFY)) {
291f5b1c8a1SJohn Marino 		BIO_puts(bio_err, "Signature file specified for non verify\n");
292f5b1c8a1SJohn Marino 		goto end;
293f5b1c8a1SJohn Marino 	}
29472c33676SMaxim Ag 	if (!pkeyutl_config.sigfile &&
29572c33676SMaxim Ag 	    (pkeyutl_config.pkey_op == EVP_PKEY_OP_VERIFY)) {
296f5b1c8a1SJohn Marino 		BIO_puts(bio_err, "No signature file specified for verify\n");
297f5b1c8a1SJohn Marino 		goto end;
298f5b1c8a1SJohn Marino 	}
299f5b1c8a1SJohn Marino 
30072c33676SMaxim Ag 	if (pkeyutl_config.pkey_op != EVP_PKEY_OP_DERIVE) {
30172c33676SMaxim Ag 		if (pkeyutl_config.infile) {
30272c33676SMaxim Ag 			if (!(in = BIO_new_file(pkeyutl_config.infile, "rb"))) {
303f5b1c8a1SJohn Marino 				BIO_puts(bio_err,
304f5b1c8a1SJohn Marino 				    "Error Opening Input File\n");
305f5b1c8a1SJohn Marino 				ERR_print_errors(bio_err);
306f5b1c8a1SJohn Marino 				goto end;
307f5b1c8a1SJohn Marino 			}
308f5b1c8a1SJohn Marino 		} else
309f5b1c8a1SJohn Marino 			in = BIO_new_fp(stdin, BIO_NOCLOSE);
310f5b1c8a1SJohn Marino 	}
31172c33676SMaxim Ag 	if (pkeyutl_config.outfile) {
31272c33676SMaxim Ag 		if (!(out = BIO_new_file(pkeyutl_config.outfile, "wb"))) {
313f5b1c8a1SJohn Marino 			BIO_printf(bio_err, "Error Creating Output File\n");
314f5b1c8a1SJohn Marino 			ERR_print_errors(bio_err);
315f5b1c8a1SJohn Marino 			goto end;
316f5b1c8a1SJohn Marino 		}
317f5b1c8a1SJohn Marino 	} else {
318f5b1c8a1SJohn Marino 		out = BIO_new_fp(stdout, BIO_NOCLOSE);
319f5b1c8a1SJohn Marino 	}
320f5b1c8a1SJohn Marino 
32172c33676SMaxim Ag 	if (pkeyutl_config.sigfile) {
32272c33676SMaxim Ag 		BIO *sigbio = BIO_new_file(pkeyutl_config.sigfile, "rb");
323f5b1c8a1SJohn Marino 		if (!sigbio) {
324f5b1c8a1SJohn Marino 			BIO_printf(bio_err, "Can't open signature file %s\n",
32572c33676SMaxim Ag 			    pkeyutl_config.sigfile);
326f5b1c8a1SJohn Marino 			goto end;
327f5b1c8a1SJohn Marino 		}
32872c33676SMaxim Ag 		siglen = bio_to_mem(&sig, pkeyutl_config.keysize * 10, sigbio);
329f5b1c8a1SJohn Marino 		BIO_free(sigbio);
330f5b1c8a1SJohn Marino 		if (siglen <= 0) {
331f5b1c8a1SJohn Marino 			BIO_printf(bio_err, "Error reading signature data\n");
332f5b1c8a1SJohn Marino 			goto end;
333f5b1c8a1SJohn Marino 		}
334f5b1c8a1SJohn Marino 	}
335f5b1c8a1SJohn Marino 	if (in) {
336f5b1c8a1SJohn Marino 		/* Read the input data */
33772c33676SMaxim Ag 		buf_inlen = bio_to_mem(&buf_in, pkeyutl_config.keysize * 10, in);
338f5b1c8a1SJohn Marino 		if (buf_inlen <= 0) {
339f5b1c8a1SJohn Marino 			BIO_printf(bio_err, "Error reading input Data\n");
340f5b1c8a1SJohn Marino 			exit(1);
341f5b1c8a1SJohn Marino 		}
34272c33676SMaxim Ag 		if (pkeyutl_config.rev) {
343f5b1c8a1SJohn Marino 			size_t i;
344f5b1c8a1SJohn Marino 			unsigned char ctmp;
345f5b1c8a1SJohn Marino 			size_t l = (size_t) buf_inlen;
346f5b1c8a1SJohn Marino 			for (i = 0; i < l / 2; i++) {
347f5b1c8a1SJohn Marino 				ctmp = buf_in[i];
348f5b1c8a1SJohn Marino 				buf_in[i] = buf_in[l - 1 - i];
349f5b1c8a1SJohn Marino 				buf_in[l - 1 - i] = ctmp;
350f5b1c8a1SJohn Marino 			}
351f5b1c8a1SJohn Marino 		}
352f5b1c8a1SJohn Marino 	}
35372c33676SMaxim Ag 	if (pkeyutl_config.pkey_op == EVP_PKEY_OP_VERIFY) {
35472c33676SMaxim Ag 		rv = EVP_PKEY_verify(pkeyutl_config.ctx, sig, (size_t) siglen,
355f5b1c8a1SJohn Marino 		    buf_in, (size_t) buf_inlen);
356f5b1c8a1SJohn Marino 		if (rv == 1) {
357f5b1c8a1SJohn Marino 			BIO_puts(out, "Signature Verified Successfully\n");
358f5b1c8a1SJohn Marino 			ret = 0;
359f5b1c8a1SJohn Marino 		} else
360f5b1c8a1SJohn Marino 			BIO_puts(out, "Signature Verification Failure\n");
361f5b1c8a1SJohn Marino 		if (rv >= 0)
362f5b1c8a1SJohn Marino 			goto end;
363f5b1c8a1SJohn Marino 	} else {
36472c33676SMaxim Ag 		rv = do_keyop(pkeyutl_config.ctx, pkeyutl_config.pkey_op, NULL,
36572c33676SMaxim Ag 		    (size_t *)&buf_outlen, buf_in, (size_t) buf_inlen);
366f5b1c8a1SJohn Marino 		if (rv > 0) {
367f5b1c8a1SJohn Marino 			buf_out = malloc(buf_outlen);
368f5b1c8a1SJohn Marino 			if (!buf_out)
369f5b1c8a1SJohn Marino 				rv = -1;
370f5b1c8a1SJohn Marino 			else
37172c33676SMaxim Ag 				rv = do_keyop(pkeyutl_config.ctx,
37272c33676SMaxim Ag 				    pkeyutl_config.pkey_op,
373f5b1c8a1SJohn Marino 				    buf_out, (size_t *) & buf_outlen,
374f5b1c8a1SJohn Marino 				    buf_in, (size_t) buf_inlen);
375f5b1c8a1SJohn Marino 		}
376f5b1c8a1SJohn Marino 	}
377f5b1c8a1SJohn Marino 
378f5b1c8a1SJohn Marino 	if (rv <= 0) {
379f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Public Key operation error\n");
380f5b1c8a1SJohn Marino 		ERR_print_errors(bio_err);
381f5b1c8a1SJohn Marino 		goto end;
382f5b1c8a1SJohn Marino 	}
383f5b1c8a1SJohn Marino 	ret = 0;
38472c33676SMaxim Ag 	if (pkeyutl_config.asn1parse) {
385f5b1c8a1SJohn Marino 		if (!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1))
386f5b1c8a1SJohn Marino 			ERR_print_errors(bio_err);
38772c33676SMaxim Ag 	} else if (pkeyutl_config.hexdump)
388f5b1c8a1SJohn Marino 		BIO_dump(out, (char *) buf_out, buf_outlen);
389f5b1c8a1SJohn Marino 	else
390f5b1c8a1SJohn Marino 		BIO_write(out, buf_out, buf_outlen);
391f5b1c8a1SJohn Marino 
392f5b1c8a1SJohn Marino  end:
39372c33676SMaxim Ag 	EVP_PKEY_CTX_free(pkeyutl_config.ctx);
394f5b1c8a1SJohn Marino 	BIO_free(in);
395f5b1c8a1SJohn Marino 	BIO_free_all(out);
396f5b1c8a1SJohn Marino 	free(buf_in);
397f5b1c8a1SJohn Marino 	free(buf_out);
398f5b1c8a1SJohn Marino 	free(sig);
399f5b1c8a1SJohn Marino 
400f5b1c8a1SJohn Marino 	return ret;
401f5b1c8a1SJohn Marino }
402f5b1c8a1SJohn Marino 
40372c33676SMaxim Ag static int
init_ctx(char * keyfile)40472c33676SMaxim Ag init_ctx(char *keyfile)
405f5b1c8a1SJohn Marino {
406f5b1c8a1SJohn Marino 	EVP_PKEY *pkey = NULL;
407f5b1c8a1SJohn Marino 	char *passin = NULL;
408f5b1c8a1SJohn Marino 	int rv = -1;
409f5b1c8a1SJohn Marino 	X509 *x;
41072c33676SMaxim Ag 
41172c33676SMaxim Ag 	if (((pkeyutl_config.pkey_op == EVP_PKEY_OP_SIGN)
41272c33676SMaxim Ag 		|| (pkeyutl_config.pkey_op == EVP_PKEY_OP_DECRYPT)
41372c33676SMaxim Ag 		|| (pkeyutl_config.pkey_op == EVP_PKEY_OP_DERIVE))
41472c33676SMaxim Ag 	    && (pkeyutl_config.key_type != KEY_PRIVKEY)) {
41572c33676SMaxim Ag 		BIO_printf(bio_err,
41672c33676SMaxim Ag 		    "A private key is needed for this operation\n");
417f5b1c8a1SJohn Marino 		goto end;
418f5b1c8a1SJohn Marino 	}
41972c33676SMaxim Ag 	if (!app_passwd(bio_err, pkeyutl_config.passargin, NULL, &passin,
42072c33676SMaxim Ag 	    NULL)) {
421f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Error getting password\n");
422f5b1c8a1SJohn Marino 		goto end;
423f5b1c8a1SJohn Marino 	}
42472c33676SMaxim Ag 	switch (pkeyutl_config.key_type) {
425f5b1c8a1SJohn Marino 	case KEY_PRIVKEY:
42672c33676SMaxim Ag 		pkey = load_key(bio_err, keyfile, pkeyutl_config.keyform, 0,
427f5b1c8a1SJohn Marino 		    passin, "Private Key");
428f5b1c8a1SJohn Marino 		break;
429f5b1c8a1SJohn Marino 
430f5b1c8a1SJohn Marino 	case KEY_PUBKEY:
43172c33676SMaxim Ag 		pkey = load_pubkey(bio_err, keyfile, pkeyutl_config.keyform, 0,
432f5b1c8a1SJohn Marino 		    NULL, "Public Key");
433f5b1c8a1SJohn Marino 		break;
434f5b1c8a1SJohn Marino 
435f5b1c8a1SJohn Marino 	case KEY_CERT:
43672c33676SMaxim Ag 		x = load_cert(bio_err, keyfile, pkeyutl_config.keyform,
437f5b1c8a1SJohn Marino 		    NULL, "Certificate");
438f5b1c8a1SJohn Marino 		if (x) {
439f5b1c8a1SJohn Marino 			pkey = X509_get_pubkey(x);
440f5b1c8a1SJohn Marino 			X509_free(x);
441f5b1c8a1SJohn Marino 		}
442f5b1c8a1SJohn Marino 		break;
443f5b1c8a1SJohn Marino 	}
444f5b1c8a1SJohn Marino 
44572c33676SMaxim Ag 	pkeyutl_config.keysize = EVP_PKEY_size(pkey);
446f5b1c8a1SJohn Marino 
447f5b1c8a1SJohn Marino 	if (!pkey)
448f5b1c8a1SJohn Marino 		goto end;
449f5b1c8a1SJohn Marino 
45072c33676SMaxim Ag 	pkeyutl_config.ctx = EVP_PKEY_CTX_new(pkey, NULL);
451f5b1c8a1SJohn Marino 
452f5b1c8a1SJohn Marino 	EVP_PKEY_free(pkey);
453f5b1c8a1SJohn Marino 
45472c33676SMaxim Ag 	if (!pkeyutl_config.ctx)
455f5b1c8a1SJohn Marino 		goto end;
456f5b1c8a1SJohn Marino 
45772c33676SMaxim Ag 	switch (pkeyutl_config.pkey_op) {
458f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_SIGN:
45972c33676SMaxim Ag 		rv = EVP_PKEY_sign_init(pkeyutl_config.ctx);
460f5b1c8a1SJohn Marino 		break;
461f5b1c8a1SJohn Marino 
462f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_VERIFY:
46372c33676SMaxim Ag 		rv = EVP_PKEY_verify_init(pkeyutl_config.ctx);
464f5b1c8a1SJohn Marino 		break;
465f5b1c8a1SJohn Marino 
466f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_VERIFYRECOVER:
46772c33676SMaxim Ag 		rv = EVP_PKEY_verify_recover_init(pkeyutl_config.ctx);
468f5b1c8a1SJohn Marino 		break;
469f5b1c8a1SJohn Marino 
470f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_ENCRYPT:
47172c33676SMaxim Ag 		rv = EVP_PKEY_encrypt_init(pkeyutl_config.ctx);
472f5b1c8a1SJohn Marino 		break;
473f5b1c8a1SJohn Marino 
474f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_DECRYPT:
47572c33676SMaxim Ag 		rv = EVP_PKEY_decrypt_init(pkeyutl_config.ctx);
476f5b1c8a1SJohn Marino 		break;
477f5b1c8a1SJohn Marino 
478f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_DERIVE:
47972c33676SMaxim Ag 		rv = EVP_PKEY_derive_init(pkeyutl_config.ctx);
480f5b1c8a1SJohn Marino 		break;
481f5b1c8a1SJohn Marino 	}
482f5b1c8a1SJohn Marino 
483f5b1c8a1SJohn Marino 	if (rv <= 0) {
48472c33676SMaxim Ag 		EVP_PKEY_CTX_free(pkeyutl_config.ctx);
48572c33676SMaxim Ag 		pkeyutl_config.ctx = NULL;
486f5b1c8a1SJohn Marino 	}
487f5b1c8a1SJohn Marino 
48872c33676SMaxim Ag  end:
489f5b1c8a1SJohn Marino 	free(passin);
490f5b1c8a1SJohn Marino 
49172c33676SMaxim Ag 	if (!pkeyutl_config.ctx) {
49272c33676SMaxim Ag 		BIO_puts(bio_err, "Error initializing context\n");
49372c33676SMaxim Ag 		ERR_print_errors(bio_err);
49472c33676SMaxim Ag 		return (1);
49572c33676SMaxim Ag 	}
496f5b1c8a1SJohn Marino 
49772c33676SMaxim Ag 	return (0);
498f5b1c8a1SJohn Marino }
499f5b1c8a1SJohn Marino 
500f5b1c8a1SJohn Marino static int
setup_peer(char * file)50172c33676SMaxim Ag setup_peer(char *file)
502f5b1c8a1SJohn Marino {
503f5b1c8a1SJohn Marino 	EVP_PKEY *peer = NULL;
504f5b1c8a1SJohn Marino 	int ret;
50572c33676SMaxim Ag 
50672c33676SMaxim Ag 	if (!pkeyutl_config.ctx) {
50772c33676SMaxim Ag 		BIO_puts(bio_err, "-peerkey command before -inkey\n");
50872c33676SMaxim Ag 		return (1);
509f5b1c8a1SJohn Marino 	}
51072c33676SMaxim Ag 	peer = load_pubkey(bio_err, file, pkeyutl_config.peerform, 0, NULL,
51172c33676SMaxim Ag 	    "Peer Key");
512f5b1c8a1SJohn Marino 
513f5b1c8a1SJohn Marino 	if (!peer) {
514f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Error reading peer key %s\n", file);
51572c33676SMaxim Ag 		ERR_print_errors(bio_err);
51672c33676SMaxim Ag 		return (1);
517f5b1c8a1SJohn Marino 	}
51872c33676SMaxim Ag 	ret = EVP_PKEY_derive_set_peer(pkeyutl_config.ctx, peer);
519f5b1c8a1SJohn Marino 
520f5b1c8a1SJohn Marino 	EVP_PKEY_free(peer);
52172c33676SMaxim Ag 	if (ret <= 0) {
52272c33676SMaxim Ag 		ERR_print_errors(bio_err);
52372c33676SMaxim Ag 		return (1);
52472c33676SMaxim Ag 	}
52572c33676SMaxim Ag 
52672c33676SMaxim Ag 	return (0);
52772c33676SMaxim Ag }
52872c33676SMaxim Ag 
52972c33676SMaxim Ag static int
pkeyutl_pkeyopt(char * pkeyopt)53072c33676SMaxim Ag pkeyutl_pkeyopt(char *pkeyopt)
53172c33676SMaxim Ag {
53272c33676SMaxim Ag 	if (!pkeyutl_config.ctx) {
53372c33676SMaxim Ag 		BIO_puts(bio_err, "-pkeyopt command before -inkey\n");
53472c33676SMaxim Ag 		return (1);
53572c33676SMaxim Ag 	} else if (pkey_ctrl_string(pkeyutl_config.ctx, pkeyopt) <= 0) {
53672c33676SMaxim Ag 		BIO_puts(bio_err, "parameter setting error\n");
53772c33676SMaxim Ag 		ERR_print_errors(bio_err);
53872c33676SMaxim Ag 		return (1);
53972c33676SMaxim Ag 	}
54072c33676SMaxim Ag 
54172c33676SMaxim Ag 	return (0);
542f5b1c8a1SJohn Marino }
543f5b1c8a1SJohn Marino 
544f5b1c8a1SJohn Marino static int
do_keyop(EVP_PKEY_CTX * ctx,int pkey_op,unsigned char * out,size_t * poutlen,unsigned char * in,size_t inlen)545f5b1c8a1SJohn Marino do_keyop(EVP_PKEY_CTX * ctx, int pkey_op,
546f5b1c8a1SJohn Marino     unsigned char *out, size_t * poutlen,
547f5b1c8a1SJohn Marino     unsigned char *in, size_t inlen)
548f5b1c8a1SJohn Marino {
549f5b1c8a1SJohn Marino 	int rv = 0;
550f5b1c8a1SJohn Marino 	switch (pkey_op) {
551f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_VERIFYRECOVER:
552f5b1c8a1SJohn Marino 		rv = EVP_PKEY_verify_recover(ctx, out, poutlen, in, inlen);
553f5b1c8a1SJohn Marino 		break;
554f5b1c8a1SJohn Marino 
555f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_SIGN:
556f5b1c8a1SJohn Marino 		rv = EVP_PKEY_sign(ctx, out, poutlen, in, inlen);
557f5b1c8a1SJohn Marino 		break;
558f5b1c8a1SJohn Marino 
559f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_ENCRYPT:
560f5b1c8a1SJohn Marino 		rv = EVP_PKEY_encrypt(ctx, out, poutlen, in, inlen);
561f5b1c8a1SJohn Marino 		break;
562f5b1c8a1SJohn Marino 
563f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_DECRYPT:
564f5b1c8a1SJohn Marino 		rv = EVP_PKEY_decrypt(ctx, out, poutlen, in, inlen);
565f5b1c8a1SJohn Marino 		break;
566f5b1c8a1SJohn Marino 
567f5b1c8a1SJohn Marino 	case EVP_PKEY_OP_DERIVE:
568f5b1c8a1SJohn Marino 		rv = EVP_PKEY_derive(ctx, out, poutlen);
569f5b1c8a1SJohn Marino 		break;
570f5b1c8a1SJohn Marino 
571f5b1c8a1SJohn Marino 	}
572f5b1c8a1SJohn Marino 	return rv;
573f5b1c8a1SJohn Marino }
574