mirror of
https://github.com/saymrwulf/cryptography.git
synced 2026-05-15 20:40:20 +00:00
Dedicated check for signature hash algorithms (#6931)
* Dedicated check for signature hash algorithms Move the check for FIPS mode and blocked SHA1 signature algorithm into the backend code. Some distros will block SHA1 for RSA signatures in the near future. The new ``signature_hash_supported()`` method will allow us to flip the switch in one place. Note: The ban of SHA1 signatures does not affect MGF1's inner hash algorithm. Signed-off-by: Christian Heimes <christian@python.org> * Address flake issues * Update src/cryptography/hazmat/backends/openssl/backend.py
This commit is contained in:
parent
b0df70cd2d
commit
decec8795a
5 changed files with 113 additions and 22 deletions
|
|
@ -326,6 +326,15 @@ class Backend:
|
|||
evp_md = self._evp_md_from_algorithm(algorithm)
|
||||
return evp_md != self._ffi.NULL
|
||||
|
||||
def signature_hash_supported(
|
||||
self, algorithm: hashes.HashAlgorithm
|
||||
) -> bool:
|
||||
# Dedicated check for hashing algorithm use in message digest for
|
||||
# signatures, e.g. RSA PKCS#1 v1.5 SHA1 (sha1WithRSAEncryption).
|
||||
if self._fips_enabled and isinstance(algorithm, hashes.SHA1):
|
||||
return False
|
||||
return self.hash_supported(algorithm)
|
||||
|
||||
def scrypt_supported(self) -> bool:
|
||||
if self._fips_enabled:
|
||||
return False
|
||||
|
|
@ -723,7 +732,8 @@ class Backend:
|
|||
if isinstance(padding, PKCS1v15):
|
||||
return True
|
||||
elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1):
|
||||
# SHA1 is permissible in MGF1 in FIPS
|
||||
# SHA1 is permissible in MGF1 in FIPS even when SHA1 is blocked
|
||||
# as signature algorithm.
|
||||
if self._fips_enabled and isinstance(
|
||||
padding._mgf._algorithm, hashes.SHA1
|
||||
):
|
||||
|
|
@ -854,7 +864,7 @@ class Backend:
|
|||
def dsa_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool:
|
||||
if not self.dsa_supported():
|
||||
return False
|
||||
return self.hash_supported(algorithm)
|
||||
return self.signature_hash_supported(algorithm)
|
||||
|
||||
def cmac_algorithm_supported(self, algorithm) -> bool:
|
||||
return self.cipher_supported(
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from cryptography.hazmat.primitives import hashes, serialization
|
|||
from cryptography.hazmat.primitives.asymmetric import ed25519, rsa
|
||||
from cryptography.hazmat.primitives.serialization import pkcs7
|
||||
|
||||
from .utils import skip_signature_hash
|
||||
from ...utils import load_vectors_from_file, raises_unsupported_algorithm
|
||||
|
||||
|
||||
|
|
@ -346,8 +347,7 @@ class TestPKCS7Builder:
|
|||
def test_sign_alternate_digests_der(
|
||||
self, hash_alg, expected_value, backend
|
||||
):
|
||||
if isinstance(hash_alg, hashes.SHA1) and backend._fips_enabled:
|
||||
pytest.skip("SHA1 not supported in FIPS mode")
|
||||
skip_signature_hash(backend, hash_alg)
|
||||
|
||||
data = b"hello world"
|
||||
cert, key = _load_cert_key()
|
||||
|
|
@ -375,8 +375,7 @@ class TestPKCS7Builder:
|
|||
def test_sign_alternate_digests_detached(
|
||||
self, hash_alg, expected_value, backend
|
||||
):
|
||||
if isinstance(hash_alg, hashes.SHA1) and backend._fips_enabled:
|
||||
pytest.skip("SHA1 not supported in FIPS mode")
|
||||
skip_signature_hash(backend, hash_alg)
|
||||
|
||||
data = b"hello world"
|
||||
cert, key = _load_cert_key()
|
||||
|
|
|
|||
|
|
@ -369,7 +369,12 @@ class TestRSASignature:
|
|||
),
|
||||
skip_message="Does not support PKCS1v1.5.",
|
||||
)
|
||||
@pytest.mark.skip_fips(reason="SHA1 signing not supported in FIPS mode.")
|
||||
@pytest.mark.supported(
|
||||
only_if=lambda backend: backend.signature_hash_supported(
|
||||
hashes.SHA1()
|
||||
),
|
||||
skip_message="Does not support SHA1 signature.",
|
||||
)
|
||||
def test_pkcs1v15_signing(self, backend, disable_rsa_checks, subtests):
|
||||
vectors = _flatten_pkcs1_examples(
|
||||
load_vectors_from_file(
|
||||
|
|
@ -406,7 +411,12 @@ class TestRSASignature:
|
|||
),
|
||||
skip_message="Does not support PSS.",
|
||||
)
|
||||
@pytest.mark.skip_fips(reason="SHA1 signing not supported in FIPS mode.")
|
||||
@pytest.mark.supported(
|
||||
only_if=lambda backend: backend.signature_hash_supported(
|
||||
hashes.SHA1()
|
||||
),
|
||||
skip_message="Does not support SHA1 signature.",
|
||||
)
|
||||
def test_pss_signing(self, subtests, backend):
|
||||
for private, public, example in _flatten_pkcs1_examples(
|
||||
load_vectors_from_file(
|
||||
|
|
@ -549,7 +559,7 @@ class TestRSASignature:
|
|||
private_key.sign(
|
||||
b"msg",
|
||||
"notpadding", # type: ignore[arg-type]
|
||||
hashes.SHA1(),
|
||||
hashes.SHA256(),
|
||||
)
|
||||
|
||||
@pytest.mark.supported(
|
||||
|
|
@ -686,6 +696,12 @@ class TestRSAVerification:
|
|||
),
|
||||
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_verification(self, backend, subtests):
|
||||
vectors = _flatten_pkcs1_examples(
|
||||
load_vectors_from_file(
|
||||
|
|
@ -811,6 +827,12 @@ class TestRSAVerification:
|
|||
),
|
||||
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_verification(self, subtests, backend):
|
||||
for private, public, example in _flatten_pkcs1_examples(
|
||||
load_vectors_from_file(
|
||||
|
|
@ -843,6 +865,12 @@ class TestRSAVerification:
|
|||
),
|
||||
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.",
|
||||
)
|
||||
@pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.")
|
||||
def test_invalid_pss_signature_wrong_data(self, backend):
|
||||
public_key = rsa.RSAPublicNumbers(
|
||||
|
|
@ -878,6 +906,12 @@ class TestRSAVerification:
|
|||
),
|
||||
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.",
|
||||
)
|
||||
@pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.")
|
||||
def test_invalid_pss_signature_wrong_key(self, backend):
|
||||
signature = binascii.unhexlify(
|
||||
|
|
@ -915,6 +949,12 @@ class TestRSAVerification:
|
|||
),
|
||||
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.",
|
||||
)
|
||||
@pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.")
|
||||
def test_invalid_pss_signature_data_too_large_for_modulus(self, backend):
|
||||
# 2048 bit PSS signature
|
||||
|
|
@ -941,6 +981,12 @@ class TestRSAVerification:
|
|||
hashes.SHA1(),
|
||||
)
|
||||
|
||||
@pytest.mark.supported(
|
||||
only_if=lambda backend: backend.signature_hash_supported(
|
||||
hashes.SHA1()
|
||||
),
|
||||
skip_message="Does not support SHA1 signature.",
|
||||
)
|
||||
def test_invalid_pss_signature_recover(self, backend):
|
||||
private_key = RSA_KEY_2048.private_key(backend)
|
||||
public_key = private_key.public_key()
|
||||
|
|
@ -967,7 +1013,7 @@ class TestRSAVerification:
|
|||
public_key = private_key.public_key()
|
||||
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING):
|
||||
public_key.verify(
|
||||
b"sig", b"msg", DummyAsymmetricPadding(), hashes.SHA1()
|
||||
b"sig", b"msg", DummyAsymmetricPadding(), hashes.SHA256()
|
||||
)
|
||||
|
||||
def test_padding_incorrect_type(self, backend):
|
||||
|
|
@ -978,7 +1024,7 @@ class TestRSAVerification:
|
|||
b"sig",
|
||||
b"msg",
|
||||
"notpadding", # type: ignore[arg-type]
|
||||
hashes.SHA1(),
|
||||
hashes.SHA256(),
|
||||
)
|
||||
|
||||
@pytest.mark.supported(
|
||||
|
|
@ -997,7 +1043,7 @@ class TestRSAVerification:
|
|||
padding.PSS(
|
||||
mgf=DummyMGF(), salt_length=padding.PSS.MAX_LENGTH
|
||||
),
|
||||
hashes.SHA1(),
|
||||
hashes.SHA256(),
|
||||
)
|
||||
|
||||
@pytest.mark.supported(
|
||||
|
|
@ -1041,6 +1087,12 @@ class TestRSAVerification:
|
|||
),
|
||||
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.",
|
||||
)
|
||||
@pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.")
|
||||
def test_pss_verify_salt_length_too_long(self, backend):
|
||||
signature = binascii.unhexlify(
|
||||
|
|
@ -1109,8 +1161,11 @@ class TestRSAPSSMGF1Verification:
|
|||
mgf=padding.MGF1(hashes.SHA1()),
|
||||
salt_length=padding.PSS.MAX_LENGTH,
|
||||
)
|
||||
)
|
||||
and backend.signature_hash_supported(hashes.SHA1()),
|
||||
skip_message=(
|
||||
"Does not support PSS using MGF1 with SHA1 or SHA1 signature."
|
||||
),
|
||||
skip_message="Does not support PSS using MGF1 with SHA1.",
|
||||
)(
|
||||
generate_rsa_verification_test(
|
||||
load_rsa_nist_vectors,
|
||||
|
|
@ -1242,7 +1297,7 @@ class TestRSAPSSMGF1Verification:
|
|||
class TestRSAPKCS1Verification:
|
||||
test_rsa_pkcs1v15_verify_sha1 = pytest.mark.supported(
|
||||
only_if=lambda backend: (
|
||||
backend.hash_supported(hashes.SHA1())
|
||||
backend.signature_hash_supported(hashes.SHA1())
|
||||
and backend.rsa_padding_supported(padding.PKCS1v15())
|
||||
),
|
||||
skip_message="Does not support SHA1 and PKCS1v1.5.",
|
||||
|
|
@ -1262,7 +1317,7 @@ class TestRSAPKCS1Verification:
|
|||
|
||||
test_rsa_pkcs1v15_verify_sha224 = pytest.mark.supported(
|
||||
only_if=lambda backend: (
|
||||
backend.hash_supported(hashes.SHA224())
|
||||
backend.signature_hash_supported(hashes.SHA224())
|
||||
and backend.rsa_padding_supported(padding.PKCS1v15())
|
||||
),
|
||||
skip_message="Does not support SHA224 and PKCS1v1.5.",
|
||||
|
|
@ -1282,7 +1337,7 @@ class TestRSAPKCS1Verification:
|
|||
|
||||
test_rsa_pkcs1v15_verify_sha256 = pytest.mark.supported(
|
||||
only_if=lambda backend: (
|
||||
backend.hash_supported(hashes.SHA256())
|
||||
backend.signature_hash_supported(hashes.SHA256())
|
||||
and backend.rsa_padding_supported(padding.PKCS1v15())
|
||||
),
|
||||
skip_message="Does not support SHA256 and PKCS1v1.5.",
|
||||
|
|
@ -1302,7 +1357,7 @@ class TestRSAPKCS1Verification:
|
|||
|
||||
test_rsa_pkcs1v15_verify_sha384 = pytest.mark.supported(
|
||||
only_if=lambda backend: (
|
||||
backend.hash_supported(hashes.SHA384())
|
||||
backend.signature_hash_supported(hashes.SHA384())
|
||||
and backend.rsa_padding_supported(padding.PKCS1v15())
|
||||
),
|
||||
skip_message="Does not support SHA384 and PKCS1v1.5.",
|
||||
|
|
@ -1322,7 +1377,7 @@ class TestRSAPKCS1Verification:
|
|||
|
||||
test_rsa_pkcs1v15_verify_sha512 = pytest.mark.supported(
|
||||
only_if=lambda backend: (
|
||||
backend.hash_supported(hashes.SHA512())
|
||||
backend.signature_hash_supported(hashes.SHA512())
|
||||
and backend.rsa_padding_supported(padding.PKCS1v15())
|
||||
),
|
||||
skip_message="Does not support SHA512 and PKCS1v1.5.",
|
||||
|
|
|
|||
|
|
@ -579,3 +579,8 @@ def skip_fips_traditional_openssl(backend, fmt):
|
|||
pytest.skip(
|
||||
"Traditional OpenSSL key format is not supported in FIPS mode."
|
||||
)
|
||||
|
||||
|
||||
def skip_signature_hash(backend, hash_alg: hashes.HashAlgorithm):
|
||||
if not backend.signature_hash_supported(hash_alg):
|
||||
pytest.skip(f"{hash_alg} is not a supported signature hash algorithm.")
|
||||
|
|
|
|||
|
|
@ -830,6 +830,12 @@ class TestRSACertificate:
|
|||
assert isinstance(public_key, rsa.RSAPublicKey)
|
||||
assert len(cert.signature) == public_key.key_size // 8
|
||||
|
||||
@pytest.mark.supported(
|
||||
only_if=lambda backend: backend.signature_hash_supported(
|
||||
hashes.SHA1()
|
||||
),
|
||||
skip_message="Does not support SHA-1 signature.",
|
||||
)
|
||||
def test_tbs_certificate_bytes(self, backend):
|
||||
cert = _load_cert(
|
||||
os.path.join("x509", "custom", "post2000utctime.pem"),
|
||||
|
|
@ -1616,6 +1622,12 @@ class TestRSACertificateRequest:
|
|||
b"e36181e8c4c270c354b7f52c128db1b70639823324c7ea24791b7bc3d7005f3b"
|
||||
)
|
||||
|
||||
@pytest.mark.supported(
|
||||
only_if=lambda backend: backend.signature_hash_supported(
|
||||
hashes.SHA1()
|
||||
),
|
||||
skip_message="Does not support SHA-1 signature.",
|
||||
)
|
||||
def test_tbs_certrequest_bytes(self, backend):
|
||||
request = _load_cert(
|
||||
os.path.join("x509", "requests", "rsa_sha1.pem"),
|
||||
|
|
@ -1776,8 +1788,8 @@ class TestRSACertificateRequest:
|
|||
],
|
||||
)
|
||||
def test_build_cert(self, hashalg, hashalg_oid, backend):
|
||||
if not backend.hash_supported(hashalg()):
|
||||
pytest.skip(f"{hashalg} not supported in FIPS mode")
|
||||
if not backend.signature_hash_supported(hashalg()):
|
||||
pytest.skip(f"{hashalg} signature not supported")
|
||||
|
||||
issuer_private_key = RSA_KEY_2048.private_key(backend)
|
||||
subject_private_key = RSA_KEY_2048.private_key(backend)
|
||||
|
|
@ -2714,8 +2726,8 @@ class TestCertificateBuilder:
|
|||
self, hashalg, hashalg_oid, backend
|
||||
):
|
||||
_skip_curve_unsupported(backend, ec.SECP256R1())
|
||||
if not backend.hash_supported(hashalg()):
|
||||
pytest.skip(f"{hashalg} not supported in FIPS mode")
|
||||
if not backend.signature_hash_supported(hashalg()):
|
||||
pytest.skip(f"{hashalg} signature not supported")
|
||||
|
||||
issuer_private_key = ec.generate_private_key(ec.SECP256R1(), backend)
|
||||
subject_private_key = ec.generate_private_key(ec.SECP256R1(), backend)
|
||||
|
|
@ -4389,6 +4401,12 @@ class TestCertificateSigningRequestBuilder:
|
|||
skip_message="Does not support DSA.",
|
||||
)
|
||||
class TestDSACertificate:
|
||||
@pytest.mark.supported(
|
||||
only_if=lambda backend: backend.signature_hash_supported(
|
||||
hashes.SHA1()
|
||||
),
|
||||
skip_message="Does not support SHA-1 signature.",
|
||||
)
|
||||
def test_load_dsa_cert(self, backend):
|
||||
cert = _load_cert(
|
||||
os.path.join("x509", "custom", "dsa_selfsigned_ca.pem"),
|
||||
|
|
@ -4517,6 +4535,10 @@ class TestDSACertificate:
|
|||
only_if=lambda backend: backend.dsa_supported(),
|
||||
skip_message="Does not support DSA.",
|
||||
)
|
||||
@pytest.mark.supported(
|
||||
only_if=lambda backend: backend.signature_hash_supported(hashes.SHA1()),
|
||||
skip_message="Does not support SHA-1 signature.",
|
||||
)
|
||||
class TestDSACertificateRequest:
|
||||
@pytest.mark.parametrize(
|
||||
("path", "loader_func"),
|
||||
|
|
|
|||
Loading…
Reference in a new issue