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