django_ca.pydantic - Pydantic models

Type aliases

Reusable type aliases for Pydantic models.

django_ca.pydantic.type_aliases.Base64EncodedBytes

A bytes type that validates strings as base64-encoded strings and serializes as such when using JSON.

This type differs from pydantic.Base64Bytes in that bytes are left untouched and strings are decoded before the inner validation logic, making this type suitable for strict type validation.

alias of Annotated[bytes]

django_ca.pydantic.type_aliases.EllipticCurveTypeAlias

A type alias for EllipticCurve instances.

This type alias validates names from ELLIPTIC_CURVE_TYPES and serializes to the canonical name in JSON. Models using this type alias can be used with strict schema validation.

alias of Annotated[EllipticCurve]

django_ca.pydantic.type_aliases.HashAlgorithmTypeAlias

A type alias for HashAlgorithm instances.

This type alias validates names from HASH_ALGORITHM_TYPES and serializes to the canonical name in JSON. Models using this type alias can be used with strict schema validation.

alias of Annotated[Union[SHA224, SHA256, SHA384, SHA512, SHA3_224, SHA3_256, SHA3_384, SHA3_512]]

django_ca.pydantic.type_aliases.PowerOfTwoTypeAlias

A type alias for an integer that is a power of two, e.g. an RSA/DSA KeySize.

Note that this type alias does not validate CA_MIN_KEY_SIZE, as validators in this module must not use any settings, as this would cause a circular import.

alias of Annotated[int]

django_ca.pydantic.type_aliases.Serial

A certificate serial as a hex string, as they are stored in the database.

This type will convert integers to hex and upper-case any lower-case strings. The minimum length is 1 character, the maximum length is 40 (RFC 5280, section 4.1.2.2 specifies a maximum of 20 octets, which equals 40 characters in hex).

alias of Annotated[str]

Cryptography classes

All cryptography-related classes share that they can be instantiated from cryptography instances using model_validate() and share a cryptography property that converts a model instance into a cryptography instance:

>>> from cryptography import x509
>>> from cryptography.x509.oid import NameOID
>>> from django_ca.pydantic.name import NameAttributeModel
>>> attr = x509.NameAttribute(oid=NameOID.COMMON_NAME, value="example.com")
>>> model = NameAttributeModel.model_validate(attr)
>>> model
NameAttributeModel(oid='2.5.4.3', value='example.com')
>>> model.cryptography == attr
True

Name

class django_ca.pydantic.NameAttributeModel(*, oid: str, value: str)[source]

Pydantic model wrapping NameAttribute.

For the oid, you can either use a dotted string or an alias from NAME_OID_TYPES:

from django_ca.pydantic import NameAttributeModel

NameAttributeModel(
    oid="CN",  #  or "commonName" or NameOID.COMMON_NAME or just "2.5.4.3"
    value="example.com",
)
from cryptography import x509
from cryptography.x509.oid import NameOID

x509.NameAttribute(oid=NameOID.COMMON_NAME, value="example.com")
{
    "oid": "2.5.4.3",
    "value": "example.com"
}

When processing a x500 unique identifier attribute, the value is expected to be base64 encoded:

import base64

from django_ca.pydantic import NameAttributeModel

value = base64.b64encode(b"example.com")
NameAttributeModel(oid="x500UniqueIdentifier", value=value)
from cryptography import x509
from cryptography.x509.name import _ASN1Type
from cryptography.x509.oid import NameOID

x509.NameAttribute(
    oid=NameOID.X500_UNIQUE_IDENTIFIER, value=b"example.com", _type=_ASN1Type.BitString
)
{
    "oid": "2.5.4.45",
    "value": "ZXhhbXBsZS5jb20="
}

property cryptography: NameAttribute

The NameAttribute instance for this model.

class django_ca.pydantic.NameModel(root: RootModelRootType = PydanticUndefined)[source]

Pydantic model wrapping Name.

This model is a Pydantic RootModel that takes a list of NameAttributeModel instances:

from django_ca.pydantic import NameAttributeModel, NameModel

NameModel(
    [
        NameAttributeModel(oid="C", value="AT"),
        NameAttributeModel(oid="CN", value="example.com"),
    ]
)
from cryptography import x509
from cryptography.x509.oid import NameOID

x509.Name(
    [
        x509.NameAttribute(oid=NameOID.COUNTRY_NAME, value="AT"),
        x509.NameAttribute(oid=NameOID.COMMON_NAME, value="example.com"),
    ]
)
[
    {
        "oid": "2.5.4.6",
        "value": "AT"
    },
    {
        "oid": "2.5.4.3",
        "value": "example.com"
    }
]

property cryptography: Name

The Name instance for this model.

GeneralName

class django_ca.pydantic.GeneralNameModel(*, type: Literal['email', 'URI', 'IP', 'DNS', 'RID', 'dirName', 'otherName'], value: str | NameModel | OtherNameModel | IPv4Address | IPv6Address | IPv4Network | IPv6Network)[source]

Pydantic model wrapping NameAttribute.

This model takes a type named in GENERAL_NAME_TYPES and a value that is usually a str:

from django_ca.pydantic import GeneralNameModel

GeneralNameModel(type="DNS", value="example.com")
from cryptography import x509

x509.DNSName("example.com")
{
    "type": "DNS",
    "value": "example.com"
}

For directory names, you have to pass a NameModel instead:

from django_ca.pydantic import GeneralNameModel, NameAttributeModel, NameModel

name = NameModel([NameAttributeModel(oid="CN", value="example.com")])
GeneralNameModel(type="dirName", value=name)
from cryptography import x509
from cryptography.x509.oid import NameOID

name = x509.Name([x509.NameAttribute(oid=NameOID.COMMON_NAME, value="example.com")])
x509.DirectoryName(name)
{
    "type": "dirName",
    "value": [
        {
            "oid": "2.5.4.3",
            "value": "example.com"
        }
    ]
}

For OtherName instances, pass a OtherNameModel instead:

from django_ca.pydantic import GeneralNameModel, OtherNameModel

other_name = OtherNameModel(oid="1.2.3", type="UTF8String", value="some_string")
GeneralNameModel(type="otherName", value=other_name)
from asn1crypto.core import UTF8String
from cryptography import x509

