Skip to content
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

Remove deprecated support for x.509 signing with SHA1 and MD5 #7573

Merged
merged 1 commit into from
Sep 7, 2022
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
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ Changelog
and
:meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.from_encoded_point`
should be used instead.
* **BACKWARDS INCOMPATIBLE:** Support for using MD5 or SHA1 in
:class:`~cryptography.x509.CertificateBuilder` and
other X.509 builders has been removed.

.. _v38-0-0:

Expand Down
1 change: 0 additions & 1 deletion src/cryptography/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class CryptographyDeprecationWarning(UserWarning):
DeprecatedIn35 = CryptographyDeprecationWarning
DeprecatedIn36 = CryptographyDeprecationWarning
DeprecatedIn37 = CryptographyDeprecationWarning
DeprecatedIn38 = CryptographyDeprecationWarning


def _check_bytes(name: str, value: bytes) -> None:
Expand Down
4 changes: 0 additions & 4 deletions src/rust/src/x509/oid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ pub(crate) const FRESHEST_CRL_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29,
pub(crate) const INHIBIT_ANY_POLICY_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 54);

// Signing methods
pub(crate) const ECDSA_WITH_SHA1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 10045, 4, 1);
pub(crate) const ECDSA_WITH_SHA224_OID: asn1::ObjectIdentifier =
asn1::oid!(1, 2, 840, 10045, 4, 3, 1);
pub(crate) const ECDSA_WITH_SHA256_OID: asn1::ObjectIdentifier =
Expand All @@ -61,8 +60,6 @@ pub(crate) const ECDSA_WITH_SHA3_384_OID: asn1::ObjectIdentifier =
pub(crate) const ECDSA_WITH_SHA3_512_OID: asn1::ObjectIdentifier =
asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 12);

pub(crate) const RSA_WITH_MD5_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 4);
pub(crate) const RSA_WITH_SHA1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 5);
pub(crate) const RSA_WITH_SHA224_OID: asn1::ObjectIdentifier =
asn1::oid!(1, 2, 840, 113549, 1, 1, 14);
pub(crate) const RSA_WITH_SHA256_OID: asn1::ObjectIdentifier =
Expand All @@ -80,7 +77,6 @@ pub(crate) const RSA_WITH_SHA3_384_OID: asn1::ObjectIdentifier =
pub(crate) const RSA_WITH_SHA3_512_OID: asn1::ObjectIdentifier =
asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 16);

pub(crate) const DSA_WITH_SHA1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 10040, 4, 3);
pub(crate) const DSA_WITH_SHA224_OID: asn1::ObjectIdentifier =
asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 1);
pub(crate) const DSA_WITH_SHA256_OID: asn1::ObjectIdentifier =
Expand Down
47 changes: 0 additions & 47 deletions src/rust/src/x509/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ enum KeyType {

enum HashType {
None,
Md5,
Sha1,
Sha224,
Sha256,
Sha384,
Expand Down Expand Up @@ -97,32 +95,6 @@ fn identify_hash_type(
.getattr(crate::intern!(py, "name"))?
.extract()?
{
"md5" => {
let cryptography_warning = py
.import("cryptography.utils")?
.getattr(crate::intern!(py, "DeprecatedIn38"))?;
pyo3::PyErr::warn(
py,
cryptography_warning,
"MD5 signatures are deprecated and support for them will be removed in the next version.",
1
)?;

Ok(HashType::Md5)
}
"sha1" => {
let cryptography_warning = py
.import("cryptography.utils")?
.getattr(crate::intern!(py, "DeprecatedIn38"))?;
pyo3::PyErr::warn(
py,
cryptography_warning,
"SHA1 signatures are deprecated and support for them will be removed in the next version.",
1
)?;

Ok(HashType::Sha1)
}
"sha224" => Ok(HashType::Sha224),
"sha256" => Ok(HashType::Sha256),
"sha384" => Ok(HashType::Sha384),
Expand Down Expand Up @@ -161,10 +133,6 @@ pub(crate) fn compute_signature_algorithm<'p>(
))
}

(KeyType::Ec, HashType::Sha1) => Ok(x509::AlgorithmIdentifier {
oid: (oid::ECDSA_WITH_SHA1_OID).clone(),
params: None,
}),
(KeyType::Ec, HashType::Sha224) => Ok(x509::AlgorithmIdentifier {
oid: (oid::ECDSA_WITH_SHA224_OID).clone(),
params: None,
Expand Down Expand Up @@ -198,14 +166,6 @@ pub(crate) fn compute_signature_algorithm<'p>(
params: None,
}),

(KeyType::Rsa, HashType::Md5) => Ok(x509::AlgorithmIdentifier {
oid: (oid::RSA_WITH_MD5_OID).clone(),
params: Some(*NULL_TLV),
}),
(KeyType::Rsa, HashType::Sha1) => Ok(x509::AlgorithmIdentifier {
oid: (oid::RSA_WITH_SHA1_OID).clone(),
params: Some(*NULL_TLV),
}),
(KeyType::Rsa, HashType::Sha224) => Ok(x509::AlgorithmIdentifier {
oid: (oid::RSA_WITH_SHA224_OID).clone(),
params: Some(*NULL_TLV),
Expand Down Expand Up @@ -239,10 +199,6 @@ pub(crate) fn compute_signature_algorithm<'p>(
params: Some(*NULL_TLV),
}),

(KeyType::Dsa, HashType::Sha1) => Ok(x509::AlgorithmIdentifier {
oid: (oid::DSA_WITH_SHA1_OID).clone(),
params: None,
}),
(KeyType::Dsa, HashType::Sha224) => Ok(x509::AlgorithmIdentifier {
oid: (oid::DSA_WITH_SHA224_OID).clone(),
params: None,
Expand All @@ -269,9 +225,6 @@ pub(crate) fn compute_signature_algorithm<'p>(
(_, HashType::None) => Err(pyo3::exceptions::PyTypeError::new_err(
"Algorithm must be a registered hash algorithm, not None.",
)),
(_, HashType::Md5) => Err(pyo3::exceptions::PyValueError::new_err(
"MD5 hash algorithm is only supported with RSA keys",
)),
}
}

Expand Down
69 changes: 1 addition & 68 deletions tests/x509/test_x509.py
Original file line number Diff line number Diff line change
Expand Up @@ -1856,7 +1856,6 @@ def test_hash(self, backend):
@pytest.mark.parametrize(
("hashalg", "hashalg_oid"),
[
(hashes.SHA1, x509.SignatureAlgorithmOID.RSA_WITH_SHA1),
(hashes.SHA224, x509.SignatureAlgorithmOID.RSA_WITH_SHA224),
(hashes.SHA256, x509.SignatureAlgorithmOID.RSA_WITH_SHA256),
(hashes.SHA384, x509.SignatureAlgorithmOID.RSA_WITH_SHA384),
Expand Down Expand Up @@ -2067,7 +2066,7 @@ def test_checks_for_unsupported_extensions(self, backend):
)

with pytest.raises(NotImplementedError):
builder.sign(private_key, hashes.SHA1(), backend)
builder.sign(private_key, hashes.SHA256(), backend)

def test_encode_nonstandard_aia(self, backend):
private_key = RSA_KEY_2048.private_key(backend)
Expand Down Expand Up @@ -2640,28 +2639,6 @@ def test_sign_with_unsupported_hash_ed448(self, backend):
with pytest.raises(ValueError):
builder.sign(private_key, hashes.SHA256(), backend)

@pytest.mark.supported(
only_if=lambda backend: backend.hash_supported(hashes.MD5()),
skip_message="Requires OpenSSL with MD5 support",
)
def test_sign_rsa_with_md5(self, backend):
private_key = RSA_KEY_2048.private_key(backend)
builder = x509.CertificateBuilder()
builder = (
builder.subject_name(
x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")])
)
.issuer_name(
x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")])
)
.serial_number(1)
.public_key(private_key.public_key())
.not_valid_before(datetime.datetime(2002, 1, 1, 12, 1))
.not_valid_after(datetime.datetime(2032, 1, 1, 12, 1))
)
cert = builder.sign(private_key, hashes.MD5(), backend)
assert isinstance(cert.signature_hash_algorithm, hashes.MD5)

@pytest.mark.supported(
only_if=lambda backend: backend.hash_supported(hashes.MD5()),
skip_message="Requires OpenSSL with MD5 support",
Expand Down Expand Up @@ -2728,7 +2705,6 @@ def test_sign_ec_with_md5(self, backend):
@pytest.mark.parametrize(
("hashalg", "hashalg_oid"),
[
(hashes.SHA1, x509.SignatureAlgorithmOID.DSA_WITH_SHA1),
(hashes.SHA224, x509.SignatureAlgorithmOID.DSA_WITH_SHA224),
(hashes.SHA256, x509.SignatureAlgorithmOID.DSA_WITH_SHA256),
(hashes.SHA384, x509.SignatureAlgorithmOID.DSA_WITH_SHA384),
Expand Down Expand Up @@ -2791,7 +2767,6 @@ def test_build_cert_with_dsa_private_key(
@pytest.mark.parametrize(
("hashalg", "hashalg_oid"),
[
(hashes.SHA1, x509.SignatureAlgorithmOID.ECDSA_WITH_SHA1),
(hashes.SHA224, x509.SignatureAlgorithmOID.ECDSA_WITH_SHA224),
(hashes.SHA256, x509.SignatureAlgorithmOID.ECDSA_WITH_SHA256),
(hashes.SHA384, x509.SignatureAlgorithmOID.ECDSA_WITH_SHA384),
Expand Down Expand Up @@ -3753,48 +3728,6 @@ def test_request_with_unsupported_hash_ed448(self, backend):
with pytest.raises(ValueError):
builder.sign(private_key, hashes.SHA256(), backend)

@pytest.mark.supported(
only_if=lambda backend: backend.hash_supported(hashes.MD5()),
skip_message="Requires OpenSSL with MD5 support",
)
def test_sign_rsa_with_md5(self, backend):
private_key = RSA_KEY_2048.private_key(backend)

builder = x509.CertificateSigningRequestBuilder().subject_name(
x509.Name([x509.NameAttribute(NameOID.ORGANIZATION_NAME, "PyCA")])
)
request = builder.sign(private_key, hashes.MD5(), backend)
assert isinstance(request.signature_hash_algorithm, hashes.MD5)

@pytest.mark.supported(
only_if=lambda backend: backend.hash_supported(hashes.MD5()),
skip_message="Requires OpenSSL with MD5 support",
)
@pytest.mark.supported(
only_if=lambda backend: backend.dsa_supported(),
skip_message="Does not support DSA.",
)
def test_sign_dsa_with_md5(self, backend):
private_key = DSA_KEY_2048.private_key(backend)
builder = x509.CertificateSigningRequestBuilder().subject_name(
x509.Name([x509.NameAttribute(NameOID.ORGANIZATION_NAME, "PyCA")])
)
with pytest.raises(ValueError):
builder.sign(private_key, hashes.MD5(), backend)

@pytest.mark.supported(
only_if=lambda backend: backend.hash_supported(hashes.MD5()),
skip_message="Requires OpenSSL with MD5 support",
)
def test_sign_ec_with_md5(self, backend):
_skip_curve_unsupported(backend, ec.SECP256R1())
private_key = EC_KEY_SECP256R1.private_key(backend)
builder = x509.CertificateSigningRequestBuilder().subject_name(
x509.Name([x509.NameAttribute(NameOID.ORGANIZATION_NAME, "PyCA")])
)
with pytest.raises(ValueError):
builder.sign(private_key, hashes.MD5(), backend)

def test_no_subject_name(self, backend):
private_key = RSA_KEY_2048.private_key(backend)

Expand Down