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 ofNameAttributeModel
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" } ]
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 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
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 aOtherNameModel
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
orOTHER_NAME_ALIASES
.The type of the value argument depends on the type value. String variants (
UTFString
, etc.) require astr
, boolean requires abool
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
andGENERALIZEDTIME
), 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 anint
or astr
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')>
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 isFalse
and 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
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 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
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 forone.example.com
andtwo.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 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
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 toNone
:>>> 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 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
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' )
- 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)