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