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