X509: Certificates and Verification

To be able to verify structures, Signify has a library to allow validating certificates. The Certificate is an object that abstracts a x509 certificate and has the ability to be verified. The verification requires the creation of a validation chain, that lead back to a trusted certificate authority.

You can use this module as follows:

trust_store = FileSystemCertificateStore(location=pathlib.Path("certificates/authenticode/"), trusted=True)
context = VerificationContext(trust_store)
with open("certificate.pem", "rb") as f, open("certificate2.pem", "rb") as g:
    to_verify1 = Certificate.from_pem(f.read())
    to_verify2 = Certificate.from_pem(g.read())

to_verify1.verify(context)  # prints True
to_verify2.verify(context)  # raises VerificationError

Certificate

class signify.x509.Certificate(asn1: Certificate | CertificateChoices)

Representation of a certificate. It is built from an ASN.1 structure.

property extensions: dict[str, Any]

This is a list of extension objects.

classmethod from_der(content: bytes) Certificate

Load the Certificate object from DER-encoded data

classmethod from_pem(content: bytes) Certificate

Reads a Certificate from a PEM formatted file.

classmethod from_pems(content: bytes) Iterator[Certificate]

Reads a Certificate from a PEM formatted file.

property issuer: CertificateName

The CertificateName for the issuer.

potential_chains(context: VerificationContext) Iterator[list[Certificate]]

Alias for VerificationContext.potential_chains()

property serial_number: int

The full integer serial number of the certificate

property signature_algorithm: str

These values are considered part of the certificate, but not fully parsed.

property signature_value: bytes

These values are considered part of the certificate, but not fully parsed.

property subject: CertificateName

The CertificateName for the subject.

property subject_public_algorithm: AlgorithmIdentifier

These values are considered part of the certificate, but not fully parsed.

property subject_public_key: bytes

These values are considered part of the certificate, but not fully parsed.

property to_der: bytes

Returns the DER-encoded data from this certificate.

property valid_from: datetime

The datetime objects between which the certificate is valid.

property valid_to: datetime

The datetime objects between which the certificate is valid.

verify(context: VerificationContext) Iterable[Certificate]

Alias for VerificationContext.verify()

verify_signature(signature: bytes, data: bytes, algorithm: HashFunction, allow_legacy: bool = False) None

Verifies whether the signature bytes match the data using the hashing algorithm. Supports RSA and EC keys. Note that not all hashing algorithms are supported.

Parameters:
  • signature – The signature to verify

  • data – The data that must be verified

  • algorithm – The hashing algorithm to use

  • allow_legacy

    If True, allows legacy signature verification. This method is intended for the case where the signature does not contain an ASN.1 structure, but a raw hash value instead. It is attempted automatically when verification of the RSA signature fails.

    This case is described in more detail on https://mta.openssl.org/pipermail/openssl-users/2015-September/002053.html

property version: str

This is the version of the certificate

class signify.x509.CertificateName(asn1: Name | GeneralName)
property dn: str

Returns an (almost) rfc2253 compatible string given a RDNSequence

get_components(component_type: None = None) Iterator[tuple[str, str]]
get_components(component_type: str) Iterator[str]

Get individual components of this CertificateName

Parameters:

component_type – if provided, yields only values of this type, if not provided, yields tuples of (type, value)

property rdns: Iterable[tuple[str, str]]

A list of all components of the object.

Certificate Store

class signify.x509.CertificateStore(*args: Certificate | Iterable[Certificate], trusted: bool = False, ctl: CertificateTrustList | dict[str, list[str] | None] | None = None)

A list of Certificate objects.

__init__(*args: Certificate | Iterable[Certificate], trusted: bool = False, ctl: CertificateTrustList | dict[str, list[str] | None] | None = None)
Parameters:
  • trusted – If true, all certificates that are appended to this structure are set to trusted.

  • ctl – The certificate trust list to use (if any), or a mapping of SHA-1 hashes to acceptable EKU’s.

find_certificate(**kwargs: Any) Certificate

Finds the certificate as specified by the keyword arguments. See find_certificates() for all possible arguments. If there is not exactly 1 certificate matching the parameters, i.e. there are zero or there are multiple, an error is raised.

Raises:

KeyError

find_certificates(*, subject: CertificateName | None = None, serial_number: int | None = None, issuer: CertificateName | None = None, sha256_fingerprint: str | None = None) Iterable[Certificate]

Finds all certificates given by the specified properties. A property can be omitted by specifying None. Calling this function without arguments is the same as iterating over this store

Parameters:
  • subject – Certificate subject to look for, as CertificateName

  • serial_number (int) – Serial number to look for.

  • issuer – Certificate issuer to look for, as CertificateName

  • sha256_fingerprint (str) – The SHA-256 fingerprint to look for

is_trusted(certificate: Certificate) bool
Returns whether the provided certificate is trusted by this certificate

store.

Warning

This check does not verify that the certificate is valid according to the Trust List, if set. It merely checks that the provided certificate is in a trusted certificate store. You still need to verify the chain for its full trust.

verify_trust(chain: list[Certificate], context: VerificationContext | None = None) bool

Verifies that the chain is trusted given the context.

