django_ca.pydantic - Pydantic models

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.name.NameAttributeModel(*, oid: str, value: str)[source]

Pydantic model wrapping NameAttribute.

>>> from cryptography.x509.oid import NameOID
>>> NameAttributeModel(oid=NameOID.COMMON_NAME.dotted_string, value="example.com")
NameAttributeModel(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
>>> value = base64.b64encode(b"example.com")
>>> NameAttributeModel(oid=NameOID.X500_UNIQUE_IDENTIFIER.dotted_string, value=value)
NameAttributeModel(oid='2.5.4.45', value='ZXhhbXBsZS5jb20=')
property cryptography: NameAttribute

The NameAttribute instance for this model.

>>> NameAttributeModel(oid='2.5.4.3', value="example.com").cryptography
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value='example.com')>
classmethod parse_cryptography(data: Any) Any[source]

Validator to handle x500 unique identifiers.

validate_name_attribute() NameAttributeModel[source]

Validate that country code OIDs have exactly two characters.

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

Pydantic model wrapping Name.

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

>>> NameModel(
...     [
...         {'oid': '2.5.4.6', 'value': 'AT'},
...         {'oid': '2.5.4.3', 'value': 'example.com'}
...     ]
... ) 
NameModel(root=[
    NameAttributeModel(oid='2.5.4.6', value='AT'),
    NameAttributeModel(oid='2.5.4.3', value='example.com')
])
property cryptography: Name

The Name instance for this model.

classmethod parse_cryptography(data: Any) Any[source]

Validator for parsing Name.

validate_duplicates() NameModel[source]

Validator to make sure that OIDs do not occur multiple times.

GeneralName

class django_ca.pydantic.general_name.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:

>>> GeneralNameModel(type="DNS", value="example.com")
GeneralNameModel(type='DNS', value='example.com')

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

>>> GeneralNameModel(
...     type="dirName", value=[{"oid": "2.5.4.3", "value": "example.com"}]
... )  
GeneralNameModel(type='dirName',
                 value=NameModel(root=[NameAttributeModel(oid='2.5.4.3', value='example.com')]))

For OtherName instances, pass a OtherNameModel instead:

>>> GeneralNameModel(
...     type="otherName", value={"oid": "2.5.4.3", "type": "BOOLEAN", 'value': True}
... )  
GeneralNameModel(type='otherName',
                 value=OtherNameModel(oid='2.5.4.3', type='BOOLEAN', value=True))
property cryptography: GeneralName

Convert to a GeneralName instance.

classmethod parse_cryptography(data: Any) Any[source]

Validator to parse cryptography values.

validate_value() GeneralNameModel[source]

Validator to make sure that value is of the right type.

class django_ca.pydantic.general_name.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:

>>> OtherNameModel(oid="1.2.3", type="BOOLEAN", value=True)
OtherNameModel(oid='1.2.3', type='BOOLEAN', value=True)
>>> OtherNameModel(oid="1.2.3", type="NULL", value=None)
OtherNameModel(oid='1.2.3', type='NULL', value=None)

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

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

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

>>> OtherNameModel(oid="1.2.3", type="INTEGER", value=12)
OtherNameModel(oid='1.2.3', type='INTEGER', value=12)
>>> OtherNameModel(oid="1.2.3", type="INTEGER", value="0x123")  # 0x123 is 291 in decimal
OtherNameModel(oid='1.2.3', type='INTEGER', value=291)

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

>>> OtherNameModel(oid="1.2.3", type="OctetString", value=b"\x61\x62\x63")
OtherNameModel(oid='1.2.3', type='OctetString', value='616263')
>>> OtherNameModel(oid="1.2.3", type="OctetString", value="09CFF1A")
OtherNameModel(oid='1.2.3', type='OctetString', value='09CFF1A')

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')>
check_consistency() OtherNameModel[source]

Validator to check that the type matches the type of value.

property cryptography: OtherName

Convert to a OtherName instance.

classmethod parse_cryptography(data: Any) Any[source]

