Host a Certificate Revocation List (CRL)

A Certificate Revocation List (CRL) contains all revoked certificates signed by a certificate authority. Having a CRL is completely optional (e.g. Let’s Encrypt certificates don’t have one).

A URL to the CRL is usually included in the certificates (in the crlDistributionPoints x509 extension) so clients can fetch the CRL and verify that the certificate has not been revoked. Some services (e.g. OpenVPN) also just keep a local copy of a CRL.

Note

CRLs are usually hosted via HTTP, not HTTPS. CRLs are always signed, so hosting them via HTTP is not a security vulnerability. Further, you cannot verify the the certificate used when fetching the CRL anyway, since you would need the CRL for that.

Use default CRLs

If you have (correctly) configured a CA_DEFAULT_HOSTNAME and setup the web server under that URL, you do not have to do anything to provide CRLs.

django-ca provides the generic view CertificateRevocationListView to provide CRLs via HTTP. Since CRLs are always signed directly by the CA, it is currently required that the private key of the CA is available to the web server.

Override default hostname

By default, django-ca will generate CRL URLs based on CA_DEFAULT_HOSTNAME. If you want to generate a CA to use a different hostname (e.g. a CA for internal use only, where you can reach the CRL under a local domain), you can override the default hostname:

$ python manage.py init_ca \
>     --default-hostname=ca.local.tld
>     ...

… or disable it altogether, in which case the CA will not contain any URLs:

$ python manage.py init_ca \
>     --no-default-hostname
>     ...

Customize CRL URLs

If you want to statically generate CRLs and copy them to a custom location (e.g. for performance reasons), you can customize the CRL URLs used for a CA when generating it (note that you cannot set a CRL URL in the CA certificate if it is a root CA):

$ python manage.py init_ca \
>     --parent=... \
>     --crl-url=http://custom.example.com/cert.crl \
>     --ca-crl-url=http://custom.example.com/ca.crl \
>     ...

You can also change the CRL URL for newly issued certificates:

$ python manage.py list_cas
34:D6:02:B5:B8:27:4F:51:9A:16:0C:B8:56:B7:79:3F - Root CA
$ python manage.py edit_ca --crl-url=http://ca.example.com/crl.pem \
>     34:D6:02:B5:B8:27:4F:51:9A:16:0C:B8:56:B7:79:3F

Host custom CRLs

django-ca hosts CRLs in a format that is usually understood by CRL clients, but you might want to host CRLs in a different format in your own URL configuration:

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.serialization import Encoding
from django_ca.views import CertificateRevocationListView

urlpatterns = [
   ...

   # we need a PEM CRL signed with SHA256 for some reason:
   path('<hex:serial>.pem', views.CertificateRevocationListView.as_view(
      type=Encoding.PEM,
      digest=hashes.SHA256()
   ), name='custom-crl'),
]
class django_ca.views.CertificateRevocationListView(**kwargs)[source]

Generic view that provides Certificate Revocation Lists (CRLs).

content_type = None

Value of the Content-Type header used in the response. For CRLs in PEM format, use text/plain.

expires = 600

CRL expires in this many seconds.

get_key_backend_options(ca: CertificateAuthority) BaseModel[source]

Method to get the key backend options to access the private key.

If a custom CA backend needs transient parameters (e.g. passwords), a view overriding this method must be implemented.

include_issuing_distribution_point: bool | None = None

Boolean flag to force inclusion/exclusion of IssuingDistributionPoint extension.

password = None

Password used to load the private key of the certificate authority. If not set, the private key is assumed to be unencrypted.

scope: Literal['ca', 'user', 'attribute'] | None = 'user'

Set to "user" to limit CRL to certificates or "ca" to certificate authorities or None to include both.

type = 'DER'

Encoding for CRL.

Write a CRL to a file

You can generate the CRL with the manage.py dump_crl command:

$ python manage.py dump_crl -f PEM /var/www/crl.pem

Note

The dump_crl command uses the first enabled CA by default, you can force a particular CA with --ca=<serial>.

CRLs expire after a certain time (default: one day, configure with --expires=SECS), so you must periodically regenerate it, e.g. via a cron-job.

How and where to host the file is entirely up to you. If you run a Django project with a web server already, one possibility is to dump it to your MEDIA_ROOT directory.