Annotation of src/usr.bin/openssl/pkeyutl.c, Revision 1.16
1.16 ! guenther 1: /* $OpenBSD: pkeyutl.c,v 1.15 2019/02/17 15:01:08 inoguchi Exp $ */
1.1 jsing 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:
1.15 inoguchi 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;
1.1 jsing 86:
1.15 inoguchi 87: static void pkeyutl_usage(void);
1.1 jsing 88:
1.15 inoguchi 89: static int init_ctx(char *keyfile);
90:
91: static int setup_peer(char *file);
92:
93: static int pkeyutl_pkeyopt(char *pkeyopt);
1.1 jsing 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:
1.16 ! guenther 99: static const struct option pkeyutl_options[] = {
1.15 inoguchi 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:
1.1 jsing 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;
1.12 inoguchi 261: size_t buf_outlen = 0;
1.1 jsing 262: int buf_inlen = 0, siglen = -1;
263:
264: int ret = 1, rv = -1;
1.8 doug 265:
266: if (single_execution) {
1.11 deraadt 267: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
1.8 doug 268: perror("pledge");
1.10 doug 269: exit(1);
270: }
1.8 doug 271: }
1.1 jsing 272:
1.15 inoguchi 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;
1.1 jsing 279:
1.15 inoguchi 280: if (options_parse(argc, argv, pkeyutl_options, NULL, NULL) != 0) {
281: pkeyutl_usage();
282: goto end;
1.1 jsing 283: }
284:
1.15 inoguchi 285: if (!pkeyutl_config.ctx) {
286: pkeyutl_usage();
1.1 jsing 287: goto end;
288: }
1.15 inoguchi 289: if (pkeyutl_config.sigfile &&
290: (pkeyutl_config.pkey_op != EVP_PKEY_OP_VERIFY)) {
1.1 jsing 291: BIO_puts(bio_err, "Signature file specified for non verify\n");
292: goto end;
293: }
1.15 inoguchi 294: if (!pkeyutl_config.sigfile &&
295: (pkeyutl_config.pkey_op == EVP_PKEY_OP_VERIFY)) {
1.1 jsing 296: BIO_puts(bio_err, "No signature file specified for verify\n");
297: goto end;
298: }
299:
1.15 inoguchi 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"))) {
1.1 jsing 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: }
1.15 inoguchi 311: if (pkeyutl_config.outfile) {
312: if (!(out = BIO_new_file(pkeyutl_config.outfile, "wb"))) {
1.1 jsing 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:
1.15 inoguchi 321: if (pkeyutl_config.sigfile) {
322: BIO *sigbio = BIO_new_file(pkeyutl_config.sigfile, "rb");
1.1 jsing 323: if (!sigbio) {
324: BIO_printf(bio_err, "Can't open signature file %s\n",
1.15 inoguchi 325: pkeyutl_config.sigfile);
1.1 jsing 326: goto end;
327: }
1.15 inoguchi 328: siglen = bio_to_mem(&sig, pkeyutl_config.keysize * 10, sigbio);
1.1 jsing 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 */
1.15 inoguchi 337: buf_inlen = bio_to_mem(&buf_in, pkeyutl_config.keysize * 10, in);
1.1 jsing 338: if (buf_inlen <= 0) {
339: BIO_printf(bio_err, "Error reading input Data\n");
340: exit(1);
341: }
1.15 inoguchi 342: if (pkeyutl_config.rev) {
1.1 jsing 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: }
1.15 inoguchi 353: if (pkeyutl_config.pkey_op == EVP_PKEY_OP_VERIFY) {
354: rv = EVP_PKEY_verify(pkeyutl_config.ctx, sig, (size_t) siglen,
1.1 jsing 355: buf_in, (size_t) buf_inlen);
1.5 bcook 356: if (rv == 1) {
357: BIO_puts(out, "Signature Verified Successfully\n");
358: ret = 0;
359: } else
1.1 jsing 360: BIO_puts(out, "Signature Verification Failure\n");
361: if (rv >= 0)
362: goto end;
363: } else {
1.15 inoguchi 364: rv = do_keyop(pkeyutl_config.ctx, pkeyutl_config.pkey_op, NULL,
365: (size_t *)&buf_outlen, buf_in, (size_t) buf_inlen);
1.1 jsing 366: if (rv > 0) {
367: buf_out = malloc(buf_outlen);
368: if (!buf_out)
369: rv = -1;
370: else
1.15 inoguchi 371: rv = do_keyop(pkeyutl_config.ctx,
372: pkeyutl_config.pkey_op,
1.1 jsing 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;
1.15 inoguchi 384: if (pkeyutl_config.asn1parse) {
1.1 jsing 385: if (!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1))
386: ERR_print_errors(bio_err);
1.15 inoguchi 387: } else if (pkeyutl_config.hexdump)
1.1 jsing 388: BIO_dump(out, (char *) buf_out, buf_outlen);
389: else
390: BIO_write(out, buf_out, buf_outlen);
391:
1.14 jsing 392: end:
1.15 inoguchi 393: EVP_PKEY_CTX_free(pkeyutl_config.ctx);
1.1 jsing 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:
1.15 inoguchi 403: static int
404: init_ctx(char *keyfile)
1.1 jsing 405: {
406: EVP_PKEY *pkey = NULL;
407: char *passin = NULL;
408: int rv = -1;
409: X509 *x;
1.15 inoguchi 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");
1.1 jsing 417: goto end;
418: }
1.15 inoguchi 419: if (!app_passwd(bio_err, pkeyutl_config.passargin, NULL, &passin,
420: NULL)) {
1.1 jsing 421: BIO_printf(bio_err, "Error getting password\n");
422: goto end;
423: }
1.15 inoguchi 424: switch (pkeyutl_config.key_type) {
1.1 jsing 425: case KEY_PRIVKEY:
1.15 inoguchi 426: pkey = load_key(bio_err, keyfile, pkeyutl_config.keyform, 0,
1.7 bcook 427: passin, "Private Key");
1.1 jsing 428: break;
429:
430: case KEY_PUBKEY:
1.15 inoguchi 431: pkey = load_pubkey(bio_err, keyfile, pkeyutl_config.keyform, 0,
1.7 bcook 432: NULL, "Public Key");
1.1 jsing 433: break;
434:
435: case KEY_CERT:
1.15 inoguchi 436: x = load_cert(bio_err, keyfile, pkeyutl_config.keyform,
1.7 bcook 437: NULL, "Certificate");
1.1 jsing 438: if (x) {
439: pkey = X509_get_pubkey(x);
440: X509_free(x);
441: }
442: break;
443: }
444:
1.15 inoguchi 445: pkeyutl_config.keysize = EVP_PKEY_size(pkey);
1.1 jsing 446:
447: if (!pkey)
448: goto end;
449:
1.15 inoguchi 450: pkeyutl_config.ctx = EVP_PKEY_CTX_new(pkey, NULL);
1.1 jsing 451:
452: EVP_PKEY_free(pkey);
453:
1.15 inoguchi 454: if (!pkeyutl_config.ctx)
1.1 jsing 455: goto end;
456:
1.15 inoguchi 457: switch (pkeyutl_config.pkey_op) {
1.1 jsing 458: case EVP_PKEY_OP_SIGN:
1.15 inoguchi 459: rv = EVP_PKEY_sign_init(pkeyutl_config.ctx);
1.1 jsing 460: break;
461:
462: case EVP_PKEY_OP_VERIFY:
1.15 inoguchi 463: rv = EVP_PKEY_verify_init(pkeyutl_config.ctx);
1.1 jsing 464: break;
465:
466: case EVP_PKEY_OP_VERIFYRECOVER:
1.15 inoguchi 467: rv = EVP_PKEY_verify_recover_init(pkeyutl_config.ctx);
1.1 jsing 468: break;
469:
470: case EVP_PKEY_OP_ENCRYPT:
1.15 inoguchi 471: rv = EVP_PKEY_encrypt_init(pkeyutl_config.ctx);
1.1 jsing 472: break;
473:
474: case EVP_PKEY_OP_DECRYPT:
1.15 inoguchi 475: rv = EVP_PKEY_decrypt_init(pkeyutl_config.ctx);
1.1 jsing 476: break;
477:
478: case EVP_PKEY_OP_DERIVE:
1.15 inoguchi 479: rv = EVP_PKEY_derive_init(pkeyutl_config.ctx);
1.1 jsing 480: break;
481: }
482:
483: if (rv <= 0) {
1.15 inoguchi 484: EVP_PKEY_CTX_free(pkeyutl_config.ctx);
485: pkeyutl_config.ctx = NULL;
1.1 jsing 486: }
1.15 inoguchi 487:
1.14 jsing 488: end:
1.1 jsing 489: free(passin);
490:
1.15 inoguchi 491: if (!pkeyutl_config.ctx) {
492: BIO_puts(bio_err, "Error initializing context\n");
493: ERR_print_errors(bio_err);
494: return (1);
495: }
1.1 jsing 496:
1.15 inoguchi 497: return (0);
1.1 jsing 498: }
499:
500: static int
1.15 inoguchi 501: setup_peer(char *file)
1.1 jsing 502: {
503: EVP_PKEY *peer = NULL;
504: int ret;
1.15 inoguchi 505:
506: if (!pkeyutl_config.ctx) {
507: BIO_puts(bio_err, "-peerkey command before -inkey\n");
508: return (1);
1.1 jsing 509: }
1.15 inoguchi 510: peer = load_pubkey(bio_err, file, pkeyutl_config.peerform, 0, NULL,
511: "Peer Key");
1.1 jsing 512:
513: if (!peer) {
514: BIO_printf(bio_err, "Error reading peer key %s\n", file);
1.15 inoguchi 515: ERR_print_errors(bio_err);
516: return (1);
1.1 jsing 517: }
1.15 inoguchi 518: ret = EVP_PKEY_derive_set_peer(pkeyutl_config.ctx, peer);
1.1 jsing 519:
520: EVP_PKEY_free(peer);
1.15 inoguchi 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);
1.1 jsing 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: }