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