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