From 6a8b12974acca7f3f73c8006983ce7c8dc3bf92c Mon Sep 17 00:00:00 2001 From: Jah Kosha Date: Wed, 15 Oct 2025 13:06:33 +0200 Subject: [PATCH 01/10] Allow RSA signing with raw data (without a DigestInfo) --- .../hazmat/primitives/asymmetric/rsa.py | 2 +- src/rust/src/backend/rsa.rs | 24 +++++-- tests/hazmat/primitives/test_rsa.py | 65 +++++++++++++++++++ tests/hazmat/primitives/utils.py | 25 +++++++ 4 files changed, 111 insertions(+), 5 deletions(-) diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index 5cdbef32b733..f53ad91ef25b 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -40,7 +40,7 @@ def sign( self, data: bytes, padding: AsymmetricPadding, - algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, + algorithm: None | asym_utils.Prehashed | hashes.HashAlgorithm, ) -> bytes: """ Signs the data. diff --git a/src/rust/src/backend/rsa.rs b/src/rust/src/backend/rsa.rs index 9c5ccc26a7cb..92e7a8cee858 100644 --- a/src/rust/src/backend/rsa.rs +++ b/src/rust/src/backend/rsa.rs @@ -290,8 +290,16 @@ impl RsaPrivateKey { padding: &pyo3::Bound<'p, pyo3::PyAny>, algorithm: &pyo3::Bound<'p, pyo3::PyAny>, ) -> CryptographyResult> { - let (data, algorithm) = - utils::calculate_digest_and_algorithm(py, data.as_bytes(), algorithm)?; + let (data, algorithm) = { + if algorithm.is_none() { + ( + utils::BytesOrPyBytes::Bytes(data.as_bytes()), + algorithm.clone(), + ) + } else { + utils::calculate_digest_and_algorithm(py, data.as_bytes(), algorithm)? + } + }; let mut ctx = openssl::pkey_ctx::PkeyCtx::new(&self.pkey)?; ctx.sign_init().map_err(|_| { @@ -441,8 +449,16 @@ impl RsaPublicKey { padding: &pyo3::Bound<'_, pyo3::PyAny>, algorithm: &pyo3::Bound<'_, pyo3::PyAny>, ) -> CryptographyResult<()> { - let (data, algorithm) = - utils::calculate_digest_and_algorithm(py, data.as_bytes(), algorithm)?; + let (data, algorithm) = { + if algorithm.is_none() { + ( + utils::BytesOrPyBytes::Bytes(data.as_bytes()), + algorithm.clone(), + ) + } else { + utils::calculate_digest_and_algorithm(py, data.as_bytes(), algorithm)? + } + }; let mut ctx = openssl::pkey_ctx::PkeyCtx::new(&self.pkey)?; ctx.verify_init()?; diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 04472fb2394d..3074d33d61d1 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -51,7 +51,9 @@ ) from .utils import ( _check_rsa_private_numbers, + compute_rsa_hash_digest, generate_rsa_verification_test, + generate_rsa_verification_without_digest_test, skip_fips_traditional_openssl, ) @@ -442,6 +444,49 @@ def test_pkcs1v15_signing(self, backend, subtests): ) assert binascii.hexlify(signature) == example["signature"] + @pytest.mark.supported( + only_if=lambda backend: backend.rsa_padding_supported( + padding.PKCS1v15() + ), + skip_message="Does not support PKCS1v1.5.", + ) + @pytest.mark.supported( + only_if=lambda backend: backend.signature_hash_supported( + hashes.SHA1() + ), + skip_message="Does not support SHA1 signature.", + ) + def test_pkcs1v15_signing_without_digest(self, backend, subtests): + vectors = _flatten_pkcs1_examples( + load_vectors_from_file( + os.path.join("asymmetric", "RSA", "pkcs1v15sign-vectors.txt"), + load_pkcs1_vectors, + ) + ) + for private, public, example in vectors: + with subtests.test(): + private_key = rsa.RSAPrivateNumbers( + p=private["p"], + q=private["q"], + d=private["private_exponent"], + dmp1=private["dmp1"], + dmq1=private["dmq1"], + iqmp=private["iqmp"], + public_numbers=rsa.RSAPublicNumbers( + e=private["public_exponent"], n=private["modulus"] + ), + ).private_key(backend, unsafe_skip_rsa_key_validation=True) + signature = private_key.sign( + binascii.unhexlify( + compute_rsa_hash_digest( + backend, hashes.SHA1(), example["message"] + ) + ), + padding.PKCS1v15(), + None, + ) + assert binascii.hexlify(signature) == example["signature"] + @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( @@ -1522,6 +1567,26 @@ class TestRSAPKCS1Verification: ) ) + test_rsa_pkcs1v15_verify_sha1_without_digest = pytest.mark.supported( + only_if=lambda backend: ( + backend.signature_hash_supported(hashes.SHA1()) + and backend.rsa_padding_supported(padding.PKCS1v15()) + ), + skip_message="Does not support SHA1 and PKCS1v1.5.", + )( + generate_rsa_verification_without_digest_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGen15_186-2.rsp", + "SigGen15_186-3.rsp", + "SigVer15_186-3.rsp", + ], + hashes.SHA1(), + lambda params, hash_alg: padding.PKCS1v15(), + ) + ) + test_rsa_pkcs1v15_verify_sha224 = pytest.mark.supported( only_if=lambda backend: ( backend.signature_hash_supported(hashes.SHA224()) diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index ac97ce9d83b9..9f1506c2b1d3 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -47,6 +47,13 @@ def _load_all_params(path, file_names, param_loader): return all_params +def compute_rsa_hash_digest(backend, hash_alg, msg): + oid = _hash_alg_oids[hash_alg.name] + h = hashes.Hash(hash_alg, backend=backend) + h.update(binascii.unhexlify(msg)) + return binascii.hexlify(oid) + binascii.hexlify(h.finalize()) + + def generate_encrypt_test( param_loader, path, file_names, cipher_factory, mode_factory ): @@ -501,6 +508,24 @@ def test_rsa_verification(self, backend, subtests): return test_rsa_verification +def generate_rsa_verification_without_digest_test( + param_loader, path, file_names, hash_alg, pad_factory +): + def test_rsa_verification(self, backend, subtests): + all_params = _load_all_params(path, file_names, param_loader) + all_params = [ + i for i in all_params if i["algorithm"] == hash_alg.name.upper() + ] + for params in all_params: + with subtests.test(): + params["msg"] = compute_rsa_hash_digest( + backend, hash_alg, params["msg"] + ) + rsa_verification_test(backend, params, None, pad_factory) + + return test_rsa_verification + + def rsa_verification_test(backend, params, hash_alg, pad_factory): public_numbers = rsa.RSAPublicNumbers( e=params["public_exponent"], n=params["modulus"] From 6bf891fab6f16bfcc67c62382f6438173b322531 Mon Sep 17 00:00:00 2001 From: Jah Kosha Date: Tue, 4 Nov 2025 14:06:23 +0100 Subject: [PATCH 02/10] Add `NoDigestInfo` to sign using RSA with raw data --- src/cryptography/hazmat/primitives/asymmetric/rsa.py | 4 +++- src/cryptography/hazmat/primitives/asymmetric/utils.py | 4 ++++ src/rust/src/backend/rsa.rs | 8 ++++---- src/rust/src/types.rs | 4 ++++ tests/hazmat/primitives/test_rsa.py | 2 +- tests/hazmat/primitives/utils.py | 5 ++++- 6 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index f53ad91ef25b..5d99ead7ff4a 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -40,7 +40,9 @@ def sign( self, data: bytes, padding: AsymmetricPadding, - algorithm: None | asym_utils.Prehashed | hashes.HashAlgorithm, + algorithm: asym_utils.Prehashed + | hashes.HashAlgorithm + | asym_utils.NoDigestInfo, ) -> bytes: """ Signs the data. diff --git a/src/cryptography/hazmat/primitives/asymmetric/utils.py b/src/cryptography/hazmat/primitives/asymmetric/utils.py index 826b9567b47b..c01c34274be5 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/utils.py +++ b/src/cryptography/hazmat/primitives/asymmetric/utils.py @@ -11,6 +11,10 @@ encode_dss_signature = asn1.encode_dss_signature +class NoDigestInfo: + pass + + class Prehashed: def __init__(self, algorithm: hashes.HashAlgorithm): if not isinstance(algorithm, hashes.HashAlgorithm): diff --git a/src/rust/src/backend/rsa.rs b/src/rust/src/backend/rsa.rs index 92e7a8cee858..d0d4eda3b52a 100644 --- a/src/rust/src/backend/rsa.rs +++ b/src/rust/src/backend/rsa.rs @@ -291,10 +291,10 @@ impl RsaPrivateKey { algorithm: &pyo3::Bound<'p, pyo3::PyAny>, ) -> CryptographyResult> { let (data, algorithm) = { - if algorithm.is_none() { + if algorithm.is_instance(&types::NO_DIGEST_INFO.get(py)?)? { ( utils::BytesOrPyBytes::Bytes(data.as_bytes()), - algorithm.clone(), + pyo3::types::PyNone::get(py).to_owned().into_any(), ) } else { utils::calculate_digest_and_algorithm(py, data.as_bytes(), algorithm)? @@ -450,10 +450,10 @@ impl RsaPublicKey { algorithm: &pyo3::Bound<'_, pyo3::PyAny>, ) -> CryptographyResult<()> { let (data, algorithm) = { - if algorithm.is_none() { + if algorithm.is_instance(&types::NO_DIGEST_INFO.get(py)?)? { ( utils::BytesOrPyBytes::Bytes(data.as_bytes()), - algorithm.clone(), + pyo3::types::PyNone::get(py).to_owned().into_any(), ) } else { utils::calculate_digest_and_algorithm(py, data.as_bytes(), algorithm)? diff --git a/src/rust/src/types.rs b/src/rust/src/types.rs index 30c5376f0f2e..3a7b02c6d69e 100644 --- a/src/rust/src/types.rs +++ b/src/rust/src/types.rs @@ -393,6 +393,10 @@ pub static SHA1: LazyPyImport = pub static SHA256: LazyPyImport = LazyPyImport::new("cryptography.hazmat.primitives.hashes", &["SHA256"]); +pub static NO_DIGEST_INFO: LazyPyImport = LazyPyImport::new( + "cryptography.hazmat.primitives.asymmetric.utils", + &["NoDigestInfo"], +); pub static PREHASHED: LazyPyImport = LazyPyImport::new( "cryptography.hazmat.primitives.asymmetric.utils", &["Prehashed"], diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 3074d33d61d1..6d34f61697f0 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -483,7 +483,7 @@ def test_pkcs1v15_signing_without_digest(self, backend, subtests): ) ), padding.PKCS1v15(), - None, + asym_utils.NoDigestInfo(), ) assert binascii.hexlify(signature) == example["signature"] diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 9f1506c2b1d3..371f966f0955 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -21,6 +21,7 @@ ) from cryptography.hazmat.primitives import hashes, hmac, serialization from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils from cryptography.hazmat.primitives.ciphers import ( BlockCipherAlgorithm, Cipher, @@ -521,7 +522,9 @@ def test_rsa_verification(self, backend, subtests): params["msg"] = compute_rsa_hash_digest( backend, hash_alg, params["msg"] ) - rsa_verification_test(backend, params, None, pad_factory) + rsa_verification_test( + backend, params, asym_utils.NoDigestInfo(), pad_factory + ) return test_rsa_verification From 813c8dc526578bcf21507a26ebda4cbf4bd99ec9 Mon Sep 17 00:00:00 2001 From: Jah Kosha Date: Tue, 4 Nov 2025 14:10:12 +0100 Subject: [PATCH 03/10] Support NoDigestInfo in `recover_data_from_signature` --- src/cryptography/hazmat/primitives/asymmetric/rsa.py | 2 +- src/rust/src/backend/rsa.rs | 5 +++++ tests/hazmat/primitives/test_rsa.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index 5d99ead7ff4a..a85a02bb92e4 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -129,7 +129,7 @@ def recover_data_from_signature( self, signature: bytes, padding: AsymmetricPadding, - algorithm: hashes.HashAlgorithm | None, + algorithm: hashes.HashAlgorithm | asym_utils.NoDigestInfo | None, ) -> bytes: """ Recovers the original data from the signature. diff --git a/src/rust/src/backend/rsa.rs b/src/rust/src/backend/rsa.rs index d0d4eda3b52a..21aaaf9861e4 100644 --- a/src/rust/src/backend/rsa.rs +++ b/src/rust/src/backend/rsa.rs @@ -504,6 +504,11 @@ impl RsaPublicKey { padding: &pyo3::Bound<'_, pyo3::PyAny>, algorithm: &pyo3::Bound<'_, pyo3::PyAny>, ) -> CryptographyResult> { + let algorithm = if algorithm.is_instance(&types::NO_DIGEST_INFO.get(py)?)? { + &pyo3::types::PyNone::get(py).to_owned().into_any() + } else { + algorithm + }; if algorithm.is_instance(&types::PREHASHED.get(py)?)? { return Err(CryptographyError::from( pyo3::exceptions::PyTypeError::new_err( diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 6d34f61697f0..3fcff0844b54 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -955,7 +955,7 @@ def test_pkcs1v15_verification(self, backend, subtests): # Test recovery of all data (full DigestInfo) with hash alg. as # None rec_sig_data = public_key.recover_data_from_signature( - signature, padding.PKCS1v15(), None + signature, padding.PKCS1v15(), asym_utils.NoDigestInfo() ) assert len(rec_sig_data) > len(msg_digest) assert msg_digest == rec_sig_data[-len(msg_digest) :] From 2d66d22a32f2295bef027e41ba3b7c41892f204c Mon Sep 17 00:00:00 2001 From: Jah Kosha Date: Mon, 17 Nov 2025 13:47:42 +0100 Subject: [PATCH 04/10] Use SHA256 instead of SHA1 were possible during RSA NoDigestInfo testing --- tests/hazmat/primitives/test_rsa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 3fcff0844b54..2254732908f4 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -1582,7 +1582,7 @@ class TestRSAPKCS1Verification: "SigGen15_186-3.rsp", "SigVer15_186-3.rsp", ], - hashes.SHA1(), + hashes.SHA256(), lambda params, hash_alg: padding.PKCS1v15(), ) ) From 8b64ab878794f230a977bf8ddaf60ed6b32ebfd4 Mon Sep 17 00:00:00 2001 From: Jah Kosha Date: Mon, 17 Nov 2025 13:48:43 +0100 Subject: [PATCH 05/10] Update documentation for `NoDigestInfo` --- docs/hazmat/primitives/asymmetric/rsa.rst | 5 +++-- docs/hazmat/primitives/asymmetric/utils.rst | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst index 54190ae2dd38..2112c7d2a0aa 100644 --- a/docs/hazmat/primitives/asymmetric/rsa.rst +++ b/docs/hazmat/primitives/asymmetric/rsa.rst @@ -784,9 +784,10 @@ Key interfaces ``algorithm`` parameters must match the ones used when the signature was created for the recovery to succeed. - The ``algorithm`` parameter can also be set to ``None`` to recover all + The ``algorithm`` parameter can also be set to ``NoDigestInfo`` to recover all the data present in the signature, without regard to its format or the - hash algorithm used for its creation. + hash algorithm used for its creation. (Note that setting ``algorithm`` to ``None` + is deprecated and have the same semantic as setting ``NoDigestInfo``.) For :class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15` diff --git a/docs/hazmat/primitives/asymmetric/utils.rst b/docs/hazmat/primitives/asymmetric/utils.rst index 487926e91256..9dc3b1098098 100644 --- a/docs/hazmat/primitives/asymmetric/utils.rst +++ b/docs/hazmat/primitives/asymmetric/utils.rst @@ -29,6 +29,19 @@ Asymmetric Utilities :return bytes: The encoded signature. +.. class:: NoDigestInfo() + + .. versionadded:: 47.0.0 + + Use a non-standard RSA signature formats where the PKCS #1-padded data is without DigestInfo. + + ``NoDigestInfo`` can be passed as the ``algorithm`` in the RSA + :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey.sign`, + :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey.verify` + and + :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey.recover_data_from_signature` + methods. + .. class:: Prehashed(algorithm) .. versionadded:: 1.6 From 9c5ddeb9f848dd52b8e3de5ce177f894a8c60c38 Mon Sep 17 00:00:00 2001 From: Jah Kosha Date: Mon, 24 Nov 2025 11:45:33 +0100 Subject: [PATCH 06/10] Mention NoDigestInfo in the CHANGELOG --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f787f92c185a..a184b31cf7b7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -78,6 +78,8 @@ Changelog :class:`~cryptography.hazmat.primitives.ciphers.aead.AESSIV`, and :class:`~cryptography.hazmat.primitives.ciphers.aead.ChaCha20Poly1305` to allow encrypting directly into a pre-allocated buffer. +* Added support for PKCS1v15 signing without DigestInfo using + :class:`~cryptography.hazmat.primitives.asymmetric.utils.NoDigestInfo`. .. _v46-0-3: From de5824ff3ad4a15012fab94c38990f3dac1eb7b4 Mon Sep 17 00:00:00 2001 From: Jah Kosha Date: Mon, 24 Nov 2025 11:46:29 +0100 Subject: [PATCH 07/10] Use NSA vectors (with SHA256) for NoDigestInfo tests Instead of relying on outdated vectors that uses SHA1 --- tests/hazmat/primitives/test_rsa.py | 50 +++++++++++++++++------------ 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 2254732908f4..b63175f3ddec 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -452,40 +452,50 @@ def test_pkcs1v15_signing(self, backend, subtests): ) @pytest.mark.supported( only_if=lambda backend: backend.signature_hash_supported( - hashes.SHA1() + hashes.SHA256() ), - skip_message="Does not support SHA1 signature.", + skip_message="Does not support SHA256 signature.", ) def test_pkcs1v15_signing_without_digest(self, backend, subtests): - vectors = _flatten_pkcs1_examples( - load_vectors_from_file( - os.path.join("asymmetric", "RSA", "pkcs1v15sign-vectors.txt"), - load_pkcs1_vectors, - ) + vectors = load_vectors_from_file( + os.path.join( + "asymmetric", "RSA", "FIPS_186-2", "SigVer15_186-3.rsp" + ), + load_rsa_nist_vectors, ) - for private, public, example in vectors: + for params in vectors: + if params["fail"] or params["algorithm"] != "SHA256": + continue with subtests.test(): + dmp1 = rsa.rsa_crt_dmp1( + params["private_exponent"], params["p"] + ) + dmq1 = rsa.rsa_crt_dmq1( + params["private_exponent"], params["q"] + ) + iqmp = rsa.rsa_crt_iqmp(params["p"], params["q"]) + private_key = rsa.RSAPrivateNumbers( - p=private["p"], - q=private["q"], - d=private["private_exponent"], - dmp1=private["dmp1"], - dmq1=private["dmq1"], - iqmp=private["iqmp"], + p=params["p"], + q=params["q"], + d=params["private_exponent"], + dmp1=dmp1, + dmq1=dmq1, + iqmp=iqmp, public_numbers=rsa.RSAPublicNumbers( - e=private["public_exponent"], n=private["modulus"] + e=params["public_exponent"], n=params["modulus"] ), ).private_key(backend, unsafe_skip_rsa_key_validation=True) signature = private_key.sign( binascii.unhexlify( compute_rsa_hash_digest( - backend, hashes.SHA1(), example["message"] + backend, hashes.SHA256(), params["msg"] ) ), padding.PKCS1v15(), asym_utils.NoDigestInfo(), ) - assert binascii.hexlify(signature) == example["signature"] + assert binascii.hexlify(signature) == params["s"] @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -1567,12 +1577,12 @@ class TestRSAPKCS1Verification: ) ) - test_rsa_pkcs1v15_verify_sha1_without_digest = pytest.mark.supported( + test_rsa_pkcs1v15_verify_sha256_without_digest = pytest.mark.supported( only_if=lambda backend: ( - backend.signature_hash_supported(hashes.SHA1()) + backend.signature_hash_supported(hashes.SHA256()) and backend.rsa_padding_supported(padding.PKCS1v15()) ), - skip_message="Does not support SHA1 and PKCS1v1.5.", + skip_message="Does not support SHA256 and PKCS1v1.5.", )( generate_rsa_verification_without_digest_test( load_rsa_nist_vectors, From 90f5e82a94b3400aad56e7877e3b2afe87c840fb Mon Sep 17 00:00:00 2001 From: Jah Kosha Date: Tue, 25 Nov 2025 12:15:01 +0100 Subject: [PATCH 08/10] Specialize `compute_rsa_hash_digest` into `compute_rsa_hash_digest_sha256` --- tests/hazmat/primitives/test_rsa.py | 6 ++---- tests/hazmat/primitives/utils.py | 10 +++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index b63175f3ddec..c8412dba7549 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -51,7 +51,7 @@ ) from .utils import ( _check_rsa_private_numbers, - compute_rsa_hash_digest, + compute_rsa_hash_digest_sha256, generate_rsa_verification_test, generate_rsa_verification_without_digest_test, skip_fips_traditional_openssl, @@ -488,9 +488,7 @@ def test_pkcs1v15_signing_without_digest(self, backend, subtests): ).private_key(backend, unsafe_skip_rsa_key_validation=True) signature = private_key.sign( binascii.unhexlify( - compute_rsa_hash_digest( - backend, hashes.SHA256(), params["msg"] - ) + compute_rsa_hash_digest_sha256(backend, params["msg"]) ), padding.PKCS1v15(), asym_utils.NoDigestInfo(), diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 371f966f0955..91f32c9ac85d 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -48,9 +48,9 @@ def _load_all_params(path, file_names, param_loader): return all_params -def compute_rsa_hash_digest(backend, hash_alg, msg): - oid = _hash_alg_oids[hash_alg.name] - h = hashes.Hash(hash_alg, backend=backend) +def compute_rsa_hash_digest_sha256(backend, msg): + oid = binascii.unhexlify(b"3031300d060960864801650304020105000420") + h = hashes.Hash(hashes.SHA256(), backend=backend) h.update(binascii.unhexlify(msg)) return binascii.hexlify(oid) + binascii.hexlify(h.finalize()) @@ -519,8 +519,8 @@ def test_rsa_verification(self, backend, subtests): ] for params in all_params: with subtests.test(): - params["msg"] = compute_rsa_hash_digest( - backend, hash_alg, params["msg"] + params["msg"] = compute_rsa_hash_digest_sha256( + backend, params["msg"] ) rsa_verification_test( backend, params, asym_utils.NoDigestInfo(), pad_factory From 17083dc2d960130b0e64dd8f27fbb5228edc8a9c Mon Sep 17 00:00:00 2001 From: Jah Kosha Date: Mon, 1 Dec 2025 11:55:27 +0100 Subject: [PATCH 09/10] Check FIPS key length during RSA test with NoDigestInfo --- tests/hazmat/primitives/test_rsa.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index c8412dba7549..f184753d57a3 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -486,6 +486,9 @@ def test_pkcs1v15_signing_without_digest(self, backend, subtests): e=params["public_exponent"], n=params["modulus"] ), ).private_key(backend, unsafe_skip_rsa_key_validation=True) + + _check_fips_key_length(backend, private_key) + signature = private_key.sign( binascii.unhexlify( compute_rsa_hash_digest_sha256(backend, params["msg"]) From 712d5e28f7cd05c367c2c97c4d054febd45407af Mon Sep 17 00:00:00 2001 From: Jah Kosha Date: Tue, 2 Dec 2025 17:52:06 +0100 Subject: [PATCH 10/10] Add test case when signing using PSS without digest --- tests/hazmat/primitives/test_rsa.py | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index f184753d57a3..6761193e75b3 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -559,6 +559,52 @@ def test_pss_signing(self, subtests, backend): hashes.SHA1(), ) + @pytest.mark.supported( + only_if=lambda backend: backend.rsa_padding_supported( + padding.PSS( + mgf=padding.MGF1(hashes.SHA1()), + salt_length=padding.PSS.MAX_LENGTH, + ) + ), + skip_message="Does not support PSS.", + ) + @pytest.mark.supported( + only_if=lambda backend: backend.signature_hash_supported( + hashes.SHA1() + ), + skip_message="Does not support SHA1 signature.", + ) + def test_pss_signing_without_digest(self, backend, subtests): + for private, public, example in _flatten_pkcs1_examples( + load_vectors_from_file( + os.path.join( + "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "pss-vect.txt" + ), + load_pkcs1_vectors, + ) + ): + with subtests.test(): + private_key = rsa.RSAPrivateNumbers( + p=private["p"], + q=private["q"], + d=private["private_exponent"], + dmp1=private["dmp1"], + dmq1=private["dmq1"], + iqmp=private["iqmp"], + public_numbers=rsa.RSAPublicNumbers( + e=private["public_exponent"], n=private["modulus"] + ), + ).private_key(backend, unsafe_skip_rsa_key_validation=True) + with pytest.raises(TypeError): + private_key.sign( + binascii.unhexlify(example["message"]), + padding.PSS( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + salt_length=padding.PSS.MAX_LENGTH, + ), + asym_utils.NoDigestInfo(), + ) + @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS(