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.Base64Bytesin 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.CertificateRevocationListEncodingTypeAlias¶
A type alias for
Encodinginstances.This type alias validates names from
CERTIFICATE_REVOCATION_LIST_ENCODING_TYPESand serializes to the canonical name in JSON. Models using this type alias can be used with strict schema validation.
- django_ca.pydantic.type_aliases.EllipticCurveTypeAlias¶
A type alias for
EllipticCurveinstances.This type alias validates names from
ELLIPTIC_CURVE_TYPESand 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
HashAlgorithminstances.This type alias validates names from
HASH_ALGORITHM_TYPESand 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.PowerOfTwoInt¶
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, upper-case any lower-case strings and remove ‘:’. 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
NameAttributeinstance for this model.
- class django_ca.pydantic.NameModel(root: RootModelRootType = PydanticUndefined)[source]¶
Pydantic model wrapping
Name.This model is a Pydantic
RootModelthat takes a list ofNameAttributeModelinstances: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" } ]
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_TYPESand a value that is usually astr: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
NameModelinstead: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
OtherNameinstances, pass aOtherNameModelinstead: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
GeneralNameinstance.
- 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_TYPESorOTHER_NAME_ALIASES.The type of the value argument depends on the type value. String variants (
UTFString, etc.) require astr, boolean requires aboolvalue 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 (
UTCTIMEandGENERALIZEDTIME), 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 anintor astrfor 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
cryptographyproperty 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')>
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
AuthorityInformationAccessextension.The value is a list of
AccessDescriptionModelinstances: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
AuthorityKeyIdentifierextension.The value is a
AuthorityKeyIdentifierValueModelinstance: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
BasicConstraintsextension.The value is a
BasicConstraintsValueModelinstance. For example, for end-entity certificates, ca isFalseand path_length isNone: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
CRLDistributionPointsextension.The value is a list of
DistributionPointModelinstances: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
CertificatePoliciesextension.The value is a list of
PolicyInformationModelinstances: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
ExtendedKeyUsageextension.The value is a list valid object identifiers as dotted strings. For convenience, any name from
EXTENDED_KEY_USAGE_NAMEScan 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
FreshestCRLextension.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
InhibitAnyPolicyextension.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
IssuerAlternativeNameextension.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
KeyUsageextension.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 inKEY_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
MSCertificateTemplateextension.The value is a
MSCertificateTemplateValueModelinstance, 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
NameConstraintsextension.The value is a
NameConstraintsValueModelinstance, where at least one of permitted_subtrees and excluded_subtrees must be given. For example, a certificate authority that can only sign certificates under.comwould 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 forone.example.comandtwo.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
OCSPNoCheckextension.This extension does not have a value, and thus can be instantiated without any parameters (but
Noneis 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
PolicyConstraintsextension.The value is a
PolicyConstraintsValueModelinstance. 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
PrecertPoisonextension.This extension does not have a value, and thus can be instantiated without any parameters (but
Noneis 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
PrecertificateSignedCertificateTimestampsextension.Note
Due to library limitations, this model cannot be converted to a cryptography class.
The value is a list of
SignedCertificateTimestampModelinstances:>>> 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
SignedCertificateTimestampsextension.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
SubjectAlternativeNameextension.The general_names attribute is a list of
GeneralNameModelinstances: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
SubjectInformationAccessextension.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
SubjectKeyIdentifierextension.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
TLSFeatureextension.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
UnrecognizedExtensionextension.The value a
UnrecognizedExtensionValueModelvalue, 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 aGeneralNameModel: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
AccessDescriptioninstance.
- 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
bytesvalue, 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
AuthorityKeyIdentifierinstance.
- 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
Trueand 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
Falseand must set path_length toNone:>>> BasicConstraintsValueModel(ca=False, path_length=None) BasicConstraintsValueModel(ca=False, path_length=None)
- property cryptography: BasicConstraints¶
Convert to a
BasicConstraintsinstance.
- 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
DistributionPointinstance.
- 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
IssuingDistributionPointinstance.
- 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
MSCertificateTemplateinstance.
- 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
GeneralNameModelinstances:>>> NameConstraintsValueModel( ... permitted_subtrees=[{"type": "DNS", "value": ".com"}] ... ) NameConstraintsValueModel( permitted_subtrees=[GeneralNameModel(type='DNS', value='.com')], excluded_subtrees=None )
- property cryptography: NameConstraints¶
Convert to a
NameConstraintsinstance.
- 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
NoticeReferenceinstance.
- 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
PolicyConstraintsinstance.
- 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
stror aUserNoticeModel:>>> 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
PolicyInformationinstance.
- 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' )
- class django_ca.pydantic.extension_attributes.UnrecognizedExtensionValueModel(*, oid: str, value: bytes)[source]¶
Pydantic model for a
UnrecognizedExtensionextension.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
UnrecognizedExtensioninstance.
- 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
UserNoticeinstance.
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
CRLNumberextension.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
DeltaCRLIndicatorextension.The value is an integer:
>>> DeltaCRLIndicatorModel(value=1) DeltaCRLIndicatorModel(critical=True, value=1)