Parse cryptography instances.

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.extensions.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:

>>> ocsp = AccessDescriptionModel(
...     access_method='ocsp',
...     access_location={'type': 'URI', 'value': 'http://ocsp.example.com'}
... )
>>> issuers = AccessDescriptionModel(
...     access_method='ca_issuers',
...     access_location={'type': 'URI', 'value': 'http://example.com'}
... )
>>> AuthorityInformationAccessModel(value=[ocsp, issuers])  
AuthorityInformationAccessModel(
    critical=False,
    value=[
        AccessDescriptionModel(
            access_method='1.3.6.1.5.5.7.48.1',
            access_location=GeneralNameModel(type='URI', value='http://ocsp.example.com')
        ),
        AccessDescriptionModel(
            access_method='1.3.6.1.5.5.7.48.2',
            access_location=GeneralNameModel(type='URI', value='http://example.com')
        )
    ]
)
model_post_init(_ModelMetaclass__context: Any) None

We need to both initialize private attributes and call the user-defined model_post_init method.

class django_ca.pydantic.extensions.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:

>>> value = AuthorityKeyIdentifierValueModel(key_identifier=b"MTIz")
>>> AuthorityKeyIdentifierModel(value=value)  
AuthorityKeyIdentifierModel(
    critical=False,
    value=AuthorityKeyIdentifierValueModel(
        key_identifier=b'123', authority_cert_issuer=None, authority_cert_serial_number=None
    )
)
property extension_type: AuthorityKeyIdentifier

Convert to a AuthorityKeyIdentifier instance.

class django_ca.pydantic.extensions.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 a certificate authority:

>>> value = BasicConstraintsValueModel(ca=True, path_length=0)
>>> BasicConstraintsModel(value=value)
BasicConstraintsModel(critical=True, value=BasicConstraintsValueModel(ca=True, path_length=0))

For end-entity certificates, sets ca to False and path_length to None:

>>> value = BasicConstraintsValueModel(ca=False, path_length=None)
>>> BasicConstraintsModel(value=value)
BasicConstraintsModel(critical=True, value=BasicConstraintsValueModel(ca=False, path_length=None))
property extension_type: BasicConstraints

Convert to a BasicConstraints instance.

class django_ca.pydantic.extensions.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:

>>> 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
    )]
)

Please refer to the DistributionPointModel documentation for full information on how to instantiate this model.

model_post_init(_ModelMetaclass__context: Any) None

We need to both initialize private attributes and call the user-defined model_post_init method.

django_ca.pydantic.extensions.CertificateExtensions

Union type for all known extensions that may occur in any type of certificate.

alias of Annotated[Union[AuthorityInformationAccessModel, AuthorityKeyIdentifierModel, BasicConstraintsModel, CRLDistributionPointsModel, CertificatePoliciesModel, ExtendedKeyUsageModel, FreshestCRLModel, InhibitAnyPolicyModel, IssuerAlternativeNameModel, KeyUsageModel, MSCertificateTemplateModel, NameConstraintsModel, OCSPNoCheckModel, PolicyConstraintsModel, PrecertPoisonModel, PrecertificateSignedCertificateTimestampsModel, SignedCertificateTimestampsModel, SubjectAlternativeNameModel, SubjectInformationAccessModel, SubjectKeyIdentifierModel, TLSFeatureModel, UnrecognizedExtensionModel]]

class django_ca.pydantic.extensions.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:

>>> policy = PolicyInformationModel(policy_identifier="2.5.29.32.0")
>>> CertificatePoliciesModel(value=[policy])  
CertificatePoliciesModel(
    critical=False,
    value=[
        PolicyInformationModel(policy_identifier='2.5.29.32.0', policy_qualifiers=None)
    ]
)
property extension_type: CertificatePolicies

Convert to a CertificatePolicies instance.

classmethod parse_cryptography(data: Any) Any[source]

Parse cryptography instances.

class django_ca.pydantic.extensions.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:

