mirror of
https://github.com/saymrwulf/cryptography.git
synced 2026-05-14 20:37:55 +00:00
support RSA PSS for CRLs (#10013)
adds rsa_padding kwarg to sign and also adds signature_algorithm_parameters as a method to CRLs
This commit is contained in:
parent
9ca6fd1e15
commit
2525eb048a
6 changed files with 157 additions and 21 deletions
|
|
@ -18,12 +18,16 @@ Changelog
|
|||
values, as documented in the 41.0.2 release notes.
|
||||
* Updated the minimum supported Rust version (MSRV) to 1.63.0, from 1.56.0.
|
||||
* Support :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` for
|
||||
X.509 certificate signing requests with the keyword-only argument
|
||||
``rsa_padding`` on
|
||||
:meth:`~cryptography.x509.CertificateSigningRequestBuilder.sign`.
|
||||
X.509 certificate signing requests and certificate revocation lists with the
|
||||
keyword-only argument ``rsa_padding`` on the ``sign`` methods for
|
||||
:class:`~cryptography.x509.CertificateSigningRequestBuilder` and
|
||||
:class:`~cryptography.x509.CertificateRevocationListBuilder`.
|
||||
* Added support for obtaining X.509 certificate signing request signature
|
||||
algorithm parameters (including PSS) via
|
||||
:meth:`~cryptography.x509.CertificateSigningRequest.signature_algorithm_parameters`.
|
||||
* Added support for obtaining X.509 certificate revocation list signature
|
||||
algorithm parameters (including PSS) via
|
||||
:meth:`~cryptography.x509.CertificateRevocationList.signature_algorithm_parameters`.
|
||||
* Added `mgf` property to
|
||||
:class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS`.
|
||||
* Added `algorithm` and `mgf` properties to
|
||||
|
|
|
|||
|
|
@ -716,6 +716,27 @@ X.509 CRL (Certificate Revocation List) Object
|
|||
>>> crl.signature_algorithm_oid
|
||||
<ObjectIdentifier(oid=1.2.840.113549.1.1.11, name=sha256WithRSAEncryption)>
|
||||
|
||||
.. attribute:: signature_algorithm_parameters
|
||||
|
||||
.. versionadded:: 42.0.0
|
||||
|
||||
Returns the parameters of the signature algorithm used to sign the
|
||||
certificate revocation list. 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 the CRL signature.
|
||||
|
||||
:returns: None,
|
||||
:class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15`,
|
||||
:class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS`, or
|
||||
:class:`~cryptography.hazmat.primitives.asymmetric.ec.ECDSA`
|
||||
|
||||
.. attribute:: issuer
|
||||
|
||||
:type: :class:`Name`
|
||||
|
|
@ -1212,7 +1233,7 @@ X.509 Certificate Revocation List Builder
|
|||
obtained from an existing CRL or created with
|
||||
:class:`~cryptography.x509.RevokedCertificateBuilder`.
|
||||
|
||||
.. method:: sign(private_key, algorithm)
|
||||
.. method:: sign(private_key, algorithm, *, rsa_padding=None)
|
||||
|
||||
Sign this CRL using the CA's private key.
|
||||
|
||||
|
|
@ -1231,6 +1252,22 @@ X.509 Certificate Revocation List Builder
|
|||
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
|
||||
otherwise.
|
||||
|
||||
:param rsa_padding:
|
||||
|
||||
.. versionadded:: 42.0.0
|
||||
|
||||
This is a keyword-only argument. If ``private_key`` is an
|
||||
``RSAPrivateKey`` then this can be set to either
|
||||
:class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15` or
|
||||
:class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` to sign
|
||||
with those respective paddings. If this is ``None`` then RSA
|
||||
keys will default to ``PKCS1v15`` padding. All other key types **must**
|
||||
not pass a value other than ``None``.
|
||||
|
||||
:type rsa_padding: ``None``,
|
||||
:class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15`,
|
||||
or :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS`
|
||||
|
||||
:returns: :class:`~cryptography.x509.CertificateRevocationList`
|
||||
|
||||
X.509 Revoked Certificate Object
|
||||
|
|
|
|||
|
|
@ -24,18 +24,19 @@ def create_x509_certificate(
|
|||
builder: x509.CertificateBuilder,
|
||||
private_key: PrivateKeyTypes,
|
||||
hash_algorithm: hashes.HashAlgorithm | None,
|
||||
padding: PKCS1v15 | PSS | None,
|
||||
rsa_padding: PKCS1v15 | PSS | None,
|
||||
) -> x509.Certificate: ...
|
||||
def create_x509_csr(
|
||||
builder: x509.CertificateSigningRequestBuilder,
|
||||
private_key: PrivateKeyTypes,
|
||||
hash_algorithm: hashes.HashAlgorithm | None,
|
||||
padding: PKCS1v15 | PSS | None,
|
||||
rsa_padding: PKCS1v15 | PSS | None,
|
||||
) -> x509.CertificateSigningRequest: ...
|
||||
def create_x509_crl(
|
||||
builder: x509.CertificateRevocationListBuilder,
|
||||
private_key: PrivateKeyTypes,
|
||||
hash_algorithm: hashes.HashAlgorithm | None,
|
||||
rsa_padding: PKCS1v15 | PSS | None,
|
||||
) -> x509.CertificateRevocationList: ...
|
||||
def create_server_verifier(
|
||||
name: x509.verification.Subject,
|
||||
|
|
|
|||
|
|
@ -423,6 +423,15 @@ class CertificateRevocationList(metaclass=abc.ABCMeta):
|
|||
Returns the ObjectIdentifier of the signature algorithm.
|
||||
"""
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def signature_algorithm_parameters(
|
||||
self,
|
||||
) -> None | padding.PSS | padding.PKCS1v15 | ec.ECDSA:
|
||||
"""
|
||||
Returns the signature algorithm parameters.
|
||||
"""
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def issuer(self) -> Name:
|
||||
|
|
@ -1146,6 +1155,8 @@ class CertificateRevocationListBuilder:
|
|||
private_key: CertificateIssuerPrivateKeyTypes,
|
||||
algorithm: _AllowedHashTypes | None,
|
||||
backend: typing.Any = None,
|
||||
*,
|
||||
rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
|
||||
) -> CertificateRevocationList:
|
||||
if self._issuer_name is None:
|
||||
raise ValueError("A CRL must have an issuer name")
|
||||
|
|
@ -1156,7 +1167,15 @@ class CertificateRevocationListBuilder:
|
|||
if self._next_update is None:
|
||||
raise ValueError("A CRL must have a next update time")
|
||||
|
||||
return rust_x509.create_x509_crl(self, private_key, algorithm)
|
||||
if rsa_padding is not None:
|
||||
if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)):
|
||||
raise TypeError("Padding must be PSS or PKCS1v15")
|
||||
if not isinstance(private_key, rsa.RSAPrivateKey):
|
||||
raise TypeError("Padding is only supported for RSA keys")
|
||||
|
||||
return rust_x509.create_x509_crl(
|
||||
self, private_key, algorithm, rsa_padding
|
||||
)
|
||||
|
||||
|
||||
class RevokedCertificateBuilder:
|
||||
|
|
|
|||
|
|
@ -194,6 +194,17 @@ impl CertificateRevocationList {
|
|||
}
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn signature_algorithm_parameters<'p>(
|
||||
&'p self,
|
||||
py: pyo3::Python<'p>,
|
||||
) -> CryptographyResult<&'p pyo3::PyAny> {
|
||||
sign::identify_signature_algorithm_parameters(
|
||||
py,
|
||||
&self.owned.borrow_dependent().signature_algorithm,
|
||||
)
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn signature(&self) -> &[u8] {
|
||||
self.owned.borrow_dependent().signature_value.as_bytes()
|
||||
|
|
@ -594,13 +605,10 @@ fn create_x509_crl(
|
|||
builder: &pyo3::PyAny,
|
||||
private_key: &pyo3::PyAny,
|
||||
hash_algorithm: &pyo3::PyAny,
|
||||
rsa_padding: &pyo3::PyAny,
|
||||
) -> CryptographyResult<CertificateRevocationList> {
|
||||
let sigalg = x509::sign::compute_signature_algorithm(
|
||||
py,
|
||||
private_key,
|
||||
hash_algorithm,
|
||||
py.None().into_ref(py),
|
||||
)?;
|
||||
let sigalg =
|
||||
x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm, rsa_padding)?;
|
||||
let mut revoked_certs = vec![];
|
||||
for py_revoked_cert in builder
|
||||
.getattr(pyo3::intern!(py, "_revoked_certificates"))?
|
||||
|
|
@ -648,13 +656,8 @@ fn create_x509_crl(
|
|||
};
|
||||
|
||||
let tbs_bytes = asn1::write_single(&tbs_cert_list)?;
|
||||
let signature = x509::sign::sign_data(
|
||||
py,
|
||||
private_key,
|
||||
hash_algorithm,
|
||||
py.None().into_ref(py),
|
||||
&tbs_bytes,
|
||||
)?;
|
||||
let signature =
|
||||
x509::sign::sign_data(py, private_key, hash_algorithm, rsa_padding, &tbs_bytes)?;
|
||||
let data = asn1::write_single(&crl::CertificateRevocationList {
|
||||
tbs_cert_list,
|
||||
signature_algorithm: sigalg,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,13 @@ import pytest
|
|||
from cryptography import utils, x509
|
||||
from cryptography.exceptions import UnsupportedAlgorithm
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import ec, ed448, ed25519, rsa
|
||||
from cryptography.hazmat.primitives.asymmetric import (
|
||||
ec,
|
||||
ed448,
|
||||
ed25519,
|
||||
padding,
|
||||
rsa,
|
||||
)
|
||||
from cryptography.x509.oid import (
|
||||
AuthorityInformationAccessOID,
|
||||
NameOID,
|
||||
|
|
@ -204,6 +210,38 @@ class TestCertificateRevocationListBuilder:
|
|||
with pytest.raises(ValueError):
|
||||
builder.sign(private_key, hashes.SHA256(), backend)
|
||||
|
||||
def test_sign_invalid_padding(
|
||||
self, rsa_key_2048: rsa.RSAPrivateKey, backend
|
||||
):
|
||||
last_update = datetime.datetime(2002, 1, 1, 12, 1)
|
||||
next_update = datetime.datetime(2030, 1, 1, 12, 1)
|
||||
builder = (
|
||||
x509.CertificateRevocationListBuilder()
|
||||
.issuer_name(
|
||||
x509.Name(
|
||||
[
|
||||
x509.NameAttribute(
|
||||
NameOID.COMMON_NAME, "cryptography.io CA"
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
.last_update(last_update)
|
||||
.next_update(next_update)
|
||||
)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
builder.sign(
|
||||
rsa_key_2048,
|
||||
hashes.SHA256(),
|
||||
rsa_padding=b"notapadding", # type: ignore[arg-type]
|
||||
)
|
||||
eckey = ec.generate_private_key(ec.SECP256R1())
|
||||
with pytest.raises(TypeError):
|
||||
builder.sign(
|
||||
eckey, hashes.SHA256(), rsa_padding=padding.PKCS1v15()
|
||||
)
|
||||
|
||||
def test_sign_empty_list(self, rsa_key_2048: rsa.RSAPrivateKey, backend):
|
||||
private_key = rsa_key_2048
|
||||
last_update = datetime.datetime(2002, 1, 1, 12, 1)
|
||||
|
|
@ -235,6 +273,40 @@ class TestCertificateRevocationListBuilder:
|
|||
tzinfo=datetime.timezone.utc
|
||||
)
|
||||
|
||||
def test_sign_pss(self, rsa_key_2048: rsa.RSAPrivateKey, backend):
|
||||
private_key = rsa_key_2048
|
||||
last_update = datetime.datetime(2002, 1, 1, 12, 1)
|
||||
next_update = datetime.datetime(2030, 1, 1, 12, 1)
|
||||
builder = (
|
||||
x509.CertificateRevocationListBuilder()
|
||||
.issuer_name(
|
||||
x509.Name(
|
||||
[
|
||||
x509.NameAttribute(
|
||||
NameOID.COMMON_NAME, "cryptography.io CA"
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
.last_update(last_update)
|
||||
.next_update(next_update)
|
||||
)
|
||||
|
||||
pss = padding.PSS(
|
||||
mgf=padding.MGF1(hashes.SHA256()),
|
||||
salt_length=padding.PSS.DIGEST_LENGTH,
|
||||
)
|
||||
crl = builder.sign(private_key, hashes.SHA256(), rsa_padding=pss)
|
||||
assert len(crl) == 0
|
||||
assert isinstance(crl.signature_algorithm_parameters, padding.PSS)
|
||||
assert crl.signature_algorithm_parameters._salt_length == 32
|
||||
private_key.public_key().verify(
|
||||
crl.signature,
|
||||
crl.tbs_certlist_bytes,
|
||||
crl.signature_algorithm_parameters,
|
||||
hashes.SHA256(),
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"extension",
|
||||
[
|
||||
|
|
|
|||
Loading…
Reference in a new issue