Skip to content

Commit b999005

Browse files
authored
Backport tolerate (#9006)
* tolerate NULL params in ECDSA SHA2 AlgorithmIdentifier (#9002) * tolerate NULL params in ECDSA SHA2 AlgorithmIdentifier Java 11 does this incorrectly. It was fixed in Java16+ and they are planning to do a backport, but we'll need to tolerate this invalid encoding for a while. * test both inner and outer * changelog entry * language
1 parent c4d494f commit b999005

File tree

7 files changed

+99
-21
lines changed

7 files changed

+99
-21
lines changed

CHANGELOG.rst

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
Changelog
22
=========
33

4+
.. _v41-0-1:
5+
6+
41.0.1 - 2023-06-01
7+
~~~~~~~~~~~~~~~~~~~
8+
9+
* Temporarily allow invalid ECDSA signature algorithm parameters in X.509
10+
certificates, which are generated by older versions of Java.
11+
412
.. _v41-0-0:
513

614
41.0.0 - 2023-05-30

docs/development/test-vectors.rst

+2
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,8 @@ Custom X.509 Vectors
499499
* ``rsa_pss_sha256_no_null.pem`` - A certificate with an RSA PSS signature
500500
with no encoded ``NULL`` for the PSS hash algorithm parameters. This certificate
501501
was generated by LibreSSL.
502+
* ``ecdsa_null_alg.pem`` - A certificate with an ECDSA signature with ``NULL``
503+
algorithm parameters. This encoding is invalid, but was generated by Java 11.
502504

503505
Custom X.509 Request Vectors
504506
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

src/rust/cryptography-x509/src/common.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,18 @@ pub enum AlgorithmParameters<'a> {
4545
#[defined_by(oid::ED448_OID)]
4646
Ed448,
4747

48+
// These ECDSA algorithms should have no parameters,
49+
// but Java 11 (up to at least 11.0.19) encodes them
50+
// with NULL parameters. The JDK team is looking to
51+
// backport the fix as of June 2023.
4852
#[defined_by(oid::ECDSA_WITH_SHA224_OID)]
49-
EcDsaWithSha224,
53+
EcDsaWithSha224(Option<asn1::Null>),
5054
#[defined_by(oid::ECDSA_WITH_SHA256_OID)]
51-
EcDsaWithSha256,
55+
EcDsaWithSha256(Option<asn1::Null>),
5256
#[defined_by(oid::ECDSA_WITH_SHA384_OID)]
53-
EcDsaWithSha384,
57+
EcDsaWithSha384(Option<asn1::Null>),
5458
#[defined_by(oid::ECDSA_WITH_SHA512_OID)]
55-
EcDsaWithSha512,
59+
EcDsaWithSha512(Option<asn1::Null>),
5660

5761
#[defined_by(oid::ECDSA_WITH_SHA3_224_OID)]
5862
EcDsaWithSha3_224,

src/rust/src/x509/certificate.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::asn1::{
88
use crate::error::{CryptographyError, CryptographyResult};
99
use crate::x509::{extensions, sct, sign};
1010
use crate::{exceptions, x509};
11-
use cryptography_x509::common::Asn1ReadableOrWritable;
11+
use cryptography_x509::common::{AlgorithmParameters, Asn1ReadableOrWritable};
1212
use cryptography_x509::extensions::Extension;
1313
use cryptography_x509::extensions::{
1414
AuthorityKeyIdentifier, BasicConstraints, DisplayText, DistributionPoint,
@@ -391,6 +391,10 @@ fn load_der_x509_certificate(
391391
// determine if the serial is negative and raise a warning if it is. We want to drop support
392392
// for this sort of invalid encoding eventually.
393393
warn_if_negative_serial(py, raw.borrow_value().tbs_cert.serial.as_bytes())?;
394+
// determine if the signature algorithm has incorrect parameters and raise a warning if it
395+
// does. this is a bug in JDK11 and we want to drop support for it eventually.
396+
warn_if_invalid_ecdsa_params(py, raw.borrow_value().signature_alg.params.clone())?;
397+
warn_if_invalid_ecdsa_params(py, raw.borrow_value().tbs_cert.signature_alg.params.clone())?;
394398

395399
Ok(Certificate {
396400
raw,
@@ -413,6 +417,30 @@ fn warn_if_negative_serial(py: pyo3::Python<'_>, bytes: &'_ [u8]) -> pyo3::PyRes
413417
Ok(())
414418
}
415419

420+
fn warn_if_invalid_ecdsa_params(
421+
py: pyo3::Python<'_>,
422+
params: AlgorithmParameters<'_>,
423+
) -> pyo3::PyResult<()> {
424+
match params {
425+
AlgorithmParameters::EcDsaWithSha224(Some(..))
426+
| AlgorithmParameters::EcDsaWithSha256(Some(..))
427+
| AlgorithmParameters::EcDsaWithSha384(Some(..))
428+
| AlgorithmParameters::EcDsaWithSha512(Some(..)) => {
429+
let cryptography_warning = py
430+
.import(pyo3::intern!(py, "cryptography.utils"))?
431+
.getattr(pyo3::intern!(py, "DeprecatedIn41"))?;
432+
pyo3::PyErr::warn(
433+
py,
434+
cryptography_warning,
435+
"The parsed certificate contains a NULL parameter value in its signature algorithm parameters. This is invalid and will be rejected in a future version of cryptography. If this certificate was created via Java, please upgrade to JDK16+ or the latest JDK11 once a fix is issued. If this certificate was created in some other fashion please report the issue to the cryptography issue tracker. See https://github.com/pyca/cryptography/issues/8996 for more details.",
436+
2,
437+
)?;
438+
}
439+
_ => {}
440+
}
441+
Ok(())
442+
}
443+
416444
fn parse_display_text(
417445
py: pyo3::Python<'_>,
418446
text: DisplayText<'_>,

src/rust/src/x509/sign.rs

+28-16
Original file line numberDiff line numberDiff line change
@@ -234,19 +234,19 @@ pub(crate) fn compute_signature_algorithm<'p>(
234234

235235
(KeyType::Ec, HashType::Sha224) => Ok(common::AlgorithmIdentifier {
236236
oid: asn1::DefinedByMarker::marker(),
237-
params: common::AlgorithmParameters::EcDsaWithSha224,
237+
params: common::AlgorithmParameters::EcDsaWithSha224(None),
238238
}),
239239
(KeyType::Ec, HashType::Sha256) => Ok(common::AlgorithmIdentifier {
240240
oid: asn1::DefinedByMarker::marker(),
241-
params: common::AlgorithmParameters::EcDsaWithSha256,
241+
params: common::AlgorithmParameters::EcDsaWithSha256(None),
242242
}),
243243
(KeyType::Ec, HashType::Sha384) => Ok(common::AlgorithmIdentifier {
244244
oid: asn1::DefinedByMarker::marker(),
245-
params: common::AlgorithmParameters::EcDsaWithSha384,
245+
params: common::AlgorithmParameters::EcDsaWithSha384(None),
246246
}),
247247
(KeyType::Ec, HashType::Sha512) => Ok(common::AlgorithmIdentifier {
248248
oid: asn1::DefinedByMarker::marker(),
249-
params: common::AlgorithmParameters::EcDsaWithSha512,
249+
params: common::AlgorithmParameters::EcDsaWithSha512(None),
250250
}),
251251
(KeyType::Ec, HashType::Sha3_224) => Ok(common::AlgorithmIdentifier {
252252
oid: asn1::DefinedByMarker::marker(),
@@ -483,10 +483,10 @@ fn identify_key_type_for_algorithm_params(
483483
| common::AlgorithmParameters::RsaWithSha3_384(..)
484484
| common::AlgorithmParameters::RsaWithSha3_512(..)
485485
| common::AlgorithmParameters::RsaPss(..) => Ok(KeyType::Rsa),
486-
common::AlgorithmParameters::EcDsaWithSha224
487-
| common::AlgorithmParameters::EcDsaWithSha256
488-
| common::AlgorithmParameters::EcDsaWithSha384
489-
| common::AlgorithmParameters::EcDsaWithSha512
486+
common::AlgorithmParameters::EcDsaWithSha224(..)
487+
| common::AlgorithmParameters::EcDsaWithSha256(..)
488+
| common::AlgorithmParameters::EcDsaWithSha384(..)
489+
| common::AlgorithmParameters::EcDsaWithSha512(..)
490490
| common::AlgorithmParameters::EcDsaWithSha3_224
491491
| common::AlgorithmParameters::EcDsaWithSha3_256
492492
| common::AlgorithmParameters::EcDsaWithSha3_384
@@ -616,10 +616,10 @@ pub(crate) fn identify_signature_algorithm_parameters<'p>(
616616
.call0()?;
617617
Ok(pkcs)
618618
}
619-
common::AlgorithmParameters::EcDsaWithSha224
620-
| common::AlgorithmParameters::EcDsaWithSha256
621-
| common::AlgorithmParameters::EcDsaWithSha384
622-
| common::AlgorithmParameters::EcDsaWithSha512
619+
common::AlgorithmParameters::EcDsaWithSha224(_)
620+
| common::AlgorithmParameters::EcDsaWithSha256(_)
621+
| common::AlgorithmParameters::EcDsaWithSha384(_)
622+
| common::AlgorithmParameters::EcDsaWithSha512(_)
623623
| common::AlgorithmParameters::EcDsaWithSha3_224
624624
| common::AlgorithmParameters::EcDsaWithSha3_256
625625
| common::AlgorithmParameters::EcDsaWithSha3_384
@@ -682,10 +682,22 @@ mod tests {
682682
&common::AlgorithmParameters::RsaWithSha3_512(Some(())),
683683
KeyType::Rsa,
684684
),
685-
(&common::AlgorithmParameters::EcDsaWithSha224, KeyType::Ec),
686-
(&common::AlgorithmParameters::EcDsaWithSha256, KeyType::Ec),
687-
(&common::AlgorithmParameters::EcDsaWithSha384, KeyType::Ec),
688-
(&common::AlgorithmParameters::EcDsaWithSha512, KeyType::Ec),
685+
(
686+
&common::AlgorithmParameters::EcDsaWithSha224(None),
687+
KeyType::Ec,
688+
),
689+
(
690+
&common::AlgorithmParameters::EcDsaWithSha256(None),
691+
KeyType::Ec,
692+
),
693+
(
694+
&common::AlgorithmParameters::EcDsaWithSha384(None),
695+
KeyType::Ec,
696+
),
697+
(
698+
&common::AlgorithmParameters::EcDsaWithSha512(None),
699+
KeyType::Ec,
700+
),
689701
(&common::AlgorithmParameters::EcDsaWithSha3_224, KeyType::Ec),
690702
(&common::AlgorithmParameters::EcDsaWithSha3_256, KeyType::Ec),
691703
(&common::AlgorithmParameters::EcDsaWithSha3_384, KeyType::Ec),

tests/x509/test_x509.py

+15
Original file line numberDiff line numberDiff line change
@@ -5199,6 +5199,21 @@ def test_load_ecdsa_cert(self, backend):
51995199
cert.signature_algorithm_parameters,
52005200
)
52015201

5202+
def test_load_ecdsa_cert_null_alg_params(self, backend):
5203+
"""
5204+
This test verifies that we successfully load certificates with encoded
5205+
null parameters in the signature AlgorithmIdentifier. This is invalid,
5206+
but Java 11 (up to at least 11.0.19) generates certificates with this
5207+
encoding so we need to tolerate it at the moment.
5208+
"""
5209+
with pytest.warns(utils.DeprecatedIn41):
5210+
cert = _load_cert(
5211+
os.path.join("x509", "custom", "ecdsa_null_alg.pem"),
5212+
x509.load_pem_x509_certificate,
5213+
)
5214+
assert isinstance(cert.signature_hash_algorithm, hashes.SHA256)
5215+
assert isinstance(cert.public_key(), ec.EllipticCurvePublicKey)
5216+
52025217
def test_load_bitstring_dn(self, backend):
52035218
cert = _load_cert(
52045219
os.path.join("x509", "scottishpower-bitstring-dn.pem"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIBNDCB2aADAgECAgRnI7YfMAwGCCqGSM49BAMCBQAwDzENMAsGA1UEAxMEdGVz
3+
dDAeFw0yMzA1MzExMjI5MDNaFw0yNDA1MjUxMjI5MDNaMA8xDTALBgNVBAMTBHRl
4+
c3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS2LuMFnF5OcuYcldiufvppacg2
5+
8fF/KeJ/4QLMOTbnkatgx5wNPOUvlkzfT31MscwYyzkv1oTqe58iQ+R75C27oyEw
6+
HzAdBgNVHQ4EFgQUD6COpW8C9Ns86r2BDE0jP0teCTswDAYIKoZIzj0EAwIFAANI
7+
ADBFAiBKOlNsFpW6Bz7CK7Z5zXrCetnMiSH3NrbKSZBXJV62KQIhAKmjGu3rxlJr
8+
xXpK+Uz8AsoFJ0BlgqPpdMtTGSrDq1AN
9+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)