1 /* $OpenBSD: pkeyutl.c,v 1.20 2023/07/23 11:39:29 tb 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 static 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 } cfg;
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 static const struct option pkeyutl_options[] = {
100 {
101 .name = "asn1parse",
102 .desc = "ASN.1 parse the output data",
103 .type = OPTION_FLAG,
104 .opt.flag = &cfg.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 = &cfg.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 = &cfg.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 = &cfg.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 = &cfg.pkey_op,
133 },
134 {
135 .name = "hexdump",
136 .desc = "Hex dump the output data",
137 .type = OPTION_FLAG,
138 .opt.flag = &cfg.hexdump,
139 },
140 {
141 .name = "in",
142 .argname = "file",
143 .desc = "Input file (default stdin)",
144 .type = OPTION_ARG,
145 .opt.arg = &cfg.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 = &cfg.keyform,
160 },
161 {
162 .name = "out",
163 .argname = "file",
164 .desc = "Output file (default stdout)",
165 .type = OPTION_ARG,
166 .opt.arg = &cfg.outfile,
167 },
168 {
169 .name = "passin",
170 .argname = "arg",
171 .desc = "Key password source",
172 .type = OPTION_ARG,
173 .opt.arg = &cfg.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 = &cfg.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 = &cfg.key_type,
202 },
203 {
204 .name = "rev",
205 .desc = "Reverse the input data",
206 .type = OPTION_FLAG,
207 .opt.flag = &cfg.rev,
208 },
209 {
210 .name = "sigfile",
211 .argname = "file",
212 .desc = "Signature file (verify operation only)",
213 .type = OPTION_ARG,
214 .opt.arg = &cfg.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 = &cfg.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 = &cfg.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 = &cfg.pkey_op,
236 },
237
238 {NULL},
239 };
240
241 static void
pkeyutl_usage(void)242 pkeyutl_usage(void)
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
pkeyutl_main(int argc,char ** argv)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 (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
267 perror("pledge");
268 exit(1);
269 }
270
271 memset(&cfg, 0, sizeof(cfg));
272 cfg.pkey_op = EVP_PKEY_OP_SIGN;
273 cfg.key_type = KEY_PRIVKEY;
274 cfg.keyform = FORMAT_PEM;
275 cfg.peerform = FORMAT_PEM;
276 cfg.keysize = -1;
277
278 if (options_parse(argc, argv, pkeyutl_options, NULL, NULL) != 0) {
279 pkeyutl_usage();
280 goto end;
281 }
282
283 if (!cfg.ctx) {
284 pkeyutl_usage();
285 goto end;
286 }
287 if (cfg.sigfile &&
288 (cfg.pkey_op != EVP_PKEY_OP_VERIFY)) {
289 BIO_puts(bio_err, "Signature file specified for non verify\n");
290 goto end;
291 }
292 if (!cfg.sigfile &&
293 (cfg.pkey_op == EVP_PKEY_OP_VERIFY)) {
294 BIO_puts(bio_err, "No signature file specified for verify\n");
295 goto end;
296 }
297
298 if (cfg.pkey_op != EVP_PKEY_OP_DERIVE) {
299 if (cfg.infile) {
300 if (!(in = BIO_new_file(cfg.infile, "rb"))) {
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 }
309 if (cfg.outfile) {
310 if (!(out = BIO_new_file(cfg.outfile, "wb"))) {
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
319 if (cfg.sigfile) {
320 BIO *sigbio = BIO_new_file(cfg.sigfile, "rb");
321 if (!sigbio) {
322 BIO_printf(bio_err, "Can't open signature file %s\n",
323 cfg.sigfile);
324 goto end;
325 }
326 siglen = bio_to_mem(&sig, cfg.keysize * 10, sigbio);
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 */
335 buf_inlen = bio_to_mem(&buf_in, cfg.keysize * 10, in);
336 if (buf_inlen <= 0) {
337 BIO_printf(bio_err, "Error reading input Data\n");
338 exit(1);
339 }
340 if (cfg.rev) {
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 }
351 if (cfg.pkey_op == EVP_PKEY_OP_VERIFY) {
352 rv = EVP_PKEY_verify(cfg.ctx, sig, (size_t) siglen,
353 buf_in, (size_t) buf_inlen);
354 if (rv == 1) {
355 BIO_puts(out, "Signature Verified Successfully\n");
356 ret = 0;
357 } else
358 BIO_puts(out, "Signature Verification Failure\n");
359 if (rv >= 0)
360 goto end;
361 } else {
362 rv = do_keyop(cfg.ctx, cfg.pkey_op, NULL,
363 (size_t *)&buf_outlen, buf_in, (size_t) buf_inlen);
364 if (rv > 0) {
365 buf_out = malloc(buf_outlen);
366 if (!buf_out)
367 rv = -1;
368 else
369 rv = do_keyop(cfg.ctx,
370 cfg.pkey_op,
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;
382 if (cfg.asn1parse) {
383 if (!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1))
384 ERR_print_errors(bio_err);
385 } else if (cfg.hexdump)
386 BIO_dump(out, (char *) buf_out, buf_outlen);
387 else
388 BIO_write(out, buf_out, buf_outlen);
389
390 end:
391 EVP_PKEY_CTX_free(cfg.ctx);
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
401 static int
init_ctx(char * keyfile)402 init_ctx(char *keyfile)
403 {
404 EVP_PKEY *pkey = NULL;
405 char *passin = NULL;
406 int rv = -1;
407 X509 *x;
408
409 if (((cfg.pkey_op == EVP_PKEY_OP_SIGN)
410 || (cfg.pkey_op == EVP_PKEY_OP_DECRYPT)
411 || (cfg.pkey_op == EVP_PKEY_OP_DERIVE))
412 && (cfg.key_type != KEY_PRIVKEY)) {
413 BIO_printf(bio_err,
414 "A private key is needed for this operation\n");
415 goto end;
416 }
417 if (!app_passwd(bio_err, cfg.passargin, NULL, &passin,
418 NULL)) {
419 BIO_printf(bio_err, "Error getting password\n");
420 goto end;
421 }
422 switch (cfg.key_type) {
423 case KEY_PRIVKEY:
424 pkey = load_key(bio_err, keyfile, cfg.keyform, 0,
425 passin, "Private Key");
426 break;
427
428 case KEY_PUBKEY:
429 pkey = load_pubkey(bio_err, keyfile, cfg.keyform, 0,
430 NULL, "Public Key");
431 break;
432
433 case KEY_CERT:
434 x = load_cert(bio_err, keyfile, cfg.keyform,
435 NULL, "Certificate");
436 if (x) {
437 pkey = X509_get_pubkey(x);
438 X509_free(x);
439 }
440 break;
441 }
442
443 cfg.keysize = EVP_PKEY_size(pkey);
444
445 if (!pkey)
446 goto end;
447
448 cfg.ctx = EVP_PKEY_CTX_new(pkey, NULL);
449
450 EVP_PKEY_free(pkey);
451
452 if (!cfg.ctx)
453 goto end;
454
455 switch (cfg.pkey_op) {
456 case EVP_PKEY_OP_SIGN:
457 rv = EVP_PKEY_sign_init(cfg.ctx);
458 break;
459
460 case EVP_PKEY_OP_VERIFY:
461 rv = EVP_PKEY_verify_init(cfg.ctx);
462 break;
463
464 case EVP_PKEY_OP_VERIFYRECOVER:
465 rv = EVP_PKEY_verify_recover_init(cfg.ctx);
466 break;
467
468 case EVP_PKEY_OP_ENCRYPT:
469 rv = EVP_PKEY_encrypt_init(cfg.ctx);
470 break;
471
472 case EVP_PKEY_OP_DECRYPT:
473 rv = EVP_PKEY_decrypt_init(cfg.ctx);
474 break;
475
476 case EVP_PKEY_OP_DERIVE:
477 rv = EVP_PKEY_derive_init(cfg.ctx);
478 break;
479 }
480
481 if (rv <= 0) {
482 EVP_PKEY_CTX_free(cfg.ctx);
483 cfg.ctx = NULL;
484 }
485
486 end:
487 free(passin);
488
489 if (!cfg.ctx) {
490 BIO_puts(bio_err, "Error initializing context\n");
491 ERR_print_errors(bio_err);
492 return (1);
493 }
494
495 return (0);
496 }
497
498 static int
setup_peer(char * file)499 setup_peer(char *file)
500 {
501 EVP_PKEY *peer = NULL;
502 int ret;
503
504 if (!cfg.ctx) {
505 BIO_puts(bio_err, "-peerkey command before -inkey\n");
506 return (1);
507 }
508 peer = load_pubkey(bio_err, file, cfg.peerform, 0, NULL,
509 "Peer Key");
510
511 if (!peer) {
512 BIO_printf(bio_err, "Error reading peer key %s\n", file);
513 ERR_print_errors(bio_err);
514 return (1);
515 }
516 ret = EVP_PKEY_derive_set_peer(cfg.ctx, peer);
517
518 EVP_PKEY_free(peer);
519 if (ret <= 0) {
520 ERR_print_errors(bio_err);
521 return (1);
522 }
523
524 return (0);
525 }
526
527 static int
pkeyutl_pkeyopt(char * pkeyopt)528 pkeyutl_pkeyopt(char *pkeyopt)
529 {
530 if (!cfg.ctx) {
531 BIO_puts(bio_err, "-pkeyopt command before -inkey\n");
532 return (1);
533 } else if (pkey_ctrl_string(cfg.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);
540 }
541
542 static int
do_keyop(EVP_PKEY_CTX * ctx,int pkey_op,unsigned char * out,size_t * poutlen,unsigned char * in,size_t inlen)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 }
572