This commit is contained in:
Iliyan Angelov
2025-11-19 12:27:01 +02:00
parent 2043ac897c
commit 34b4c969d4
469 changed files with 26870 additions and 8329 deletions

View File

@@ -4,7 +4,7 @@
from __future__ import annotations
from cryptography.x509 import certificate_transparency
from cryptography.x509 import certificate_transparency, verification
from cryptography.x509.base import (
Attribute,
AttributeNotFound,
@@ -30,6 +30,8 @@ from cryptography.x509.base import (
)
from cryptography.x509.extensions import (
AccessDescription,
Admission,
Admissions,
AuthorityInformationAccess,
AuthorityKeyIdentifier,
BasicConstraints,
@@ -55,6 +57,7 @@ from cryptography.x509.extensions import (
KeyUsage,
MSCertificateTemplate,
NameConstraints,
NamingAuthority,
NoticeReference,
OCSPAcceptableResponses,
OCSPNoCheck,
@@ -63,6 +66,8 @@ from cryptography.x509.extensions import (
PolicyInformation,
PrecertificateSignedCertificateTimestamps,
PrecertPoison,
PrivateKeyUsagePeriod,
ProfessionInfo,
ReasonFlags,
SignedCertificateTimestamps,
SubjectAlternativeName,
@@ -97,6 +102,7 @@ from cryptography.x509.oid import (
ExtensionOID,
NameOID,
ObjectIdentifier,
PublicKeyAlgorithmOID,
SignatureAlgorithmOID,
)
@@ -110,6 +116,7 @@ OID_FRESHEST_CRL = ExtensionOID.FRESHEST_CRL
OID_INHIBIT_ANY_POLICY = ExtensionOID.INHIBIT_ANY_POLICY
OID_ISSUER_ALTERNATIVE_NAME = ExtensionOID.ISSUER_ALTERNATIVE_NAME
OID_KEY_USAGE = ExtensionOID.KEY_USAGE
OID_PRIVATE_KEY_USAGE_PERIOD = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD
OID_NAME_CONSTRAINTS = ExtensionOID.NAME_CONSTRAINTS
OID_OCSP_NO_CHECK = ExtensionOID.OCSP_NO_CHECK
OID_POLICY_CONSTRAINTS = ExtensionOID.POLICY_CONSTRAINTS
@@ -170,86 +177,94 @@ OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS
OID_OCSP = AuthorityInformationAccessOID.OCSP
__all__ = [
"certificate_transparency",
"load_pem_x509_certificate",
"load_pem_x509_certificates",
"load_der_x509_certificate",
"load_pem_x509_csr",
"load_der_x509_csr",
"load_pem_x509_crl",
"load_der_x509_crl",
"random_serial_number",
"OID_CA_ISSUERS",
"OID_OCSP",
"AccessDescription",
"Admission",
"Admissions",
"Attribute",
"AttributeNotFound",
"Attributes",
"InvalidVersion",
"DeltaCRLIndicator",
"DuplicateExtension",
"ExtensionNotFound",
"UnsupportedGeneralNameType",
"NameAttribute",
"Name",
"RelativeDistinguishedName",
"ObjectIdentifier",
"ExtensionType",
"Extensions",
"Extension",
"ExtendedKeyUsage",
"FreshestCRL",
"IssuingDistributionPoint",
"TLSFeature",
"TLSFeatureType",
"OCSPAcceptableResponses",
"OCSPNoCheck",
"BasicConstraints",
"CRLNumber",
"KeyUsage",
"AuthorityInformationAccess",
"SubjectInformationAccess",
"AccessDescription",
"CertificatePolicies",
"PolicyInformation",
"UserNotice",
"NoticeReference",
"SubjectKeyIdentifier",
"NameConstraints",
"CRLDistributionPoints",
"DistributionPoint",
"ReasonFlags",
"InhibitAnyPolicy",
"SubjectAlternativeName",
"IssuerAlternativeName",
"AuthorityKeyIdentifier",
"GeneralNames",
"GeneralName",
"RFC822Name",
"DNSName",
"UniformResourceIdentifier",
"RegisteredID",
"DirectoryName",
"IPAddress",
"OtherName",
"BasicConstraints",
"CRLDistributionPoints",
"CRLNumber",
"CRLReason",
"Certificate",
"CertificateBuilder",
"CertificateIssuer",
"CertificatePolicies",
"CertificateRevocationList",
"CertificateRevocationListBuilder",
"CertificateSigningRequest",
"CertificateSigningRequestBuilder",
"DNSName",
"DeltaCRLIndicator",
"DirectoryName",
"DistributionPoint",
"DuplicateExtension",
"ExtendedKeyUsage",
"Extension",
"ExtensionNotFound",
"ExtensionType",
"Extensions",
"FreshestCRL",
"GeneralName",
"GeneralNames",
"IPAddress",
"InhibitAnyPolicy",
"InvalidVersion",
"InvalidityDate",
"IssuerAlternativeName",
"IssuingDistributionPoint",
"KeyUsage",
"MSCertificateTemplate",
"Name",
"NameAttribute",
"NameConstraints",
"NameOID",
"NamingAuthority",
"NoticeReference",
"OCSPAcceptableResponses",
"OCSPNoCheck",
"OCSPNonce",
"ObjectIdentifier",
"OtherName",
"PolicyConstraints",
"PolicyInformation",
"PrecertPoison",
"PrecertificateSignedCertificateTimestamps",
"PrivateKeyUsagePeriod",
"ProfessionInfo",
"PublicKeyAlgorithmOID",
"RFC822Name",
"ReasonFlags",
"RegisteredID",
"RelativeDistinguishedName",
"RevokedCertificate",
"RevokedCertificateBuilder",
"CertificateSigningRequestBuilder",
"CertificateBuilder",
"Version",
"OID_CA_ISSUERS",
"OID_OCSP",
"CertificateIssuer",
"CRLReason",
"InvalidityDate",
"UnrecognizedExtension",
"PolicyConstraints",
"PrecertificateSignedCertificateTimestamps",
"PrecertPoison",
"OCSPNonce",
"SignedCertificateTimestamps",
"SignatureAlgorithmOID",
"NameOID",
"MSCertificateTemplate",
"SignedCertificateTimestamps",
"SubjectAlternativeName",
"SubjectInformationAccess",
"SubjectKeyIdentifier",
"TLSFeature",
"TLSFeatureType",
"UniformResourceIdentifier",
"UnrecognizedExtension",
"UnsupportedGeneralNameType",
"UserNotice",
"Version",
"certificate_transparency",
"load_der_x509_certificate",
"load_der_x509_crl",
"load_der_x509_csr",
"load_pem_x509_certificate",
"load_pem_x509_certificates",
"load_pem_x509_crl",
"load_pem_x509_csr",
"random_serial_number",
"verification",
"verification",
]

View File

@@ -8,10 +8,12 @@ import abc
import datetime
import os
import typing
import warnings
from collections.abc import Iterable
from cryptography import utils
from cryptography.hazmat.bindings._rust import x509 as rust_x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import (
dsa,
ec,
@@ -24,7 +26,6 @@ from cryptography.hazmat.primitives.asymmetric import (
)
from cryptography.hazmat.primitives.asymmetric.types import (
CertificateIssuerPrivateKeyTypes,
CertificateIssuerPublicKeyTypes,
CertificatePublicKeyTypes,
)
from cryptography.x509.extensions import (
@@ -60,7 +61,7 @@ class AttributeNotFound(Exception):
def _reject_duplicate_extension(
extension: Extension[ExtensionType],
extensions: typing.List[Extension[ExtensionType]],
extensions: list[Extension[ExtensionType]],
) -> None:
# This is quadratic in the number of extensions
for e in extensions:
@@ -70,9 +71,7 @@ def _reject_duplicate_extension(
def _reject_duplicate_attribute(
oid: ObjectIdentifier,
attributes: typing.List[
typing.Tuple[ObjectIdentifier, bytes, typing.Optional[int]]
],
attributes: list[tuple[ObjectIdentifier, bytes, int | None]],
) -> None:
# This is quadratic in the number of attributes
for attr_oid, _, _ in attributes:
@@ -133,7 +132,7 @@ class Attribute:
class Attributes:
def __init__(
self,
attributes: typing.Iterable[Attribute],
attributes: Iterable[Attribute],
) -> None:
self._attributes = list(attributes)
@@ -161,145 +160,7 @@ class InvalidVersion(Exception):
self.parsed_version = parsed_version
class Certificate(metaclass=abc.ABCMeta):
@abc.abstractmethod
def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes:
"""
Returns bytes using digest passed.
"""
@property
@abc.abstractmethod
def serial_number(self) -> int:
"""
Returns certificate serial number
"""
@property
@abc.abstractmethod
def version(self) -> Version:
"""
Returns the certificate version
"""
@abc.abstractmethod
def public_key(self) -> CertificatePublicKeyTypes:
"""
Returns the public key
"""
@property
@abc.abstractmethod
def not_valid_before(self) -> datetime.datetime:
"""
Not before time (represented as UTC datetime)
"""
@property
@abc.abstractmethod
def not_valid_after(self) -> datetime.datetime:
"""
Not after time (represented as UTC datetime)
"""
@property
@abc.abstractmethod
def issuer(self) -> Name:
"""
Returns the issuer name object.
"""
@property
@abc.abstractmethod
def subject(self) -> Name:
"""
Returns the subject name object.
"""
@property
@abc.abstractmethod
def signature_hash_algorithm(
self,
) -> typing.Optional[hashes.HashAlgorithm]:
"""
Returns a HashAlgorithm corresponding to the type of the digest signed
in the certificate.
"""
@property
@abc.abstractmethod
def signature_algorithm_oid(self) -> ObjectIdentifier:
"""
Returns the ObjectIdentifier of the signature algorithm.
"""
@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.
"""
@property
@abc.abstractmethod
def signature(self) -> bytes:
"""
Returns the signature bytes.
"""
@property
@abc.abstractmethod
def tbs_certificate_bytes(self) -> bytes:
"""
Returns the tbsCertificate payload bytes as defined in RFC 5280.
"""
@property
@abc.abstractmethod
def tbs_precertificate_bytes(self) -> bytes:
"""
Returns the tbsCertificate payload bytes with the SCT list extension
stripped.
"""
@abc.abstractmethod
def __eq__(self, other: object) -> bool:
"""
Checks equality.
"""
@abc.abstractmethod
def __hash__(self) -> int:
"""
Computes a hash.
"""
@abc.abstractmethod
def public_bytes(self, encoding: serialization.Encoding) -> bytes:
"""
Serializes the certificate to PEM or DER format.
"""
@abc.abstractmethod
def verify_directly_issued_by(self, issuer: Certificate) -> None:
"""
This method verifies that certificate issuer name matches the
issuer subject name and that the certificate is signed by the
issuer's private key. No other validation is performed.
"""
# Runtime isinstance checks need this since the rust class is not a subclass.
Certificate.register(rust_x509.Certificate)
Certificate = rust_x509.Certificate
class RevokedCertificate(metaclass=abc.ABCMeta):
@@ -317,6 +178,14 @@ class RevokedCertificate(metaclass=abc.ABCMeta):
Returns the date of when this certificate was revoked.
"""
@property
@abc.abstractmethod
def revocation_date_utc(self) -> datetime.datetime:
"""
Returns the date of when this certificate was revoked as a non-naive
UTC datetime.
"""
@property
@abc.abstractmethod
def extensions(self) -> Extensions:
@@ -346,290 +215,45 @@ class _RawRevokedCertificate(RevokedCertificate):
@property
def revocation_date(self) -> datetime.datetime:
warnings.warn(
"Properties that return a naïve datetime object have been "
"deprecated. Please switch to revocation_date_utc.",
utils.DeprecatedIn42,
stacklevel=2,
)
return self._revocation_date
@property
def revocation_date_utc(self) -> datetime.datetime:
return self._revocation_date.replace(tzinfo=datetime.timezone.utc)
@property
def extensions(self) -> Extensions:
return self._extensions
class CertificateRevocationList(metaclass=abc.ABCMeta):
@abc.abstractmethod
def public_bytes(self, encoding: serialization.Encoding) -> bytes:
"""
Serializes the CRL to PEM or DER format.
"""
@abc.abstractmethod
def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes:
"""
Returns bytes using digest passed.
"""
@abc.abstractmethod
def get_revoked_certificate_by_serial_number(
self, serial_number: int
) -> typing.Optional[RevokedCertificate]:
"""
Returns an instance of RevokedCertificate or None if the serial_number
is not in the CRL.
"""
@property
@abc.abstractmethod
def signature_hash_algorithm(
self,
) -> typing.Optional[hashes.HashAlgorithm]:
"""
Returns a HashAlgorithm corresponding to the type of the digest signed
in the certificate.
"""
@property
@abc.abstractmethod
def signature_algorithm_oid(self) -> ObjectIdentifier:
"""
Returns the ObjectIdentifier of the signature algorithm.
"""
@property
@abc.abstractmethod
def issuer(self) -> Name:
"""
Returns the X509Name with the issuer of this CRL.
"""
@property
@abc.abstractmethod
def next_update(self) -> typing.Optional[datetime.datetime]:
"""
Returns the date of next update for this CRL.
"""
@property
@abc.abstractmethod
def last_update(self) -> datetime.datetime:
"""
Returns the date of last update for this CRL.
"""
@property
@abc.abstractmethod
def extensions(self) -> Extensions:
"""
Returns an Extensions object containing a list of CRL extensions.
"""
@property
@abc.abstractmethod
def signature(self) -> bytes:
"""
Returns the signature bytes.
"""
@property
@abc.abstractmethod
def tbs_certlist_bytes(self) -> bytes:
"""
Returns the tbsCertList payload bytes as defined in RFC 5280.
"""
@abc.abstractmethod
def __eq__(self, other: object) -> bool:
"""
Checks equality.
"""
@abc.abstractmethod
def __len__(self) -> int:
"""
Number of revoked certificates in the CRL.
"""
@typing.overload
def __getitem__(self, idx: int) -> RevokedCertificate:
...
@typing.overload
def __getitem__(self, idx: slice) -> typing.List[RevokedCertificate]:
...
@abc.abstractmethod
def __getitem__(
self, idx: typing.Union[int, slice]
) -> typing.Union[RevokedCertificate, typing.List[RevokedCertificate]]:
"""
Returns a revoked certificate (or slice of revoked certificates).
"""
@abc.abstractmethod
def __iter__(self) -> typing.Iterator[RevokedCertificate]:
"""
Iterator over the revoked certificates
"""
@abc.abstractmethod
def is_signature_valid(
self, public_key: CertificateIssuerPublicKeyTypes
) -> bool:
"""
Verifies signature of revocation list against given public key.
"""
CertificateRevocationList = rust_x509.CertificateRevocationList
CertificateSigningRequest = rust_x509.CertificateSigningRequest
CertificateRevocationList.register(rust_x509.CertificateRevocationList)
load_pem_x509_certificate = rust_x509.load_pem_x509_certificate
load_der_x509_certificate = rust_x509.load_der_x509_certificate
load_pem_x509_certificates = rust_x509.load_pem_x509_certificates
class CertificateSigningRequest(metaclass=abc.ABCMeta):
@abc.abstractmethod
def __eq__(self, other: object) -> bool:
"""
Checks equality.
"""
load_pem_x509_csr = rust_x509.load_pem_x509_csr
load_der_x509_csr = rust_x509.load_der_x509_csr
@abc.abstractmethod
def __hash__(self) -> int:
"""
Computes a hash.
"""
@abc.abstractmethod
def public_key(self) -> CertificatePublicKeyTypes:
"""
Returns the public key
"""
@property
@abc.abstractmethod
def subject(self) -> Name:
"""
Returns the subject name object.
"""
@property
@abc.abstractmethod
def signature_hash_algorithm(
self,
) -> typing.Optional[hashes.HashAlgorithm]:
"""
Returns a HashAlgorithm corresponding to the type of the digest signed
in the certificate.
"""
@property
@abc.abstractmethod
def signature_algorithm_oid(self) -> ObjectIdentifier:
"""
Returns the ObjectIdentifier of the signature algorithm.
"""
@property
@abc.abstractmethod
def extensions(self) -> Extensions:
"""
Returns the extensions in the signing request.
"""
@property
@abc.abstractmethod
def attributes(self) -> Attributes:
"""
Returns an Attributes object.
"""
@abc.abstractmethod
def public_bytes(self, encoding: serialization.Encoding) -> bytes:
"""
Encodes the request to PEM or DER format.
"""
@property
@abc.abstractmethod
def signature(self) -> bytes:
"""
Returns the signature bytes.
"""
@property
@abc.abstractmethod
def tbs_certrequest_bytes(self) -> bytes:
"""
Returns the PKCS#10 CertificationRequestInfo bytes as defined in RFC
2986.
"""
@property
@abc.abstractmethod
def is_signature_valid(self) -> bool:
"""
Verifies signature of signing request.
"""
@abc.abstractmethod
def get_attribute_for_oid(self, oid: ObjectIdentifier) -> bytes:
"""
Get the attribute value for a given OID.
"""
# Runtime isinstance checks need this since the rust class is not a subclass.
CertificateSigningRequest.register(rust_x509.CertificateSigningRequest)
# Backend argument preserved for API compatibility, but ignored.
def load_pem_x509_certificate(
data: bytes, backend: typing.Any = None
) -> Certificate:
return rust_x509.load_pem_x509_certificate(data)
def load_pem_x509_certificates(data: bytes) -> typing.List[Certificate]:
return rust_x509.load_pem_x509_certificates(data)
# Backend argument preserved for API compatibility, but ignored.
def load_der_x509_certificate(
data: bytes, backend: typing.Any = None
) -> Certificate:
return rust_x509.load_der_x509_certificate(data)
# Backend argument preserved for API compatibility, but ignored.
def load_pem_x509_csr(
data: bytes, backend: typing.Any = None
) -> CertificateSigningRequest:
return rust_x509.load_pem_x509_csr(data)
# Backend argument preserved for API compatibility, but ignored.
def load_der_x509_csr(
data: bytes, backend: typing.Any = None
) -> CertificateSigningRequest:
return rust_x509.load_der_x509_csr(data)
# Backend argument preserved for API compatibility, but ignored.
def load_pem_x509_crl(
data: bytes, backend: typing.Any = None
) -> CertificateRevocationList:
return rust_x509.load_pem_x509_crl(data)
# Backend argument preserved for API compatibility, but ignored.
def load_der_x509_crl(
data: bytes, backend: typing.Any = None
) -> CertificateRevocationList:
return rust_x509.load_der_x509_crl(data)
load_pem_x509_crl = rust_x509.load_pem_x509_crl
load_der_x509_crl = rust_x509.load_der_x509_crl
class CertificateSigningRequestBuilder:
def __init__(
self,
subject_name: typing.Optional[Name] = None,
extensions: typing.List[Extension[ExtensionType]] = [],
attributes: typing.List[
typing.Tuple[ObjectIdentifier, bytes, typing.Optional[int]]
] = [],
subject_name: Name | None = None,
extensions: list[Extension[ExtensionType]] = [],
attributes: list[tuple[ObjectIdentifier, bytes, int | None]] = [],
):
"""
Creates an empty X.509 certificate request (v1).
@@ -664,7 +288,7 @@ class CertificateSigningRequestBuilder:
return CertificateSigningRequestBuilder(
self._subject_name,
self._extensions + [extension],
[*self._extensions, extension],
self._attributes,
)
@@ -673,7 +297,7 @@ class CertificateSigningRequestBuilder:
oid: ObjectIdentifier,
value: bytes,
*,
_tag: typing.Optional[_ASN1Type] = None,
_tag: _ASN1Type | None = None,
) -> CertificateSigningRequestBuilder:
"""
Adds an X.509 attribute with an OID and associated value.
@@ -697,35 +321,57 @@ class CertificateSigningRequestBuilder:
return CertificateSigningRequestBuilder(
self._subject_name,
self._extensions,
self._attributes + [(oid, value, tag)],
[*self._attributes, (oid, value, tag)],
)
def sign(
self,
private_key: CertificateIssuerPrivateKeyTypes,
algorithm: typing.Optional[_AllowedHashTypes],
algorithm: _AllowedHashTypes | None,
backend: typing.Any = None,
*,
rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
ecdsa_deterministic: bool | None = None,
) -> CertificateSigningRequest:
"""
Signs the request using the requestor's private key.
"""
if self._subject_name is None:
raise ValueError("A CertificateSigningRequest must have a subject")
return rust_x509.create_x509_csr(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")
if ecdsa_deterministic is not None:
if not isinstance(private_key, ec.EllipticCurvePrivateKey):
raise TypeError(
"Deterministic ECDSA is only supported for EC keys"
)
return rust_x509.create_x509_csr(
self,
private_key,
algorithm,
rsa_padding,
ecdsa_deterministic,
)
class CertificateBuilder:
_extensions: typing.List[Extension[ExtensionType]]
_extensions: list[Extension[ExtensionType]]
def __init__(
self,
issuer_name: typing.Optional[Name] = None,
subject_name: typing.Optional[Name] = None,
public_key: typing.Optional[CertificatePublicKeyTypes] = None,
serial_number: typing.Optional[int] = None,
not_valid_before: typing.Optional[datetime.datetime] = None,
not_valid_after: typing.Optional[datetime.datetime] = None,
extensions: typing.List[Extension[ExtensionType]] = [],
issuer_name: Name | None = None,
subject_name: Name | None = None,
public_key: CertificatePublicKeyTypes | None = None,
serial_number: int | None = None,
not_valid_before: datetime.datetime | None = None,
not_valid_after: datetime.datetime | None = None,
extensions: list[Extension[ExtensionType]] = [],
) -> None:
self._version = Version.v3
self._issuer_name = issuer_name
@@ -824,7 +470,7 @@ class CertificateBuilder:
# zero.
if number.bit_length() >= 160: # As defined in RFC 5280
raise ValueError(
"The serial number should not be more than 159 " "bits."
"The serial number should not be more than 159 bits."
)
return CertificateBuilder(
self._issuer_name,
@@ -876,8 +522,7 @@ class CertificateBuilder:
time = _convert_to_naive_utc_time(time)
if time < _EARLIEST_UTC_TIME:
raise ValueError(
"The not valid after date must be on or after"
" 1950 January 1."
"The not valid after date must be on or after 1950 January 1."
)
if (
self._not_valid_before is not None
@@ -916,18 +561,17 @@ class CertificateBuilder:
self._serial_number,
self._not_valid_before,
self._not_valid_after,
self._extensions + [extension],
[*self._extensions, extension],
)
def sign(
self,
private_key: CertificateIssuerPrivateKeyTypes,
algorithm: typing.Optional[_AllowedHashTypes],
algorithm: _AllowedHashTypes | None,
backend: typing.Any = None,
*,
rsa_padding: typing.Optional[
typing.Union[padding.PSS, padding.PKCS1v15]
] = None,
rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
ecdsa_deterministic: bool | None = None,
) -> Certificate:
"""
Signs the certificate using the CA's private key.
@@ -956,22 +600,32 @@ class CertificateBuilder:
if not isinstance(private_key, rsa.RSAPrivateKey):
raise TypeError("Padding is only supported for RSA keys")
if ecdsa_deterministic is not None:
if not isinstance(private_key, ec.EllipticCurvePrivateKey):
raise TypeError(
"Deterministic ECDSA is only supported for EC keys"
)
return rust_x509.create_x509_certificate(
self, private_key, algorithm, rsa_padding
self,
private_key,
algorithm,
rsa_padding,
ecdsa_deterministic,
)
class CertificateRevocationListBuilder:
_extensions: typing.List[Extension[ExtensionType]]
_revoked_certificates: typing.List[RevokedCertificate]
_extensions: list[Extension[ExtensionType]]
_revoked_certificates: list[RevokedCertificate]
def __init__(
self,
issuer_name: typing.Optional[Name] = None,
last_update: typing.Optional[datetime.datetime] = None,
next_update: typing.Optional[datetime.datetime] = None,
extensions: typing.List[Extension[ExtensionType]] = [],
revoked_certificates: typing.List[RevokedCertificate] = [],
issuer_name: Name | None = None,
last_update: datetime.datetime | None = None,
next_update: datetime.datetime | None = None,
extensions: list[Extension[ExtensionType]] = [],
revoked_certificates: list[RevokedCertificate] = [],
):
self._issuer_name = issuer_name
self._last_update = last_update
@@ -1004,7 +658,7 @@ class CertificateRevocationListBuilder:
last_update = _convert_to_naive_utc_time(last_update)
if last_update < _EARLIEST_UTC_TIME:
raise ValueError(
"The last update date must be on or after" " 1950 January 1."
"The last update date must be on or after 1950 January 1."
)
if self._next_update is not None and last_update > self._next_update:
raise ValueError(
@@ -1028,7 +682,7 @@ class CertificateRevocationListBuilder:
next_update = _convert_to_naive_utc_time(next_update)
if next_update < _EARLIEST_UTC_TIME:
raise ValueError(
"The last update date must be on or after" " 1950 January 1."
"The last update date must be on or after 1950 January 1."
)
if self._last_update is not None and next_update < self._last_update:
raise ValueError(
@@ -1057,7 +711,7 @@ class CertificateRevocationListBuilder:
self._issuer_name,
self._last_update,
self._next_update,
self._extensions + [extension],
[*self._extensions, extension],
self._revoked_certificates,
)
@@ -1075,14 +729,17 @@ class CertificateRevocationListBuilder:
self._last_update,
self._next_update,
self._extensions,
self._revoked_certificates + [revoked_certificate],
[*self._revoked_certificates, revoked_certificate],
)
def sign(
self,
private_key: CertificateIssuerPrivateKeyTypes,
algorithm: typing.Optional[_AllowedHashTypes],
algorithm: _AllowedHashTypes | None,
backend: typing.Any = None,
*,
rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
ecdsa_deterministic: bool | None = None,
) -> CertificateRevocationList:
if self._issuer_name is None:
raise ValueError("A CRL must have an issuer name")
@@ -1093,15 +750,33 @@ 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")
if ecdsa_deterministic is not None:
if not isinstance(private_key, ec.EllipticCurvePrivateKey):
raise TypeError(
"Deterministic ECDSA is only supported for EC keys"
)
return rust_x509.create_x509_crl(
self,
private_key,
algorithm,
rsa_padding,
ecdsa_deterministic,
)
class RevokedCertificateBuilder:
def __init__(
self,
serial_number: typing.Optional[int] = None,
revocation_date: typing.Optional[datetime.datetime] = None,
extensions: typing.List[Extension[ExtensionType]] = [],
serial_number: int | None = None,
revocation_date: datetime.datetime | None = None,
extensions: list[Extension[ExtensionType]] = [],
):
self._serial_number = serial_number
self._revocation_date = revocation_date
@@ -1119,7 +794,7 @@ class RevokedCertificateBuilder:
# zero.
if number.bit_length() >= 160: # As defined in RFC 5280
raise ValueError(
"The serial number should not be more than 159 " "bits."
"The serial number should not be more than 159 bits."
)
return RevokedCertificateBuilder(
number, self._revocation_date, self._extensions
@@ -1135,7 +810,7 @@ class RevokedCertificateBuilder:
time = _convert_to_naive_utc_time(time)
if time < _EARLIEST_UTC_TIME:
raise ValueError(
"The revocation date must be on or after" " 1950 January 1."
"The revocation date must be on or after 1950 January 1."
)
return RevokedCertificateBuilder(
self._serial_number, time, self._extensions
@@ -1152,7 +827,7 @@ class RevokedCertificateBuilder:
return RevokedCertificateBuilder(
self._serial_number,
self._revocation_date,
self._extensions + [extension],
[*self._extensions, extension],
)
def build(self, backend: typing.Any = None) -> RevokedCertificate:

View File

@@ -4,12 +4,8 @@
from __future__ import annotations
import abc
import datetime
from cryptography import utils
from cryptography.hazmat.bindings._rust import x509 as rust_x509
from cryptography.hazmat.primitives.hashes import HashAlgorithm
class LogEntryType(utils.Enum):
@@ -36,62 +32,4 @@ class SignatureAlgorithm(utils.Enum):
ECDSA = 3
class SignedCertificateTimestamp(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
def version(self) -> Version:
"""
Returns the SCT version.
"""
@property
@abc.abstractmethod
def log_id(self) -> bytes:
"""
Returns an identifier indicating which log this SCT is for.
"""
@property
@abc.abstractmethod
def timestamp(self) -> datetime.datetime:
"""
Returns the timestamp for this SCT.
"""
@property
@abc.abstractmethod
def entry_type(self) -> LogEntryType:
"""
Returns whether this is an SCT for a certificate or pre-certificate.
"""
@property
@abc.abstractmethod
def signature_hash_algorithm(self) -> HashAlgorithm:
"""
Returns the hash algorithm used for the SCT's signature.
"""
@property
@abc.abstractmethod
def signature_algorithm(self) -> SignatureAlgorithm:
"""
Returns the signing algorithm used for the SCT's signature.
"""
@property
@abc.abstractmethod
def signature(self) -> bytes:
"""
Returns the signature for this SCT.
"""
@property
@abc.abstractmethod
def extension_bytes(self) -> bytes:
"""
Returns the raw bytes of any extensions for this SCT.
"""
SignedCertificateTimestamp.register(rust_x509.Sct)
SignedCertificateTimestamp = rust_x509.Sct

View File

@@ -269,9 +269,7 @@ class OtherName(GeneralName):
return self._value
def __repr__(self) -> str:
return "<OtherName(type_id={}, value={!r})>".format(
self.type_id, self.value
)
return f"<OtherName(type_id={self.type_id}, value={self.value!r})>"
def __eq__(self, other: object) -> bool:
if not isinstance(other, OtherName):

View File

@@ -9,6 +9,7 @@ import re
import sys
import typing
import warnings
from collections.abc import Iterable, Iterator
from cryptography import utils
from cryptography.hazmat.bindings._rust import x509 as rust_x509
@@ -31,7 +32,7 @@ class _ASN1Type(utils.Enum):
_ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type}
_NAMEOID_DEFAULT_TYPE: typing.Dict[ObjectIdentifier, _ASN1Type] = {
_NAMEOID_DEFAULT_TYPE: dict[ObjectIdentifier, _ASN1Type] = {
NameOID.COUNTRY_NAME: _ASN1Type.PrintableString,
NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString,
NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString,
@@ -59,8 +60,14 @@ _NAMEOID_TO_NAME: _OidNameMap = {
}
_NAME_TO_NAMEOID = {v: k for k, v in _NAMEOID_TO_NAME.items()}
_NAMEOID_LENGTH_LIMIT = {
NameOID.COUNTRY_NAME: (2, 2),
NameOID.JURISDICTION_COUNTRY_NAME: (2, 2),
NameOID.COMMON_NAME: (1, 64),
}
def _escape_dn_value(val: typing.Union[str, bytes]) -> str:
def _escape_dn_value(val: str | bytes) -> str:
"""Escape special characters in RFC4514 Distinguished Name value."""
if not val:
@@ -108,12 +115,21 @@ def _unescape_dn_value(val: str) -> str:
return _RFC4514NameParser._PAIR_RE.sub(sub, val)
class NameAttribute:
NameAttributeValueType = typing.TypeVar(
"NameAttributeValueType",
typing.Union[str, bytes],
str,
bytes,
covariant=True,
)
class NameAttribute(typing.Generic[NameAttributeValueType]):
def __init__(
self,
oid: ObjectIdentifier,
value: typing.Union[str, bytes],
_type: typing.Optional[_ASN1Type] = None,
value: NameAttributeValueType,
_type: _ASN1Type | None = None,
*,
_validate: bool = True,
) -> None:
@@ -128,26 +144,23 @@ class NameAttribute:
)
if not isinstance(value, bytes):
raise TypeError("value must be bytes for BitString")
else:
if not isinstance(value, str):
raise TypeError("value argument must be a str")
elif not isinstance(value, str):
raise TypeError("value argument must be a str")
if (
oid == NameOID.COUNTRY_NAME
or oid == NameOID.JURISDICTION_COUNTRY_NAME
):
length_limits = _NAMEOID_LENGTH_LIMIT.get(oid)
if length_limits is not None:
min_length, max_length = length_limits
assert isinstance(value, str)
c_len = len(value.encode("utf8"))
if c_len != 2 and _validate is True:
raise ValueError(
"Country name must be a 2 character country code"
)
elif c_len != 2:
warnings.warn(
"Country names should be two characters, but the "
"attribute is {} characters in length.".format(c_len),
stacklevel=2,
if c_len < min_length or c_len > max_length:
msg = (
f"Attribute's length must be >= {min_length} and "
f"<= {max_length}, but it was {c_len}"
)
if _validate is True:
raise ValueError(msg)
else:
warnings.warn(msg, stacklevel=2)
# The appropriate ASN1 string type varies by OID and is defined across
# multiple RFCs including 2459, 3280, and 5280. In general UTF8String
@@ -162,15 +175,15 @@ class NameAttribute:
raise TypeError("_type must be from the _ASN1Type enum")
self._oid = oid
self._value = value
self._type = _type
self._value: NameAttributeValueType = value
self._type: _ASN1Type = _type
@property
def oid(self) -> ObjectIdentifier:
return self._oid
@property
def value(self) -> typing.Union[str, bytes]:
def value(self) -> NameAttributeValueType:
return self._value
@property
@@ -182,7 +195,7 @@ class NameAttribute:
return _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string)
def rfc4514_string(
self, attr_name_overrides: typing.Optional[_OidNameMap] = None
self, attr_name_overrides: _OidNameMap | None = None
) -> str:
"""
Format as RFC4514 Distinguished Name string.
@@ -208,11 +221,11 @@ class NameAttribute:
return hash((self.oid, self.value))
def __repr__(self) -> str:
return "<NameAttribute(oid={0.oid}, value={0.value!r})>".format(self)
return f"<NameAttribute(oid={self.oid}, value={self.value!r})>"
class RelativeDistinguishedName:
def __init__(self, attributes: typing.Iterable[NameAttribute]):
def __init__(self, attributes: Iterable[NameAttribute]):
attributes = list(attributes)
if not attributes:
raise ValueError("a relative distinguished name cannot be empty")
@@ -227,12 +240,13 @@ class RelativeDistinguishedName:
raise ValueError("duplicate attributes are not allowed")
def get_attributes_for_oid(
self, oid: ObjectIdentifier
) -> typing.List[NameAttribute]:
self,
oid: ObjectIdentifier,
) -> list[NameAttribute[str | bytes]]:
return [i for i in self if i.oid == oid]
def rfc4514_string(
self, attr_name_overrides: typing.Optional[_OidNameMap] = None
self, attr_name_overrides: _OidNameMap | None = None
) -> str:
"""
Format as RFC4514 Distinguished Name string.
@@ -254,7 +268,7 @@ class RelativeDistinguishedName:
def __hash__(self) -> int:
return hash(self._attribute_set)
def __iter__(self) -> typing.Iterator[NameAttribute]:
def __iter__(self) -> Iterator[NameAttribute]:
return iter(self._attributes)
def __len__(self) -> int:
@@ -266,20 +280,16 @@ class RelativeDistinguishedName:
class Name:
@typing.overload
def __init__(self, attributes: typing.Iterable[NameAttribute]) -> None:
...
def __init__(self, attributes: Iterable[NameAttribute]) -> None: ...
@typing.overload
def __init__(
self, attributes: typing.Iterable[RelativeDistinguishedName]
) -> None:
...
self, attributes: Iterable[RelativeDistinguishedName]
) -> None: ...
def __init__(
self,
attributes: typing.Iterable[
typing.Union[NameAttribute, RelativeDistinguishedName]
],
attributes: Iterable[NameAttribute | RelativeDistinguishedName],
) -> None:
attributes = list(attributes)
if all(isinstance(x, NameAttribute) for x in attributes):
@@ -301,12 +311,12 @@ class Name:
def from_rfc4514_string(
cls,
data: str,
attr_name_overrides: typing.Optional[_NameOidMap] = None,
attr_name_overrides: _NameOidMap | None = None,
) -> Name:
return _RFC4514NameParser(data, attr_name_overrides or {}).parse()
def rfc4514_string(
self, attr_name_overrides: typing.Optional[_OidNameMap] = None
self, attr_name_overrides: _OidNameMap | None = None
) -> str:
"""
Format as RFC4514 Distinguished Name string.
@@ -324,12 +334,13 @@ class Name:
)
def get_attributes_for_oid(
self, oid: ObjectIdentifier
) -> typing.List[NameAttribute]:
self,
oid: ObjectIdentifier,
) -> list[NameAttribute[str | bytes]]:
return [i for i in self if i.oid == oid]
@property
def rdns(self) -> typing.List[RelativeDistinguishedName]:
def rdns(self) -> list[RelativeDistinguishedName]:
return self._attributes
def public_bytes(self, backend: typing.Any = None) -> bytes:
@@ -346,10 +357,9 @@ class Name:
# for you, consider optimizing!
return hash(tuple(self._attributes))
def __iter__(self) -> typing.Iterator[NameAttribute]:
def __iter__(self) -> Iterator[NameAttribute]:
for rdn in self._attributes:
for ava in rdn:
yield ava
yield from rdn
def __len__(self) -> int:
return sum(len(rdn) for rdn in self._attributes)
@@ -395,7 +405,7 @@ class _RFC4514NameParser:
def _has_data(self) -> bool:
return self._idx < len(self._data)
def _peek(self) -> typing.Optional[str]:
def _peek(self) -> str | None:
if self._has_data():
return self._data[self._idx]
return None
@@ -422,6 +432,10 @@ class _RFC4514NameParser:
we parse it, we need to reverse again to get the RDNs on the
correct order.
"""
if not self._has_data():
return Name([])
rdns = [self._parse_rdn()]
while self._has_data():

View File

@@ -4,21 +4,16 @@
from __future__ import annotations
import abc
import datetime
import typing
from collections.abc import Iterable
from cryptography import utils, x509
from cryptography.hazmat.bindings._rust import ocsp
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric.types import (
CertificateIssuerPrivateKeyTypes,
)
from cryptography.x509.base import (
_EARLIEST_UTC_TIME,
_convert_to_naive_utc_time,
_reject_duplicate_extension,
)
from cryptography.x509.base import _reject_duplicate_extension
class OCSPResponderEncoding(utils.Enum):
@@ -60,20 +55,15 @@ class OCSPCertStatus(utils.Enum):
class _SingleResponse:
def __init__(
self,
cert: x509.Certificate,
issuer: x509.Certificate,
resp: tuple[x509.Certificate, x509.Certificate] | None,
resp_hash: tuple[bytes, bytes, int] | None,
algorithm: hashes.HashAlgorithm,
cert_status: OCSPCertStatus,
this_update: datetime.datetime,
next_update: typing.Optional[datetime.datetime],
revocation_time: typing.Optional[datetime.datetime],
revocation_reason: typing.Optional[x509.ReasonFlags],
next_update: datetime.datetime | None,
revocation_time: datetime.datetime | None,
revocation_reason: x509.ReasonFlags | None,
):
if not isinstance(cert, x509.Certificate) or not isinstance(
issuer, x509.Certificate
):
raise TypeError("cert and issuer must be a Certificate")
_verify_algorithm(algorithm)
if not isinstance(this_update, datetime.datetime):
raise TypeError("this_update must be a datetime object")
@@ -82,8 +72,8 @@ class _SingleResponse:
):
raise TypeError("next_update must be a datetime object or None")
self._cert = cert
self._issuer = issuer
self._resp = resp
self._resp_hash = resp_hash
self._algorithm = algorithm
self._this_update = this_update
self._next_update = next_update
@@ -107,13 +97,6 @@ class _SingleResponse:
if not isinstance(revocation_time, datetime.datetime):
raise TypeError("revocation_time must be a datetime object")
revocation_time = _convert_to_naive_utc_time(revocation_time)
if revocation_time < _EARLIEST_UTC_TIME:
raise ValueError(
"The revocation_time must be on or after"
" 1950 January 1."
)
if revocation_reason is not None and not isinstance(
revocation_reason, x509.ReasonFlags
):
@@ -127,293 +110,21 @@ class _SingleResponse:
self._revocation_reason = revocation_reason
class OCSPRequest(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
def issuer_key_hash(self) -> bytes:
"""
The hash of the issuer public key
"""
@property
@abc.abstractmethod
def issuer_name_hash(self) -> bytes:
"""
The hash of the issuer name
"""
@property
@abc.abstractmethod
def hash_algorithm(self) -> hashes.HashAlgorithm:
"""
The hash algorithm used in the issuer name and key hashes
"""
@property
@abc.abstractmethod
def serial_number(self) -> int:
"""
The serial number of the cert whose status is being checked
"""
@abc.abstractmethod
def public_bytes(self, encoding: serialization.Encoding) -> bytes:
"""
Serializes the request to DER
"""
@property
@abc.abstractmethod
def extensions(self) -> x509.Extensions:
"""
The list of request extensions. Not single request extensions.
"""
class OCSPSingleResponse(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
def certificate_status(self) -> OCSPCertStatus:
"""
The status of the certificate (an element from the OCSPCertStatus enum)
"""
@property
@abc.abstractmethod
def revocation_time(self) -> typing.Optional[datetime.datetime]:
"""
The date of when the certificate was revoked or None if not
revoked.
"""
@property
@abc.abstractmethod
def revocation_reason(self) -> typing.Optional[x509.ReasonFlags]:
"""
The reason the certificate was revoked or None if not specified or
not revoked.
"""
@property
@abc.abstractmethod
def this_update(self) -> datetime.datetime:
"""
The most recent time at which the status being indicated is known by
the responder to have been correct
"""
@property
@abc.abstractmethod
def next_update(self) -> typing.Optional[datetime.datetime]:
"""
The time when newer information will be available
"""
@property
@abc.abstractmethod
def issuer_key_hash(self) -> bytes:
"""
The hash of the issuer public key
"""
@property
@abc.abstractmethod
def issuer_name_hash(self) -> bytes:
"""
The hash of the issuer name
"""
@property
@abc.abstractmethod
def hash_algorithm(self) -> hashes.HashAlgorithm:
"""
The hash algorithm used in the issuer name and key hashes
"""
@property
@abc.abstractmethod
def serial_number(self) -> int:
"""
The serial number of the cert whose status is being checked
"""
class OCSPResponse(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
def responses(self) -> typing.Iterator[OCSPSingleResponse]:
"""
An iterator over the individual SINGLERESP structures in the
response
"""
@property
@abc.abstractmethod
def response_status(self) -> OCSPResponseStatus:
"""
The status of the response. This is a value from the OCSPResponseStatus
enumeration
"""
@property
@abc.abstractmethod
def signature_algorithm_oid(self) -> x509.ObjectIdentifier:
"""
The ObjectIdentifier of the signature algorithm
"""
@property
@abc.abstractmethod
def signature_hash_algorithm(
self,
) -> typing.Optional[hashes.HashAlgorithm]:
"""
Returns a HashAlgorithm corresponding to the type of the digest signed
"""
@property
@abc.abstractmethod
def signature(self) -> bytes:
"""
The signature bytes
"""
@property
@abc.abstractmethod
def tbs_response_bytes(self) -> bytes:
"""
The tbsResponseData bytes
"""
@property
@abc.abstractmethod
def certificates(self) -> typing.List[x509.Certificate]:
"""
A list of certificates used to help build a chain to verify the OCSP
response. This situation occurs when the OCSP responder uses a delegate
certificate.
"""
@property
@abc.abstractmethod
def responder_key_hash(self) -> typing.Optional[bytes]:
"""
The responder's key hash or None
"""
@property
@abc.abstractmethod
def responder_name(self) -> typing.Optional[x509.Name]:
"""
The responder's Name or None
"""
@property
@abc.abstractmethod
def produced_at(self) -> datetime.datetime:
"""
The time the response was produced
"""
@property
@abc.abstractmethod
def certificate_status(self) -> OCSPCertStatus:
"""
The status of the certificate (an element from the OCSPCertStatus enum)
"""
@property
@abc.abstractmethod
def revocation_time(self) -> typing.Optional[datetime.datetime]:
"""
The date of when the certificate was revoked or None if not
revoked.
"""
@property
@abc.abstractmethod
def revocation_reason(self) -> typing.Optional[x509.ReasonFlags]:
"""
The reason the certificate was revoked or None if not specified or
not revoked.
"""
@property
@abc.abstractmethod
def this_update(self) -> datetime.datetime:
"""
The most recent time at which the status being indicated is known by
the responder to have been correct
"""
@property
@abc.abstractmethod
def next_update(self) -> typing.Optional[datetime.datetime]:
"""
The time when newer information will be available
"""
@property
@abc.abstractmethod
def issuer_key_hash(self) -> bytes:
"""
The hash of the issuer public key
"""
@property
@abc.abstractmethod
def issuer_name_hash(self) -> bytes:
"""
The hash of the issuer name
"""
@property
@abc.abstractmethod
def hash_algorithm(self) -> hashes.HashAlgorithm:
"""
The hash algorithm used in the issuer name and key hashes
"""
@property
@abc.abstractmethod
def serial_number(self) -> int:
"""
The serial number of the cert whose status is being checked
"""
@property
@abc.abstractmethod
def extensions(self) -> x509.Extensions:
"""
The list of response extensions. Not single response extensions.
"""
@property
@abc.abstractmethod
def single_extensions(self) -> x509.Extensions:
"""
The list of single response extensions. Not response extensions.
"""
@abc.abstractmethod
def public_bytes(self, encoding: serialization.Encoding) -> bytes:
"""
Serializes the response to DER
"""
OCSPRequest = ocsp.OCSPRequest
OCSPResponse = ocsp.OCSPResponse
OCSPSingleResponse = ocsp.OCSPSingleResponse
class OCSPRequestBuilder:
def __init__(
self,
request: typing.Optional[
typing.Tuple[
x509.Certificate, x509.Certificate, hashes.HashAlgorithm
]
] = None,
request_hash: typing.Optional[
typing.Tuple[bytes, bytes, int, hashes.HashAlgorithm]
] = None,
extensions: typing.List[x509.Extension[x509.ExtensionType]] = [],
request: tuple[
x509.Certificate, x509.Certificate, hashes.HashAlgorithm
]
| None = None,
request_hash: tuple[bytes, bytes, int, hashes.HashAlgorithm]
| None = None,
extensions: list[x509.Extension[x509.ExtensionType]] = [],
) -> None:
self._request = request
self._request_hash = request_hash
@@ -478,7 +189,7 @@ class OCSPRequestBuilder:
_reject_duplicate_extension(extension, self._extensions)
return OCSPRequestBuilder(
self._request, self._request_hash, self._extensions + [extension]
self._request, self._request_hash, [*self._extensions, extension]
)
def build(self) -> OCSPRequest:
@@ -491,12 +202,11 @@ class OCSPRequestBuilder:
class OCSPResponseBuilder:
def __init__(
self,
response: typing.Optional[_SingleResponse] = None,
responder_id: typing.Optional[
typing.Tuple[x509.Certificate, OCSPResponderEncoding]
] = None,
certs: typing.Optional[typing.List[x509.Certificate]] = None,
extensions: typing.List[x509.Extension[x509.ExtensionType]] = [],
response: _SingleResponse | None = None,
responder_id: tuple[x509.Certificate, OCSPResponderEncoding]
| None = None,
certs: list[x509.Certificate] | None = None,
extensions: list[x509.Extension[x509.ExtensionType]] = [],
):
self._response = response
self._responder_id = responder_id
@@ -510,16 +220,67 @@ class OCSPResponseBuilder:
algorithm: hashes.HashAlgorithm,
cert_status: OCSPCertStatus,
this_update: datetime.datetime,
next_update: typing.Optional[datetime.datetime],
revocation_time: typing.Optional[datetime.datetime],
revocation_reason: typing.Optional[x509.ReasonFlags],
next_update: datetime.datetime | None,
revocation_time: datetime.datetime | None,
revocation_reason: x509.ReasonFlags | None,
) -> OCSPResponseBuilder:
if self._response is not None:
raise ValueError("Only one response per OCSPResponse.")
if not isinstance(cert, x509.Certificate) or not isinstance(
issuer, x509.Certificate
):
raise TypeError("cert and issuer must be a Certificate")
singleresp = _SingleResponse(
cert,
issuer,
(cert, issuer),
None,
algorithm,
cert_status,
this_update,
next_update,
revocation_time,
revocation_reason,
)
return OCSPResponseBuilder(
singleresp,
self._responder_id,
self._certs,
self._extensions,
)
def add_response_by_hash(
self,
issuer_name_hash: bytes,
issuer_key_hash: bytes,
serial_number: int,
algorithm: hashes.HashAlgorithm,
cert_status: OCSPCertStatus,
this_update: datetime.datetime,
next_update: datetime.datetime | None,
revocation_time: datetime.datetime | None,
revocation_reason: x509.ReasonFlags | None,
) -> OCSPResponseBuilder:
if self._response is not None:
raise ValueError("Only one response per OCSPResponse.")
if not isinstance(serial_number, int):
raise TypeError("serial_number must be an integer")
utils._check_bytes("issuer_name_hash", issuer_name_hash)
utils._check_bytes("issuer_key_hash", issuer_key_hash)
_verify_algorithm(algorithm)
if algorithm.digest_size != len(
issuer_name_hash
) or algorithm.digest_size != len(issuer_key_hash):
raise ValueError(
"issuer_name_hash and issuer_key_hash must be the same length "
"as the digest size of the algorithm"
)
singleresp = _SingleResponse(
None,
(issuer_name_hash, issuer_key_hash, serial_number),
algorithm,
cert_status,
this_update,
@@ -554,7 +315,7 @@ class OCSPResponseBuilder:
)
def certificates(
self, certs: typing.Iterable[x509.Certificate]
self, certs: Iterable[x509.Certificate]
) -> OCSPResponseBuilder:
if self._certs is not None:
raise ValueError("certificates may only be set once")
@@ -583,13 +344,13 @@ class OCSPResponseBuilder:
self._response,
self._responder_id,
self._certs,
self._extensions + [extension],
[*self._extensions, extension],
)
def sign(
self,
private_key: CertificateIssuerPrivateKeyTypes,
algorithm: typing.Optional[hashes.HashAlgorithm],
algorithm: hashes.HashAlgorithm | None,
) -> OCSPResponse:
if self._response is None:
raise ValueError("You must add a response before signing")
@@ -614,9 +375,5 @@ class OCSPResponseBuilder:
return ocsp.create_ocsp_response(response_status, None, None, None)
def load_der_ocsp_request(data: bytes) -> OCSPRequest:
return ocsp.load_der_ocsp_request(data)
def load_der_ocsp_response(data: bytes) -> OCSPResponse:
return ocsp.load_der_ocsp_response(data)
load_der_ocsp_request = ocsp.load_der_ocsp_request
load_der_ocsp_response = ocsp.load_der_ocsp_response

View File

@@ -14,6 +14,8 @@ from cryptography.hazmat._oid import (
NameOID,
ObjectIdentifier,
OCSPExtensionOID,
OtherNameFormOID,
PublicKeyAlgorithmOID,
SignatureAlgorithmOID,
SubjectInformationAccessOID,
)
@@ -28,6 +30,8 @@ __all__ = [
"NameOID",
"OCSPExtensionOID",
"ObjectIdentifier",
"OtherNameFormOID",
"PublicKeyAlgorithmOID",
"SignatureAlgorithmOID",
"SubjectInformationAccessOID",
]

View File

@@ -0,0 +1,34 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import annotations
import typing
from cryptography.hazmat.bindings._rust import x509 as rust_x509
from cryptography.x509.general_name import DNSName, IPAddress
__all__ = [
"ClientVerifier",
"Criticality",
"ExtensionPolicy",
"Policy",
"PolicyBuilder",
"ServerVerifier",
"Store",
"Subject",
"VerificationError",
"VerifiedClient",
]
Store = rust_x509.Store
Subject = typing.Union[DNSName, IPAddress]
VerifiedClient = rust_x509.VerifiedClient
ClientVerifier = rust_x509.ClientVerifier
ServerVerifier = rust_x509.ServerVerifier
PolicyBuilder = rust_x509.PolicyBuilder
Policy = rust_x509.Policy
ExtensionPolicy = rust_x509.ExtensionPolicy
Criticality = rust_x509.Criticality
VerificationError = rust_x509.VerificationError