value = UTF8String("some_string").dump()  # equals b"\x0c\x0bsome_string"
x509.OtherName(type_id=x509.ObjectIdentifier("1.2.3"), value=value)
{
    "type": "otherName",
    "value": {
        "oid": "1.2.3",
        "type": "UTF8String",
        "value": "some_string"
    }
}

property cryptography: GeneralName

Convert to a GeneralName instance.

class django_ca.pydantic.OtherNameModel(*, oid: str, type: Literal['UTF8String', 'UNIVERSALSTRING', 'IA5STRING', 'BOOLEAN', 'NULL', 'UTCTIME', 'GENERALIZEDTIME', 'INTEGER', 'OctetString'], value: str | bool | datetime | int | None)[source]

Pydantic model wrapping OtherName.

The oid argument may be any valid object identifier as dotted string (e.g. "1.2.3").

The type argument may be any type in OTHER_NAME_TYPES or OTHER_NAME_ALIASES.

The type of the value argument depends on the type value. String variants (UTFString, etc.) require a str, boolean requires a bool value and so on:

from django_ca.pydantic import OtherNameModel

OtherNameModel(oid="1.2.3", type="UTF8String", value="some_string")
from asn1crypto.core import UTF8String
from cryptography import x509

value = UTF8String("some_string").dump()  # equals b"\x0c\x0bsome_string"
x509.OtherName(type_id=x509.ObjectIdentifier("1.2.3"), value=value)
{
    "oid": "1.2.3",
    "type": "UTF8String",
    "value": "some_string"
}

For datetime variants (UTCTIME and GENERALIZEDTIME), you must pass a timezone-aware object:

from datetime import datetime, timezone

from django_ca.pydantic import OtherNameModel

dt = datetime(2021, 10, 5, 22, 1, 4, tzinfo=timezone.utc)
OtherNameModel(oid="1.2.3", type="UTCTIME", value=dt)
from datetime import datetime, timezone

from asn1crypto.core import UTCTime
from cryptography import x509

dt = datetime(2021, 10, 5, 22, 1, 4, tzinfo=timezone.utc)
value = UTCTime(dt).dump()  # equals b"\x0c\x0bsome_string"
x509.OtherName(type_id=x509.ObjectIdentifier("1.2.3"), value=value)
{
    "oid": "1.2.3",
    "type": "UTCTIME",
    "value": "2021-10-05T22:01:04Z"
}

For INTEGER, you can pass an int or a str for a base 16 integer:

from django_ca.pydantic import OtherNameModel

OtherNameModel(oid="1.2.3", type="INTEGER", value="0x0C")  # or pass 12 (equals 0x0C)
from asn1crypto.core import Integer
from cryptography import x509

value = Integer(12).dump()
x509.OtherName(type_id=x509.ObjectIdentifier("1.2.3"), value=value)
{
    "oid": "1.2.3",
    "type": "INTEGER",
    "value": 12
}

Finally, for an OctetString, pass the raw bytes or as a hex-encoded string:

from django_ca.pydantic import OtherNameModel

# Or pass decoded b"\x61\x62\x63" for a value
OtherNameModel(oid="1.2.3", type="OctetString", value="616263")
from asn1crypto.core import OctetString
from cryptography import x509

value = OctetString(b"\x61\x62\x63").dump()  # equals b"\x61\x62\x63"
x509.OtherName(type_id=x509.ObjectIdentifier("1.2.3"), value=value)
{
    "oid": "1.2.3",
    "type": "OctetString",
    "value": "616263"
}

As usual, the cryptography property will return the cryptography variant of the model:

>>> OtherNameModel(oid="1.2.3", type="IA5STRING", value="some string").cryptography
<OtherName(type_id=<ObjectIdentifier(oid=1.2.3, name=Unknown OID)>, value=b'\x16\x0bsome string')>
property cryptography: OtherName

Convert to a OtherName instance.

Extensions

Pydantic models for x509 extensions.

Every extension model has exactly three parameters, critical, value and type.

The critical parameter is a boolean value. It usually defaults to the recommended value (usually in RFC 5280), but is mandatory in some extensions where no value is defined. Default values are defined in EXTENSION_DEFAULT_CRITICAL.

The value parameter represents the actual value of the extension, and its format is different for every extension. In trivial extensions (for example in the InhibitAnyPolicyModel), this is usually a basic type:

>>> InhibitAnyPolicyModel(value=1)
InhibitAnyPolicyModel(critical=True, value=1)

More complex extensions require a nested model:

>>> dpoint = DistributionPointModel(
...     full_name=[{"type": "URI", "value": "https://ca.example.com/crl"}]
... )
>>> CRLDistributionPointsModel(value=[dpoint])  
CRLDistributionPointsModel(
    critical=False,
    value=[DistributionPointModel(
        full_name=[GeneralNameModel(type='URI', value='https://ca.example.com/crl')],
        relative_name=None, crl_issuer=None, reasons=None
    )]
)

Nested models are described in more details under Extension attributes.

Every model has a cryptography property returning the Extension instance and an extension_type property returning the ExtensionType instance:

>>> ext_model = InhibitAnyPolicyModel(value=1)
>>> ext_model.extension_type
<InhibitAnyPolicy(skip_certs=1)>
>>> ext_model.cryptography  
<Extension(
    oid=<ObjectIdentifier(oid=2.5.29.54, name=inhibitAnyPolicy)>,
    critical=True,
    value=<InhibitAnyPolicy(skip_certs=1)>
)>

Finally, the type parameter is a literal string used to identify the type of extension. It is mandatory in serialized versions of a model (e.g. as JSON), but does not have to be given when instantiating a model directly.

class django_ca.pydantic.AuthorityInformationAccessModel(*, type: Literal['authority_information_access'] = 'authority_information_access', critical: bool = False, value: list[AccessDescriptionModel])[source]

Pydantic model for a AuthorityInformationAccess extension.

The value is a list of AccessDescriptionModel instances:

from django_ca.pydantic import (
    AccessDescriptionModel,
    AuthorityInformationAccessModel,
    GeneralNameModel,
)

AuthorityInformationAccessModel(
    value=[
        AccessDescriptionModel(
            access_method="ocsp",
            access_location=GeneralNameModel(type="URI", value="http://ocsp.example.com"),
        ),
        AccessDescriptionModel(
            access_method="ca_issuers",
            access_location=GeneralNameModel(type="URI", value="http://example.com"),
        ),
    ]
)
from cryptography import x509
from cryptography.x509.oid import AuthorityInformationAccessOID, ExtensionOID

