Skip to content

Don't leak how PKCS#7 encryptedKey decryption failed - #15369

Merged
reaperhulk merged 4 commits into
pyca:mainfrom
alex:pkcs7-encrypted-key-oracle
Jul 31, 2026
Merged

Don't leak how PKCS#7 encryptedKey decryption failed#15369
reaperhulk merged 4 commits into
pyca:mainfrom
alex:pkcs7-encrypted-key-oracle

Conversation

@alex

@alex alex commented Jul 31, 2026

Copy link
Copy Markdown
Member

pkcs7_decrypt_der and its PEM and S/MIME variants reported invalid RSA PKCS#1 v1.5 padding, a recovered key of the wrong length, and a wrong key as three distinct errors, and the middle one disclosed the exact recovered length. That is a Bleichenbacher oracle for any caller that decrypts untrusted messages. The wrong-length case also returned before the AES-CBC pass, so the same distinction was observable by timing, proportional to a content size the attacker chooses.

Substitute a random key of the expected length on failure, per RFC 3218, and continue down an identical path so that every outcome looks alike.

EnvelopedData still authenticates nothing, so revealing whether decryption succeeded remains a CBC padding oracle regardless. That is a property of PKCS#7 rather than of this implementation, and is now documented instead.

alex and others added 3 commits July 31, 2026 08:16
pkcs7_decrypt_der and its PEM and S/MIME variants reported invalid RSA
PKCS#1 v1.5 padding, a recovered key of the wrong length, and a wrong
key as three distinct errors, and the middle one disclosed the exact
recovered length. That is a Bleichenbacher oracle for any caller that
decrypts untrusted messages. The wrong-length case also returned before
the AES-CBC pass, so the same distinction was observable by timing,
proportional to a content size the attacker chooses.

Substitute a random key of the expected length on failure, per RFC 3218,
and continue down an identical path so that every outcome looks alike.

EnvelopedData still authenticates nothing, so revealing whether
decryption succeeded remains a CBC padding oracle regardless. That is a
property of PKCS#7 rather than of this implementation, and is now
documented instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Only a ValueError from unwrapping the key is attacker controlled and so
deliberately silenced. A private key implemented outside of this library
can fail in other ways, and those still reach the caller -- but nothing
exercised that arm, leaving it uncovered.

Add a DummyRSAPrivateKey double whose decrypt() raises a TypeError, and
tests for each of its methods.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread tests/hazmat/primitives/test_pkcs7.py Outdated
.encrypt(serialization.Encoding.DER, [])
)

with pytest.raises(TypeError, match="the smartcard is unplugged"):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use a message that makes it clear this is a test rather than a plausible error message.

@reaperhulk
reaperhulk enabled auto-merge (squash) July 31, 2026 13:18
@reaperhulk
reaperhulk merged commit 53fccd9 into pyca:main Jul 31, 2026
69 checks passed
@alex
alex deleted the pkcs7-encrypted-key-oracle branch July 31, 2026 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants