1 /* $OpenBSD: pkeyutl.c,v 1.17 2022/11/11 17:07:39 joshua 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 (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 267 perror("pledge"); 268 exit(1); 269 } 270 271 memset(&pkeyutl_config, 0, sizeof(pkeyutl_config)); 272 pkeyutl_config.pkey_op = EVP_PKEY_OP_SIGN; 273 pkeyutl_config.key_type = KEY_PRIVKEY; 274 pkeyutl_config.keyform = FORMAT_PEM; 275 pkeyutl_config.peerform = FORMAT_PEM; 276 pkeyutl_config.keysize = -1; 277 278 if (options_parse(argc, argv, pkeyutl_options, NULL, NULL) != 0) { 279 pkeyutl_usage(); 280 goto end; 281 } 282 283 if (!pkeyutl_config.ctx) { 284 pkeyutl_usage(); 285 goto end; 286 } 287 if (pkeyutl_config.sigfile && 288 (pkeyutl_config.pkey_op != EVP_PKEY_OP_VERIFY)) { 289 BIO_puts(bio_err, "Signature file specified for non verify\n"); 290 goto end; 291 } 292 if (!pkeyutl_config.sigfile && 293 (pkeyutl_config.pkey_op == EVP_PKEY_OP_VERIFY)) { 294 BIO_puts(bio_err, "No signature file specified for verify\n"); 295 goto end; 296 } 297 298 if (pkeyutl_config.pkey_op != EVP_PKEY_OP_DERIVE) { 299 if (pkeyutl_config.infile) { 300 if (!(in = BIO_new_file(pkeyutl_config.infile, "rb"))) { 301 BIO_puts(bio_err, 302 "Error Opening Input File\n"); 303 ERR_print_errors(bio_err); 304 goto end; 305 } 306 } else 307 in = BIO_new_fp(stdin, BIO_NOCLOSE); 308 } 309 if (pkeyutl_config.outfile) { 310 if (!(out = BIO_new_file(pkeyutl_config.outfile, "wb"))) { 311 BIO_printf(bio_err, "Error Creating Output File\n"); 312 ERR_print_errors(bio_err); 313 goto end; 314 } 315 } else { 316 out = BIO_new_fp(stdout, BIO_NOCLOSE); 317 } 318 319 if (pkeyutl_config.sigfile) { 320 BIO *sigbio = BIO_new_file(pkeyutl_config.sigfile, "rb"); 321 if (!sigbio) { 322 BIO_printf(bio_err, "Can't open signature file %s\n", 323 pkeyutl_config.sigfile); 324 goto end; 325 } 326 siglen = bio_to_mem(&sig, pkeyutl_config.keysize * 10, sigbio); 327 BIO_free(sigbio); 328 if (siglen <= 0) { 329 BIO_printf(bio_err, "Error reading signature data\n"); 330 goto end; 331 } 332 } 333 if (in) { 334 /* Read the input data */ 335 buf_inlen = bio_to_mem(&buf_in, pkeyutl_config.keysize * 10, in); 336 if (buf_inlen <= 0) { 337 BIO_printf(bio_err, "Error reading input Data\n"); 338 exit(1); 339 } 340 if (pkeyutl_config.rev) { 341 size_t i; 342 unsigned char ctmp; 343 size_t l = (size_t) buf_inlen; 344 for (i = 0; i < l / 2; i++) { 345 ctmp = buf_in[i]; 346 buf_in[i] = buf_in[l - 1 - i]; 347 buf_in[l - 1 - i] = ctmp; 348 } 349 } 350 } 351 if (pkeyutl_config.pkey_op == EVP_PKEY_OP_VERIFY) { 352 rv = EVP_PKEY_verify(pkeyutl_config.ctx, sig, (size_t) siglen, 353 buf_in, (size_t) buf_inlen); 354 if (rv == 1) { 355 BIO_puts(out, "Signature Verified Successfully\n"); 356 ret = 0; 357 } else 358 BIO_puts(out, "Signature Verification Failure\n"); 359 if (rv >= 0) 360 goto end; 361 } else { 362 rv = do_keyop(pkeyutl_config.ctx, pkeyutl_config.pkey_op, NULL, 363 (size_t *)&buf_outlen, buf_in, (size_t) buf_inlen); 364 if (rv > 0) { 365 buf_out = malloc(buf_outlen); 366 if (!buf_out) 367 rv = -1; 368 else 369 rv = do_keyop(pkeyutl_config.ctx, 370 pkeyutl_config.pkey_op, 371 buf_out, (size_t *) & buf_outlen, 372 buf_in, (size_t) buf_inlen); 373 } 374 } 375 376 if (rv <= 0) { 377 BIO_printf(bio_err, "Public Key operation error\n"); 378 ERR_print_errors(bio_err); 379 goto end; 380 } 381 ret = 0; 382 if (pkeyutl_config.asn1parse) { 383 if (!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1)) 384 ERR_print_errors(bio_err); 385 } else if (pkeyutl_config.hexdump) 386 BIO_dump(out, (char *) buf_out, buf_outlen); 387 else 388 BIO_write(out, buf_out, buf_outlen); 389 390 end: 391 EVP_PKEY_CTX_free(pkeyutl_config.ctx); 392 BIO_free(in); 393 BIO_free_all(out); 394 free(buf_in); 395 free(buf_out); 396 free(sig); 397 398 return ret; 399 } 400 401 static int 402 init_ctx(char *keyfile) 403 { 404 EVP_PKEY *pkey = NULL; 405 char *passin = NULL; 406 int rv = -1; 407 X509 *x; 408 409 if (((pkeyutl_config.pkey_op == EVP_PKEY_OP_SIGN) 410 || (pkeyutl_config.pkey_op == EVP_PKEY_OP_DECRYPT) 411 || (pkeyutl_config.pkey_op == EVP_PKEY_OP_DERIVE)) 412 && (pkeyutl_config.key_type != KEY_PRIVKEY)) { 413 BIO_printf(bio_err, 414 "A private key is needed for this operation\n"); 415 goto end; 416 } 417 if (!app_passwd(bio_err, pkeyutl_config.passargin, NULL, &passin, 418 NULL)) { 419 BIO_printf(bio_err, "Error getting password\n"); 420 goto end; 421 } 422 switch (pkeyutl_config.key_type) { 423 case KEY_PRIVKEY: 424 pkey = load_key(bio_err, keyfile, pkeyutl_config.keyform, 0, 425 passin, "Private Key"); 426 break; 427 428 case KEY_PUBKEY: 429 pkey = load_pubkey(bio_err, keyfile, pkeyutl_config.keyform, 0, 430 NULL, "Public Key"); 431 break; 432 433 case KEY_CERT: 434 x = load_cert(bio_err, keyfile, pkeyutl_config.keyform, 435 NULL, "Certificate"); 436 if (x) { 437 pkey = X509_get_pubkey(x); 438 X509_free(x); 439 } 440 break; 441 } 442 443 pkeyutl_config.keysize = EVP_PKEY_size(pkey); 444 445 if (!pkey) 446 goto end; 447 448 pkeyutl_config.ctx = EVP_PKEY_CTX_new(pkey, NULL); 449 450 EVP_PKEY_free(pkey); 451 452 if (!pkeyutl_config.ctx) 453 goto end; 454 455 switch (pkeyutl_config.pkey_op) { 456 case EVP_PKEY_OP_SIGN: 457 rv = EVP_PKEY_sign_init(pkeyutl_config.ctx); 458 break; 459 460 case EVP_PKEY_OP_VERIFY: 461 rv = EVP_PKEY_verify_init(pkeyutl_config.ctx); 462 break; 463 464 case EVP_PKEY_OP_VERIFYRECOVER: 465 rv = EVP_PKEY_verify_recover_init(pkeyutl_config.ctx); 466 break; 467 468 case EVP_PKEY_OP_ENCRYPT: 469 rv = EVP_PKEY_encrypt_init(pkeyutl_config.ctx); 470 break; 471 472 case EVP_PKEY_OP_DECRYPT: 473 rv = EVP_PKEY_decrypt_init(pkeyutl_config.ctx); 474 break; 475 476 case EVP_PKEY_OP_DERIVE: 477 rv = EVP_PKEY_derive_init(pkeyutl_config.ctx); 478 break; 479 } 480 481 if (rv <= 0) { 482 EVP_PKEY_CTX_free(pkeyutl_config.ctx); 483 pkeyutl_config.ctx = NULL; 484 } 485 486 end: 487 free(passin); 488 489 if (!pkeyutl_config.ctx) { 490 BIO_puts(bio_err, "Error initializing context\n"); 491 ERR_print_errors(bio_err); 492 return (1); 493 } 494 495 return (0); 496 } 497 498 static int 499 setup_peer(char *file) 500 { 501 EVP_PKEY *peer = NULL; 502 int ret; 503 504 if (!pkeyutl_config.ctx) { 505 BIO_puts(bio_err, "-peerkey command before -inkey\n"); 506 return (1); 507 } 508 peer = load_pubkey(bio_err, file, pkeyutl_config.peerform, 0, NULL, 509 "Peer Key"); 510 511 if (!peer) { 512 BIO_printf(bio_err, "Error reading peer key %s\n", file); 513 ERR_print_errors(bio_err); 514 return (1); 515 } 516 ret = EVP_PKEY_derive_set_peer(pkeyutl_config.ctx, peer); 517 518 EVP_PKEY_free(peer); 519 if (ret <= 0) { 520 ERR_print_errors(bio_err); 521 return (1); 522 } 523 524 return (0); 525 } 526 527 static int 528 pkeyutl_pkeyopt(char *pkeyopt) 529 { 530 if (!pkeyutl_config.ctx) { 531 BIO_puts(bio_err, "-pkeyopt command before -inkey\n"); 532 return (1); 533 } else if (pkey_ctrl_string(pkeyutl_config.ctx, pkeyopt) <= 0) { 534 BIO_puts(bio_err, "parameter setting error\n"); 535 ERR_print_errors(bio_err); 536 return (1); 537 } 538 539 return (0); 540 } 541 542 static int 543 do_keyop(EVP_PKEY_CTX * ctx, int pkey_op, 544 unsigned char *out, size_t * poutlen, 545 unsigned char *in, size_t inlen) 546 { 547 int rv = 0; 548 switch (pkey_op) { 549 case EVP_PKEY_OP_VERIFYRECOVER: 550 rv = EVP_PKEY_verify_recover(ctx, out, poutlen, in, inlen); 551 break; 552 553 case EVP_PKEY_OP_SIGN: 554 rv = EVP_PKEY_sign(ctx, out, poutlen, in, inlen); 555 break; 556 557 case EVP_PKEY_OP_ENCRYPT: 558 rv = EVP_PKEY_encrypt(ctx, out, poutlen, in, inlen); 559 break; 560 561 case EVP_PKEY_OP_DECRYPT: 562 rv = EVP_PKEY_decrypt(ctx, out, poutlen, in, inlen); 563 break; 564 565 case EVP_PKEY_OP_DERIVE: 566 rv = EVP_PKEY_derive(ctx, out, poutlen); 567 break; 568 569 } 570 return rv; 571 } 572