x509.Extension(
    critical=False,
    oid=ExtensionOID.AUTHORITY_INFORMATION_ACCESS,
    value=x509.AuthorityInformationAccess(
        [
            x509.AccessDescription(
                access_method=AuthorityInformationAccessOID.OCSP,
                access_location=x509.UniformResourceIdentifier("http://ocsp.example.com"),
            ),
            x509.AccessDescription(
                access_method=AuthorityInformationAccessOID.CA_ISSUERS,
                access_location=x509.UniformResourceIdentifier("http://example.com"),
            ),
        ]
    ),
)
{
    "type": "authority_information_access",
    "critical": false,
    "value": [
        {
            "access_method": "1.3.6.1.5.5.7.48.1",
            "access_location": {
                "type": "URI",
                "value": "http://ocsp.example.com"
            }
        },
        {
            "access_method": "1.3.6.1.5.5.7.48.2",
            "access_location": {
                "type": "URI",
                "value": "http://example.com"
            }
        }
    ]
}

class django_ca.pydantic.AuthorityKeyIdentifierModel(*, type: Literal['authority_key_identifier'] = 'authority_key_identifier', critical: bool = False, value: AuthorityKeyIdentifierValueModel)[source]

Pydantic model for a AuthorityKeyIdentifier extension.

The value is a AuthorityKeyIdentifierValueModel instance:

from django_ca.pydantic import (
    AuthorityKeyIdentifierModel,
    AuthorityKeyIdentifierValueModel,
)

AuthorityKeyIdentifierModel(
    value=AuthorityKeyIdentifierValueModel(key_identifier=b"MTIz")
)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(
    critical=False,
    oid=ExtensionOID.AUTHORITY_KEY_IDENTIFIER,
    value=x509.AuthorityKeyIdentifier(
        key_identifier=b"123",
        authority_cert_issuer=None,
        authority_cert_serial_number=None,
    ),
)
{
    "type": "authority_key_identifier",
    "critical": false,
    "value": {
        "key_identifier": "MTIz\n",
        "authority_cert_issuer": null,
        "authority_cert_serial_number": null
    }
}

A version with an authority certificate would look like this:

from django_ca.pydantic import (
    AuthorityKeyIdentifierModel,
    AuthorityKeyIdentifierValueModel,
    GeneralNameModel,
)

AuthorityKeyIdentifierModel(
    value=AuthorityKeyIdentifierValueModel(
        key_identifier=None,
        authority_cert_issuer=[GeneralNameModel(type="URI", value="http://example.com")],
        authority_cert_serial_number=123,
    )
)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(
    critical=False,
    oid=ExtensionOID.AUTHORITY_KEY_IDENTIFIER,
    value=x509.AuthorityKeyIdentifier(
        key_identifier=None,
        authority_cert_issuer=[x509.UniformResourceIdentifier("http://example.com")],
        authority_cert_serial_number=123,
    ),
)
{
    "type": "authority_key_identifier",
    "critical": false,
    "value": {
        "key_identifier": null,
        "authority_cert_issuer": [
            {
                "type": "URI",
                "value": "http://example.com"
            }
        ],
        "authority_cert_serial_number": 123
    }
}

class django_ca.pydantic.BasicConstraintsModel(*, type: Literal['basic_constraints'] = 'basic_constraints', critical: bool = True, value: BasicConstraintsValueModel)[source]

Pydantic model for a BasicConstraints extension.

The value is a BasicConstraintsValueModel instance. For example, for end-entity certificates, ca is False and path_length is None:

from django_ca.pydantic import BasicConstraintsModel, BasicConstraintsValueModel

value = BasicConstraintsValueModel(ca=False, path_length=None)
BasicConstraintsModel(value=value)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

value = x509.BasicConstraints(ca=False, path_length=None)
x509.Extension(critical=True, oid=ExtensionOID.BASIC_CONSTRAINTS, value=value)
{
    "type": "basic_constraints",
    "critical": true,
    "value": {
        "ca": false,
        "path_length": null
    }
}

For certificate authorities, ca is True, and path_length may be a positive integer:

from django_ca.pydantic import BasicConstraintsModel, BasicConstraintsValueModel

value = BasicConstraintsValueModel(ca=True, path_length=0)
BasicConstraintsModel(value=value)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

value = x509.BasicConstraints(ca=True, path_length=0)
x509.Extension(critical=True, oid=ExtensionOID.BASIC_CONSTRAINTS, value=value)
{
    "type": "basic_constraints",
    "critical": true,
    "value": {
        "ca": true,
        "path_length": 0
    }
}

class django_ca.pydantic.CRLDistributionPointsModel(*, type: Literal['crl_distribution_points'] = 'crl_distribution_points', critical: bool = False, value: list[DistributionPointModel])[source]

Pydantic model for a CRLDistributionPoints extension.

The value is a list of DistributionPointModel instances:

from django_ca.pydantic import (
    CRLDistributionPointsModel,
    DistributionPointModel,
    GeneralNameModel,
    NameAttributeModel,
    NameModel,
)

simple_distribution_point = DistributionPointModel(
    full_name=[GeneralNameModel(type="URI", value="https://ca.example.com/crl")]
)

# Unusual distribution point: not observed in practice, usually only a full name is used.
unusual_distribution_point = DistributionPointModel(
    relative_name=NameModel([NameAttributeModel(oid="2.5.4.3", value="example.com")]),
    crl_issuer=[GeneralNameModel(type="URI", value="https://ca.example.com/issuer")],
    reasons={"key_compromise"},
)

CRLDistributionPointsModel(value=[simple_distribution_point, unusual_distribution_point])
from cryptography import x509
from cryptography.x509.oid import ExtensionOID, NameOID

simple_distribution_point = x509.DistributionPoint(
    full_name=[x509.UniformResourceIdentifier("https://ca.example.com/crl")],
    relative_name=None,
    crl_issuer=None,
    reasons=None,
)