>>> ExtendedKeyUsageModel(value=["clientAuth", "1.3.6.1.5.5.7.3.1"])
ExtendedKeyUsageModel(critical=False, value=['1.3.6.1.5.5.7.3.2', '1.3.6.1.5.5.7.3.1'])
property extension_type: ExtendedKeyUsage

Convert to a ExtendedKeyUsage instance.

classmethod parse_cryptography(data: Any) Any[source]

Parse cryptography instances.

class django_ca.pydantic.extensions.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.

model_post_init(_ModelMetaclass__context: Any) None

We need to both initialize private attributes and call the user-defined model_post_init method.

class django_ca.pydantic.extensions.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:

>>> InhibitAnyPolicyModel(value=1)
InhibitAnyPolicyModel(critical=True, value=1)
property extension_type: InhibitAnyPolicy

Convert to a InhibitAnyPolicy instance.

classmethod parse_cryptography(data: Any) Any[source]

Parse cryptography instances.

class django_ca.pydantic.extensions.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.

model_post_init(_ModelMetaclass__context: Any) None

We need to both initialize private attributes and call the user-defined model_post_init method.

class django_ca.pydantic.extensions.IssuingDistributionPointModel(*, type: Literal['issuing_distribution_point'] = 'issuing_distribution_point', critical: bool = True, value: IssuingDistributionPointValueModel)[source]

Pydantic model for a IssuingDistributionPoint extension.

The value is a IssuingDistributionPointValueModel instances:

>>> full_name = [{"type": "URI", "value": "https://ca.example.com/crl"}]
>>> value = IssuingDistributionPointValueModel(full_name=full_name)
>>> IssuingDistributionPointModel(value=value)  
IssuingDistributionPointModel(critical=True, value=IssuingDistributionPointValueModel(...))
property extension_type: IssuingDistributionPoint

Convert to a IssuingDistributionPoint instance.

class django_ca.pydantic.extensions.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:

>>> KeyUsageModel(value=["key_agreement", "key_encipherment"])
KeyUsageModel(critical=True, value=['key_agreement', 'key_encipherment'])
property extension_type: KeyUsage

Convert to a KeyUsage instance.

classmethod parse_cryptography(data: Any) Any[source]

Parse cryptography instances.

class django_ca.pydantic.extensions.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:

>>> value = MSCertificateTemplateValueModel(template_id="1.2.3", major_version=1)
>>> MSCertificateTemplateModel(critical=True, value=value)  
MSCertificateTemplateModel(
    critical=True,
    value=MSCertificateTemplateValueModel(template_id='1.2.3', major_version=1, minor_version=None)
)

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

property extension_type: MSCertificateTemplate

Convert to a MSCertificateTemplate instance.

class django_ca.pydantic.extensions.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:

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

The NameConstraints instance.

class django_ca.pydantic.extensions.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):

>>> OCSPNoCheckModel()
OCSPNoCheckModel(critical=False)
>>> OCSPNoCheckModel(value=None, critical=True)
OCSPNoCheckModel(critical=True)
model_post_init(_ModelMetaclass__context: Any) None

We need to both initialize private attributes and call the user-defined model_post_init method.

class django_ca.pydantic.extensions.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:

>>> value = PolicyConstraintsValueModel(require_explicit_policy=0, inhibit_policy_mapping=1)
>>> PolicyConstraintsModel(value=value)  
PolicyConstraintsModel(
    critical=True,
    value=PolicyConstraintsValueModel(require_explicit_policy=0, inhibit_policy_mapping=1)
)
property extension_type: PolicyConstraints

The PolicyConstraints instance.

class django_ca.pydantic.extensions.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):

>>> PrecertPoisonModel()
PrecertPoisonModel(critical=True)
>>> PrecertPoisonModel(value=None, critical=True)
PrecertPoisonModel(critical=True)
model_post_init(_ModelMetaclass__context: Any) None

We need to both initialize private attributes and call the user-defined model_post_init method.

class django_ca.pydantic.extensions.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'
        )
    ]
)
model_post_init(_ModelMetaclass__context: Any) None

