Implement encrypt/decrypt using RSA.
[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, char *engine);
78
79 int MAIN(int argc, char **);
80
81 int MAIN(int argc, char **argv)
82 {
83         BIO *in = NULL, *out = NULL;
84         char *infile = NULL, *outfile = NULL;
85         char *engine = NULL;
86         int pkey_op = EVP_PKEY_OP_SIGN, key_type = KEY_PRIVKEY;
87         int keyform = FORMAT_PEM;
88         char badarg = 0, rev = 0;
89         char hexdump = 0, asn1parse = 0;
90         EVP_PKEY_CTX *ctx = NULL;
91         char *passargin = NULL;
92         int keysize;
93
94         unsigned char *buf_in = NULL, *buf_out = NULL;
95         int buf_inlen, buf_outlen;
96
97         int ret = 1, rv;
98
99         argc--;
100         argv++;
101
102         if(!bio_err) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
103
104         if (!load_config(bio_err, NULL))
105                 goto end;
106         ERR_load_crypto_strings();
107         OpenSSL_add_all_algorithms();
108         
109         while(argc >= 1)
110                 {
111                 if (!strcmp(*argv,"-in"))
112                         {
113                         if (--argc < 1) badarg = 1;
114                         infile= *(++argv);
115                         }
116                 else if (!strcmp(*argv,"-out"))
117                         {
118                         if (--argc < 1) badarg = 1;
119                         outfile= *(++argv);
120                         }
121                 else if(!strcmp(*argv, "-inkey"))
122                         {
123                         if (--argc < 1)
124                                 badarg = 1;
125                         else
126                                 {
127                                 ctx = init_ctx(&keysize,
128                                                 *(++argv), keyform, key_type,
129                                                 passargin, pkey_op, engine);
130                                 if (!ctx)
131                                         {
132                                         BIO_puts(bio_err,
133                                                 "Error initializing context\n");
134                                         ERR_print_errors(bio_err);
135                                         badarg = 1;
136                                         }
137                                 }
138                         }
139                 else if (!strcmp(*argv,"-passin"))
140                         {
141                         if (--argc < 1) badarg = 1;
142                         passargin= *(++argv);
143                         }
144                 else if (strcmp(*argv,"-keyform") == 0)
145                         {
146                         if (--argc < 1) badarg = 1;
147                         keyform=str2fmt(*(++argv));
148                         }
149 #ifndef OPENSSL_NO_ENGINE
150                 else if(!strcmp(*argv, "-engine"))
151                         {
152                         if (--argc < 1) badarg = 1;
153                         engine = *(++argv);
154                         }
155 #endif
156                 else if(!strcmp(*argv, "-pubin"))
157                         key_type = KEY_PUBKEY;
158                 else if(!strcmp(*argv, "-certin"))
159                         key_type = KEY_CERT;
160                 else if(!strcmp(*argv, "-asn1parse"))
161                         asn1parse = 1;
162                 else if(!strcmp(*argv, "-hexdump"))
163                         hexdump = 1;
164                 else if(!strcmp(*argv, "-sign"))
165                         pkey_op = EVP_PKEY_OP_SIGN;
166                 else if(!strcmp(*argv, "-verifyrecover"))
167                         pkey_op = EVP_PKEY_OP_VERIFYRECOVER;
168                 else if(!strcmp(*argv, "-rev"))
169                         rev = 1;
170                 else if(!strcmp(*argv, "-encrypt"))
171                         pkey_op = EVP_PKEY_OP_ENCRYPT;
172                 else if(!strcmp(*argv, "-decrypt"))
173                         pkey_op = EVP_PKEY_OP_DECRYPT;
174                 else badarg = 1;
175                 if(badarg)
176                         {
177                         usage();
178                         goto end;
179                         }
180                 argc--;
181                 argv++;
182                 }
183
184         if (!ctx)
185                 {
186                 usage();
187                 goto end;
188                 }
189
190 /* FIXME: seed PRNG only if needed */
191         app_RAND_load_file(NULL, bio_err, 0);
192
193         if(infile) {
194                 if(!(in = BIO_new_file(infile, "rb"))) {
195                         BIO_printf(bio_err, "Error Reading Input File\n");
196                         ERR_print_errors(bio_err);      
197                         goto end;
198                 }
199         } else in = BIO_new_fp(stdin, BIO_NOCLOSE);
200
201         if(outfile) {
202                 if(!(out = BIO_new_file(outfile, "wb"))) {
203                         BIO_printf(bio_err, "Error Reading Output File\n");
204                         ERR_print_errors(bio_err);      
205                         goto end;
206                 }
207         } else {
208                 out = BIO_new_fp(stdout, BIO_NOCLOSE);
209 #ifdef OPENSSL_SYS_VMS
210                 {
211                     BIO *tmpbio = BIO_new(BIO_f_linebuffer());
212                     out = BIO_push(tmpbio, out);
213                 }
214 #endif
215         }
216
217         buf_in = OPENSSL_malloc(keysize * 2);
218         buf_out = OPENSSL_malloc(keysize);
219
220         /* Read the input data */
221         buf_inlen = BIO_read(in, buf_in, keysize * 2);
222         if(buf_inlen <= 0) {
223                 BIO_printf(bio_err, "Error reading input Data\n");
224                 exit(1);
225         }
226         if(rev) {
227                 int i;
228                 unsigned char ctmp;
229                 for(i = 0; i < buf_inlen/2; i++) {
230                         ctmp = buf_in[i];
231                         buf_in[i] = buf_in[buf_inlen - 1 - i];
232                         buf_in[buf_inlen - 1 - i] = ctmp;
233                 }
234         }
235         switch(pkey_op)
236                 {
237                 case EVP_PKEY_OP_VERIFYRECOVER:
238                 rv  = EVP_PKEY_verify_recover(ctx, buf_out, &buf_outlen,
239                                                         buf_in, buf_inlen);
240                 break;
241
242                 case EVP_PKEY_OP_SIGN:
243                 rv  = EVP_PKEY_sign(ctx, buf_out, &buf_outlen,
244                                                         buf_in, buf_inlen);
245                 break;
246
247                 case EVP_PKEY_OP_ENCRYPT:
248                 rv  = EVP_PKEY_encrypt(ctx, buf_out, &buf_outlen,
249                                                         buf_in, buf_inlen);
250                 break;
251
252                 case EVP_PKEY_OP_DECRYPT:
253                 rv  = EVP_PKEY_decrypt(ctx, buf_out, &buf_outlen,
254                                                         buf_in, buf_inlen);
255                 break;
256
257                 }
258
259         if(rv <= 0) {
260                 BIO_printf(bio_err, "Public Key operation error\n");
261                 ERR_print_errors(bio_err);
262                 goto end;
263         }
264         ret = 0;
265         if(asn1parse) {
266                 if(!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1)) {
267                         ERR_print_errors(bio_err);
268                 }
269         } else if(hexdump) BIO_dump(out, (char *)buf_out, buf_outlen);
270         else BIO_write(out, buf_out, buf_outlen);
271
272         end:
273         if (ctx)
274                 EVP_PKEY_CTX_free(ctx);
275         BIO_free(in);
276         BIO_free_all(out);
277         if(buf_in) OPENSSL_free(buf_in);
278         if(buf_out) OPENSSL_free(buf_out);
279         return ret;
280 }
281
282 static void usage()
283 {
284         BIO_printf(bio_err, "Usage: pkeyutl [options]\n");
285         BIO_printf(bio_err, "-in file        input file\n");
286         BIO_printf(bio_err, "-out file       output file\n");
287         BIO_printf(bio_err, "-inkey file     input key\n");
288         BIO_printf(bio_err, "-keyform arg    private key format - default PEM\n");
289         BIO_printf(bio_err, "-pubin          input is an RSA public\n");
290         BIO_printf(bio_err, "-certin         input is a certificate carrying an RSA public key\n");
291         BIO_printf(bio_err, "-ctrl X:Y       control parameters\n");
292         BIO_printf(bio_err, "-sign           sign with private key\n");
293         BIO_printf(bio_err, "-verify         verify with public key\n");
294         BIO_printf(bio_err, "-encrypt        encrypt with public key\n");
295         BIO_printf(bio_err, "-decrypt        decrypt with private key\n");
296         BIO_printf(bio_err, "-hexdump        hex dump output\n");
297 #ifndef OPENSSL_NO_ENGINE
298         BIO_printf(bio_err, "-engine e       use engine e, possibly a hardware device.\n");
299         BIO_printf(bio_err, "-passin arg     pass phrase source\n");
300 #endif
301
302 }
303
304 static EVP_PKEY_CTX *init_ctx(int *pkeysize,
305                                 char *keyfile, int keyform, int key_type,
306                                 char *passargin, int pkey_op, char *engine)
307         {
308         ENGINE *e = NULL;
309         EVP_PKEY *pkey = NULL;
310         EVP_PKEY_CTX *ctx = NULL;
311         char *passin = NULL;
312         int rv;
313         X509 *x;
314         if(((pkey_op == EVP_PKEY_OP_SIGN) || (pkey_op == EVP_PKEY_OP_DECRYPT))
315                 && (key_type != KEY_PRIVKEY))
316                 {
317                 BIO_printf(bio_err, "A private key is needed for this operation\n");
318                 goto end;
319                 }
320         if(!app_passwd(bio_err, passargin, NULL, &passin, NULL))
321                 {
322                 BIO_printf(bio_err, "Error getting password\n");
323                 goto end;
324                 }
325         switch(key_type)
326                 {
327                 case KEY_PRIVKEY:
328                 pkey = load_key(bio_err, keyfile, keyform, 0,
329                         passin, e, "Private Key");
330                 break;
331
332                 case KEY_PUBKEY:
333                 pkey = load_pubkey(bio_err, keyfile, keyform, 0,
334                         NULL, e, "Public Key");
335                 break;
336
337                 case KEY_CERT:
338                 x = load_cert(bio_err, keyfile, keyform,
339                         NULL, e, "Certificate");
340                 if(x)
341                         {
342                         pkey = X509_get_pubkey(x);
343                         X509_free(x);
344                         }
345                 break;
346
347                 }
348
349         *pkeysize = EVP_PKEY_size(pkey);
350
351         if (!pkey)
352                 goto end;
353
354         ctx = EVP_PKEY_CTX_new(pkey);
355
356         EVP_PKEY_free(pkey);
357
358         if (!ctx)
359                 goto end;
360
361         switch(pkey_op)
362                 {
363                 case EVP_PKEY_OP_SIGN:
364                 rv = EVP_PKEY_sign_init(ctx);
365                 break;
366
367                 case EVP_PKEY_OP_VERIFY:
368                 rv = EVP_PKEY_verify_init(ctx);
369                 break;
370
371                 case EVP_PKEY_OP_VERIFYRECOVER:
372                 rv = EVP_PKEY_verify_recover_init(ctx);
373                 break;
374
375                 case EVP_PKEY_OP_ENCRYPT:
376                 rv = EVP_PKEY_encrypt_init(ctx);
377                 break;
378
379                 case EVP_PKEY_OP_DECRYPT:
380                 rv = EVP_PKEY_decrypt_init(ctx);
381                 break;
382                 }
383
384         if (rv <= 0)
385                 {
386                 EVP_PKEY_CTX_free(ctx);
387                 ctx = NULL;
388                 }
389
390         end:
391
392         if (passin)
393                 OPENSSL_free(passin);
394
395         return ctx;
396
397
398         }
399