# Unusual distribution point: not observed in practice, usually only a full name is used.
unusual_distribution_point = x509.DistributionPoint(
    full_name=None,
    relative_name=x509.RelativeDistinguishedName(
        [x509.NameAttribute(oid=NameOID.COMMON_NAME, value="example.com")]
    ),
    crl_issuer=[x509.UniformResourceIdentifier("https://ca.example.com/issuer")],
    reasons=frozenset([x509.ReasonFlags.key_compromise]),
)

x509.Extension(
    critical=False,
    oid=ExtensionOID.CRL_DISTRIBUTION_POINTS,
    value=x509.CRLDistributionPoints(
        [simple_distribution_point, unusual_distribution_point]
    ),
)
{
    "type": "crl_distribution_points",
    "critical": false,
    "value": [
        {
            "full_name": [
                {
                    "type": "URI",
                    "value": "https://ca.example.com/crl"
                }
            ],
            "relative_name": null,
            "crl_issuer": null,
            "reasons": null
        },
        {
            "full_name": null,
            "relative_name": [
                {
                    "oid": "2.5.4.3",
                    "value": "example.com"
                }
            ],
            "crl_issuer": [
                {
                    "type": "URI",
                    "value": "https://ca.example.com/issuer"
                }
            ],
            "reasons": [
                "key_compromise"
            ]
        }
    ]
}

class django_ca.pydantic.CertificatePoliciesModel(*, type: Literal['certificate_policies'] = 'certificate_policies', critical: bool = False, value: list[PolicyInformationModel])[source]

Pydantic model for a CertificatePolicies extension.

The value is a list of PolicyInformationModel instances:

from django_ca.pydantic import (
    CertificatePoliciesModel,
    PolicyInformationModel,
    UserNoticeModel,
)

# anyPolicy model with no qualifiers.
any_policy = PolicyInformationModel(policy_identifier="2.5.29.32.0")

# CPS statement with a text and a user notice.
# NOTE: user notices are not observed in practice.
cps = PolicyInformationModel(
    policy_identifier="1.3.6.1.5.5.7.2.1",
    policy_qualifiers=[
        "https://ca.example.com/cps",
        UserNoticeModel(explicit_text="my text"),
    ],
)

CertificatePoliciesModel(value=[any_policy, cps])
from cryptography import x509
from cryptography.x509.oid import CertificatePoliciesOID, ExtensionOID

# anyPolicy model with no qualifiers.
any_policy = x509.PolicyInformation(
    policy_identifier=CertificatePoliciesOID.ANY_POLICY,
    policy_qualifiers=None,
)

# CPS statement with a text and a user notice.
# NOTE: user notices are not observed in practice.
cps = x509.PolicyInformation(
    policy_identifier=CertificatePoliciesOID.CPS_QUALIFIER,
    policy_qualifiers=[
        "https://ca.example.com/cps",
        x509.UserNotice(explicit_text="my text", notice_reference=None),
    ],
)

x509.Extension(
    critical=False,
    oid=ExtensionOID.CERTIFICATE_POLICIES,
    value=x509.CertificatePolicies([any_policy, cps]),
)
{
    "type": "certificate_policies",
    "critical": false,
    "value": [
        {
            "policy_identifier": "2.5.29.32.0",
            "policy_qualifiers": null
        },
        {
            "policy_identifier": "1.3.6.1.5.5.7.2.1",
            "policy_qualifiers": [
                "https://ca.example.com/cps",
                {
                    "notice_reference": null,
                    "explicit_text": "my text"
                }
            ]
        }
    ]
}

class django_ca.pydantic.ExtendedKeyUsageModel(*, type: Literal['extended_key_usage'] = 'extended_key_usage', critical: bool = False, value: list[str])[source]

Pydantic model for a ExtendedKeyUsage extension.

The value is a list valid object identifiers as dotted strings. For convenience, any name from EXTENDED_KEY_USAGE_NAMES can also be given:

from django_ca.pydantic import ExtendedKeyUsageModel

ExtendedKeyUsageModel(value=["clientAuth", "1.3.6.1.5.5.7.3.1"])
from cryptography import x509
from cryptography.x509.oid import ExtendedKeyUsageOID, ExtensionOID

