a3e55f5a430fee256d178c763b8b113aaba13920
[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 int MAIN(int argc, char **);
83
84 int MAIN(int argc, char **argv)
85 {
86         BIO *in = NULL, *out = NULL;
87         char *infile = NULL, *outfile = NULL, *sigfile = NULL;
88         ENGINE *e = NULL;
89         int pkey_op = EVP_PKEY_OP_SIGN, key_type = KEY_PRIVKEY;
90         int keyform = FORMAT_PEM, peerform = FORMAT_PEM;
91         char badarg = 0, rev = 0;
92         char hexdump = 0, asn1parse = 0;
93         EVP_PKEY_CTX *ctx = NULL;
94         char *passargin = NULL;
95         int keysize = -1;
96
97         unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL;
98         int buf_inlen, buf_outlen, siglen = -1;
99
100         int ret = 1, rv = -1;
101
102         argc--;
103         argv++;
104
105         if(!bio_err) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
106
107         if (!load_config(bio_err, NULL))
108                 goto end;
109         ERR_load_crypto_strings();
110         OpenSSL_add_all_algorithms();
111         
112         while(argc >= 1)
113                 {
114                 if (!strcmp(*argv,"-in"))
115                         {
116                         if (--argc < 1) badarg = 1;
117                         infile= *(++argv);
118                         }
119                 else if (!strcmp(*argv,"-out"))
120                         {
121                         if (--argc < 1) badarg = 1;
122                         outfile= *(++argv);
123                         }
124                 else if (!strcmp(*argv,"-sigfile"))
125                         {
126                         if (--argc < 1) badarg = 1;
127                         sigfile= *(++argv);
128                         }
129                 else if(!strcmp(*argv, "-inkey"))
130                         {
131                         if (--argc < 1)
132                                 badarg = 1;
133                         else
134                                 {
135                                 ctx = init_ctx(&keysize,
136                                                 *(++argv), keyform, key_type,
137                                                 passargin, pkey_op, e);
138                                 if (!ctx)
139                                         {
140                                         BIO_puts(bio_err,
141                                                 "Error initializing context\n");
142                                         ERR_print_errors(bio_err);
143                                         badarg = 1;
144                                         }
145                                 }
146                         }
147                 else if (!strcmp(*argv,"-peerkey"))
148                         {
149                         if (--argc < 1)
150                                 badarg = 1;
151                         else if (!setup_peer(bio_err, ctx, peerform, *(++argv)))
152                                 badarg = 1;
153                         }
154                 else if (!strcmp(*argv,"-passin"))
155                         {
156                         if (--argc < 1) badarg = 1;
157                         passargin= *(++argv);
158                         }
159                 else if (strcmp(*argv,"-peerform") == 0)
160                         {
161                         if (--argc < 1) badarg = 1;
162                         peerform=str2fmt(*(++argv));
163                         }
164                 else if (strcmp(*argv,"-keyform") == 0)
165                         {
166                         if (--argc < 1) badarg = 1;
167                         keyform=str2fmt(*(++argv));
168                         }
169 #ifndef OPENSSL_NO_ENGINE
170                 else if(!strcmp(*argv, "-engine"))
171                         {
172                         if (--argc < 1)
173                                 badarg = 1;
174                         else
175                                 e = setup_engine(bio_err, *(++argv), 0);
176                         }
177 #endif
178                 else if(!strcmp(*argv, "-pubin"))
179                         key_type = KEY_PUBKEY;
180                 else if(!strcmp(*argv, "-certin"))
181                         key_type = KEY_CERT;
182                 else if(!strcmp(*argv, "-asn1parse"))
183                         asn1parse = 1;
184                 else if(!strcmp(*argv, "-hexdump"))
185                         hexdump = 1;
186                 else if(!strcmp(*argv, "-sign"))
187                         pkey_op = EVP_PKEY_OP_SIGN;
188                 else if(!strcmp(*argv, "-verify"))
189                         pkey_op = EVP_PKEY_OP_VERIFY;
190                 else if(!strcmp(*argv, "-verifyrecover"))
191                         pkey_op = EVP_PKEY_OP_VERIFYRECOVER;
192                 else if(!strcmp(*argv, "-rev"))
193                         rev = 1;
194                 else if(!strcmp(*argv, "-encrypt"))
195                         pkey_op = EVP_PKEY_OP_ENCRYPT;
196                 else if(!strcmp(*argv, "-decrypt"))
197                         pkey_op = EVP_PKEY_OP_DECRYPT;
198                 else if(!strcmp(*argv, "-derive"))
199                         pkey_op = EVP_PKEY_OP_DERIVE;
200                 else if (strcmp(*argv,"-pkeyopt") == 0)
201                         {
202                         if (--argc < 1)
203                                 badarg = 1;
204                         else if (!ctx)
205                                 {
206                                 BIO_puts(bio_err,
207                                         "-pkeyopt command before -inkey\n");
208                                 badarg = 1;
209                                 }
210                         else if (pkey_ctrl_string(ctx, *(++argv)) <= 0)
211                                 {
212                                 BIO_puts(bio_err, "parameter setting error\n");
213                                 ERR_print_errors(bio_err);
214                                 goto end;
215                                 }
216                         }
217                 else badarg = 1;
218                 if(badarg)
219                         {
220                         usage();
221                         goto end;
222                         }
223                 argc--;
224                 argv++;
225                 }
226
227         if (!ctx)
228                 {
229                 usage();
230                 goto end;
231                 }
232
233         if (sigfile && (pkey_op != EVP_PKEY_OP_VERIFY))
234                 {
235                 BIO_puts(bio_err, "Signature file specified for non verify\n");
236                 goto end;
237                 }
238
239         if (!sigfile && (pkey_op == EVP_PKEY_OP_VERIFY))
240                 {
241                 BIO_puts(bio_err, "No signature file specified for verify\n");
242                 goto end;
243                 }
244
245 /* FIXME: seed PRNG only if needed */
246         app_RAND_load_file(NULL, bio_err, 0);
247
248         if (pkey_op != EVP_PKEY_OP_DERIVE)
249                 {
250                 if(infile)
251                         {
252                         if(!(in = BIO_new_file(infile, "rb")))
253                                 {
254                                 BIO_puts(bio_err,
255                                         "Error Opening Input File\n");
256                                 ERR_print_errors(bio_err);      
257                                 goto end;
258                                 }
259                         }
260                 else
261                         in = BIO_new_fp(stdin, BIO_NOCLOSE);
262                 }
263
264         if(outfile)
265                 {
266                 if(!(out = BIO_new_file(outfile, "wb")))
267                         {
268                         BIO_printf(bio_err, "Error Creating Output File\n");
269                         ERR_print_errors(bio_err);      
270                         goto end;
271                         }
272                 }
273         else
274                 {
275                 out = BIO_new_fp(stdout, BIO_NOCLOSE);
276 #ifdef OPENSSL_SYS_VMS
277                 {
278                     BIO *tmpbio = BIO_new(BIO_f_linebuffer());
279                     out = BIO_push(tmpbio, out);
280                 }
281 #endif
282         }
283
284         if (sigfile)
285                 {
286                 BIO *sigbio = BIO_new_file(sigfile, "rb");
287                 if (!sigbio)
288                         {
289                         BIO_printf(bio_err, "Can't open signature file %s\n",
290                                                                 sigfile);
291                         goto end;
292                         }
293                 siglen = bio_to_mem(&sig, keysize * 10, sigbio);
294                 BIO_free(sigbio);
295                 if (siglen <= 0)
296                         {
297                         BIO_printf(bio_err, "Error reading signature data\n");
298                         goto end;
299                         }
300                 }
301         
302         buf_out = OPENSSL_malloc(keysize);
303
304         if (in)
305                 {
306                 /* Read the input data */
307                 buf_inlen = bio_to_mem(&buf_in, keysize * 10, in);
308                 if(buf_inlen <= 0)
309                         {
310                         BIO_printf(bio_err, "Error reading input Data\n");
311                         exit(1);
312                         }
313                 if(rev)
314                         {
315                         int i;
316                         unsigned char ctmp;
317                         for(i = 0; i < buf_inlen/2; i++)
318                                 {
319                                 ctmp = buf_in[i];
320                                 buf_in[i] = buf_in[buf_inlen - 1 - i];
321                                 buf_in[buf_inlen - 1 - i] = ctmp;
322                                 }
323                         }
324                 }
325
326         switch(pkey_op)
327                 {
328                 case EVP_PKEY_OP_VERIFYRECOVER:
329                 rv  = EVP_PKEY_verify_recover(ctx, buf_out, &buf_outlen,
330                                                         buf_in, buf_inlen);
331                 break;
332
333                 case EVP_PKEY_OP_SIGN:
334                 rv  = EVP_PKEY_sign(ctx, buf_out, &buf_outlen,
335                                                         buf_in, buf_inlen);
336                 break;
337
338                 case EVP_PKEY_OP_ENCRYPT:
339                 rv  = EVP_PKEY_encrypt(ctx, buf_out, &buf_outlen,
340                                                         buf_in, buf_inlen);
341                 break;
342
343                 case EVP_PKEY_OP_DECRYPT:
344                 rv  = EVP_PKEY_decrypt(ctx, buf_out, &buf_outlen,
345                                                         buf_in, buf_inlen);
346                 break; 
347
348                 case EVP_PKEY_OP_VERIFY:
349                 rv  = EVP_PKEY_verify(ctx, sig, siglen, buf_in, buf_inlen);
350                 if (rv == 0)
351                         BIO_puts(out, "Signature Verification Failure\n");
352                 else if (rv == 1)
353                         BIO_puts(out, "Signature Verified Successfully\n");
354                 if (rv >= 0)
355                         goto end;
356                 break; 
357
358                 case EVP_PKEY_OP_DERIVE:
359                 rv  = EVP_PKEY_derive(ctx, buf_out, &buf_outlen);
360                 break;
361
362                 }
363
364         if(rv <= 0)
365                 {
366                 BIO_printf(bio_err, "Public Key operation error\n");
367                 ERR_print_errors(bio_err);
368                 goto end;
369                 }
370         ret = 0;
371         if(asn1parse)
372                 {
373                 if(!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1))
374                         ERR_print_errors(bio_err);
375                 }
376         else if(hexdump)
377                 BIO_dump(out, (char *)buf_out, buf_outlen);
378         else
379                 BIO_write(out, buf_out, buf_outlen);
380
381         end:
382         if (ctx)
383                 EVP_PKEY_CTX_free(ctx);
384         BIO_free(in);
385         BIO_free_all(out);
386         if (buf_in)
387                 OPENSSL_free(buf_in);
388         if (buf_out)
389                 OPENSSL_free(buf_out);
390         if (sig)
391                 OPENSSL_free(sig);
392         return ret;
393 }
394
395 static void usage()
396 {
397         BIO_printf(bio_err, "Usage: pkeyutl [options]\n");
398         BIO_printf(bio_err, "-in file        input file\n");
399         BIO_printf(bio_err, "-out file       output file\n");
400         BIO_printf(bio_err, "-inkey file     input key\n");
401         BIO_printf(bio_err, "-keyform arg    private key format - default PEM\n");
402         BIO_printf(bio_err, "-pubin          input is an RSA public\n");
403         BIO_printf(bio_err, "-certin         input is a certificate carrying an RSA public key\n");
404         BIO_printf(bio_err, "-ctrl X:Y       control parameters\n");
405         BIO_printf(bio_err, "-sign           sign with private key\n");
406         BIO_printf(bio_err, "-verify         verify with public key\n");
407         BIO_printf(bio_err, "-encrypt        encrypt with public key\n");
408         BIO_printf(bio_err, "-decrypt        decrypt with private key\n");
409         BIO_printf(bio_err, "-hexdump        hex dump output\n");
410 #ifndef OPENSSL_NO_ENGINE
411         BIO_printf(bio_err, "-engine e       use engine e, possibly a hardware device.\n");
412         BIO_printf(bio_err, "-passin arg     pass phrase source\n");
413 #endif
414
415 }
416
417 static EVP_PKEY_CTX *init_ctx(int *pkeysize,
418                                 char *keyfile, int keyform, int key_type,
419                                 char *passargin, int pkey_op, ENGINE *e)
420         {
421         EVP_PKEY *pkey = NULL;
422         EVP_PKEY_CTX *ctx = NULL;
423         char *passin = NULL;
424         int rv = -1;
425         X509 *x;
426         if(((pkey_op == EVP_PKEY_OP_SIGN) || (pkey_op == EVP_PKEY_OP_DECRYPT) 
427                 || (pkey_op == EVP_PKEY_OP_DERIVE))
428                 && (key_type != KEY_PRIVKEY))
429                 {
430                 BIO_printf(bio_err, "A private key is needed for this operation\n");
431                 goto end;
432                 }
433         if(!app_passwd(bio_err, passargin, NULL, &passin, NULL))
434                 {
435                 BIO_printf(bio_err, "Error getting password\n");
436                 goto end;
437                 }
438         switch(key_type)
439                 {
440                 case KEY_PRIVKEY:
441                 pkey = load_key(bio_err, keyfile, keyform, 0,
442                         passin, e, "Private Key");
443                 break;
444
445                 case KEY_PUBKEY:
446                 pkey = load_pubkey(bio_err, keyfile, keyform, 0,
447                         NULL, e, "Public Key");
448                 break;
449
450                 case KEY_CERT:
451                 x = load_cert(bio_err, keyfile, keyform,
452                         NULL, e, "Certificate");
453                 if(x)
454                         {
455                         pkey = X509_get_pubkey(x);
456                         X509_free(x);
457                         }
458                 break;
459
460                 }
461
462         *pkeysize = EVP_PKEY_size(pkey);
463
464         if (!pkey)
465                 goto end;
466
467         ctx = EVP_PKEY_CTX_new(pkey, e);
468
469         EVP_PKEY_free(pkey);
470
471         if (!ctx)
472                 goto end;
473
474         switch(pkey_op)
475                 {
476                 case EVP_PKEY_OP_SIGN:
477                 rv = EVP_PKEY_sign_init(ctx);
478                 break;
479
480                 case EVP_PKEY_OP_VERIFY:
481                 rv = EVP_PKEY_verify_init(ctx);
482                 break;
483
484                 case EVP_PKEY_OP_VERIFYRECOVER:
485                 rv = EVP_PKEY_verify_recover_init(ctx);
486                 break;
487
488                 case EVP_PKEY_OP_ENCRYPT:
489                 rv = EVP_PKEY_encrypt_init(ctx);
490                 break;
491
492                 case EVP_PKEY_OP_DECRYPT:
493                 rv = EVP_PKEY_decrypt_init(ctx);
494                 break;
495
496                 case EVP_PKEY_OP_DERIVE:
497                 rv = EVP_PKEY_derive_init(ctx);
498                 break;
499                 }
500
501         if (rv <= 0)
502                 {
503                 EVP_PKEY_CTX_free(ctx);
504                 ctx = NULL;
505                 }
506
507         end:
508
509         if (passin)
510                 OPENSSL_free(passin);
511
512         return ctx;
513
514
515         }
516
517 static int setup_peer(BIO *err, EVP_PKEY_CTX *ctx, int peerform,
518                                                         const char *file)
519         {
520         EVP_PKEY *peer = NULL;
521         int ret;
522         if (!ctx)
523                 {
524                 BIO_puts(err, "-peerkey command before -inkey\n");
525                 return 0;
526                 }
527                 
528         peer = load_pubkey(bio_err, file, peerform, 0, NULL, NULL, "Peer Key");
529
530         if (!peer)
531                 {
532                 BIO_printf(bio_err, "Error reading peer key %s\n", file);
533                 ERR_print_errors(err);
534                 return 0;
535                 }
536
537         ret = EVP_PKEY_derive_set_peer(ctx, peer);
538
539         EVP_PKEY_free(peer);
540         if (ret <= 0)
541                 ERR_print_errors(err);
542         return ret;
543         }
544