Annotation of src/usr.bin/openssl/pkeyutl.c, Revision 1.17
1.17 ! joshua 1: /* $OpenBSD: pkeyutl.c,v 1.16 2019/07/14 03:30:46 guenther 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:
1.17 ! joshua 266: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
! 267: perror("pledge");
! 268: exit(1);
1.8 doug 269: }
1.1 jsing 270:
1.15 inoguchi 271: memset(&pkeyutl_config, 0, sizeof(pkeyutl_config));
272: pkeyutl_config.pkey_op = EVP_PKEY_OP_SIGN;
273: pkeyutl_config.key_type = KEY_PRIVKEY;
274: pkeyutl_config.keyform = FORMAT_PEM;
275: pkeyutl_config.peerform = FORMAT_PEM;
276: pkeyutl_config.keysize = -1;
1.1 jsing 277:
1.15 inoguchi 278: if (options_parse(argc, argv, pkeyutl_options, NULL, NULL) != 0) {
279: pkeyutl_usage();
280: goto end;
1.1 jsing 281: }
282:
1.15 inoguchi 283: if (!pkeyutl_config.ctx) {
284: pkeyutl_usage();
1.1 jsing 285: goto end;
286: }
1.15 inoguchi 287: if (pkeyutl_config.sigfile &&
288: (pkeyutl_config.pkey_op != EVP_PKEY_OP_VERIFY)) {
1.1 jsing 289: BIO_puts(bio_err, "Signature file specified for non verify\n");
290: goto end;
291: }
1.15 inoguchi 292: if (!pkeyutl_config.sigfile &&
293: (pkeyutl_config.pkey_op == EVP_PKEY_OP_VERIFY)) {
1.1 jsing 294: BIO_puts(bio_err, "No signature file specified for verify\n");
295: goto end;
296: }
297:
1.15 inoguchi 298: if (pkeyutl_config.pkey_op != EVP_PKEY_OP_DERIVE) {
299: if (pkeyutl_config.infile) {
300: if (!(in = BIO_new_file(pkeyutl_config.infile, "rb"))) {
1.1 jsing 301: BIO_puts(bio_err,
302: "Error Opening Input File\n");
303: ERR_print_errors(bio_err);
304: goto end;
305: }
306: } else
307: in = BIO_new_fp(stdin, BIO_NOCLOSE);
308: }
1.15 inoguchi 309: if (pkeyutl_config.outfile) {
310: if (!(out = BIO_new_file(pkeyutl_config.outfile, "wb"))) {
1.1 jsing 311: BIO_printf(bio_err, "Error Creating Output File\n");
312: ERR_print_errors(bio_err);
313: goto end;
314: }
315: } else {
316: out = BIO_new_fp(stdout, BIO_NOCLOSE);
317: }
318:
1.15 inoguchi 319: if (pkeyutl_config.sigfile) {
320: BIO *sigbio = BIO_new_file(pkeyutl_config.sigfile, "rb");
1.1 jsing 321: if (!sigbio) {
322: BIO_printf(bio_err, "Can't open signature file %s\n",
1.15 inoguchi 323: pkeyutl_config.sigfile);
1.1 jsing 324: goto end;
325: }
1.15 inoguchi 326: siglen = bio_to_mem(&sig, pkeyutl_config.keysize * 10, sigbio);
1.1 jsing 327: BIO_free(sigbio);
328: if (siglen <= 0) {
329: BIO_printf(bio_err, "Error reading signature data\n");
330: goto end;
331: }
332: }
333: if (in) {
334: /* Read the input data */
1.15 inoguchi 335: buf_inlen = bio_to_mem(&buf_in, pkeyutl_config.keysize * 10, in);
1.1 jsing 336: if (buf_inlen <= 0) {
337: BIO_printf(bio_err, "Error reading input Data\n");
338: exit(1);
339: }
1.15 inoguchi 340: if (pkeyutl_config.rev) {
1.1 jsing 341: size_t i;
342: unsigned char ctmp;
343: size_t l = (size_t) buf_inlen;
344: for (i = 0; i < l / 2; i++) {
345: ctmp = buf_in[i];
346: buf_in[i] = buf_in[l - 1 - i];
347: buf_in[l - 1 - i] = ctmp;
348: }
349: }
350: }
1.15 inoguchi 351: if (pkeyutl_config.pkey_op == EVP_PKEY_OP_VERIFY) {
352: rv = EVP_PKEY_verify(pkeyutl_config.ctx, sig, (size_t) siglen,
1.1 jsing 353: buf_in, (size_t) buf_inlen);
1.5 bcook 354: if (rv == 1) {
355: BIO_puts(out, "Signature Verified Successfully\n");
356: ret = 0;
357: } else
1.1 jsing 358: BIO_puts(out, "Signature Verification Failure\n");
359: if (rv >= 0)
360: goto end;
361: } else {
1.15 inoguchi 362: rv = do_keyop(pkeyutl_config.ctx, pkeyutl_config.pkey_op, NULL,
363: (size_t *)&buf_outlen, buf_in, (size_t) buf_inlen);
1.1 jsing 364: if (rv > 0) {
365: buf_out = malloc(buf_outlen);
366: if (!buf_out)
367: rv = -1;
368: else
1.15 inoguchi 369: rv = do_keyop(pkeyutl_config.ctx,
370: pkeyutl_config.pkey_op,
1.1 jsing 371: buf_out, (size_t *) & buf_outlen,
372: buf_in, (size_t) buf_inlen);
373: }
374: }
375:
376: if (rv <= 0) {
377: BIO_printf(bio_err, "Public Key operation error\n");
378: ERR_print_errors(bio_err);
379: goto end;
380: }
381: ret = 0;
1.15 inoguchi 382: if (pkeyutl_config.asn1parse) {
1.1 jsing 383: if (!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1))
384: ERR_print_errors(bio_err);
1.15 inoguchi 385: } else if (pkeyutl_config.hexdump)
1.1 jsing 386: BIO_dump(out, (char *) buf_out, buf_outlen);
387: else
388: BIO_write(out, buf_out, buf_outlen);
389:
1.14 jsing 390: end:
1.15 inoguchi 391: EVP_PKEY_CTX_free(pkeyutl_config.ctx);
1.1 jsing 392: BIO_free(in);
393: BIO_free_all(out);
394: free(buf_in);
395: free(buf_out);
396: free(sig);
397:
398: return ret;
399: }
400:
1.15 inoguchi 401: static int
402: init_ctx(char *keyfile)
1.1 jsing 403: {
404: EVP_PKEY *pkey = NULL;
405: char *passin = NULL;
406: int rv = -1;
407: X509 *x;
1.15 inoguchi 408:
409: if (((pkeyutl_config.pkey_op == EVP_PKEY_OP_SIGN)
410: || (pkeyutl_config.pkey_op == EVP_PKEY_OP_DECRYPT)
411: || (pkeyutl_config.pkey_op == EVP_PKEY_OP_DERIVE))
412: && (pkeyutl_config.key_type != KEY_PRIVKEY)) {
413: BIO_printf(bio_err,
414: "A private key is needed for this operation\n");
1.1 jsing 415: goto end;
416: }
1.15 inoguchi 417: if (!app_passwd(bio_err, pkeyutl_config.passargin, NULL, &passin,
418: NULL)) {
1.1 jsing 419: BIO_printf(bio_err, "Error getting password\n");
420: goto end;
421: }
1.15 inoguchi 422: switch (pkeyutl_config.key_type) {
1.1 jsing 423: case KEY_PRIVKEY:
1.15 inoguchi 424: pkey = load_key(bio_err, keyfile, pkeyutl_config.keyform, 0,
1.7 bcook 425: passin, "Private Key");
1.1 jsing 426: break;
427:
428: case KEY_PUBKEY:
1.15 inoguchi 429: pkey = load_pubkey(bio_err, keyfile, pkeyutl_config.keyform, 0,
1.7 bcook 430: NULL, "Public Key");
1.1 jsing 431: break;
432:
433: case KEY_CERT:
1.15 inoguchi 434: x = load_cert(bio_err, keyfile, pkeyutl_config.keyform,
1.7 bcook 435: NULL, "Certificate");
1.1 jsing 436: if (x) {
437: pkey = X509_get_pubkey(x);
438: X509_free(x);
439: }
440: break;
441: }
442:
1.15 inoguchi 443: pkeyutl_config.keysize = EVP_PKEY_size(pkey);
1.1 jsing 444:
445: if (!pkey)
446: goto end;
447:
1.15 inoguchi 448: pkeyutl_config.ctx = EVP_PKEY_CTX_new(pkey, NULL);
1.1 jsing 449:
450: EVP_PKEY_free(pkey);
451:
1.15 inoguchi 452: if (!pkeyutl_config.ctx)
1.1 jsing 453: goto end;
454:
1.15 inoguchi 455: switch (pkeyutl_config.pkey_op) {
1.1 jsing 456: case EVP_PKEY_OP_SIGN:
1.15 inoguchi 457: rv = EVP_PKEY_sign_init(pkeyutl_config.ctx);
1.1 jsing 458: break;
459:
460: case EVP_PKEY_OP_VERIFY:
1.15 inoguchi 461: rv = EVP_PKEY_verify_init(pkeyutl_config.ctx);
1.1 jsing 462: break;
463:
464: case EVP_PKEY_OP_VERIFYRECOVER:
1.15 inoguchi 465: rv = EVP_PKEY_verify_recover_init(pkeyutl_config.ctx);
1.1 jsing 466: break;
467:
468: case EVP_PKEY_OP_ENCRYPT:
1.15 inoguchi 469: rv = EVP_PKEY_encrypt_init(pkeyutl_config.ctx);
1.1 jsing 470: break;
471:
472: case EVP_PKEY_OP_DECRYPT:
1.15 inoguchi 473: rv = EVP_PKEY_decrypt_init(pkeyutl_config.ctx);
1.1 jsing 474: break;
475:
476: case EVP_PKEY_OP_DERIVE:
1.15 inoguchi 477: rv = EVP_PKEY_derive_init(pkeyutl_config.ctx);
1.1 jsing 478: break;
479: }
480:
481: if (rv <= 0) {
1.15 inoguchi 482: EVP_PKEY_CTX_free(pkeyutl_config.ctx);
483: pkeyutl_config.ctx = NULL;
1.1 jsing 484: }
1.15 inoguchi 485:
1.14 jsing 486: end:
1.1 jsing 487: free(passin);
488:
1.15 inoguchi 489: if (!pkeyutl_config.ctx) {
490: BIO_puts(bio_err, "Error initializing context\n");
491: ERR_print_errors(bio_err);
492: return (1);
493: }
1.1 jsing 494:
1.15 inoguchi 495: return (0);
1.1 jsing 496: }
497:
498: static int
1.15 inoguchi 499: setup_peer(char *file)
1.1 jsing 500: {
501: EVP_PKEY *peer = NULL;
502: int ret;
1.15 inoguchi 503:
504: if (!pkeyutl_config.ctx) {
505: BIO_puts(bio_err, "-peerkey command before -inkey\n");
506: return (1);
1.1 jsing 507: }
1.15 inoguchi 508: peer = load_pubkey(bio_err, file, pkeyutl_config.peerform, 0, NULL,
509: "Peer Key");
1.1 jsing 510:
511: if (!peer) {
512: BIO_printf(bio_err, "Error reading peer key %s\n", file);
1.15 inoguchi 513: ERR_print_errors(bio_err);
514: return (1);
1.1 jsing 515: }
1.15 inoguchi 516: ret = EVP_PKEY_derive_set_peer(pkeyutl_config.ctx, peer);
1.1 jsing 517:
518: EVP_PKEY_free(peer);
1.15 inoguchi 519: if (ret <= 0) {
520: ERR_print_errors(bio_err);
521: return (1);
522: }
523:
524: return (0);
525: }
526:
527: static int
528: pkeyutl_pkeyopt(char *pkeyopt)
529: {
530: if (!pkeyutl_config.ctx) {
531: BIO_puts(bio_err, "-pkeyopt command before -inkey\n");
532: return (1);
533: } else if (pkey_ctrl_string(pkeyutl_config.ctx, pkeyopt) <= 0) {
534: BIO_puts(bio_err, "parameter setting error\n");
535: ERR_print_errors(bio_err);
536: return (1);
537: }
538:
539: return (0);
1.1 jsing 540: }
541:
542: static int
543: do_keyop(EVP_PKEY_CTX * ctx, int pkey_op,
544: unsigned char *out, size_t * poutlen,
545: unsigned char *in, size_t inlen)
546: {
547: int rv = 0;
548: switch (pkey_op) {
549: case EVP_PKEY_OP_VERIFYRECOVER:
550: rv = EVP_PKEY_verify_recover(ctx, out, poutlen, in, inlen);
551: break;
552:
553: case EVP_PKEY_OP_SIGN:
554: rv = EVP_PKEY_sign(ctx, out, poutlen, in, inlen);
555: break;
556:
557: case EVP_PKEY_OP_ENCRYPT:
558: rv = EVP_PKEY_encrypt(ctx, out, poutlen, in, inlen);
559: break;
560:
561: case EVP_PKEY_OP_DECRYPT:
562: rv = EVP_PKEY_decrypt(ctx, out, poutlen, in, inlen);
563: break;
564:
565: case EVP_PKEY_OP_DERIVE:
566: rv = EVP_PKEY_derive(ctx, out, poutlen);
567: break;
568:
569: }
570: return rv;
571: }