We need to both initialize private attributes and call the user-defined model_post_init method.

django_ca.pydantic.extensions.SignCertificateExtensions

Union type for extensions that may occur as input when signing a certificate.

alias of Annotated[Union[AuthorityInformationAccessModel, CertificatePoliciesModel, CRLDistributionPointsModel, ExtendedKeyUsageModel, FreshestCRLModel, IssuerAlternativeNameModel, KeyUsageModel, OCSPNoCheckModel, SubjectAlternativeNameModel, TLSFeatureModel]]

class django_ca.pydantic.extensions.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.

model_post_init(_ModelMetaclass__context: Any) None

We need to both initialize private attributes and call the user-defined model_post_init method.

class django_ca.pydantic.extensions.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:

>>> name1 = {"type": "DNS", "value": "example.com"}
>>> name2 = {"type": "DNS", "value": "example.net"}
>>> SubjectAlternativeNameModel(value=[name1, name2])  
SubjectAlternativeNameModel(
    critical=False,
    value=[
        GeneralNameModel(type='DNS', value='example.com'),
        GeneralNameModel(type='DNS', value='example.net')
    ]
)
model_post_init(_ModelMetaclass__context: Any) None

We need to both initialize private attributes and call the user-defined model_post_init method.

class django_ca.pydantic.extensions.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:

>>> access_description = AccessDescriptionModel(
...     access_method='ca_repository',
...     access_location={'type': 'URI', 'value': 'http://example.com'}
... )
>>> SubjectInformationAccessModel(value=[access_description])  
SubjectInformationAccessModel(
    critical=False,
    value=[
        AccessDescriptionModel(
            access_method='1.3.6.1.5.5.7.48.5',
            access_location=GeneralNameModel(type='URI', value='http://example.com')
        )
    ]
)
model_post_init(_ModelMetaclass__context: Any) None

We need to both initialize private attributes and call the user-defined model_post_init method.

class django_ca.pydantic.extensions.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 bytes instance:

>>> SubjectKeyIdentifierModel(value=b"kA==")
SubjectKeyIdentifierModel(critical=False, value=b'\x90')
property extension_type: SubjectKeyIdentifier

The SubjectKeyIdentifier instance.

classmethod parse_cryptography(data: Any) Any[source]

Parse cryptography instances.

class django_ca.pydantic.extensions.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".

>>> TLSFeatureModel(value=["status_request"])
TLSFeatureModel(critical=False, value=['status_request'])

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

>>> TLSFeatureModel(value=["OCSPMustStaple"])
TLSFeatureModel(critical=False, value=['status_request'])
property extension_type: TLSFeature

The TLSFeature instance.

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

Pydantic model for a UnrecognizedExtension extension.

The value a UnrecognizedExtensionValueModel value:

>>> value = UnrecognizedExtensionValueModel(value=b"MTIz", oid="1.2.3")
>>> UnrecognizedExtensionModel(critical=True, value=value)  
UnrecognizedExtensionModel(
    critical=True, value=UnrecognizedExtensionValueModel(oid='1.2.3', value=b'123')
)
property cryptography: Extension[UnrecognizedExtension]

Return the respective cryptography instance.

property extension_type: UnrecognizedExtension

The UnrecognizedExtension instance.

django_ca.pydantic.extensions.validate_cryptograph_extensions(v: Any, info: ValidationInfo) Any[source]

Parse a cryptography extension into a Pydantic model.

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:

>>> AccessDescriptionModel(
...     access_method='ocsp',
...     access_location={'type': 'URI', 'value': 'http://ocsp.example.com'}
... )  
AccessDescriptionModel(
    access_method='1.3.6.1.5.5.7.48.1',
    access_location=GeneralNameModel(type='URI', value='http://ocsp.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.

classmethod parse_cryptography(data: Any) Any[source]

Parse cryptography 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.

classmethod parse_cryptography(data: Any) Any[source]

Parse cryptography instances.

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.extensions.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.extensions.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)