Skip to content

FIPS fixes #12839

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

Merged
merged 9 commits into from
May 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/actions/fetch-vectors/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ runs:
with:
repository: "C2SP/wycheproof"
path: "wycheproof"
# Latest commit on the wycheproof master branch, as of Apr 06, 2025.
ref: "3bfb67fca7c7a2ef436e263da53cdabe0fa1dd36" # wycheproof-ref
# Latest commit on the wycheproof master branch, as of May 02, 2025.
ref: "df4e933efef449fc88af0c06e028d425d84a9495" # wycheproof-ref

- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
- {VERSION: "3.12", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.2.4", CONFIG_FLAGS: "no-legacy", NO_LEGACY: "0"}}
- {VERSION: "3.12", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.2.4", CONFIG_FLAGS: "no-legacy", NO_LEGACY: "1"}}
- {VERSION: "3.12", NOXSESSION: "tests", NOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.2.4"}}
- {VERSION: "3.12", NOXSESSION: "tests", NOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.5.0"}}
- {VERSION: "3.12", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.4.1"}}
- {VERSION: "3.12", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.5.0"}}
- {VERSION: "3.12", NOXSESSION: "rust,tests", OPENSSL: {TYPE: "libressl", VERSION: "3.9.2"}}
Expand Down
17 changes: 10 additions & 7 deletions src/cryptography/hazmat/backends/openssl/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,17 @@ def rsa_padding_supported(self, padding: AsymmetricPadding) -> bool:
if isinstance(padding, PKCS1v15):
return True
elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1):
# 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
# FIPS 186-4 only allows salt length == digest length for PSS
# It is technically acceptable to set an explicit salt length
# equal to the digest length and this will incorrectly fail, but
# since we don't do that in the tests and this method is
# private, we'll ignore that until we need to do otherwise.
if (
self._fips_enabled
and padding._salt_length != PSS.DIGEST_LENGTH
):
return True
else:
return self.hash_supported(padding._mgf._algorithm)
return False
return self.hash_supported(padding._mgf._algorithm)
elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1):
return self._oaep_hash_supported(
padding._mgf._algorithm
Expand Down
5 changes: 4 additions & 1 deletion tests/hazmat/backends/test_openssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ def test_rsa_padding_supported_pkcs1v15(self):
def test_rsa_padding_supported_pss(self):
assert (
backend.rsa_padding_supported(
padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0)
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.DIGEST_LENGTH,
)
)
is True
)
Expand Down
15 changes: 12 additions & 3 deletions tests/hazmat/primitives/test_rsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,11 +503,20 @@ 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.SHA256()),
salt_length=padding.PSS.MAX_LENGTH,
)
),
skip_message="Does not support PSS with these parameters.",
)
@pytest.mark.parametrize(
"hash_alg",
[hashes.SHA224(), hashes.SHA256(), hashes.SHA384(), hashes.SHA512()],
)
def test_pss_signing_sha2(self, rsa_key_2048, hash_alg, backend):
def test_pss_sha2_max_length(self, rsa_key_2048, hash_alg, backend):
_skip_pss_hash_algorithm_unsupported(backend, hash_alg)
private_key = rsa_key_2048
public_key = private_key.public_key()
Expand Down Expand Up @@ -1040,7 +1049,7 @@ def test_pss_verification(self, subtests, backend):
salt_length=padding.PSS.AUTO,
)
),
skip_message="Does not support PSS.",
skip_message="Does not support PSS with these parameters.",
)
def test_pss_verify_auto_salt_length(
self, rsa_key_2048: rsa.RSAPrivateKey, backend
Expand Down Expand Up @@ -1180,7 +1189,7 @@ def test_invalid_pss_signature_recover(
public_key = private_key.public_key()
pss_padding = padding.PSS(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH,
salt_length=padding.PSS.DIGEST_LENGTH,
)
signature = private_key.sign(b"sign me", pss_padding, hashes.SHA256())

Expand Down
33 changes: 22 additions & 11 deletions tests/wycheproof/test_rsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,25 +138,31 @@ def test_rsa_pkcs1v15_signature_generation(backend, wycheproof):
)
def test_rsa_pss_signature(backend, wycheproof):
digest = _DIGESTS[wycheproof.testgroup["sha"]]
if backend._fips_enabled and isinstance(digest, hashes.SHA1):
pytest.skip("Invalid params for FIPS. SHA1 is disallowed")

key = wycheproof.cache_value_to_group(
"cached_key",
lambda: serialization.load_der_public_key(
binascii.unhexlify(wycheproof.testgroup["keyDer"]),
),
)
assert isinstance(key, rsa.RSAPublicKey)
mgf_digest = _DIGESTS[wycheproof.testgroup["mgfSha"]]

if digest is None or mgf_digest is None:
pytest.skip(
"PSS with digest={} and MGF digest={} not supported".format(
wycheproof.testgroup["sha"],
wycheproof.testgroup["mgfSha"],
)
)
if backend._fips_enabled and (
isinstance(digest, hashes.SHA1)
or isinstance(mgf_digest, hashes.SHA1)
# FIPS 186-4 only allows salt length == digest length for PSS
or wycheproof.testgroup["sLen"] != mgf_digest.digest_size
# inner MGF1 hash must match outer hash
or wycheproof.testgroup["sha"] != wycheproof.testgroup["mgfSha"]
):
pytest.skip("Invalid params for FIPS")

key = wycheproof.cache_value_to_group(
"cached_key",
lambda: serialization.load_der_public_key(
binascii.unhexlify(wycheproof.testgroup["keyDer"]),
),
)
assert isinstance(key, rsa.RSAPublicKey)

if wycheproof.valid or wycheproof.acceptable:
key.verify(
Expand Down Expand Up @@ -202,6 +208,11 @@ def test_rsa_pss_signature(backend, wycheproof):
"rsa_oaep_misc_test.json",
)
def test_rsa_oaep_encryption(backend, wycheproof):
if backend._fips_enabled and wycheproof.has_flag("SmallIntegerCiphertext"):
pytest.skip(
"Small integer ciphertexts are rejected in OpenSSL 3.5 FIPS"
)

digest = _DIGESTS[wycheproof.testgroup["sha"]]
mgf_digest = _DIGESTS[wycheproof.testgroup["mgfSha"]]
assert digest is not None
Expand Down
16 changes: 12 additions & 4 deletions tests/x509/test_x509.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ def test_load_cert_pub_key(self, backend):
assert isinstance(pss, padding.PSS)
assert isinstance(pss._mgf, padding.MGF1)
assert isinstance(pss._mgf._algorithm, hashes.SHA256)
assert pss._salt_length == 222
assert pss._salt_length == 32
assert isinstance(cert.signature_hash_algorithm, hashes.SHA256)
pub_key.verify(
cert.signature,
Expand Down Expand Up @@ -2855,6 +2855,11 @@ def test_sign_pss_length_options(
computed_len,
backend,
):
pss = padding.PSS(
mgf=padding.MGF1(hashes.SHA256()), salt_length=padding_len
)
if not backend.rsa_padding_supported(pss):
pytest.skip("PSS padding with these parameters not supported")
builder = (
x509.CertificateBuilder()
.subject_name(
Expand All @@ -2868,9 +2873,6 @@ def test_sign_pss_length_options(
.not_valid_before(datetime.datetime(2020, 1, 1))
.not_valid_after(datetime.datetime(2038, 1, 1))
)
pss = padding.PSS(
mgf=padding.MGF1(hashes.SHA256()), salt_length=padding_len
)
cert = builder.sign(rsa_key_2048, hashes.SHA256(), rsa_padding=pss)
assert isinstance(cert.signature_algorithm_parameters, padding.PSS)
assert cert.signature_algorithm_parameters._salt_length == computed_len
Expand Down Expand Up @@ -5290,6 +5292,12 @@ def test_sign_pss_length_options(
computed_len,
backend,
):
pss = padding.PSS(
mgf=padding.MGF1(hashes.SHA256()), salt_length=padding_len
)
if not backend.rsa_padding_supported(pss):
pytest.skip("PSS padding with these parameters not supported")

builder = x509.CertificateSigningRequestBuilder().subject_name(
x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")])
)
Expand Down
38 changes: 19 additions & 19 deletions vectors/cryptography_vectors/x509/custom/rsa_pss_cert.pem
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDfTCCAjCgAwIBAgIUP4D/5rcT93vdYGPhsKf+hbes/JgwQgYJKoZIhvcNAQEK
MDWgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEF
AKIEAgIA3jAaMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcNMjIwNDMwMjAz
MTE4WhcNMzMwNDEyMjAzMTE4WjAaMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8w
ggEgMAsGCSqGSIb3DQEBCgOCAQ8AMIIBCgKCAQEAt1jpboUoNppBVamc+nA+zEjl
jn/gPbRFCvyveRd8Yr0p8y1mlmjKXcQlXcHPVM4TopgFXqDykIHXxJxLV56ysb4K
UGe0nxpmhEso5ZGUgkDIIoH0NAQAsS8rS2ZzNJcLrLGrMY6DRgFsa+G6h2DvMwgl
nsX++a8FIm7Vu+OZnfWpDEuhJU4TRtHVviJSYkFMckyYBB48k1MU+0b4pezHconZ
mMEisBFFbwarNvowf2i/tRESe3myKXfiJsZZ2UzdE3FqycSgw1tx8qV/Z8myozUW
uihIdw8TGbbsJhEeVFxQEP/DVzC6HHDI3EVpr2jPYeIE60hhZwM7jUmQscLerQID
AQABo1MwUTAdBgNVHQ4EFgQUb1QD8QEIQn5DALIAujTDATssNcQwHwYDVR0jBBgw
FoAUb1QD8QEIQn5DALIAujTDATssNcQwDwYDVR0TAQH/BAUwAwEB/zBCBgkqhkiG
9w0BAQowNaAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFl
AwQCAQUAogQCAgDeA4IBAQAvKBXlx07tdmtfhNTPn16dupBIS5344ZE4tfGSE5Ir
iA1X0bukKQ6V+6xJXGreaIw0wvwtIeI/R0JwcR114HBDqjt40vklyNSpGCJzgkfD
Q/d8JXN/MLyQrk+5F9JMy+HuZAgefAQAjugC6389Klpqx2Z1CgwmALhjIs48GnMp
Iz9vU2O6RDkMBlBRdmfkJVjhhPvJYpDDW1ic5O3pxtMoiC1tAHHMm4gzM1WCFeOh
cDNxABlvVNPTnqkOhKBmmwRaBwdvvksgeu2RyBNR0KEy44gWzYB9/Ter2t4Z8ASq
qCv8TuYr2QGaCnI2FVS5S9n6l4JNkFHqPMtuhrkr3gEz
MIIDeTCCAi2gAwIBAgIUXlaVdgeEIMp9IqY8UwE76aL54owwQQYJKoZIhvcNAQEK
MDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEF
AKIDAgEgMBkxFzAVBgNVBAMMDmNyeXB0b2dhcGh5LmlvMB4XDTI1MDUwMTE5MTcx
NVoXDTI2MDUwMTE5MTcxNVowGTEXMBUGA1UEAwwOY3J5cHRvZ2FwaHkuaW8wggEg
MAsGCSqGSIb3DQEBCgOCAQ8AMIIBCgKCAQEAt1jpboUoNppBVamc+nA+zEjljn/g
PbRFCvyveRd8Yr0p8y1mlmjKXcQlXcHPVM4TopgFXqDykIHXxJxLV56ysb4KUGe0
nxpmhEso5ZGUgkDIIoH0NAQAsS8rS2ZzNJcLrLGrMY6DRgFsa+G6h2DvMwglnsX+
+a8FIm7Vu+OZnfWpDEuhJU4TRtHVviJSYkFMckyYBB48k1MU+0b4pezHconZmMEi
sBFFbwarNvowf2i/tRESe3myKXfiJsZZ2UzdE3FqycSgw1tx8qV/Z8myozUWuihI
dw8TGbbsJhEeVFxQEP/DVzC6HHDI3EVpr2jPYeIE60hhZwM7jUmQscLerQIDAQAB
o1MwUTAdBgNVHQ4EFgQUb1QD8QEIQn5DALIAujTDATssNcQwHwYDVR0jBBgwFoAU
b1QD8QEIQn5DALIAujTDATssNcQwDwYDVR0TAQH/BAUwAwEB/zBBBgkqhkiG9w0B
AQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQC
AQUAogMCASADggEBAFQIq9+51vAjBwHapeNe6LaTfPoVrWAKBFz9oJn5rHsk1DQP
glLyi7CQYzz5ByYvA4oXMzN84iSmi500uGeG2g5gPWQJfGFdycmyCEfEzXO6xnJR
YxsHVOcBUI0iME7BnREVmHrAMY4wKRDNzF3Cau/STT3m/RTEGWZM6gMx2SeWw5c0
uUusHoStyIxM53UyydrwImauiKdFj8uDcELPP7CK+xhEqfxUg8P2q2kKfKN8ODne
7UdQ8aZBvey/n28qZimDY9Q96cjLgI6h/RkhQ/4tVNg6D3sPtUu1XEYyc5rZ97T6
x63waW4waRdIPbIfVc9s21432MVBscXZNaHopOM=
-----END CERTIFICATE-----
Loading