Profiles¶
A profile defines default properties, including certificate extensions, for TLS certificates. These properties define who can use the certificate for what purpose, how a peer can validate it and what clients are compatible with the certificates.
django-ca defines a set of default profiles that should be sufficient for most use cases:
Name |
Purpose |
---|---|
|
Certificate can be used for TLS client authentication. |
|
Certificate can be used for TLS client authentication and code and email signing. |
|
Certificate can be used for a OCSP responder, marked as automatically generated by default. |
|
Certificate can be used for both a TLS server and a TLS client. |
|
(default) Certificate can be used for a TLS server but not for TLS client authentication. |
You can configure the default profile to use using the CA_DEFAULT_PROFILE setting. You can also add new profiles or modify existing ones using the CA_PROFILES setting.
Using profiles¶
You can use a profile when signing certificates:
When you use the command line:
$ python manage.py sign_cert --client ...
In the Web interface you can select a profile when adding a certificate.
In the Python API:
>>> from django_ca.models import Certificate >>> from django_ca.profiles import profiles >>> Certificate.objects.create_cert(ca, csr, profile=profiles['client'])
or by even defining a temporary profile just for this certificate:
>>> from django_ca.profiles import Profile >>> prof = Profile(...) >>> Certificate.objects.create_cert(ca, csr, profile=prof)
Preconfigured profiles¶
client
¶
Certificates with this profile can be used for TLS client authentication. Use it when the certificate should be used by a client to authenticate itself (not the server).
It defines the following extensions and values:
KeyUsage: digital_signature
ExtendedKeyUsage: clientAuth
webserver
¶
Certificates with this profile can be used for TLS server authentication. Use it when the certificate should be used by a server to provide TLS connections, e.g. HTTPS.
Note
The profile name is actually a misnomer, as it cannot be used just for web servers but any server. The certificate could just as well be used by a mail server, MQTT server or anything else.
It defines the following extensions:
server
¶
Certificates with this profile can be used for both TLS client and server authentication. Use it when the certificate should be used by a daemon that both accepts and initiates TLS connections (an example would be a federated XMPP server).
It defines the following extensions and values:
KeyUsage: digital_signature, key_agreement, key_encipherment
ExtendedKeyUsage: clientAuth, serverAuth
enduser
¶
Certificates with this profile can be used by users to perform client authentication and sign code and emails.
It defines the following extensions and values:
KeyUsage: data_encipherment, digital_signature, key_encipherment
ExtendedKeyUsage: clientAuth, codeSigning, emailProtection
ocsp
¶
Certificates with this profile can be used in an OCSP responder. Automatic creation of OCSP responder keys use this profile.
It defines the following extensions and values:
KeyUsage: non_repudiation, digital_signature, key_encipherment
ExtendedKeyUsage: OCSPSigning
OCSPNoCheck
Configure profiles¶
You can add new profiles with the CA_PROFILES setting. The setting a dictionary with the key identifying the certificate and the values configuring various aspects of certificates signed using this profile. A simple profile might look like this:
CA_PROFILES = {
"example": { # actually a duplicate of the predefined "client" profile
"description": "An example profile.",
"extensions": {
"key_usage": {"value": ["digitalSignature"]},
"extended_key_usage": {"value": ["clientAuth"]},
},
},
}
CA_PROFILES:
example:
description: An example profile
extensions:
key_usage:
value:
- digitalSignature
extended_key_usage:
value:
- clientAuth
After defining a profile, it can be immediately used with the Python API, the Admin web interface (WSGI servers typically need to reload the code to see the new profile) or the command line:
$ python manage.py sign_cert -h
...
profiles:
Sign certificate based on the given profile. A profile only sets the the default values, options like --key-
usage still override the profile.
--client A certificate for a client.
--server A certificate for a server, allows client and server authentication.
--webserver A certificate for a webserver.
--enduser A certificate for an enduser, allows client authentication, code and email signing.
--ocsp A certificate for an OCSP responder.
--example An example profile.
Available options¶
There are many available options for a profile, of course all of them are optional:
Option |
Default |
Description |
---|---|---|
|
|
Set to |
|
|
Set to |
|
|
Set to |
|
|
Set to |
|
The algorithm used for signing, defaults to
CA_DEFAULT_SIGNATURE_HASH_ALGORITHM for |
|
|
|
Set to |
|
|
Informal text explaining what the profile is. |
|
A |
|
|
|
A dictionary of extensions to add. Please see below for more details. |
|
|
Set an alternative issuer name from the CA. Note that this will usually break any certificate validation, so this is definitely for experts only. |
|
The default subject to use, overrides CA_DEFAULT_SUBJECT. |
Configure the subject¶
The subject in a profile serves as a default value for subjects when signing certificates. You can use the
CA_DEFAULT_SUBJECT setting to set a default value for all profiles. If a profile should not
set any setting (despite CA_DEFAULT_SUBJECT being set), set False
for the subject.
The format used for the subject is the same as the CA_DEFAULT_SUBJECT setting, please refer to the settings documentation for the exact syntax. When signing via the command line or issuing certificates via ACMEv2, the subject will be sorted according to CA_DEFAULT_NAME_ORDER.
When issuing certificates via ACMEv2, the subject of the issued certificate will be the subject of the
profile, with the first DNS name requested by the client used as common name. You can configure the profile
being used for each certificate authority via the admin interface or via manage.py edit_ca --acme-profile
.
When signing certificates via the API, this value is not used, the caller is expected to provide the full subject. When signing certificates via the admin interface, this subject will be the default values in the subject field of the form.
When issuing certificates via the command line, the given subject is merged with the subject of the profile, with explicitly given values taking precedence. For example, given the following configuration:
CA_PROFILES = {
"example": {
"description": "Profile defining a custom subject.",
"subject": (
("C", "AT"),
("ST", "Vienna"),
),
# ... other options
}
}
CA_PROFILES:
example:
description: Profile defining a custom subject.
subject:
- [ C, AT ]
- [ ST, Vienna ]
# ... any other options
… signing a certificate with
$ manage.py sign_cert --subject-format rfc4514 --subject "CN=example.com" ...
will give the certificate a subject of C=AT,ST=Vienna,CN=example.com
. If you sign with
$ manage.py sign_cert --subject-format rfc4514 --subject "ST=Styria,L=Graz,CN=graz.example.com" ...
you will get C=AT,ST=Styria,L=Graz,CN=graz.example.com
as a subject.
Configure extensions¶
Many extensions (such as the Authority Key Identifier and Basic Constraints extensions) are added by default
since they are required to create a useful certificate. Further extensions (such as the CRL Distribution
Points and Authority Information Access) are added depending on the values for the CA you are using and the
add_{...}_url
settings described below.
You can define any extension in a profile with a dictionary.
Use the key
from EXTENSION_KEYS
as a dictionary key and a dictionary as a
value describing the extension.
The dictionary has an optional critical
key. If it is not defined, the critical value will come from
EXTENSION_DEFAULT_CRITICAL
.
All extensions use a value
key to describe the extension value. It is usually a dict
for convenience,
but can also be a Extension
or ExtensionType
for convenience (or special cases). For example, for the Key
Usage extension, use:
CA_PROFILES = {
'example': {
# ...
'extensions': {
'key_usage': {
'critical': False, # usually critical, but not here for some reason
'value': ['digitalSignature']
},
},
},
}
Find how to specify the value
key for the most important extensions below.
Certificate Policies¶
Key: certificate_policies
Note
This extension usually comes from the certificate authority and is not usually set in a profile.
The format is based on CertificatePoliciesModel
. The value is a list of
policy information objects. Each consists of a policy_identifier (a dotted string for an OID) and an
optional list of policy_qualifier objects.
A policy_qualifier is a list of either strings (usually a certificate practice statement) or a user notice object. Please see the model information for these more exotic use cases.
CA_PROFILES = {
"example-profile": {
"extensions": {
"certificate_policies": {
"value": [
{"policy_identifier": "2.5.29.32.0"},
{
"policy_identifier": "1.3.6.1.5.5.7.2.1",
"policy_qualifiers": [
"https://ca.example.com/cps",
{"explicit_text": "my text"},
],
},
],
}
}
}
}
CA_PROFILES:
example-profile:
extensions:
certificate_policies:
value:
- policy_identifier: 2.5.29.32.0
- policy_identifier: 1.3.6.1.5.5.7.2.1
policy_qualifiers:
- https://ca.example.com/cps
- explicit_text: my text
When issuing certificates via the command-line, not all of the possible values can be represented. You can
set a full value either here or by setting the sign_certificate_policies
model field of
CertificateAuthority
.
CRL Distribution Points¶
Key: crl_distribution_points
Note
This extension usually comes from the certificate authority and is not usually set in a profile.
The format is based on CRLDistributionPointsModel
. The value is a list of
distribution point objects. In it’s (by far) most common form, it has only a full_name with an URI where
the CRL can be downloaded.
Other fields of a distribution point object are relative_name (an RDN), crl_issuer (a list of general
names) and reasons (a set of reasons). At least one of full_name and relative_name, other values are
optional. As with any name or RDN, the OID may also use an alias from
NAME_OID_TYPES
.
This example sets two distribution points, a common one (only a full name) and one demonstrating all the other fields.
CA_PROFILES = {
"example-profile": {
"extensions": {
"crl_distribution_points": {
"value": [
{
"full_name": [
{"type": "URI", "value": "https://ca.example.com/crl"}
],
},
{
"relative_name": [{"oid": "commonName", "value": "example.com"}],
"crl_issuer": [
{"type": "URI", "value": "https://ca.example.com/issuer"}
],
"reasons": ["key_compromise"],
},
],
}
}
}
}
CA_PROFILES:
example-profile:
extensions:
crl_distribution_points:
value:
- full_name:
- type: URI
value: https://ca.example.com/crl
- crl_issuer:
- type: URI
value: https://ca.example.com/issuer
reasons:
- key_compromise
relative_name:
- oid: 2.5.4.3
value: example.com
If you do specify the extension in a profile, the value from the certificate authority will take precedence
over any value from the profile (unless the profile specifies add_crl_url=False
).
Extended Key Usage¶
Key: extended_key_usage
The value is a list of extended key usages as defined in RFC 5280, section 4.2.1.12. Alternatively you can also pass any valid OID as dotted string. For example:
CA_PROFILES = {
"example-profile": {
"extensions": {
# NOTE: "1.3.6.1.5.5.7.3.1" is equivalent to "serverAuth", but any valid
# dotted string can be given here.
"extended_key_usage": {"value": ["clientAuth", "1.3.6.1.5.5.7.3.1"]},
}
}
}
Values can be a dotted string or a name (e.g. "clientAuth"
).
CA_PROFILES:
example-profile:
extensions:
extended_key_usage:
value:
- 1.3.6.1.5.5.7.3.2
- 1.3.6.1.5.5.7.3.1
Freshest CRL¶
Key: freshest_crl
Note
This extension usually comes from the certificate authority and is not usually set in a profile.
The syntax is the same as for the CRL Distribution Points extension.
Key Usage¶
Key: key_usage
The value is a list of key usages as defined in RFC 5280, section 4.2.1.3. Example:
CA_PROFILES = {
"example-profile": {
"extensions": {"key_usage": {"value": ["keyAgreement", "keyEncipherment"]}}
}
}
CA_PROFILES:
example-profile:
extensions:
key_usage:
value:
- key_agreement
- key_encipherment
OCSP No Check¶
Key: ocsp_no_check
The value is optional, as the extension has no value (besides being present).
from typing import Any
CA_PROFILES: dict[str, dict[str, Any]] = {
"example-profile": {
"extensions": {
"ocsp_no_check": {},
}
}
}
CA_PROFILES:
example-profile:
extensions:
ocsp_no_check: {}
TLS Feature¶
Key: tls_feature
The value is a list of features as defined in RFC 7633 (so status_request
and status_request_v2
). For
convenience, OCSPMustStaple
and MultipleCertStatusRequest
is also supported. Example:
CA_PROFILES = {
"example-profile": {
"extensions": {
"tls_feature": {
"value": ["status_request"],
}
}
}
}
CA_PROFILES:
example-profile:
extensions:
tls_feature:
value:
- status_request
The add_..._url
settings¶
By default, certificates will include some extensions based on the CA used to sign it. The CA usually defines
CRL and OCSP URLs that can be used to retrieve information if the certificate is still valid. This is usually
what you want, but there are some exceptions. For example, a certificate for an OCSP responder should not
include the OCSP URL, as it makes no sense to validate the OCSP responder certificate using the OCSP responder
itself. The ocsp
profile thus already sets add_ocsp_url
to False
.
If your profile defines a CRL Distribution Points or Authority Information Access extension, CRL, OCSP and
Issuer URLs from the CA will be appended if the add_..._url
setting is True
.
Update existing profile¶
You can update an existing profile the same way as configuring a new profile. Any values will replace existing
values. To update the default subject for the (predefined) enduser
profile:
CA_PROFILES = {
"enduser": {
"subject": "/C=AT/L=Vienna/", # base for the subject when creating a new cert
},
}
Note that django-ca also replaces the whole extensions
value. That means you cannot update one extension
from the profile, you’ll have to specify all extensions.
Remove a profile¶
You can remove a predefined profile by just setting the value to None
:
CA_PROFILES = {
"client": None # we really don't need this one
}