cnert
Class cnert.CA
CA
CA(
subject_attrs: NameAttrs | None = None,
issuer_attrs: NameAttrs | None = None,
path_length: int = 9,
not_valid_before: datetime | None = None,
not_valid_after: datetime | None = None,
serial_number: int | None = None,
parent: CA | None = None,
intermediate_num: int = 0,
signature_hash: HashAlgorithm
| str
| _UnsetType
| None = _UNSET,
extensions: Sequence[tuple[ExtensionType, bool]] = (),
private_key: CertificateIssuerPrivateKeyTypes
| None = None,
builtin_extensions: bool = True,
)
A CA object.
Examples: >>> ca = cnert.CA() >>> ca.is_root_ca True >>> ca.is_intermediate_ca False >>> ca.parent is None True
Parameters:
subject_attrs: Subject Name Attributes.
subject_attrs: Issuer Name Attributes.
path_length: Maximum path length certificates subordinate.
not_valid_before: CA not valid before date.
not_valid_after: CA not valid after date.
parent: Parent of CA.
intermediate_num: Number of intermediates.
signature_hash: Signature hash algorithm for the CA's own
certificate. Defaults to SHA-256, or to None for an
Edwards key, which takes no hash.
extensions: Extra (extension, critical) pairs for the CA's
own certificate. One that collides with a built-in
extension replaces it wholesale.
private_key: Private key for the CA's own certificate;
generated when omitted. Reusing one key across a chain is
allowed, and is how a key-reuse fixture is built.
builtin_extensions: Add cnert's own extensions to the CA's
own certificate. When false, only the supplied pairs are
added. An authority without basic constraints is not a
usable authority, which is deliberate.
Methods:
-
issue_cert–Issues a certificate
-
issue_intermediate–Issues an intermediate CA.
| Attributes: |
|---|
is_intermediate_ca
property
is_intermediate_ca: bool
Returns: Whether CA is a intermediate CA or not.
is_root_ca
property
is_root_ca: bool
Examples: >>> ca = CA() >>> ca.is_root_ca True >>> intermediate = ca.issue_intermediate() >>> intermediate.is_root_ca False
Returns: Whether CA is a root CA or not.
issue_cert
issue_cert(
*sans: str,
subject_attrs: NameAttrs | None = None,
not_valid_before: datetime | None = None,
not_valid_after: datetime | None = None,
serial_number: int | None = None,
csr: CSR | None = None,
signature_hash: HashAlgorithm
| str
| _UnsetType
| None = _UNSET,
extensions: Sequence[tuple[ExtensionType, bool]] = (),
private_key: CertificateIssuerPrivateKeyTypes
| None = None,
builtin_extensions: bool = True,
) -> Cert
Issues a certificate
Examples:
>>> ca = CA()
>>> ca.issue_cert()
Parameters:
sans: Subject Alternative Names as positional arguments.
subject_attrs: Subject Name Attributes.
not_valid_before: Certificate not valid before date.
not_valid_after: Certificate not valid after date.
csr: A CSR object.
signature_hash: Signature hash algorithm. Defaults to
SHA-256, or to None when this CA's key is an Edwards
key, which takes no hash.
extensions: Extra (extension, critical) pairs. One that
collides with a built-in extension replaces it
wholesale.
private_key: Private key for the certificate; generated
when omitted. It is the certificate's subject key
only: the signature always comes from this CA's key.
A csr carries its own key, so the two are mutually
exclusive.
builtin_extensions: Add cnert's own extensions. When
false, only the supplied pairs are added, subject
alternative names included. The result is not a valid
certificate for real use, which is the point: it is
how a bare certificate is built.
Raises:
ValueError: If both private_key and csr are given.
Returns: A Cert object.
issue_intermediate
issue_intermediate(
subject_attrs: NameAttrs | None = None,
not_valid_before: datetime | None = None,
not_valid_after: datetime | None = None,
serial_number: int | None = None,
signature_hash: HashAlgorithm
| str
| _UnsetType
| None = _UNSET,
extensions: Sequence[tuple[ExtensionType, bool]] = (),
private_key: CertificateIssuerPrivateKeyTypes
| None = None,
builtin_extensions: bool = True,
) -> CA
Issues an intermediate CA.
Parameters:
subject_attrs: Subject Name Attributes.
not_valid_before: Intermediate not valid before date.
not_valid_after: Intermediate not valid after date.
serial_number: Serial number.
signature_hash: Signature hash algorithm for the
intermediate's certificate.
extensions: Extra (extension, critical) pairs.
private_key: Private key for the intermediate; generated
when omitted. The intermediate is still signed by this
CA's key.
builtin_extensions: Add cnert's own extensions. When
false, only the supplied pairs are added.
Raises: ValueError: If this CA's path length is 0.
Returns: A CA object.
Class cnert.NameAttrs
Instances are frozen and hashable; comparing against a non-NameAttrs
object returns False instead of raising.
A value may be a sequence, which emits one attribute per value in the order given. That is how a distinguished name repeats an attribute type, which a lossless DN parse has to be tested against:
import cnert
subject = cnert.NameAttrs(
COMMON_NAME="example.com", ORGANIZATIONAL_UNIT_NAME=["OU-A", "OU-B"]
)
Each value becomes its own relative distinguished name. The
plus-joined OU=A+OU=B form, one relative distinguished name holding
both, is not reachable this way. A multi-valued attribute reads back
as a tuple. Note that rfc4514_string() prints most-specific first,
so it renders the name above with OU-B before OU-A; the attribute
order is still the one given.
Anything that is not a NameAttrs passed as subject_attrs or
issuer_attrs raises TypeError.
NameAttrs
Bases: Freezer
An object for storing (and freezing) Name Attributes for Subject Name Attributes and Issuer Name Attributes.
Accepts any valid x509.NameAttribute as key arguments with arbitrary string values.
Has methods for returning initialized attributes in a dict and for
returning a cryptography.x509.Name
There is alse a method for showing the allowed attributes.
Examples:
>>> subject_attrs = cnert.NameAttrs(COMMON_NAME="example.com")
>>> subject_attrs.COMMON_NAME
'example.com'
>>> subject_attrs.dict_
{'COMMON_NAME': 'example.com'}
>>> subject_attrs.x509_name()
[`allowed_keys()`][cnert.NameAttrs.allowed_keys],
each with a value or a sequence of values. A sequence
emits one attribute per value in the order given, so
`ORGANIZATIONAL_UNIT_NAME=["A", "B"]` renders as
`OU=A,OU=B`. Attribute types are ordered
alphabetically; only values within one type follow
the caller.
Methods:
-
allowed_keys–Returns a list of allowed key arguments.
-
x509_name–Examples:
allowed_keys
Returns a list of allowed key arguments.
Examples: >>> cnert.NameAttrs().allowed_keys() ['BUSINESS_CATEGORY', 'COMMON_NAME', 'COUNTRY_NAME', 'DN_QUALIFIER', 'DOMAIN_COMPONENT', 'EMAIL_ADDRESS', 'GENERATION_QUALIFIER', 'GIVEN_NAME', 'INN', 'JURISDICTION_COUNTRY_NAME', 'JURISDICTION_LOCALITY_NAME', 'JURISDICTION_STATE_OR_PROVINCE_NAME', 'LOCALITY_NAME', 'OGRN', 'ORGANIZATIONAL_UNIT_NAME', 'ORGANIZATION_NAME', 'POSTAL_ADDRESS', 'POSTAL_CODE', 'PSEUDONYM', 'SERIAL_NUMBER', 'SNILS', 'STATE_OR_PROVINCE_NAME', 'STREET_ADDRESS', 'SURNAME', 'TITLE', 'UNSTRUCTURED_NAME', 'USER_ID', 'X500_UNIQUE_IDENTIFIER']
Returns: A list of valid key attributes.
x509_name
x509_name() -> Name
Examples:
>>> subject_attrs = cnert.NameAttrs(COMMON_NAME="example.com")
>>> subject_attrs.x509_name()
Returns:
A cryptography.x509.Name
Class cnert._CertBuilder
_CertBuilder
_CertBuilder()
Builds and signs a X509 Certificate.
Methods:
-
build–Does the Certificate building.
build
build(
sans: tuple[str, ...],
subject_attrs_X509_name: Name,
issuer_attrs_X509_name: Name,
serial_number: int,
not_valid_before: datetime,
not_valid_after: datetime,
is_ca: bool,
public_key: CertificateIssuerPublicKeyTypes,
issuer_public_key: CertificateIssuerPublicKeyTypes
| None = None,
path_length: int | None = None,
extensions: Sequence[tuple[ExtensionType, bool]] = (),
builtin_extensions: bool = True,
) -> None
Does the Certificate building.
Parameters:
sans: Subject Alternative Names as positional arguments.
subject_attrs_X509_name: Subject Attributes Names.
issuer_attrs_X509_name: Issuer Atributes Names.
serial_number: Serial number.
not_valid_before: Not valid before date.
not_valid_after: Note valid after date.
is_ca: Add CA extension.
public_key: Public key for the certificate.
issuer_public_key: Issuer public key.
path_length: Max path length.
extensions: Extra (extension, critical) pairs. One that
collides with a built-in extension replaces it.
builtin_extensions: Add cnert's own extensions. When
false, only the supplied pairs are added, subject
alternative names included.
Class cnert.Cert
Cert was named _Cert through 0.10.x even though the public
CA.issue_cert() returned it; the old name remains as a deprecated
alias.
Cert
Cert(
*sans: str,
subject_attrs: NameAttrs,
issuer_attrs: NameAttrs,
not_valid_before: datetime | None = None,
not_valid_after: datetime | None = None,
serial_number: int | None = None,
parent: Cert | None = None,
private_key: CertificateIssuerPrivateKeyTypes
| None = None,
signature_hash: HashAlgorithm
| str
| _UnsetType
| None = _UNSET,
extensions: Sequence[tuple[ExtensionType, bool]] = (),
builtin_extensions: bool = True,
path_length: int = 0,
is_ca: bool = False,
)
A Cert object.
This object is returned by cnert.CA().issue_cert()
Examples:
>>> ca = CA()
>>> cert = ca.issue_cert()
>>> cert.subject_attrs
NameAttrs(COMMON_NAME="example.com")
>>> cert.issuer_attrs
NameAttrs(ORGANIZATION_NAME="Root CA")
>>> cert.not_valid_before
datetime.datetime(2023, 3, 24, 23, 56, 55, 901545)
>>> cert.not_valid_after
datetime.datetime(2023, 6, 23, 23, 56, 55, 901545)
Parameters:
sans: Subject Alternative Names as positional arguments
subject_attrs: Subject Name Attributes
issuer_attrs: Issure Name Attributes
not_valid_before: CA not valid before date
not_valid_after: CA not valid after date
serial_number: Serial number
parent: Certificate of CA.
private_key: Private key; generated when omitted.
signature_hash: Signature hash algorithm. Defaults to
SHA-256, or to None when the signing key is an
Edwards key, which takes no hash.
extensions: Extra (extension, critical) pairs. One that
collides with a built-in extension replaces it
wholesale.
builtin_extensions: Add cnert's own extensions. When
false, only the supplied pairs are added, subject
alternative names included. The result is not a valid
certificate for real use, which is the point: it is
how a bare certificate is built.
path_length: Path length
is_ca: if CA
Raises:
ValueError: If signature_hash does not suit the signing
key. See
cnert.build_private_key.
| Attributes: |
|
|---|
MD5
property
MD5: str
Examples: >>> cert = cnert.CA().issue_cert() >>> cert.MD5 'A03D37486DD47BE3E9C7EC1624073856'
Returns: MD5 Fingerprint string in hexadecimal and upper case.
SHA1
property
SHA1: str
Examples: >>> cert = cnert.CA().issue_cert() >>> cert.SHA1 '9E0A06CFB37B352FDA5B2226E6D631CF07D5D185'
Returns: SHA1 Fingerprint string in hexadecimal and upper case.
SHA256
property
SHA256: str
Examples: >>> cert = cnert.CA().issue_cert() >>> cert.SHA256 '68307A6CBE2804038DF85FB53AEE96AB47EA81439AB2E059DDDEA9F901097D84'
Returns: SHA256 Fingerprint string in hexadecimal and upper case.
authority_key_identifier_digest
property
authority_key_identifier_digest: str | None
Examples: >>> cert = cnert.CA().issue_cert() >>> cert.authority_key_identifier_digest '8F85C564F62E39D5A5CA346CA26AAE67029B671E'
Returns: The binary value of the authority key identifier in hexadecimal and upper case or None when certificate has no subject key identifier extension.
private_key_pem_PKCS1
property
private_key_pem_PKCS1: bytes
Examples: >>> cert = CA().issue_cert() >>> cert.private_key_pem_PKCS1 b'-----begin rsa private key----- ...
Raises: ValueError: If the key is not an RSA key. PKCS#1 is RSA-only.
Returns: PEM encoded serialized key in TraditionalOpenSSL format.
private_key_pem_PKCS8
property
private_key_pem_PKCS8: bytes
Examples: >>> cert = CA().issue_cert() >>> cert.private_key_pem_PKCS8 b'-----BEGIN PRIVATE KEY----- ...
Returns: PEM encoded serialized key in PKCS8 format.
public_key
property
public_key: CertificateIssuerPublicKeyTypes
Examples:
>>> cert = cnert.CA().issue_cert()
>>> cert.public_key
Returns: The public key matching this certificate's private key.
public_key_pem
property
public_key_pem: bytes
Examples: >>> cert = CA().issue_cert() >>> cert.public_key_pem b'-----BEGIN PUBLIC KEY----- ...
Returns: PEM encoded serialized key in RSAPublicKey format.
subject_key_identifier_digest
property
subject_key_identifier_digest: str
Examples: >>> cert = cnert.CA().issue_cert() >>> cert.subject_key_identifier_digest '8F85C564F62E39D5A5CA346CA26AAE67029B671E'
Returns: The binary value of the subject key identifier in hexadecimal and upper case.
Class cnert.CSR
CSR
CSR(
*sans: str,
subject_attrs: NameAttrs | None = None,
private_key: CertificateIssuerPrivateKeyTypes
| None = None,
signature_hash: HashAlgorithm
| str
| _UnsetType
| None = _UNSET,
extensions: Sequence[tuple[ExtensionType, bool]] = (),
builtin_extensions: bool = True,
)
A CSR object.
Examples: >>> csr = cnert.CSR()
Parameters:
sans: Subject Alternative Names as positional arguments
subject_attrs: Subject Name Attributes
private_key: Private key; generated when omitted.
signature_hash: Signature hash algorithm. Defaults to SHA-256,
or to None for an Edwards key, which takes no hash.
extensions: Extra (extension, critical) pairs. One that
collides with a built-in extension replaces it wholesale.
builtin_extensions: Add cnert's own extensions. When false,
only the supplied pairs are added, subject alternative
names included.
| Attributes: |
|
|---|
private_key_pem_PKCS1
property
private_key_pem_PKCS1: bytes
Raises: ValueError: If the key is not an RSA key. PKCS#1 is RSA-only.
Returns: PEM encoded serialized key in TraditionalOpenSSL format.
Function build_private_key
build_private_key
build_private_key(
key_size: int | None = None,
public_exponent: int | None = None,
algorithm: str = "rsa",
) -> CertificateIssuerPrivateKeyTypes
Creates a private key.
Examples: >>> build_private_key() # 2048-bit RSA >>> build_private_key(algorithm="ed25519") >>> build_private_key(key_size=1024)
Parameters:
key_size: RSA key size, default 2048. RSA only.
public_exponent: RSA public exponent, default 65537. RSA only.
algorithm: One of cnert.KEY_ALGORITHMS: rsa (default),
ed25519, ed448, or an EC curve name such as
secp256r1.
Raises:
ValueError: If algorithm is unknown, or if key_size or
public_exponent is given for a non-RSA algorithm.
Returns: A private key of the requested algorithm.
Key algorithms
cnert.KEY_ALGORITHMS is the tuple of names build_private_key
accepts: rsa (the default), ed25519, ed448, and the curve names
secp256r1, secp384r1 and secp521r1.
Signature hashes are chosen with the signature_hash argument on
Cert, CSR, CA and CA.issue_cert(). It takes a name from
cnert.SIGNATURE_HASHES or a cryptography hash object:
import cnert
cert = cnert.CA().issue_cert("example.com", signature_hash="sha512")
It defaults to SHA-256, and to None for an Edwards key, which signs
without a separate hash. SHA-1 and MD5 are refused by either form:
they cannot sign an X.509 certificate.
Extra extensions
Cert, CSR, CA and CA.issue_cert() take an extensions
sequence of (extension, critical) pairs, for anything cnert does not
model itself:
from cryptography import x509
import cnert
must_staple = x509.TLSFeature([x509.TLSFeatureType.status_request])
cert = cnert.CA().issue_cert("example.com", extensions=[(must_staple, False)])
A supplied extension whose object identifier matches one cnert adds by itself replaces cnert's version wholesale, keeping its position. That makes the argument an override as well as an addition, and it is the only way to change key usage or basic constraints.
To subtract instead, pass builtin_extensions=False. Only the
supplied pairs are then added, subject alternative names included, so
a bare certificate carrying exactly one chosen extension is one call:
import cnert
bare = cnert.CA().issue_cert("example.com", builtin_extensions=False)
A certificate built that way is not valid for any real use, and an authority built that way is not a usable authority. That is the point. It is how a parser test proves an absent extension reads as absent.
Supplying keys
CA(), CA.issue_intermediate() and CA.issue_cert() take a
private_key, which is how an undersized key or an unusual public
exponent becomes reachable:
import cnert
ca = cnert.CA(private_key=cnert.build_private_key(key_size=1024))
cert = ca.issue_cert(
"example.com", private_key=cnert.build_private_key(public_exponent=3)
)
A supplied key is the certificate's subject key only. The signature
always comes from the issuing CA's key. A csr already carries a key,
so passing both a csr and a private_key raises ValueError.
Passing the same key at several levels is allowed, and is how a
key-reuse fixture is built.
Function idna_encode
idna_encode
Creates a valid internationalized domain name
Parameters: _string: Internationalized domain name
Function identity_string_to_x509
identity_string_to_x509
identity_string_to_x509(identity: str) -> GeneralName
Creates a x509.GeneralName from a string.
Parameters: identity: IP Address, DNS name or email address.