1 /* $OpenBSD: pk7_smime.c,v 1.23 2021/11/01 20:53:08 tb Exp $ */ 2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 * project. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 1999-2004 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 /* Simple PKCS#7 processing functions */ 60 61 #include <stdio.h> 62 63 #include <openssl/err.h> 64 #include <openssl/x509.h> 65 #include <openssl/x509v3.h> 66 67 #include "x509_lcl.h" 68 69 static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si); 70 71 PKCS7 * 72 PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, BIO *data, 73 int flags) 74 { 75 PKCS7 *p7; 76 int i; 77 78 if (!(p7 = PKCS7_new())) { 79 PKCS7error(ERR_R_MALLOC_FAILURE); 80 return NULL; 81 } 82 83 if (!PKCS7_set_type(p7, NID_pkcs7_signed)) 84 goto err; 85 86 if (!PKCS7_content_new(p7, NID_pkcs7_data)) 87 goto err; 88 89 if (pkey && !PKCS7_sign_add_signer(p7, signcert, pkey, NULL, flags)) { 90 PKCS7error(PKCS7_R_PKCS7_ADD_SIGNER_ERROR); 91 goto err; 92 } 93 94 if (!(flags & PKCS7_NOCERTS)) { 95 for (i = 0; i < sk_X509_num(certs); i++) { 96 if (!PKCS7_add_certificate(p7, sk_X509_value(certs, i))) 97 goto err; 98 } 99 } 100 101 if (flags & PKCS7_DETACHED) 102 PKCS7_set_detached(p7, 1); 103 104 if (flags & (PKCS7_STREAM|PKCS7_PARTIAL)) 105 return p7; 106 107 if (PKCS7_final(p7, data, flags)) 108 return p7; 109 110 err: 111 PKCS7_free(p7); 112 return NULL; 113 } 114 115 int 116 PKCS7_final(PKCS7 *p7, BIO *data, int flags) 117 { 118 BIO *p7bio; 119 int ret = 0; 120 121 if (!(p7bio = PKCS7_dataInit(p7, NULL))) { 122 PKCS7error(ERR_R_MALLOC_FAILURE); 123 return 0; 124 } 125 126 SMIME_crlf_copy(data, p7bio, flags); 127 128 (void)BIO_flush(p7bio); 129 130 if (!PKCS7_dataFinal(p7, p7bio)) { 131 PKCS7error(PKCS7_R_PKCS7_DATASIGN); 132 goto err; 133 } 134 135 ret = 1; 136 137 err: 138 BIO_free_all(p7bio); 139 140 return ret; 141 } 142 143 /* Check to see if a cipher exists and if so add S/MIME capabilities */ 144 145 static int 146 add_cipher_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg) 147 { 148 if (EVP_get_cipherbynid(nid)) 149 return PKCS7_simple_smimecap(sk, nid, arg); 150 return 1; 151 } 152 153 static int 154 add_digest_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg) 155 { 156 if (EVP_get_digestbynid(nid)) 157 return PKCS7_simple_smimecap(sk, nid, arg); 158 return 1; 159 } 160 161 PKCS7_SIGNER_INFO * 162 PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert, EVP_PKEY *pkey, 163 const EVP_MD *md, int flags) 164 { 165 PKCS7_SIGNER_INFO *si = NULL; 166 STACK_OF(X509_ALGOR) *smcap = NULL; 167 168 if (!X509_check_private_key(signcert, pkey)) { 169 PKCS7error(PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); 170 return NULL; 171 } 172 173 if (!(si = PKCS7_add_signature(p7, signcert, pkey, md))) { 174 PKCS7error(PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR); 175 return NULL; 176 } 177 178 if (!(flags & PKCS7_NOCERTS)) { 179 if (!PKCS7_add_certificate(p7, signcert)) 180 goto err; 181 } 182 183 if (!(flags & PKCS7_NOATTR)) { 184 if (!PKCS7_add_attrib_content_type(si, NULL)) 185 goto err; 186 /* Add SMIMECapabilities */ 187 if (!(flags & PKCS7_NOSMIMECAP)) { 188 if (!(smcap = sk_X509_ALGOR_new_null())) { 189 PKCS7error(ERR_R_MALLOC_FAILURE); 190 goto err; 191 } 192 if (!add_cipher_smcap(smcap, NID_aes_256_cbc, -1) || 193 !add_digest_smcap(smcap, NID_id_GostR3411_94, -1) || 194 !add_digest_smcap(smcap, NID_id_tc26_gost3411_2012_256, -1) || 195 !add_digest_smcap(smcap, NID_id_tc26_gost3411_2012_512, -1) || 196 !add_cipher_smcap(smcap, NID_id_Gost28147_89, -1) || 197 !add_cipher_smcap(smcap, NID_aes_192_cbc, -1) || 198 !add_cipher_smcap(smcap, NID_aes_128_cbc, -1) || 199 !add_cipher_smcap(smcap, NID_des_ede3_cbc, -1) || 200 !add_cipher_smcap(smcap, NID_rc2_cbc, 128) || 201 !add_cipher_smcap(smcap, NID_rc2_cbc, 64) || 202 !add_cipher_smcap(smcap, NID_des_cbc, -1) || 203 !add_cipher_smcap(smcap, NID_rc2_cbc, 40) || 204 !PKCS7_add_attrib_smimecap(si, smcap)) 205 goto err; 206 sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); 207 smcap = NULL; 208 } 209 if (flags & PKCS7_REUSE_DIGEST) { 210 if (!pkcs7_copy_existing_digest(p7, si)) 211 goto err; 212 if (!(flags & PKCS7_PARTIAL) && 213 !PKCS7_SIGNER_INFO_sign(si)) 214 goto err; 215 } 216 } 217 return si; 218 219 err: 220 if (smcap) 221 sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); 222 return NULL; 223 } 224 225 /* Search for a digest matching SignerInfo digest type and if found 226 * copy across. 227 */ 228 229 static int 230 pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si) 231 { 232 int i; 233 STACK_OF(PKCS7_SIGNER_INFO) *sinfos; 234 PKCS7_SIGNER_INFO *sitmp; 235 ASN1_OCTET_STRING *osdig = NULL; 236 237 sinfos = PKCS7_get_signer_info(p7); 238 for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { 239 sitmp = sk_PKCS7_SIGNER_INFO_value(sinfos, i); 240 if (si == sitmp) 241 break; 242 if (sk_X509_ATTRIBUTE_num(sitmp->auth_attr) <= 0) 243 continue; 244 if (!OBJ_cmp(si->digest_alg->algorithm, 245 sitmp->digest_alg->algorithm)) { 246 osdig = PKCS7_digest_from_attributes(sitmp->auth_attr); 247 break; 248 } 249 250 } 251 252 if (osdig) 253 return PKCS7_add1_attrib_digest(si, osdig->data, osdig->length); 254 255 PKCS7error(PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND); 256 return 0; 257 } 258 259 int 260 PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, BIO *indata, 261 BIO *out, int flags) 262 { 263 STACK_OF(X509) *signers; 264 X509 *signer; 265 STACK_OF(PKCS7_SIGNER_INFO) *sinfos; 266 PKCS7_SIGNER_INFO *si; 267 X509_STORE_CTX cert_ctx; 268 char buf[4096]; 269 int i, j = 0, k, ret = 0; 270 BIO *p7bio; 271 BIO *tmpin, *tmpout; 272 273 if (!p7) { 274 PKCS7error(PKCS7_R_INVALID_NULL_POINTER); 275 return 0; 276 } 277 278 if (!PKCS7_type_is_signed(p7)) { 279 PKCS7error(PKCS7_R_WRONG_CONTENT_TYPE); 280 return 0; 281 } 282 283 /* Check for no data and no content: no data to verify signature */ 284 if (PKCS7_get_detached(p7) && !indata) { 285 PKCS7error(PKCS7_R_NO_CONTENT); 286 return 0; 287 } 288 289 /* 290 * Very old Netscape illegally included empty content with 291 * a detached signature. Very old users should upgrade. 292 */ 293 /* Check for data and content: two sets of data */ 294 if (!PKCS7_get_detached(p7) && indata) { 295 PKCS7error(PKCS7_R_CONTENT_AND_DATA_PRESENT); 296 return 0; 297 } 298 299 sinfos = PKCS7_get_signer_info(p7); 300 301 if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) { 302 PKCS7error(PKCS7_R_NO_SIGNATURES_ON_DATA); 303 return 0; 304 } 305 306 307 signers = PKCS7_get0_signers(p7, certs, flags); 308 309 if (!signers) 310 return 0; 311 312 /* Now verify the certificates */ 313 314 if (!(flags & PKCS7_NOVERIFY)) 315 for (k = 0; k < sk_X509_num(signers); k++) { 316 signer = sk_X509_value (signers, k); 317 if (!(flags & PKCS7_NOCHAIN)) { 318 if (!X509_STORE_CTX_init(&cert_ctx, store, 319 signer, p7->d.sign->cert)) { 320 PKCS7error(ERR_R_X509_LIB); 321 sk_X509_free(signers); 322 return 0; 323 } 324 if (X509_STORE_CTX_set_default(&cert_ctx, 325 "smime_sign") == 0) { 326 sk_X509_free(signers); 327 return 0; 328 } 329 } else if (!X509_STORE_CTX_init(&cert_ctx, store, 330 signer, NULL)) { 331 PKCS7error(ERR_R_X509_LIB); 332 sk_X509_free(signers); 333 return 0; 334 } 335 if (!(flags & PKCS7_NOCRL)) 336 X509_STORE_CTX_set0_crls(&cert_ctx, p7->d.sign->crl); 337 i = X509_verify_cert(&cert_ctx); 338 if (i <= 0) 339 j = X509_STORE_CTX_get_error(&cert_ctx); 340 X509_STORE_CTX_cleanup(&cert_ctx); 341 if (i <= 0) { 342 PKCS7error(PKCS7_R_CERTIFICATE_VERIFY_ERROR); 343 ERR_asprintf_error_data("Verify error:%s", 344 X509_verify_cert_error_string(j)); 345 sk_X509_free(signers); 346 return 0; 347 } 348 /* Check for revocation status here */ 349 } 350 351 /* 352 * Performance optimization: if the content is a memory BIO then 353 * store its contents in a temporary read only memory BIO. This 354 * avoids potentially large numbers of slow copies of data which will 355 * occur when reading from a read write memory BIO when signatures 356 * are calculated. 357 */ 358 if (indata && (BIO_method_type(indata) == BIO_TYPE_MEM)) { 359 char *ptr; 360 long len; 361 362 len = BIO_get_mem_data(indata, &ptr); 363 tmpin = BIO_new_mem_buf(ptr, len); 364 if (tmpin == NULL) { 365 PKCS7error(ERR_R_MALLOC_FAILURE); 366 return 0; 367 } 368 } else 369 tmpin = indata; 370 371 372 if (!(p7bio = PKCS7_dataInit(p7, tmpin))) 373 goto err; 374 375 if (flags & PKCS7_TEXT) { 376 if (!(tmpout = BIO_new(BIO_s_mem()))) { 377 PKCS7error(ERR_R_MALLOC_FAILURE); 378 goto err; 379 } 380 BIO_set_mem_eof_return(tmpout, 0); 381 } else 382 tmpout = out; 383 384 /* We now have to 'read' from p7bio to calculate digests etc. */ 385 for (;;) { 386 i = BIO_read(p7bio, buf, sizeof(buf)); 387 if (i <= 0) 388 break; 389 if (tmpout) 390 BIO_write(tmpout, buf, i); 391 } 392 393 if (flags & PKCS7_TEXT) { 394 if (!SMIME_text(tmpout, out)) { 395 PKCS7error(PKCS7_R_SMIME_TEXT_ERROR); 396 BIO_free(tmpout); 397 goto err; 398 } 399 BIO_free(tmpout); 400 } 401 402 /* Now Verify All Signatures */ 403 if (!(flags & PKCS7_NOSIGS)) 404 for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { 405 si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); 406 signer = sk_X509_value (signers, i); 407 j = PKCS7_signatureVerify(p7bio, p7, si, signer); 408 if (j <= 0) { 409 PKCS7error(PKCS7_R_SIGNATURE_FAILURE); 410 goto err; 411 } 412 } 413 414 ret = 1; 415 416 err: 417 if (tmpin == indata) { 418 if (indata) 419 BIO_pop(p7bio); 420 } 421 BIO_free_all(p7bio); 422 sk_X509_free(signers); 423 424 return ret; 425 } 426 427 STACK_OF(X509) * 428 PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags) 429 { 430 STACK_OF(X509) *signers; 431 STACK_OF(PKCS7_SIGNER_INFO) *sinfos; 432 PKCS7_SIGNER_INFO *si; 433 PKCS7_ISSUER_AND_SERIAL *ias; 434 X509 *signer; 435 int i; 436 437 if (!p7) { 438 PKCS7error(PKCS7_R_INVALID_NULL_POINTER); 439 return NULL; 440 } 441 442 if (!PKCS7_type_is_signed(p7)) { 443 PKCS7error(PKCS7_R_WRONG_CONTENT_TYPE); 444 return NULL; 445 } 446 447 /* Collect all the signers together */ 448 sinfos = PKCS7_get_signer_info(p7); 449 if (sk_PKCS7_SIGNER_INFO_num(sinfos) <= 0) { 450 PKCS7error(PKCS7_R_NO_SIGNERS); 451 return 0; 452 } 453 454 if (!(signers = sk_X509_new_null())) { 455 PKCS7error(ERR_R_MALLOC_FAILURE); 456 return NULL; 457 } 458 459 for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { 460 si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); 461 ias = si->issuer_and_serial; 462 signer = NULL; 463 /* If any certificates passed they take priority */ 464 if (certs) 465 signer = X509_find_by_issuer_and_serial (certs, 466 ias->issuer, ias->serial); 467 if (!signer && !(flags & PKCS7_NOINTERN) && p7->d.sign->cert) 468 signer = 469 X509_find_by_issuer_and_serial(p7->d.sign->cert, 470 ias->issuer, ias->serial); 471 if (!signer) { 472 PKCS7error(PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND); 473 sk_X509_free(signers); 474 return 0; 475 } 476 477 if (!sk_X509_push(signers, signer)) { 478 sk_X509_free(signers); 479 return NULL; 480 } 481 } 482 return signers; 483 } 484 485 /* Build a complete PKCS#7 enveloped data */ 486 487 PKCS7 * 488 PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, 489 int flags) 490 { 491 PKCS7 *p7; 492 BIO *p7bio = NULL; 493 int i; 494 X509 *x509; 495 496 if (!(p7 = PKCS7_new())) { 497 PKCS7error(ERR_R_MALLOC_FAILURE); 498 return NULL; 499 } 500 501 if (!PKCS7_set_type(p7, NID_pkcs7_enveloped)) 502 goto err; 503 if (!PKCS7_set_cipher(p7, cipher)) { 504 PKCS7error(PKCS7_R_ERROR_SETTING_CIPHER); 505 goto err; 506 } 507 508 for (i = 0; i < sk_X509_num(certs); i++) { 509 x509 = sk_X509_value(certs, i); 510 if (!PKCS7_add_recipient(p7, x509)) { 511 PKCS7error(PKCS7_R_ERROR_ADDING_RECIPIENT); 512 goto err; 513 } 514 } 515 516 if (flags & PKCS7_STREAM) 517 return p7; 518 519 if (PKCS7_final(p7, in, flags)) 520 return p7; 521 522 err: 523 BIO_free_all(p7bio); 524 PKCS7_free(p7); 525 return NULL; 526 } 527 528 int 529 PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags) 530 { 531 BIO *tmpmem; 532 int ret, i; 533 char buf[4096]; 534 535 if (!p7) { 536 PKCS7error(PKCS7_R_INVALID_NULL_POINTER); 537 return 0; 538 } 539 540 if (!PKCS7_type_is_enveloped(p7)) { 541 PKCS7error(PKCS7_R_WRONG_CONTENT_TYPE); 542 return 0; 543 } 544 545 if (cert && !X509_check_private_key(cert, pkey)) { 546 PKCS7error(PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); 547 return 0; 548 } 549 550 if (!(tmpmem = PKCS7_dataDecode(p7, pkey, NULL, cert))) { 551 PKCS7error(PKCS7_R_DECRYPT_ERROR); 552 return 0; 553 } 554 555 if (flags & PKCS7_TEXT) { 556 BIO *tmpbuf; 557 558 /* Encrypt BIOs can't do BIO_gets() so add a buffer BIO */ 559 if (!(tmpbuf = BIO_new(BIO_f_buffer()))) { 560 PKCS7error(ERR_R_MALLOC_FAILURE); 561 BIO_free_all(tmpmem); 562 return 0; 563 } 564 BIO_push(tmpbuf, tmpmem); 565 ret = SMIME_text(tmpbuf, data); 566 if (ret > 0 && BIO_method_type(tmpmem) == BIO_TYPE_CIPHER) { 567 if (!BIO_get_cipher_status(tmpmem)) 568 ret = 0; 569 } 570 BIO_free_all(tmpbuf); 571 return ret; 572 } else { 573 for (;;) { 574 i = BIO_read(tmpmem, buf, sizeof(buf)); 575 if (i <= 0) { 576 ret = 1; 577 if (BIO_method_type(tmpmem) == 578 BIO_TYPE_CIPHER) { 579 if (!BIO_get_cipher_status(tmpmem)) 580 ret = 0; 581 } 582 break; 583 } 584 if (BIO_write(data, buf, i) != i) { 585 ret = 0; 586 break; 587 } 588 } 589 BIO_free_all(tmpmem); 590 return ret; 591 } 592 } 593