Webcrypto: fix RSA-OAEP digest being ignored for non-SHA-1 hashes - #1101
Open
tompsota wants to merge 1 commit into
Open
Webcrypto: fix RSA-OAEP digest being ignored for non-SHA-1 hashes#1101tompsota wants to merge 1 commit into
tompsota wants to merge 1 commit into
Conversation
njs_cipher_pkey() and qjs_cipher_pkey() configured the OAEP digest with EVP_PKEY_CTX_set_signature_md(), which is not a valid control for an encrypt or decrypt operation. OpenSSL rejects it with "command not supported", and since the return value was not checked, the OAEP digest silently remained at its SHA-1 default while MGF1 was set to the requested hash. RSA-OAEP with any hash other than SHA-1 therefore used a non-standard digest pair. Ciphertext produced by another implementation failed to decrypt with "oaep decoding error", and ciphertext produced by njs could not be decrypted anywhere else. The round-trip tests did not catch this because njs applied the same substitution when encrypting and when decrypting, so it stayed consistent with itself. The only test using an externally generated ciphertext used SHA-1, which is the digest njs silently fell back to. Use EVP_PKEY_CTX_set_rsa_oaep_md() instead, and add externally generated SHA-256 and SHA-384 ciphertexts to the RSA-OAEP decoding test. Co-authored-by: Cursor <cursoragent@cursor.com>
|
✅ All required contributors have signed the F5 CLA for this PR. Thank you! |
Author
|
I have hereby read the F5 CLA and agree to its terms |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
njs_cipher_pkey()sets up RSA-OAEP like this:EVP_PKEY_CTX_set_signature_md()is not a valid control for an encrypt ordecrypt operation, so OpenSSL rejects it with
command not supported. Thereturn value is not checked, so the OAEP digest silently stays at its SHA-1
default while MGF1 is set to the requested hash.
The result is that
RSA-OAEPwith any hash other than SHA-1 uses the digestpair OAEP/SHA-1 + MGF1/
<requested>, which is not what the caller asked for andnot what any other implementation produces:
error:02000079:rsa routines::oaep decoding errorEVP_PKEY_CTX_set_rsa_oaep_md()is currently not called anywhere in the tree.qjs_cipher_pkey()inexternal/qjs_webcrypto_module.chas the same threelines and the same problem.
Reproduction
Encrypt with OpenSSL using OAEP/SHA-256 and decrypt in njs:
Decrypting the same ciphertext with OAEP digest SHA-1 and MGF1 digest SHA-256
succeeds, which confirms the digest njs actually negotiated.
Reproduced on njs 0.8.4, 0.8.9, 0.8.10, 0.9.6 and current master, against
OpenSSL 3.1.4 through 3.5.6, in both the njs and QuickJS engines.
Why the tests did not catch it
test/webcrypto/rsa.t.mjsis a round trip: it encrypts and decrypts withcrypto.subtle. Both directions make the same substitution, so the mismatchcancels out and the SHA-256 and SHA-384 cases pass while being incompatible
with every other implementation.
test/webcrypto/rsa_decoding.t.mjsis the only test that decrypts anexternally generated ciphertext, and it covers SHA-1 only, which happens to be
the digest njs silently falls back to.
Changes
EVP_PKEY_CTX_set_rsa_oaep_md()innjs_cipher_pkey()andqjs_cipher_pkey()rsa_decoding.t.mjs, encrypted with the existingrsa.pkcs8test keyThe new fixtures were produced outside njs, so they fail on an unpatched build
and cannot be masked by a round trip.
Test results
Before the fix:
After the fix:
Compatibility note
This changes the ciphertext njs produces and accepts for RSA-OAEP with non-SHA-1
hashes. Anything that stored ciphertext generated by an affected njs build using
those hashes was already unreadable by other implementations; it will now need
the OAEP digest that was actually used (SHA-1) to be read back.
Made with Cursor