Add prototypes and pkey accessor function for EVP_PKEY_CTX.
[openssl.git] / apps / pkeyutl.c
1 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
2  * project 2006.
3  */
4 /* ====================================================================
5  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer. 
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. All advertising materials mentioning features or use of this
20  *    software must display the following acknowledgment:
21  *    "This product includes software developed by the OpenSSL Project
22  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23  *
24  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25  *    endorse or promote products derived from this software without
26  *    prior written permission. For written permission, please contact
27  *    licensing@OpenSSL.org.
28  *
29  * 5. Products derived from this software may not be called "OpenSSL"
30  *    nor may "OpenSSL" appear in their names without prior written
31  *    permission of the OpenSSL Project.
32  *
33  * 6. Redistributions of any form whatsoever must retain the following
34  *    acknowledgment:
35  *    "This product includes software developed by the OpenSSL Project
36  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49  * OF THE POSSIBILITY OF SUCH DAMAGE.
50  * ====================================================================
51  *
52  * This product includes cryptographic software written by Eric Young
53  * (eay@cryptsoft.com).  This product includes software written by Tim
54  * Hudson (tjh@cryptsoft.com).
55  *
56  */
57
58
59 #include "apps.h"
60 #include <string.h>
61 #include <openssl/err.h>
62 #include <openssl/pem.h>
63 #include <openssl/evp.h>
64
65 #define KEY_PRIVKEY     1
66 #define KEY_PUBKEY      2
67 #define KEY_CERT        3
68
69 static void usage(void);
70
71 #undef PROG
72
73 #define PROG pkeyutl_main
74
75 static EVP_PKEY_CTX *init_ctx(int *pkeysize,
76                                 char *keyfile, int keyform, int key_type,
77                                 char *passargin, int pkey_op, ENGINE *e);
78
79 static int setup_peer(BIO *err, EVP_PKEY_CTX *ctx, int peerform,
80                                                         const char *file);
81
82 static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op,
83                 unsigned char *out, int *poutlen,
84                 unsigned char *in, int inlen);
85
86 int MAIN(int argc, char **);
87
88 int MAIN(int argc, char **argv)
89 {
90         BIO *in = NULL, *out = NULL;
91         char *infile = NULL, *outfile = NULL, *sigfile = NULL;
92         ENGINE *e = NULL;
93         int pkey_op = EVP_PKEY_OP_SIGN, key_type = KEY_PRIVKEY;
94         int keyform = FORMAT_PEM, peerform = FORMAT_PEM;
95         char badarg = 0, rev = 0;
96         char hexdump = 0, asn1parse = 0;
97         EVP_PKEY_CTX *ctx = NULL;
98         char *passargin = NULL;
99         int keysize = -1;
100
101         unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL;
102         int buf_inlen, buf_outlen, siglen = -1;
103
104         int ret = 1, rv = -1;
105
106         argc--;
107         argv++;
108
109         if(!bio_err) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
110
111         if (!load_config(bio_err, NULL))
112                 goto end;
113         ERR_load_crypto_strings();
114         OpenSSL_add_all_algorithms();
115         
116         while(argc >= 1)
117                 {
118                 if (!strcmp(*argv,"-in"))
119                         {
120                         if (--argc < 1) badarg = 1;
121                         infile= *(++argv);
122                         }
123                 else if (!strcmp(*argv,"-out"))
124                         {
125                         if (--argc < 1) badarg = 1;
126                         outfile= *(++argv);
127                         }
128                 else if (!strcmp(*argv,"-sigfile"))
129                         {
130                         if (--argc < 1) badarg = 1;
131                         sigfile= *(++argv);
132                         }
133                 else if(!strcmp(*argv, "-inkey"))
134                         {
135                         if (--argc < 1)
136                                 badarg = 1;
137                         else
138                                 {
139                                 ctx = init_ctx(&keysize,
140                                                 *(++argv), keyform, key_type,
141                                                 passargin, pkey_op, e);
142                                 if (!ctx)
143                                         {
144                                         BIO_puts(bio_err,
145                                                 "Error initializing context\n");
146                                         ERR_print_errors(bio_err);
147                                         badarg = 1;
148                                         }
149                                 }
150                         }
151                 else if (!strcmp(*argv,"-peerkey"))
152                         {
153                         if (--argc < 1)
154                                 badarg = 1;
155                         else if (!setup_peer(bio_err, ctx, peerform, *(++argv)))
156                                 badarg = 1;
157                         }
158                 else if (!strcmp(*argv,"-passin"))
159                         {
160                         if (--argc < 1) badarg = 1;
161                         passargin= *(++argv);
162                         }
163                 else if (strcmp(*argv,"-peerform") == 0)
164                         {
165                         if (--argc < 1) badarg = 1;
166                         peerform=str2fmt(*(++argv));
167                         }
168                 else if (strcmp(*argv,"-keyform") == 0)
169                         {
170                         if (--argc < 1) badarg = 1;
171                         keyform=str2fmt(*(++argv));
172                         }
173 #ifndef OPENSSL_NO_ENGINE
174                 else if(!strcmp(*argv, "-engine"))
175                         {
176                         if (--argc < 1)
177                                 badarg = 1;
178                         else
179                                 e = setup_engine(bio_err, *(++argv), 0);
180                         }
181 #endif
182                 else if(!strcmp(*argv, "-pubin"))
183                         key_type = KEY_PUBKEY;
184                 else if(!strcmp(*argv, "-certin"))
185                         key_type = KEY_CERT;
186                 else if(!strcmp(*argv, "-asn1parse"))
187                         asn1parse = 1;
188                 else if(!strcmp(*argv, "-hexdump"))
189                         hexdump = 1;
190                 else if(!strcmp(*argv, "-sign"))
191                         pkey_op = EVP_PKEY_OP_SIGN;
192                 else if(!strcmp(*argv, "-verify"))
193                         pkey_op = EVP_PKEY_OP_VERIFY;
194                 else if(!strcmp(*argv, "-verifyrecover"))
195                         pkey_op = EVP_PKEY_OP_VERIFYRECOVER;
196                 else if(!strcmp(*argv, "-rev"))
197                         rev = 1;
198                 else if(!strcmp(*argv, "-encrypt"))
199                         pkey_op = EVP_PKEY_OP_ENCRYPT;
200                 else if(!strcmp(*argv, "-decrypt"))
201                         pkey_op = EVP_PKEY_OP_DECRYPT;
202                 else if(!strcmp(*argv, "-derive"))
203                         pkey_op = EVP_PKEY_OP_DERIVE;
204                 else if (strcmp(*argv,"-pkeyopt") == 0)
205                         {
206                         if (--argc < 1)
207                                 badarg = 1;
208                         else if (!ctx)
209                                 {
210                                 BIO_puts(bio_err,
211                                         "-pkeyopt command before -inkey\n");
212                                 badarg = 1;
213                                 }
214                         else if (pkey_ctrl_string(ctx, *(++argv)) <= 0)
215                                 {
216                                 BIO_puts(bio_err, "parameter setting error\n");
217                                 ERR_print_errors(bio_err);
218                                 goto end;
219                                 }
220                         }
221                 else badarg = 1;
222                 if(badarg)
223                         {
224                         usage();
225                         goto end;
226                         }
227                 argc--;
228                 argv++;
229                 }
230
231         if (!ctx)
232                 {
233                 usage();
234                 goto end;
235                 }
236
237         if (sigfile && (pkey_op != EVP_PKEY_OP_VERIFY))
238                 {
239                 BIO_puts(bio_err, "Signature file specified for non verify\n");
240                 goto end;
241                 }
242
243         if (!sigfile && (pkey_op == EVP_PKEY_OP_VERIFY))
244                 {
245                 BIO_puts(bio_err, "No signature file specified for verify\n");
246                 goto end;
247                 }
248
249 /* FIXME: seed PRNG only if needed */
250         app_RAND_load_file(NULL, bio_err, 0);
251
252         if (pkey_op != EVP_PKEY_OP_DERIVE)
253                 {
254                 if(infile)
255                         {
256                         if(!(in = BIO_new_file(infile, "rb")))
257                                 {
258                                 BIO_puts(bio_err,
259                                         "Error Opening Input File\n");
260                                 ERR_print_errors(bio_err);      
261                                 goto end;
262                                 }
263                         }
264                 else
265                         in = BIO_new_fp(stdin, BIO_NOCLOSE);
266                 }
267
268         if(outfile)
269                 {
270                 if(!(out = BIO_new_file(outfile, "wb")))
271                         {
272                         BIO_printf(bio_err, "Error Creating Output File\n");
273                         ERR_print_errors(bio_err);      
274                         goto end;
275                         }
276                 }
277         else
278                 {
279                 out = BIO_new_fp(stdout, BIO_NOCLOSE);
280 #ifdef OPENSSL_SYS_VMS
281                 {
282                     BIO *tmpbio = BIO_new(BIO_f_linebuffer());
283                     out = BIO_push(tmpbio, out);
284                 }
285 #endif
286         }
287
288         if (sigfile)
289                 {
290                 BIO *sigbio = BIO_new_file(sigfile, "rb");
291                 if (!sigbio)
292                         {
293                         BIO_printf(bio_err, "Can't open signature file %s\n",
294                                                                 sigfile);
295                         goto end;
296                         }
297                 siglen = bio_to_mem(&sig, keysize * 10, sigbio);
298                 BIO_free(sigbio);
299                 if (siglen <= 0)
300                         {
301                         BIO_printf(bio_err, "Error reading signature data\n");
302                         goto end;
303                         }
304                 }
305         
306         if (in)
307                 {
308                 /* Read the input data */
309                 buf_inlen = bio_to_mem(&buf_in, keysize * 10, in);
310                 if(buf_inlen <= 0)
311                         {
312                         BIO_printf(bio_err, "Error reading input Data\n");
313                         exit(1);
314                         }
315                 if(rev)
316                         {
317                         int i;
318                         unsigned char ctmp;
319                         for(i = 0; i < buf_inlen/2; i++)
320                                 {
321                                 ctmp = buf_in[i];
322                                 buf_in[i] = buf_in[buf_inlen - 1 - i];
323                                 buf_in[buf_inlen - 1 - i] = ctmp;
324                                 }
325                         }
326                 }
327
328         if(pkey_op == EVP_PKEY_OP_VERIFY)
329                 {
330                 rv  = EVP_PKEY_verify(ctx, sig, siglen, buf_in, buf_inlen);
331                 if (rv == 0)
332                         BIO_puts(out, "Signature Verification Failure\n");
333                 else if (rv == 1)
334                         BIO_puts(out, "Signature Verified Successfully\n");
335                 if (rv >= 0)
336                         goto end;
337                 }
338         else
339                 {       
340                 rv = do_keyop(ctx, pkey_op, NULL, &buf_outlen,
341                                                         buf_in, buf_inlen);
342                 if (rv > 0)
343                         {
344                         buf_out = OPENSSL_malloc(buf_outlen);
345                         if (!buf_out)
346                                 rv = -1;
347                         else
348                                 rv = do_keyop(ctx, pkey_op,
349                                                 buf_out, &buf_outlen,
350                                                 buf_in, buf_inlen);
351                         }
352                 }
353
354         if(rv <= 0)
355                 {
356                 BIO_printf(bio_err, "Public Key operation error\n");
357                 ERR_print_errors(bio_err);
358                 goto end;
359                 }
360         ret = 0;
361         if(asn1parse)
362                 {
363                 if(!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1))
364                         ERR_print_errors(bio_err);
365                 }
366         else if(hexdump)
367                 BIO_dump(out, (char *)buf_out, buf_outlen);
368         else
369                 BIO_write(out, buf_out, buf_outlen);
370
371         end:
372         if (ctx)
373                 EVP_PKEY_CTX_free(ctx);
374         BIO_free(in);
375         BIO_free_all(out);
376         if (buf_in)
377                 OPENSSL_free(buf_in);
378         if (buf_out)
379                 OPENSSL_free(buf_out);
380         if (sig)
381                 OPENSSL_free(sig);
382         return ret;
383 }
384
385 static void usage()
386 {
387         BIO_printf(bio_err, "Usage: pkeyutl [options]\n");
388         BIO_printf(bio_err, "-in file        input file\n");
389         BIO_printf(bio_err, "-out file       output file\n");
390         BIO_printf(bio_err, "-inkey file     input key\n");
391         BIO_printf(bio_err, "-keyform arg    private key format - default PEM\n");
392         BIO_printf(bio_err, "-pubin          input is an RSA public\n");
393         BIO_printf(bio_err, "-certin         input is a certificate carrying an RSA public key\n");
394         BIO_printf(bio_err, "-ctrl X:Y       control parameters\n");
395         BIO_printf(bio_err, "-sign           sign with private key\n");
396         BIO_printf(bio_err, "-verify         verify with public key\n");
397         BIO_printf(bio_err, "-encrypt        encrypt with public key\n");
398         BIO_printf(bio_err, "-decrypt        decrypt with private key\n");
399         BIO_printf(bio_err, "-hexdump        hex dump output\n");
400 #ifndef OPENSSL_NO_ENGINE
401         BIO_printf(bio_err, "-engine e       use engine e, possibly a hardware device.\n");
402         BIO_printf(bio_err, "-passin arg     pass phrase source\n");
403 #endif
404
405 }
406
407 static EVP_PKEY_CTX *init_ctx(int *pkeysize,
408                                 char *keyfile, int keyform, int key_type,
409                                 char *passargin, int pkey_op, ENGINE *e)
410         {
411         EVP_PKEY *pkey = NULL;
412         EVP_PKEY_CTX *ctx = NULL;
413         char *passin = NULL;
414         int rv = -1;
415         X509 *x;
416         if(((pkey_op == EVP_PKEY_OP_SIGN) || (pkey_op == EVP_PKEY_OP_DECRYPT) 
417                 || (pkey_op == EVP_PKEY_OP_DERIVE))
418                 && (key_type != KEY_PRIVKEY))
419                 {
420                 BIO_printf(bio_err, "A private key is needed for this operation\n");
421                 goto end;
422                 }
423         if(!app_passwd(bio_err, passargin, NULL, &passin, NULL))
424                 {
425                 BIO_printf(bio_err, "Error getting password\n");
426                 goto end;
427                 }
428         switch(key_type)
429                 {
430                 case KEY_PRIVKEY:
431                 pkey = load_key(bio_err, keyfile, keyform, 0,
432                         passin, e, "Private Key");
433                 break;
434
435                 case KEY_PUBKEY:
436                 pkey = load_pubkey(bio_err, keyfile, keyform, 0,
437                         NULL, e, "Public Key");
438                 break;
439
440                 case KEY_CERT:
441                 x = load_cert(bio_err, keyfile, keyform,
442                         NULL, e, "Certificate");
443                 if(x)
444                         {
445                         pkey = X509_get_pubkey(x);
446                         X509_free(x);
447                         }
448                 break;
449
450                 }
451
452         *pkeysize = EVP_PKEY_size(pkey);
453
454         if (!pkey)
455                 goto end;
456
457         ctx = EVP_PKEY_CTX_new(pkey, e);
458
459         EVP_PKEY_free(pkey);
460
461         if (!ctx)
462                 goto end;
463
464         switch(pkey_op)
465                 {
466                 case EVP_PKEY_OP_SIGN:
467                 rv = EVP_PKEY_sign_init(ctx);
468                 break;
469
470                 case EVP_PKEY_OP_VERIFY:
471                 rv = EVP_PKEY_verify_init(ctx);
472                 break;
473
474                 case EVP_PKEY_OP_VERIFYRECOVER:
475                 rv = EVP_PKEY_verify_recover_init(ctx);
476                 break;
477
478                 case EVP_PKEY_OP_ENCRYPT:
479                 rv = EVP_PKEY_encrypt_init(ctx);
480                 break;
481
482                 case EVP_PKEY_OP_DECRYPT:
483                 rv = EVP_PKEY_decrypt_init(ctx);
484                 break;
485
486                 case EVP_PKEY_OP_DERIVE:
487                 rv = EVP_PKEY_derive_init(ctx);
488                 break;
489                 }
490
491         if (rv <= 0)
492                 {
493                 EVP_PKEY_CTX_free(ctx);
494                 ctx = NULL;
495                 }
496
497         end:
498
499         if (passin)
500                 OPENSSL_free(passin);
501
502         return ctx;
503
504
505         }
506
507 static int setup_peer(BIO *err, EVP_PKEY_CTX *ctx, int peerform,
508                                                         const char *file)
509         {
510         EVP_PKEY *peer = NULL;
511         int ret;
512         if (!ctx)
513                 {
514                 BIO_puts(err, "-peerkey command before -inkey\n");
515                 return 0;
516                 }
517                 
518         peer = load_pubkey(bio_err, file, peerform, 0, NULL, NULL, "Peer Key");
519
520         if (!peer)
521                 {
522                 BIO_printf(bio_err, "Error reading peer key %s\n", file);
523                 ERR_print_errors(err);
524                 return 0;
525                 }
526
527         ret = EVP_PKEY_derive_set_peer(ctx, peer);
528
529         EVP_PKEY_free(peer);
530         if (ret <= 0)
531                 ERR_print_errors(err);
532         return ret;
533         }
534
535 static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op,
536                 unsigned char *out, int *poutlen,
537                 unsigned char *in, int inlen)
538         {
539         int rv;
540         switch(pkey_op)
541                 {
542                 case EVP_PKEY_OP_VERIFYRECOVER:
543                 rv  = EVP_PKEY_verify_recover(ctx, out, poutlen, in, inlen);
544                 break;
545
546                 case EVP_PKEY_OP_SIGN:
547                 rv  = EVP_PKEY_sign(ctx, out, poutlen, in, inlen);
548                 break;
549
550                 case EVP_PKEY_OP_ENCRYPT:
551                 rv  = EVP_PKEY_encrypt(ctx, out, poutlen, in, inlen);
552                 break;
553
554                 case EVP_PKEY_OP_DECRYPT:
555                 rv  = EVP_PKEY_decrypt(ctx, out, poutlen, in, inlen);
556                 break; 
557
558                 case EVP_PKEY_OP_DERIVE:
559                 rv  = EVP_PKEY_derive(ctx, out, poutlen);
560                 break;
561
562                 }
563         return rv;
564         }