summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2023-05-07 15:26:45 -0500
committerGitHub <noreply@github.com>2023-05-07 20:26:45 +0000
commitb436fafa7cf43c96f66d50162ac495c99ade1f39 (patch)
tree20a69e87bbc1cc2c60c1059941b9c9e88a86adaf
parent8834b590ede72c79532ccd34857a6904c48d3634 (diff)
downloadcryptography-b436fafa7cf43c96f66d50162ac495c99ade1f39.tar.gz
add signature_algorithm_parameters to certificate (#8795)
this allows easier verification of cert signatures, but more specifically allows PSS signature verification
-rw-r--r--CHANGELOG.rst3
-rw-r--r--docs/x509/reference.rst52
-rw-r--r--src/cryptography/x509/base.py10
-rw-r--r--src/rust/cryptography-x509/src/common.rs57
-rw-r--r--src/rust/cryptography-x509/src/oid.rs13
-rw-r--r--src/rust/src/x509/certificate.rs130
-rw-r--r--tests/x509/test_x509.py92
7 files changed, 338 insertions, 19 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index fcc6f28cb..d4fd57624 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -20,6 +20,9 @@ Changelog
* Implemented support for equality checks on all asymmetric public key types.
* Added support for ``aes256-gcm@openssh.com`` encrypted keys in
:func:`~cryptography.hazmat.primitives.serialization.load_ssh_private_key`.
+* Added support for obtaining X.509 certificate signature algorithm parameters
+ (including PSS) via
+ :meth:`~cryptography.x509.Certificate.signature_algorithm_parameters`.
.. _v40-0-2:
diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst
index 71a6eb179..647666c5c 100644
--- a/docs/x509/reference.rst
+++ b/docs/x509/reference.rst
@@ -146,6 +146,30 @@ X.509 Reference
-----END CERTIFICATE-----
""".strip()
+ rsa_pss_pem_cert = b"""
+ -----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
+ -----END CERTIFICATE-----
+ """.strip()
+
Loading Certificates
~~~~~~~~~~~~~~~~~~~~
@@ -413,6 +437,34 @@ X.509 Certificate Object
>>> cert.signature_algorithm_oid
<ObjectIdentifier(oid=1.2.840.113549.1.1.11, name=sha256WithRSAEncryption)>
+ .. attribute:: signature_algorithm_parameters
+
+ .. versionadded:: 41.0.0
+
+ Returns the parameters of the signature algorithm used to sign the
+ certificate. For RSA signatures it will return either a
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15` or
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` object.
+
+ For ECDSA signatures it will
+ return an :class:`~cryptography.hazmat.primitives.asymmetric.ec.ECDSA`.
+
+ For EdDSA and DSA signatures it will return ``None``.
+
+ These objects can be used to verify signatures on the certificate.
+
+ :returns: None,
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15`,
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS`, or
+ :class:`~cryptography.hazmat.primitives.asymmetric.ec.ECDSA`
+
+ .. doctest::
+
+ >>> from cryptography.hazmat.primitives.asymmetric import padding
+ >>> pss_cert = x509.load_pem_x509_certificate(rsa_pss_pem_cert)
+ >>> isinstance(pss_cert.signature_algorithm_parameters, padding.PSS)
+ True
+
.. attribute:: extensions
:type: :class:`Extensions`
diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py
index 63eaa6bd4..64453eb70 100644
--- a/src/cryptography/x509/base.py
+++ b/src/cryptography/x509/base.py
@@ -17,6 +17,7 @@ from cryptography.hazmat.primitives.asymmetric import (
ec,
ed448,
ed25519,
+ padding,
rsa,
x448,
x25519,
@@ -234,6 +235,15 @@ class Certificate(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
+ def signature_algorithm_parameters(
+ self,
+ ) -> typing.Union[None, padding.PSS, padding.PKCS1v15, ec.ECDSA]:
+ """
+ Returns the signature algorithm parameters.
+ """
+
+ @property
+ @abc.abstractmethod
def extensions(self) -> Extensions:
"""
Returns an Extensions object.
diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs
index 9668ae237..d09971659 100644
--- a/src/rust/cryptography-x509/src/common.rs
+++ b/src/rust/cryptography-x509/src/common.rs
@@ -6,7 +6,7 @@ use crate::oid;
use asn1::Asn1DefinedByWritable;
use std::marker::PhantomData;
-#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)]
+#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone, Eq)]
pub struct AlgorithmIdentifier<'a> {
pub oid: asn1::DefinedByMarker<asn1::ObjectIdentifier>,
#[defined_by(oid)]
@@ -55,6 +55,11 @@ pub enum AlgorithmParameters<'a> {
#[defined_by(oid::ECDSA_WITH_SHA3_512_OID)]
EcDsaWithSha3_512,
+ #[defined_by(oid::RSA_WITH_SHA1_OID)]
+ RsaWithSha1(Option<asn1::Null>),
+ #[defined_by(oid::RSA_WITH_SHA1_ALT_OID)]
+ RsaWithSha1Alt(Option<asn1::Null>),
+
#[defined_by(oid::RSA_WITH_SHA224_OID)]
RsaWithSha224(Option<asn1::Null>),
#[defined_by(oid::RSA_WITH_SHA256_OID)]
@@ -73,6 +78,12 @@ pub enum AlgorithmParameters<'a> {
#[defined_by(oid::RSA_WITH_SHA3_512_OID)]
RsaWithSha3_512(Option<asn1::Null>),
+ // RsaPssParameters must be present in Certificate::tbs_cert::signature_alg::params
+ // and Certificate::signature_alg::params, but Certificate::tbs_cert::spki::algorithm::oid
+ // also uses RSASSA_PSS_OID and the params field is omitted since it has no meaning there.
+ #[defined_by(oid::RSASSA_PSS_OID)]
+ RsaPss(Option<Box<RsaPssParameters<'a>>>),
+
#[defined_by(oid::DSA_WITH_SHA224_OID)]
DsaWithSha224,
#[defined_by(oid::DSA_WITH_SHA256_OID)]
@@ -205,6 +216,50 @@ pub struct DHParams<'a> {
pub g: asn1::BigUint<'a>,
pub q: Option<asn1::BigUint<'a>>,
}
+// RSA-PSS ASN.1 default hash algorithm
+pub const PSS_SHA1_HASH_ALG: AlgorithmIdentifier<'_> = AlgorithmIdentifier {
+ oid: asn1::DefinedByMarker::marker(),
+ params: AlgorithmParameters::Sha1(()),
+};
+
+// This is defined as an AlgorithmIdentifier in RFC 4055,
+// but the mask generation algorithm **must** contain an AlgorithmIdentifier
+// in its params, so we define it this way.
+#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, Clone, PartialEq, Eq)]
+pub struct MaskGenAlgorithm<'a> {
+ pub oid: asn1::ObjectIdentifier,
+ pub params: AlgorithmIdentifier<'a>,
+}
+
+// RSA-PSS ASN.1 default mask gen algorithm
+pub const PSS_SHA1_MASK_GEN_ALG: MaskGenAlgorithm<'_> = MaskGenAlgorithm {
+ oid: oid::MGF1_OID,
+ params: PSS_SHA1_HASH_ALG,
+};
+
+// From RFC 4055 section 3.1:
+// RSASSA-PSS-params ::= SEQUENCE {
+// hashAlgorithm [0] HashAlgorithm DEFAULT
+// sha1Identifier,
+// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT
+// mgf1SHA1Identifier,
+// saltLength [2] INTEGER DEFAULT 20,
+// trailerField [3] INTEGER DEFAULT 1 }
+#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, Clone, PartialEq, Eq)]
+pub struct RsaPssParameters<'a> {
+ #[explicit(0)]
+ #[default(PSS_SHA1_HASH_ALG)]
+ pub hash_algorithm: AlgorithmIdentifier<'a>,
+ #[explicit(1)]
+ #[default(PSS_SHA1_MASK_GEN_ALG)]
+ pub mask_gen_algorithm: MaskGenAlgorithm<'a>,
+ #[explicit(2)]
+ #[default(20u16)]
+ pub salt_length: u16,
+ #[explicit(3)]
+ #[default(1u8)]
+ _trailer_field: u8,
+}
/// A VisibleString ASN.1 element whose contents is not validated as meeting the
/// requirements (visible characters of IA5), and instead is only known to be
diff --git a/src/rust/cryptography-x509/src/oid.rs b/src/rust/cryptography-x509/src/oid.rs
index b2d22ebdd..ac80b9a31 100644
--- a/src/rust/cryptography-x509/src/oid.rs
+++ b/src/rust/cryptography-x509/src/oid.rs
@@ -57,6 +57,8 @@ pub const ECDSA_WITH_SHA3_384_OID: asn1::ObjectIdentifier =
pub const ECDSA_WITH_SHA3_512_OID: asn1::ObjectIdentifier =
asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 12);
+pub const RSA_WITH_SHA1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 5);
+pub const RSA_WITH_SHA1_ALT_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 14, 3, 2, 29);
pub const RSA_WITH_SHA224_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 14);
pub const RSA_WITH_SHA256_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 11);
pub const RSA_WITH_SHA384_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 12);
@@ -84,3 +86,14 @@ pub const SHA224_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3,
pub const SHA256_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 1);
pub const SHA384_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 2);
pub const SHA512_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 3);
+pub const SHA3_224_OID: asn1::ObjectIdentifier =
+ asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 224);
+pub const SHA3_256_OID: asn1::ObjectIdentifier =
+ asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 256);
+pub const SHA3_384_OID: asn1::ObjectIdentifier =
+ asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 384);
+pub const SHA3_512_OID: asn1::ObjectIdentifier =
+ asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 512);
+
+pub const MGF1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 8);
+pub const RSASSA_PSS_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 10);
diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs
index 98f1a073f..03d8ae883 100644
--- a/src/rust/src/x509/certificate.rs
+++ b/src/rust/src/x509/certificate.rs
@@ -17,10 +17,28 @@ use cryptography_x509::extensions::{
};
use cryptography_x509::extensions::{Extension, Extensions};
use cryptography_x509::{common, name, oid};
+use once_cell::sync::Lazy;
use pyo3::{IntoPy, ToPyObject};
use std::collections::hash_map::DefaultHasher;
+use std::collections::HashMap;
use std::hash::{Hash, Hasher};
+// This is similar to a hashmap in ocsp.rs but contains more hash algorithms
+// that aren't allowable in OCSP
+static HASH_OIDS_TO_HASH: Lazy<HashMap<&asn1::ObjectIdentifier, &str>> = Lazy::new(|| {
+ let mut h = HashMap::new();
+ h.insert(&oid::SHA1_OID, "SHA1");
+ h.insert(&oid::SHA224_OID, "SHA224");
+ h.insert(&oid::SHA256_OID, "SHA256");
+ h.insert(&oid::SHA384_OID, "SHA384");
+ h.insert(&oid::SHA512_OID, "SHA512");
+ h.insert(&oid::SHA3_224_OID, "SHA3_224");
+ h.insert(&oid::SHA3_256_OID, "SHA3_256");
+ h.insert(&oid::SHA3_384_OID, "SHA3_384");
+ h.insert(&oid::SHA3_512_OID, "SHA3_512");
+ h
+});
+
#[ouroboros::self_referencing]
pub(crate) struct OwnedCertificate {
data: pyo3::Py<pyo3::types::PyBytes>,
@@ -241,15 +259,25 @@ impl Certificate {
let sig_oids_to_hash = py
.import(pyo3::intern!(py, "cryptography.hazmat._oid"))?
.getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))?;
- let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?);
- match hash_alg {
- Ok(data) => Ok(data),
- Err(_) => Err(CryptographyError::from(
- exceptions::UnsupportedAlgorithm::new_err(format!(
- "Signature algorithm OID: {} not recognized",
- self.raw.borrow_value().signature_alg.oid(),
- )),
- )),
+ match &self.raw.borrow_value().signature_alg.params {
+ common::AlgorithmParameters::RsaPss(opt_pss) => {
+ let pss = opt_pss.as_ref().ok_or_else(|| {
+ pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters")
+ })?;
+ hash_oid_py_hash(py, pss.hash_algorithm.oid().clone())
+ }
+ _ => {
+ let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?);
+ match hash_alg {
+ Ok(data) => Ok(data),
+ Err(_) => Err(CryptographyError::from(
+ exceptions::UnsupportedAlgorithm::new_err(format!(
+ "Signature algorithm OID: {} not recognized",
+ self.raw.borrow_value().signature_alg.oid()
+ )),
+ )),
+ }
+ }
}
}
@@ -259,6 +287,74 @@ impl Certificate {
}
#[getter]
+ fn signature_algorithm_parameters<'p>(
+ &'p self,
+ py: pyo3::Python<'p>,
+ ) -> CryptographyResult<&'p pyo3::PyAny> {
+ match &self.raw.borrow_value().signature_alg.params {
+ common::AlgorithmParameters::RsaPss(opt_pss) => {
+ let pss = opt_pss.as_ref().ok_or_else(|| {
+ pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters")
+ })?;
+ if pss.mask_gen_algorithm.oid != oid::MGF1_OID {
+ return Err(CryptographyError::from(
+ pyo3::exceptions::PyValueError::new_err(format!(
+ "Unsupported mask generation OID: {}",
+ pss.mask_gen_algorithm.oid
+ )),
+ ));
+ }
+ let py_mask_gen_hash_alg =
+ hash_oid_py_hash(py, pss.mask_gen_algorithm.params.oid().clone())?;
+ let padding = py.import(pyo3::intern!(
+ py,
+ "cryptography.hazmat.primitives.asymmetric.padding"
+ ))?;
+ let py_mgf = padding
+ .getattr(pyo3::intern!(py, "MGF1"))?
+ .call1((py_mask_gen_hash_alg,))?;
+ Ok(padding
+ .getattr(pyo3::intern!(py, "PSS"))?
+ .call1((py_mgf, pss.salt_length))?)
+ }
+ common::AlgorithmParameters::RsaWithSha1(_)
+ | common::AlgorithmParameters::RsaWithSha1Alt(_)
+ | common::AlgorithmParameters::RsaWithSha224(_)
+ | common::AlgorithmParameters::RsaWithSha256(_)
+ | common::AlgorithmParameters::RsaWithSha384(_)
+ | common::AlgorithmParameters::RsaWithSha512(_)
+ | common::AlgorithmParameters::RsaWithSha3_224(_)
+ | common::AlgorithmParameters::RsaWithSha3_256(_)
+ | common::AlgorithmParameters::RsaWithSha3_384(_)
+ | common::AlgorithmParameters::RsaWithSha3_512(_) => {
+ let pkcs = py
+ .import(pyo3::intern!(
+ py,
+ "cryptography.hazmat.primitives.asymmetric.padding"
+ ))?
+ .getattr(pyo3::intern!(py, "PKCS1v15"))?
+ .call0()?;
+ Ok(pkcs)
+ }
+ common::AlgorithmParameters::EcDsaWithSha224
+ | common::AlgorithmParameters::EcDsaWithSha256
+ | common::AlgorithmParameters::EcDsaWithSha384
+ | common::AlgorithmParameters::EcDsaWithSha512
+ | common::AlgorithmParameters::EcDsaWithSha3_224
+ | common::AlgorithmParameters::EcDsaWithSha3_256
+ | common::AlgorithmParameters::EcDsaWithSha3_384
+ | common::AlgorithmParameters::EcDsaWithSha3_512 => Ok(py
+ .import(pyo3::intern!(
+ py,
+ "cryptography.hazmat.primitives.asymmetric.ec"
+ ))?
+ .getattr(pyo3::intern!(py, "ECDSA"))?
+ .call1((self.signature_hash_algorithm(py)?,))?),
+ _ => Ok(py.None().into_ref(py)),
+ }
+ }
+
+ #[getter]
fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::PyObject> {
let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?;
x509::parse_and_cache_extensions(
@@ -853,6 +949,22 @@ pub fn parse_cert_ext<'p>(
}
}
+fn hash_oid_py_hash(
+ py: pyo3::Python<'_>,
+ oid: asn1::ObjectIdentifier,
+) -> CryptographyResult<&pyo3::PyAny> {
+ let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?;
+ match HASH_OIDS_TO_HASH.get(&oid) {
+ Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?),
+ None => Err(CryptographyError::from(
+ exceptions::UnsupportedAlgorithm::new_err(format!(
+ "Signature algorithm OID: {} not recognized",
+ &oid
+ )),
+ )),
+ }
+}
+
pub(crate) fn time_from_py(
py: pyo3::Python<'_>,
val: &pyo3::PyAny,
diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py
index 1de45192b..a32dfca93 100644
--- a/tests/x509/test_x509.py
+++ b/tests/x509/test_x509.py
@@ -729,15 +729,15 @@ class TestRevokedCertificate:
assert crl[2].serial_number == 3
+@pytest.mark.supported(
+ only_if=lambda backend: (
+ not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL
+ and not backend._lib.CRYPTOGRAPHY_IS_BORINGSSL
+ and not backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E
+ ),
+ skip_message="Does not support RSA PSS loading",
+)
class TestRSAPSSCertificate:
- @pytest.mark.supported(
- only_if=lambda backend: (
- not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL
- and not backend._lib.CRYPTOGRAPHY_IS_BORINGSSL
- and not backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E
- ),
- skip_message="Does not support RSA PSS loading",
- )
def test_load_cert_pub_key(self, backend):
cert = _load_cert(
os.path.join("x509", "custom", "rsa_pss_cert.pem"),
@@ -751,7 +751,47 @@ class TestRSAPSSCertificate:
assert isinstance(expected_pub_key, rsa.RSAPublicKey)
pub_key = cert.public_key()
assert isinstance(pub_key, rsa.RSAPublicKey)
- assert pub_key.public_numbers() == expected_pub_key.public_numbers()
+ assert pub_key == expected_pub_key
+ pss = cert.signature_algorithm_parameters
+ assert isinstance(pss, padding.PSS)
+ assert isinstance(pss._mgf, padding.MGF1)
+ assert isinstance(pss._mgf._algorithm, hashes.SHA256)
+ assert pss._salt_length == 222
+ assert isinstance(cert.signature_hash_algorithm, hashes.SHA256)
+ pub_key.verify(
+ cert.signature,
+ cert.tbs_certificate_bytes,
+ pss,
+ cert.signature_hash_algorithm,
+ )
+
+ def test_invalid_mgf(self, backend):
+ cert = _load_cert(
+ os.path.join("x509", "custom", "rsa_pss_cert_invalid_mgf.der"),
+ x509.load_der_x509_certificate,
+ )
+ with pytest.raises(ValueError):
+ cert.signature_algorithm_parameters
+
+ def test_unsupported_mgf_hash(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "custom", "rsa_pss_cert_unsupported_mgf_hash.der"
+ ),
+ x509.load_der_x509_certificate,
+ )
+ with pytest.raises(UnsupportedAlgorithm):
+ cert.signature_algorithm_parameters
+
+ def test_no_sig_params(self, backend):
+ cert = _load_cert(
+ os.path.join("x509", "custom", "rsa_pss_cert_no_sig_params.der"),
+ x509.load_der_x509_certificate,
+ )
+ with pytest.raises(ValueError):
+ cert.signature_algorithm_parameters
+ with pytest.raises(ValueError):
+ cert.signature_hash_algorithm
class TestRSACertificate:
@@ -768,6 +808,28 @@ class TestRSACertificate:
assert (
cert.signature_algorithm_oid == SignatureAlgorithmOID.RSA_WITH_SHA1
)
+ assert isinstance(
+ cert.signature_algorithm_parameters, padding.PKCS1v15
+ )
+
+ def test_check_pkcs1_signature_algorithm_parameters(self, backend):
+ cert = _load_cert(
+ os.path.join("x509", "custom", "ca", "rsa_ca.pem"),
+ x509.load_pem_x509_certificate,
+ )
+ assert isinstance(cert, x509.Certificate)
+ assert isinstance(
+ cert.signature_algorithm_parameters, padding.PKCS1v15
+ )
+ pk = cert.public_key()
+ assert isinstance(pk, rsa.RSAPublicKey)
+ assert cert.signature_hash_algorithm is not None
+ pk.verify(
+ cert.signature,
+ cert.tbs_certificate_bytes,
+ cert.signature_algorithm_parameters,
+ cert.signature_hash_algorithm,
+ )
def test_load_legacy_pem_header(self, backend):
cert = _load_cert(
@@ -4599,6 +4661,7 @@ class TestDSACertificate:
assert isinstance(cert.signature_hash_algorithm, hashes.SHA1)
public_key = cert.public_key()
assert isinstance(public_key, dsa.DSAPublicKey)
+ assert cert.signature_algorithm_parameters is None
num = public_key.public_numbers()
assert num.y == int(
"4c08bfe5f2d76649c80acf7d431f6ae2124b217abc8c9f6aca776ddfa94"
@@ -4847,6 +4910,15 @@ class TestECDSACertificate:
16,
)
assert isinstance(num.curve, ec.SECP384R1)
+ assert isinstance(cert.signature_algorithm_parameters, ec.ECDSA)
+ assert isinstance(
+ cert.signature_algorithm_parameters.algorithm, hashes.SHA384
+ )
+ public_key.verify(
+ cert.signature,
+ cert.tbs_certificate_bytes,
+ cert.signature_algorithm_parameters,
+ )
def test_load_bitstring_dn(self, backend):
cert = _load_cert(
@@ -5590,6 +5662,7 @@ class TestEd25519Certificate:
assert cert.serial_number == 9579446940964433301
assert cert.signature_hash_algorithm is None
assert cert.signature_algorithm_oid == SignatureAlgorithmOID.ED25519
+ assert cert.signature_algorithm_parameters is None
def test_deepcopy(self, backend):
cert = _load_cert(
@@ -5635,6 +5708,7 @@ class TestEd448Certificate:
assert cert.serial_number == 448
assert cert.signature_hash_algorithm is None
assert cert.signature_algorithm_oid == SignatureAlgorithmOID.ED448
+ assert cert.signature_algorithm_parameters is None
def test_verify_directly_issued_by_ed448(self, backend):
issuer_private_key = ed448.Ed448PrivateKey.generate()