-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Allow RSA signing with raw data (without a DigestInfo) #13740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -290,8 +290,16 @@ impl RsaPrivateKey { | |
| padding: &pyo3::Bound<'p, pyo3::PyAny>, | ||
| algorithm: &pyo3::Bound<'p, pyo3::PyAny>, | ||
| ) -> CryptographyResult<pyo3::Bound<'p, pyo3::types::PyAny>> { | ||
| let (data, algorithm) = | ||
| utils::calculate_digest_and_algorithm(py, data.as_bytes(), algorithm)?; | ||
| let (data, algorithm) = { | ||
| if algorithm.is_instance(&types::NO_DIGEST_INFO.get(py)?)? { | ||
| ( | ||
| utils::BytesOrPyBytes::Bytes(data.as_bytes()), | ||
| pyo3::types::PyNone::get(py).to_owned().into_any(), | ||
| ) | ||
| } 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(|_| { | ||
|
|
@@ -434,8 +442,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_instance(&types::NO_DIGEST_INFO.get(py)?)? { | ||
| ( | ||
| utils::BytesOrPyBytes::Bytes(data.as_bytes()), | ||
| pyo3::types::PyNone::get(py).to_owned().into_any(), | ||
| ) | ||
| } else { | ||
| utils::calculate_digest_and_algorithm(py, data.as_bytes(), algorithm)? | ||
| } | ||
| }; | ||
|
|
||
| let mut ctx = openssl::pkey_ctx::PkeyCtx::new(&self.pkey)?; | ||
| ctx.verify_init()?; | ||
|
|
@@ -481,6 +497,11 @@ impl RsaPublicKey { | |
| padding: &pyo3::Bound<'_, pyo3::PyAny>, | ||
| algorithm: &pyo3::Bound<'_, pyo3::PyAny>, | ||
| ) -> CryptographyResult<pyo3::Bound<'p, pyo3::types::PyBytes>> { | ||
| let algorithm = if algorithm.is_instance(&types::NO_DIGEST_INFO.get(py)?)? { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| &pyo3::types::PyNone::get(py).to_owned().into_any() | ||
jahkosha marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } else { | ||
| algorithm | ||
| }; | ||
| if algorithm.is_instance(&types::PREHASHED.get(py)?)? { | ||
| return Err(CryptographyError::from( | ||
| pyo3::exceptions::PyTypeError::new_err( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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"] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer we used SHA256 for the tests here because otherwise we'll increasingly have coverage challenges as more and more things disable SHA1. |
||
| ) | ||
| ), | ||
| padding.PKCS1v15(), | ||
| asym_utils.NoDigestInfo(), | ||
| ) | ||
| assert binascii.hexlify(signature) == example["signature"] | ||
|
|
||
| @pytest.mark.supported( | ||
| only_if=lambda backend: backend.rsa_padding_supported( | ||
| padding.PSS( | ||
|
|
@@ -910,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( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to document that |
||
| 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) :] | ||
|
|
@@ -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.", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same SHA1 concern |
||
| )( | ||
| 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()) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to document this in the same section as
Prehashed