x509.Extension(
    critical=False,
    oid=ExtensionOID.EXTENDED_KEY_USAGE,
    value=x509.ExtendedKeyUsage(
        [ExtendedKeyUsageOID.CLIENT_AUTH, x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1")]
    ),
)
{
    "type": "extended_key_usage",
    "critical": false,
    "value": [
        "1.3.6.1.5.5.7.3.2",
        "1.3.6.1.5.5.7.3.1"
    ]
}

class django_ca.pydantic.FreshestCRLModel(*, type: Literal['freshest_crl'] = 'freshest_crl', critical: bool = False, value: list[DistributionPointModel])[source]

Pydantic model for a FreshestCRL extension.

This model behaves exactly like CRLDistributionPointsModel.

class django_ca.pydantic.InhibitAnyPolicyModel(*, type: Literal['inhibit_any_policy'] = 'inhibit_any_policy', critical: bool = True, value: int)[source]

Pydantic model for a InhibitAnyPolicy extension.

The value attribute is an integer:

from django_ca.pydantic import InhibitAnyPolicyModel

InhibitAnyPolicyModel(value=1)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(
    critical=True, oid=ExtensionOID.INHIBIT_ANY_POLICY, value=x509.InhibitAnyPolicy(1)
)
{
    "type": "inhibit_any_policy",
    "critical": true,
    "value": 1
}

class django_ca.pydantic.IssuerAlternativeNameModel(*, type: Literal['issuer_alternative_name'] = 'issuer_alternative_name', critical: bool = False, value: list[GeneralNameModel])[source]

Pydantic model for a IssuerAlternativeName extension.

This model behaves exactly like SubjectAlternativeNameModel.

class django_ca.pydantic.KeyUsageModel(*, type: Literal['key_usage'] = 'key_usage', critical: bool = True, value: list[Literal['crl_sign', 'data_encipherment', 'decipher_only', 'digital_signature', 'encipher_only', 'key_agreement', 'key_cert_sign', 'key_encipherment', 'content_commitment']])[source]

Pydantic model for a KeyUsage extension.

All key usages default to False, so you can skip giving any usages you don’t care about. For convenience, the model also accepts values as used in RFC 5280 (full mapping in KEY_USAGE_NAMES):

from django_ca.pydantic import KeyUsageModel

# Use key OR value from KEY_USAGE_NAMES:
KeyUsageModel(value=["key_agreement", "keyEncipherment"])
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(
    critical=True,
    oid=ExtensionOID.KEY_USAGE,
    value=x509.KeyUsage(
        content_commitment=False,
        crl_sign=False,
        data_encipherment=False,
        decipher_only=False,
        digital_signature=False,
        encipher_only=False,
        key_agreement=True,
        key_cert_sign=False,
        key_encipherment=True,
    ),
)
{
    "type": "key_usage",
    "critical": true,
    "value": [
        "key_agreement",
        "key_encipherment"
    ]
}

class django_ca.pydantic.MSCertificateTemplateModel(*, type: Literal['ms_certificate_template'] = 'ms_certificate_template', critical: bool, value: MSCertificateTemplateValueModel)[source]

Pydantic model for a MSCertificateTemplate extension.

The value is a MSCertificateTemplateValueModel instance, where major_version and minor_version are both optional:

from django_ca.pydantic import MSCertificateTemplateModel, MSCertificateTemplateValueModel

MSCertificateTemplateModel(
    critical=True,
    value=MSCertificateTemplateValueModel(
        template_id="1.2.3", major_version=1, minor_version=2
    ),
)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(
    critical=True,
    oid=ExtensionOID.MS_CERTIFICATE_TEMPLATE,
    value=x509.MSCertificateTemplate(
        template_id=x509.ObjectIdentifier("1.2.3"), major_version=1, minor_version=2
    ),
)
{
    "type": "ms_certificate_template",
    "critical": true,
    "value": {
        "template_id": "1.2.3",
        "major_version": 1,
        "minor_version": 2
    }
}

Note that this extension does not have a default defined for the critical parameter, so it is mandatory.

class django_ca.pydantic.NameConstraintsModel(*, type: Literal['name_constraints'] = 'name_constraints', critical: bool = True, value: NameConstraintsValueModel)[source]

Pydantic model for a NameConstraints extension.

The value is a NameConstraintsValueModel instance, where at least one of permitted_subtrees and excluded_subtrees must be given. For example, a certificate authority that can only sign certificates under .com would look like this:

from django_ca.pydantic import (
    GeneralNameModel,
    NameConstraintsModel,
    NameConstraintsValueModel,
)

value = NameConstraintsValueModel(
    permitted_subtrees=[GeneralNameModel(type="DNS", value=".com")]
)
NameConstraintsModel(value=value)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(
    critical=True,
    oid=ExtensionOID.NAME_CONSTRAINTS,
    value=x509.NameConstraints(
        permitted_subtrees=[x509.DNSName(".com")], excluded_subtrees=None
    ),
)
{
    "type": "name_constraints",
    "critical": true,
    "value": {
        "permitted_subtrees": [
            {
                "type": "DNS",
                "value": ".com"
            }
        ],
        "excluded_subtrees": null
    }
}

In this example, the certificate authority can sign certificates for .com, except for one.example.com and two.example.com:

from django_ca.pydantic import (
    GeneralNameModel,
    NameConstraintsModel,
    NameConstraintsValueModel,
)

value = NameConstraintsValueModel(
    permitted_subtrees=[GeneralNameModel(type="DNS", value=".com")],
    excluded_subtrees=[
        GeneralNameModel(type="DNS", value="one.example.com"),
        GeneralNameModel(type="DNS", value="two.example.com"),
    ],
)
NameConstraintsModel(value=value)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(
    critical=True,
    oid=ExtensionOID.NAME_CONSTRAINTS,
    value=x509.NameConstraints(
        permitted_subtrees=[x509.DNSName(".com")],
        excluded_subtrees=[
            x509.DNSName("one.example.com"),
            x509.DNSName("two.example.com"),
        ],
    ),
)
{
    "type": "name_constraints",
    "critical": true,
    "value": {
        "permitted_subtrees": [
            {
                "type": "DNS",
                "value": ".com"
            }
        ],
        "excluded_subtrees": [
            {
                "type": "DNS",
                "value": "one.example.com"
            },
            {
                "type": "DNS",
                "value": "two.example.com"
            }
        ]
    }
}

class django_ca.pydantic.OCSPNoCheckModel(*, type: Literal['ocsp_no_check'] = 'ocsp_no_check', critical: bool = False, value: None = None)[source]

Pydantic model for a OCSPNoCheck extension.

This extension does not have a value, and thus can be instantiated without any parameters (but None is also accepted):

from django_ca.pydantic import OCSPNoCheckModel

OCSPNoCheckModel()
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(critical=False, oid=ExtensionOID.OCSP_NO_CHECK, value=x509.OCSPNoCheck())
{
    "type": "ocsp_no_check",
    "critical": false,
    "value": null
}

class django_ca.pydantic.PolicyConstraintsModel(*, type: Literal['policy_constraints'] = 'policy_constraints', critical: bool = True, value: PolicyConstraintsValueModel)[source]

Pydantic model for a PolicyConstraints extension.

The value is a PolicyConstraintsValueModel instance. Both require_explicit_policy and inhibit_policy_mapping are optional integers >= 0, but at least one of them must be set:

from django_ca.pydantic import PolicyConstraintsModel, PolicyConstraintsValueModel

value = PolicyConstraintsValueModel(require_explicit_policy=0, inhibit_policy_mapping=1)
PolicyConstraintsModel(value=value)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

value = x509.PolicyConstraints(require_explicit_policy=0, inhibit_policy_mapping=1)
x509.Extension(critical=True, oid=ExtensionOID.POLICY_CONSTRAINTS, value=value)
{
    "type": "policy_constraints",
    "critical": true,
    "value": {
        "require_explicit_policy": 0,
        "inhibit_policy_mapping": 1
    }
}

class django_ca.pydantic.PrecertPoisonModel(*, type: Literal['precert_poison'] = 'precert_poison', critical: bool = True, value: None = None)[source]

Pydantic model for a PrecertPoison extension.

This extension does not have a value, and thus can be instantiated without any parameters (but None is also accepted):

from django_ca.pydantic import PrecertPoisonModel

PrecertPoisonModel()
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(critical=True, oid=ExtensionOID.PRECERT_POISON, value=x509.PrecertPoison())
{
    "type": "precert_poison",
    "critical": true,
    "value": null
}

class django_ca.pydantic.PrecertificateSignedCertificateTimestampsModel(*, type: Literal['precertificate_signed_certificate_timestamps'] = 'precertificate_signed_certificate_timestamps', critical: bool = False, value: list[SignedCertificateTimestampModel])[source]

Model for a PrecertificateSignedCertificateTimestamps extension.

Note

Due to library limitations, this model cannot be converted to a cryptography class.

The value is a list of SignedCertificateTimestampModel instances:

>>> from datetime import datetime
>>> sct = SignedCertificateTimestampModel(
...     log_id=b"MTIz", timestamp=datetime(2023, 12, 10), entry_type="precertificate"
... )
>>> PrecertificateSignedCertificateTimestampsModel(
...     value=[sct]
... )  
PrecertificateSignedCertificateTimestampsModel(
    critical=False,
    value=[
        SignedCertificateTimestampModel(
            version='v1',
            log_id=b'123',
            timestamp=datetime.datetime(2023, 12, 10, 0, 0),
            entry_type='precertificate'
        )
    ]
)
class django_ca.pydantic.SignedCertificateTimestampsModel(*, type: Literal['signed_certificate_timestamps'] = 'signed_certificate_timestamps', critical: bool = False, value: list[SignedCertificateTimestampModel])[source]

Pydantic model for a SignedCertificateTimestamps extension.

This model behaves exactly like PrecertificateSignedCertificateTimestampsModel.

class django_ca.pydantic.SubjectAlternativeNameModel(*, type: Literal['subject_alternative_name'] = 'subject_alternative_name', critical: bool = False, value: list[GeneralNameModel])[source]

Pydantic model for a SubjectAlternativeName extension.

The general_names attribute is a list of GeneralNameModel instances:

from django_ca.pydantic import GeneralNameModel, SubjectAlternativeNameModel

SubjectAlternativeNameModel(
    value=[
        GeneralNameModel(type="DNS", value="example.com"),
        GeneralNameModel(type="DNS", value="example.net"),
    ]
)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

value = x509.SubjectAlternativeName(
    [x509.DNSName("example.com"), x509.DNSName("example.net")]
)
x509.Extension(critical=False, oid=ExtensionOID.SUBJECT_ALTERNATIVE_NAME, value=value)
{
    "type": "subject_alternative_name",
    "critical": false,
    "value": [
        {
            "type": "DNS",
            "value": "example.com"
        },
        {
            "type": "DNS",
            "value": "example.net"
        }
    ]
}

class django_ca.pydantic.SubjectInformationAccessModel(*, type: Literal['subject_information_access'] = 'subject_information_access', critical: bool = False, value: list[AccessDescriptionModel])[source]

Pydantic model for a SubjectInformationAccess extension.

This model behaves like the AuthorityInformationAccessModel, except that the access methods have to be ca_repository.

class django_ca.pydantic.SubjectKeyIdentifierModel(*, type: Literal['subject_key_identifier'] = 'subject_key_identifier', critical: bool = False, value: bytes)[source]

Pydantic model for a SubjectKeyIdentifier extension.

The value is a base64-encoded for the model:

from django_ca.pydantic import SubjectKeyIdentifierModel

SubjectKeyIdentifierModel(value="kA==", critical=False)
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(
    critical=False,
    oid=ExtensionOID.SUBJECT_KEY_IDENTIFIER,
    value=x509.SubjectKeyIdentifier(b"\x90"),
)
{
    "type": "subject_key_identifier",
    "critical": false,
    "value": "kA==\n"
}

class django_ca.pydantic.TLSFeatureModel(*, type: Literal['tls_feature'] = 'tls_feature', critical: bool = False, value: list[Literal['status_request', 'status_request_v2']])[source]

Pydantic model for a TLSFeature extension.

The value is a list of one or both of "status_request" and "status_request_v2".

from django_ca.pydantic import TLSFeatureModel

TLSFeatureModel(value=["status_request"])
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(
    critical=False,
    oid=ExtensionOID.TLS_FEATURE,
    value=x509.TLSFeature([x509.TLSFeatureType.status_request]),
)
{
    "type": "tls_feature",
    "critical": false,
    "value": [
        "status_request"
    ]
}

For convenience, the model also accepts keys named in TLS_FEATURE_NAMES:

from django_ca.pydantic import TLSFeatureModel

TLSFeatureModel(value=["OCSPMustStaple"])
from cryptography import x509
from cryptography.x509.oid import ExtensionOID

x509.Extension(
    critical=False,
    oid=ExtensionOID.TLS_FEATURE,
    value=x509.TLSFeature([x509.TLSFeatureType.status_request]),
)
{
    "type": "tls_feature",
    "critical": false,
    "value": [
        "status_request"
    ]
}

class django_ca.pydantic.UnrecognizedExtensionModel(*, type: Literal['unknown'] = 'unknown', critical: bool, value: UnrecognizedExtensionValueModel)[source]

Pydantic model for a UnrecognizedExtension extension.

The value a UnrecognizedExtensionValueModel value, the value is thus base64 encoded for the model:

from django_ca.pydantic import UnrecognizedExtensionModel, UnrecognizedExtensionValueModel

value = UnrecognizedExtensionValueModel(value="MTIz", oid="1.2.3")
UnrecognizedExtensionModel(critical=True, value=value)
from cryptography import x509

oid = x509.ObjectIdentifier("1.2.3")
value = x509.UnrecognizedExtension(oid=oid, value=b"123")
x509.Extension(critical=True, oid=oid, value=value)
{
    "type": "unknown",
    "critical": true,
    "value": {
        "oid": "1.2.3",
        "value": "MTIz\n"
    }
}

Extension attributes

Some extensions use a more complex datastructure, so attributes are represented as nested models.

class django_ca.pydantic.extension_attributes.AccessDescriptionModel(*, access_method: str, access_location: GeneralNameModel)[source]

Pydantic model wrapping AccessDescription.

The access_method may be a dotted string OID or one of the aliases listed in ACCESS_METHOD_TYPES. The access_location is a GeneralNameModel:

from django_ca.pydantic import AccessDescriptionModel, GeneralNameModel

access_location = GeneralNameModel(type="URI", value="http://ocsp.example.com")
AccessDescriptionModel(
    access_method="ocsp",  # or the OID: "1.3.6.1.5.5.7.48.1"
    access_location=access_location,
)
from cryptography import x509
from cryptography.x509.oid import AuthorityInformationAccessOID

access_location = x509.UniformResourceIdentifier("http://ocsp.example.com")
x509.AccessDescription(
    access_method=AuthorityInformationAccessOID.OCSP, access_location=access_location
)
{
    "access_method": "1.3.6.1.5.5.7.48.1",
    "access_location": {
        "type": "URI",
        "value": "http://ocsp.example.com"
    }
}

The syntax is identical for CA issuers:

from django_ca.pydantic import AccessDescriptionModel, GeneralNameModel

access_location = GeneralNameModel(type="URI", value="http://ca-issuers.example.com")
AccessDescriptionModel(
    access_method="ca_issuers",  # or the OID: "1.3.6.1.5.5.7.48.2"
    access_location=access_location,
)
from cryptography import x509
from cryptography.x509.oid import AuthorityInformationAccessOID

access_location = x509.UniformResourceIdentifier("http://ca-issuers.example.com")
x509.AccessDescription(
    access_method=AuthorityInformationAccessOID.CA_ISSUERS,
    access_location=access_location,
)
{
    "access_method": "1.3.6.1.5.5.7.48.2",
    "access_location": {
        "type": "URI",
        "value": "http://ca-issuers.example.com"
    }
}

property cryptography: AccessDescription

Convert to a AccessDescription instance.

class django_ca.pydantic.extension_attributes.AuthorityKeyIdentifierValueModel(*, key_identifier: bytes | None, authority_cert_issuer: list[GeneralNameModel] | None = None, authority_cert_serial_number: int | None = None)[source]

Pydantic model wrapping AuthorityKeyIdentifier.

In its by far most common form, this model will just set the key_identifier attribute, with a value based on the certificate authority. Since this is a bytes value, the input must be base64 encoded:

>>> AuthorityKeyIdentifierValueModel(key_identifier=b"MTIz")  
AuthorityKeyIdentifierValueModel(
    key_identifier=b'123', authority_cert_issuer=None, authority_cert_serial_number=None
)

You can also give a authority_cert_issuer (a list of GeneralNameModel) and an authority_cert_serial_number:

>>> AuthorityKeyIdentifierValueModel(
...     key_identifier=None,
...     authority_cert_issuer=[{'type': 'URI', 'value': 'http://example.com'}],
...     authority_cert_serial_number=123
... )  
AuthorityKeyIdentifierValueModel(
    key_identifier=None,
    authority_cert_issuer=[GeneralNameModel(type='URI', value='http://example.com')],
    authority_cert_serial_number=123
)

The restrictions defined in RFC 5280 apply, so authority_cert_issuer and authority_cert_serial_number must either be both present or None, and either key_identifier and/or authority_cert_issuer must be given.

property cryptography: AuthorityKeyIdentifier

Convert to a AuthorityKeyIdentifier instance.

class django_ca.pydantic.extension_attributes.BasicConstraintsValueModel(*, ca: bool, path_length: int | None)[source]

Pydantic model wrapping BasicConstraints.

For a certificate representing a certificate authority, this extension sets ca to True and a path length, which may be None:

>>> BasicConstraintsValueModel(ca=True, path_length=0)
BasicConstraintsValueModel(ca=True, path_length=0)

For end-entity certificates, this extension sets ca to False and must set path_length to None:

>>> BasicConstraintsValueModel(ca=False, path_length=None)
BasicConstraintsValueModel(ca=False, path_length=None)
property cryptography: BasicConstraints

Convert to a BasicConstraints instance.

class django_ca.pydantic.extension_attributes.DistributionPointModel(*, full_name: list[GeneralNameModel] | None = None, relative_name: NameModel | None = None, crl_issuer: list[GeneralNameModel] | None = None, reasons: set[Literal['aa_compromise', 'affiliation_changed', 'ca_compromise', 'certificate_hold', 'cessation_of_operation', 'key_compromise', 'privilege_withdrawn', 'superseded']] | None = None)[source]

Pydantic model wrapping DistributionPoint.

In its by far most common form, this model only has a full_name containing a URI:

>>> DistributionPointModel(
...     full_name=[{"type": "URI", "value": "https://ca.example.com/crl"}]
... )  
DistributionPointModel(
    full_name=[GeneralNameModel(type='URI', value='https://ca.example.com/crl')],
    relative_name=None, crl_issuer=None, reasons=None
)

Of course, other fields are also supported:

>>> DistributionPointModel(
...     relative_name=[{"oid": "2.5.4.3", "value": "example.com"}],
...     crl_issuer=[{"type": "URI", "value": "https://ca.example.com/issuer"}],
...     reasons={"key_compromise",}
... )  
DistributionPointModel(
    full_name=None,
    relative_name=NameModel(root=[NameAttributeModel(oid='2.5.4.3', value='example.com')]),
    crl_issuer=[GeneralNameModel(type='URI', value='https://ca.example.com/issuer')],
    reasons={'key_compromise'}
)
property cryptography: DistributionPoint

Convert to a DistributionPoint instance.

class django_ca.pydantic.extension_attributes.IssuingDistributionPointValueModel(*, only_contains_user_certs: bool = False, only_contains_ca_certs: bool = False, indirect_crl: bool = False, only_contains_attribute_certs: bool = False, only_some_reasons: set[Literal['aa_compromise', 'affiliation_changed', 'ca_compromise', 'certificate_hold', 'cessation_of_operation', 'key_compromise', 'privilege_withdrawn', 'superseded']] | None = None, full_name: list[GeneralNameModel] | None = None, relative_name: NameModel | None = None)[source]

Pydantic model wrapping IssuingDistributionPoint.

>>> full_name = [{"type": "URI", "value": "https://ca.example.com/crl"}]
>>> IssuingDistributionPointValueModel(full_name=full_name)  
IssuingDistributionPointValueModel(
    only_contains_user_certs=False,
    only_contains_ca_certs=False,
    indirect_crl=False,
    only_contains_attribute_certs=False,
    only_some_reasons=None,
    full_name=[GeneralNameModel(type='URI', value='https://ca.example.com/crl')],
    relative_name=None
)

Note that all attributes default to False or None and can thus be omitted, but at least one parameter needs to be given.

property cryptography: IssuingDistributionPoint

Convert to a IssuingDistributionPoint instance.

class django_ca.pydantic.extension_attributes.MSCertificateTemplateValueModel(*, template_id: str, major_version: int | None = None, minor_version: int | None = None)[source]

Pydantic model wrapping MSCertificateTemplate.

The template_id parameter is a dotted-string object identifier, while major_version and minor_version are optional integers:

>>> MSCertificateTemplateValueModel(template_id="1.2.3", major_version=1)
MSCertificateTemplateValueModel(template_id='1.2.3', major_version=1, minor_version=None)
property cryptography: MSCertificateTemplate

Convert to a MSCertificateTemplate instance.

class django_ca.pydantic.extension_attributes.NameConstraintsValueModel(*, permitted_subtrees: list[GeneralNameModel] | None = None, excluded_subtrees: list[GeneralNameModel] | None = None)[source]

Pydantic model wrapping NameConstraints.

Both permitted_subtrees and excluded_subtrees are optional, but at least one of them must be given. They are a list of GeneralNameModel instances:

>>> NameConstraintsValueModel(
...     permitted_subtrees=[{"type": "DNS", "value": ".com"}]
... )  
NameConstraintsValueModel(
    permitted_subtrees=[GeneralNameModel(type='DNS', value='.com')], excluded_subtrees=None
)
property cryptography: NameConstraints

Convert to a NameConstraints instance.

class django_ca.pydantic.extension_attributes.NoticeReferenceModel(*, organization: str | None = None, notice_numbers: list[int])[source]

Pydantic model wrapping NoticeReference.

>>> NoticeReferenceModel(organization="MyOrg", notice_numbers=[1, 2, 3])
NoticeReferenceModel(organization='MyOrg', notice_numbers=[1, 2, 3])

Note that organization is optional.

property cryptography: NoticeReference

Convert to a NoticeReference instance.

class django_ca.pydantic.extension_attributes.PolicyConstraintsValueModel(*, require_explicit_policy: int | None, inhibit_policy_mapping: int | None)[source]

Pydantic model wrapping PolicyConstraints.

The require_explicit_policy and inhibit_policy_mapping are both optional and must be integers if set. At least one value must be given.

>>> PolicyConstraintsValueModel(require_explicit_policy=0, inhibit_policy_mapping=1)
PolicyConstraintsValueModel(require_explicit_policy=0, inhibit_policy_mapping=1)
property cryptography: PolicyConstraints

Convert to a PolicyConstraints instance.

class django_ca.pydantic.extension_attributes.PolicyInformationModel(*, policy_identifier: str, policy_qualifiers: list[str | UserNoticeModel] | None = None)[source]

Pydantic model wrapping PolicyInformation.

In its simplest for, this model requires only a policy_identifier:

>>> PolicyInformationModel(policy_identifier="2.5.29.32.0")
PolicyInformationModel(policy_identifier='2.5.29.32.0', policy_qualifiers=None)

A list of policy_qualifiers may also be passed, with elements being either a str or a UserNoticeModel:

>>> notice = UserNoticeModel(explicit_text="my text")
>>> PolicyInformationModel(
...     policy_identifier="1.3.6.1.5.5.7.2.1",
...     policy_qualifiers=["https://ca.example.com/cps", notice]
... )  
PolicyInformationModel(
    policy_identifier='1.3.6.1.5.5.7.2.1',
    policy_qualifiers=[
        'https://ca.example.com/cps',
        UserNoticeModel(notice_reference=None, explicit_text='my text')
    ]
)
property cryptography: PolicyInformation

Convert to a PolicyInformation instance.

class django_ca.pydantic.extension_attributes.SignedCertificateTimestampModel(*, version: Literal['v1'] = 'v1', log_id: bytes, timestamp: datetime, entry_type: Literal['precertificate', 'x509_certificate'])[source]

Pydantic model wrapping SignedCertificateTimestamp.

Note

Due to library limitations, this model cannot be converted to a cryptography class.

>>> SignedCertificateTimestampModel(
...     log_id=b"MTIz", timestamp=datetime(2023, 12, 10), entry_type="precertificate"
... )  
SignedCertificateTimestampModel(
    version='v1',
    log_id=b'123',
    timestamp=datetime.datetime(2023, 12, 10, 0, 0),
    entry_type='precertificate'
)
property cryptography: NoReturn

Will always raise an exception for this class.

class django_ca.pydantic.extension_attributes.UnrecognizedExtensionValueModel(*, oid: str, value: bytes)[source]

Pydantic model for a UnrecognizedExtension extension.

The value a base64 encoded bytes value, and the oid is any dotted string:

>>> UnrecognizedExtensionValueModel(value=b"MTIz", oid="1.2.3")
UnrecognizedExtensionValueModel(oid='1.2.3', value=b'123')
property cryptography: UnrecognizedExtension

The UnrecognizedExtension instance.

class django_ca.pydantic.extension_attributes.UserNoticeModel(*, notice_reference: NoticeReferenceModel | None = None, explicit_text: str | None)[source]

Pydantic model wrapping UserNotice.

In its simplest form, the model can just take an explicit text:

>>> UserNoticeModel(explicit_text="my text")
UserNoticeModel(notice_reference=None, explicit_text='my text')

But it may also take notice reference:

>>> ref = NoticeReferenceModel(notice_numbers=[1, 2, 3])
>>> UserNoticeModel(notice_reference=ref, explicit_text="my text")  
UserNoticeModel(notice_reference=NoticeReferenceModel(organization=None,
                    notice_numbers=[1, 2, 3]),
                explicit_text='my text')
property cryptography: UserNotice

Convert to a UserNotice instance.

CRL extensions

Models for CRL extensions are not currently used within the project itself.

class django_ca.pydantic.CRLNumberModel(*, type: Literal['crl_number'] = 'crl_number', critical: bool = False, value: int)[source]

Pydantic model for a CRLNumber extension.

The value is an integer:

>>> CRLNumberModel(value=1)
CRLNumberModel(critical=False, value=1)
class django_ca.pydantic.DeltaCRLIndicatorModel(*, type: Literal['delta_crl_indicator'] = 'delta_crl_indicator', critical: bool = True, value: int)[source]

Pydantic model for a DeltaCRLIndicator extension.

The value is an integer:

>>> DeltaCRLIndicatorModel(value=1)
DeltaCRLIndicatorModel(critical=True, value=1)