class signify.x509.FileSystemCertificateStore(location: Path, *args: Any, **kwargs: Any)

A list of Certificate objects loaded from the file system.

__init__(location: Path, *args: Any, **kwargs: Any)
Parameters:
  • location – The file system location for the certificates.

  • trusted – If true, all certificates that are appended to this structure are set to trusted.

Verification

class signify.x509.VerificationContext(*stores: CertificateStore, timestamp: datetime | None = None, key_usages: Iterable[str] | None = None, optional_ku: Literal['critical'] | bool = True, extended_key_usages: Iterable[str] | None = None, optional_eku: Literal['critical'] | bool = True, allow_legacy: bool = True, revocation_mode: Literal['soft-fail', 'hard-fail', 'require'] = 'soft-fail', allow_fetching: bool = False, fetch_timeout: int = 30, crls: Iterable[CertificateList] | None = None, ocsps: Iterable[OCSPResponse] | None = None)
__init__(*stores: CertificateStore, timestamp: datetime | None = None, key_usages: Iterable[str] | None = None, optional_ku: Literal['critical'] | bool = True, extended_key_usages: Iterable[str] | None = None, optional_eku: Literal['critical'] | bool = True, allow_legacy: bool = True, revocation_mode: Literal['soft-fail', 'hard-fail', 'require'] = 'soft-fail', allow_fetching: bool = False, fetch_timeout: int = 30, crls: Iterable[CertificateList] | None = None, ocsps: Iterable[OCSPResponse] | None = None)

A context holding properties about the verification of a signature or certificate.

Parameters:
  • stores – A list of CertificateStore objects that contain certificates

  • timestamp – The timestamp to verify with. If None, the current time is used. Must be a timezone-aware timestamp.

  • key_usages – An iterable with the keyUsages to check for. For valid options, see certvalidator.CertificateValidator.validate_usage()

  • optional_ku – If True, sets the key_usages as optionally present in the certificates, i.e. the certificate successfully validates when the keyUsage extension is missing from the certificate. When False, the key_usages must be present. When critical, the key usage is considered validly absent when the keyUsage extension is not marked as critical.

  • extended_key_usages – An iterable with the EKU’s to check for. See certvalidator.CertificateValidator.validate_usage()

  • optional_eku – If True, sets the extended_key_usages as optionally present in the certificates, i.e. the certificate validates successfully validates when the extendedKeyUsage extension is missing from the certificate. When False, the extended_key_usages must be present. When critical, the extended key usage is considered validly absent when the extendedKeyUsage extension is not marked as critical.

  • allow_legacy – If True, allows chain verification if the signature hash algorithm is very old (e.g. MD2). Additionally, allows the verification of encrypted hashes in Certificate.verify_signature() instead of encrypted DigestInfo ASN.1 structures. Both are found in the wild, but setting to True does reduce the reliability of the verification.

  • revocation_mode – Can be either soft-fail, hard-fail or require. See the documentation of certvalidator.ValidationContext() for the full definition

  • allow_fetching – If True, allows the underlying verification module to obtain CRL and OSCP responses when needed.

  • fetch_timeout – The timeout used when fetching CRL/OSCP responses

  • crls – List of asn1crypto.crl.CertificateList objects to aid in verifying revocation statuses.

  • ocsps – List of asn1crypto.ocsp.OCSPResponse objects to aid in verifying revocation statuses.

add_store(store: CertificateStore) None

Adds a certificate store to the VerificationContext

property certificates: Iterator[Certificate]

Iterates over all certificates in the associated stores.

find_certificate(**kwargs: Any) Certificate

Finds the certificate as specified by the keyword arguments. See find_certificates() for all possible arguments. If there is not exactly 1 certificate matching the parameters, i.e. there are zero or there are multiple, an error is raised.

Raises:

KeyError

find_certificates(**kwargs: Any) Iterator[Certificate]

Finds all certificates given by the specified keyword arguments. See CertificateStore.find_certificates() for a list of all supported arguments.

is_trusted(certificate: Certificate) bool

Returns whether the provided certificate is trusted by a trusted certificate store.

Warning

This check does not verify that the certificate is valid according to the Trust List, if set. It merely checks that the provided certificate is in a trusted certificate store. You still need to verify the chain for its full trust.

potential_chains(certificate: Certificate, depth: int = 10) Iterator[list[Certificate]]

Returns all possible chains from the provided certificate, solely based on issuer/subject matching.

THIS METHOD DOES NOT VERIFY WHETHER A CHAIN IS ACTUALLY VALID. Use verify() for that.

Parameters:
  • certificate – The certificate to build a potential chain for

  • depth – The maximum depth, used for recursion

Returns:

A iterable of all possible certificate chains

verify(certificate: Certificate) list[Certificate]

Verifies the certificate, and its chain.

Parameters:

certificate – The certificate to verify

Returns:

A valid certificate chain for this certificate.

Raises:

AuthenticodeVerificationError – When the certificate could not be verified.

verify_trust(chain: list[Certificate]) bool

Determines whether the given certificate chain is trusted by a trusted certificate store.

Parameters:

chain – The certificate chain to verify trust for.

Returns:

True if the certificate chain is trusted by a certificate store.