Skip to content

ext/openssl: Defer pkcs7/cms verify output writes until verification succeeds#65

Open
iliaal wants to merge 1 commit into
PHP-8.4from
fix/openssl-ss004-pre-verify-truncation
Open

ext/openssl: Defer pkcs7/cms verify output writes until verification succeeds#65
iliaal wants to merge 1 commit into
PHP-8.4from
fix/openssl-ss004-pre-verify-truncation

Conversation

@iliaal
Copy link
Copy Markdown
Owner

@iliaal iliaal commented May 13, 2026

openssl_pkcs7_verify() and openssl_cms_verify() take a $content output path (6th positional) and a $output_filename p7b path (7th). Both were opened via php_openssl_bio_new_file() in write mode before the verify call, which truncated the destination files on open. When verify failed, the caller's pre-existing content at those paths was destroyed and replaced with nothing. Reachable from any workflow that points $content at a long-lived destination (mail-decode pipeline, signed-message inbox, log file) and processes an attacker-supplied envelope.

Replace the dataout file BIO with an in-memory BIO during the verify call. On success, open the destination file and copy the verified bytes out of the memory BIO into it. On failure, return without touching the file. Defer the p7bout file open until inside the success branch, after the signers section, so the file is only created and truncated when the PKCS7/CMS structure is actually going to be written.

The memory-BIO buffering is bounded by the size of the verified content, which is typically small for PKCS#7 / CMS envelopes.

Regression test exercises the failure shape with a real signed message and a CA bundle that does not include the signer.

…succeeds

openssl_pkcs7_verify() and openssl_cms_verify() take a $content output
path (6th positional) and a $output_filename p7b path (7th). Both were
opened via php_openssl_bio_new_file() in write mode before the verify
call, which truncated the destination files on open. When verify
failed, the caller's pre-existing content at those paths was destroyed
and replaced with nothing.

Reachable from any workflow that points $content at a long-lived
destination (mail-decode pipeline, signed-message inbox, log file) and
processes an attacker-supplied envelope: every failed verify wipes the
destination.

Replace the dataout file BIO with an in-memory BIO during the verify
call. On success, open the destination file and copy the verified bytes
out of the memory BIO into it. On failure, return without touching the
file. Defer the p7bout file open until inside the success branch, after
the signers section, so the file is only created and truncated when the
PKCS7/CMS structure is actually going to be written.

The memory-BIO buffering is bounded by the size of the verified content,
which is typically small for PKCS#7 / CMS envelopes (kB range).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant