/* Provenance: openssl/openssl PKCS7_verify (fixed). * repo: openssl/openssl * commit: f4129fbe3cde786d363510069fe297234f99be8f * parent: 609bcb24866d64f1fc49d38b852edbb39057d721 * commit_url: https://github.com/openssl/openssl/commit/f4129fbe3cde786d363510069fe297234f99be8f * cve: CVE-2026-45447 * license: Apache-2.0 * function: PKCS7_verify * relpath: crypto/pkcs7/pk7_smime.c */ int PKCS7_verify(PKCS7 *p7, const STACK_OF(X509) *certs, X509_STORE *store, BIO *indata, BIO *out, int flags) { STACK_OF(X509) *signers; STACK_OF(X509) *included_certs; STACK_OF(X509) *untrusted = NULL; X509 *signer; STACK_OF(PKCS7_SIGNER_INFO) *sinfos; PKCS7_SIGNER_INFO *si; X509_STORE_CTX *cert_ctx = NULL; char *buf = NULL; int i, j = 0, k, ret = 0; BIO *p7bio = NULL; BIO *tmpout = NULL; BIO *next = NULL; const PKCS7_CTX *p7_ctx; if (p7 == NULL) { ERR_raise(ERR_LIB_PKCS7, PKCS7_R_INVALID_NULL_POINTER); return 0; } if (!PKCS7_type_is_signed(p7)) { ERR_raise(ERR_LIB_PKCS7, PKCS7_R_WRONG_CONTENT_TYPE); return 0; } /* Check for no data and no content: no data to verify signature */ if (PKCS7_get_detached(p7) && indata == NULL) { ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT); return 0; } if (flags & PKCS7_NO_DUAL_CONTENT) { /* * This was originally "#if 0" because we thought that only old broken * Netscape did this. It turns out that Authenticode uses this kind * of "extended" PKCS7 format, and things like UEFI secure boot and * tools like osslsigncode need it. In Authenticode the verification * process is different, but the existing PKCs7 verification works. */ if (!PKCS7_get_detached(p7) && indata != NULL) { ERR_raise(ERR_LIB_PKCS7, PKCS7_R_CONTENT_AND_DATA_PRESENT); return 0; } } sinfos = PKCS7_get_signer_info(p7); if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) { ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_SIGNATURES_ON_DATA); return 0; } signers = PKCS7_get0_signers(p7, certs, flags); if (signers == NULL) return 0; /* Now verify the certificates */ p7_ctx = ossl_pkcs7_get0_ctx(p7); cert_ctx = X509_STORE_CTX_new_ex(ossl_pkcs7_ctx_get0_libctx(p7_ctx), ossl_pkcs7_ctx_get0_propq(p7_ctx)); if (cert_ctx == NULL) goto err; if ((flags & PKCS7_NOVERIFY) == 0) { if (!ossl_x509_add_certs_new(&untrusted, certs, X509_ADD_FLAG_NO_DUP)) goto err; included_certs = pkcs7_get0_certificates(p7); if ((flags & PKCS7_NOCHAIN) == 0 && !ossl_x509_add_certs_new(&untrusted, included_certs, X509_ADD_FLAG_NO_DUP)) goto err; for (k = 0; k < sk_X509_num(signers); k++) { signer = sk_X509_value(signers, k); if (!X509_STORE_CTX_init(cert_ctx, store, signer, untrusted)) { ERR_raise(ERR_LIB_PKCS7, ERR_R_X509_LIB); goto err; } if ((flags & PKCS7_NOCHAIN) == 0 && !X509_STORE_CTX_set_default(cert_ctx, "smime_sign")) goto err; if (!(flags & PKCS7_NOCRL)) X509_STORE_CTX_set0_crls(cert_ctx, p7->d.sign->crl); i = X509_verify_cert(cert_ctx); if (i <= 0) { j = X509_STORE_CTX_get_error(cert_ctx); ERR_raise_data(ERR_LIB_PKCS7, PKCS7_R_CERTIFICATE_VERIFY_ERROR, "Verify error: %s", X509_verify_cert_error_string(j)); goto err; } /* Check for revocation status here */ } } if ((p7bio = PKCS7_dataInit(p7, indata)) == NULL) goto err; if (flags & PKCS7_TEXT) { if ((tmpout = BIO_new(BIO_s_mem())) == NULL) { ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB); goto err; } BIO_set_mem_eof_return(tmpout, 0); } else tmpout = out; /* We now have to 'read' from p7bio to calculate digests etc. */ if ((buf = OPENSSL_malloc(BUFFERSIZE)) == NULL) goto err; for (;;) { i = BIO_read(p7bio, buf, BUFFERSIZE); if (i <= 0) break; if (tmpout) BIO_write(tmpout, buf, i); } if (flags & PKCS7_TEXT) { if (!SMIME_text(tmpout, out)) { ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SMIME_TEXT_ERROR); goto err; } } /* Now Verify All Signatures */ if (!(flags & PKCS7_NOSIGS)) for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); signer = sk_X509_value(signers, i); j = PKCS7_signatureVerify(p7bio, p7, si, signer); if (j <= 0) { ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SIGNATURE_FAILURE); goto err; } } ret = 1; err: if (flags & PKCS7_TEXT) BIO_free(tmpout); X509_STORE_CTX_free(cert_ctx); OPENSSL_free(buf); while (p7bio != NULL && p7bio != indata) { next = BIO_pop(p7bio); BIO_free(p7bio); p7bio = next; } sk_X509_free(signers); sk_X509_free(untrusted); return ret; }