Certificate authority management

django-ca supports managing multiple certificate authorities as well as child certificate authorities.

The only way to create certificate authorities is via the command-line interface. It is obviously most important that the private keys of the certificate authorities are never exposed to any attacker, and any web interface would pose an unnecessary risk.

For the same reason, the private key of a certificate authority is stored on the filesystem and not in the database. The initial location of the private key is configured by the CA_DIR setting. This also means that you can run your django-ca on two hosts, where one host has the private key and only uses the command line, and one with the webinterface that can still be used to revoke certificates.

To manage certificate authorities, use the following manage.py commands:

Command Description
init_ca Create a new certificate authority.
list_cas List all currently configured certificate authorities.
edit_ca Edit a certificate authority.
view_ca View details of a certificate authority.
dump_ca Write the CA certificate to a file.

Various details of the certificate authority, mostly the x509 extensions used when signing a certificate, can also be managed via the webinterface.

Here is a shell session that illustrates the respective manage.py commands:

$ python manage.py init_ca --pathlen=2
>     --crl-url=http://ca.example.com/crl \
>     --ocsp-url=http://ocsp.ca.example.com \
>     --issuer-url=http://ca.example.com/ca.crt \
>     TestCA /C=AT/L=Vienna/L=Vienna/O=Example/OU=ExampleUnit/CN=ca.example.com
$ python manage.py list_cas
BD:5B:AB:5B:A2:1C:49:0D:9A:B2:AA:BC:68:ED:ED:7D - TestCA

$ python manage.py view_ca BD:5B:AB:5B:A2
...
* OCSP URL: http://ocsp.ca.example.com
$ python manage.py edit_ca --ocsp-url=http://new-ocsp.ca.example.com \
>     BD:5B:AB:5B:A2
$ python manage.py view_ca BD:5B:AB:5B:A2
...
* OCSP URL: http://new-ocsp.ca.example.com

Note that you can just use the start of a serial to identify the CA, as long as that still uniquely identifies the CA.

Create intermediate CAs

Intermediate CAs are created, just like normal CAs, using manage.py init_ca. For intermediate CAs to be valid, CAs however must have a correct pathlen x509 extension. Its value is an integer describing how many levels of intermediate CAs a CA may have. A pathlen of “0” means that a CA cannot have any intermediate CAs, if it is not present, a CA may have an infinite number of intermediate CAs.

Note

django-ca by default sets a pathlen of “0”, as it aims to be secure by default. The pathlen attribute cannot be changed in hindsight (not without resigning the CA). If you plan to create intermediate CAs, you have to consider this when creating the root CA.

So for example, if you want two levels of intermediate CAs, , you’d need the following pathlen values (the pathlen value is the minimum value, it could always be a larger number):

index CA pathlen description
1 example.com 2 Your root CA.
2 sub1.example.com 1 Your first intermediate CA, a sub-CA from (1).
3 sub2.example.com 0 A second intermediate CA, also a sub-CA from (1).
4 sub.sub1.example.com 0 An intermediate CA of (2).

If in the above example, CA (1) had pathlen of “1” or CA (2) had a pathlen of “0”, CA (4) would no longer be a valid CA.

By default, django-ca sets a pathlen of 0, so CAs will not be able to have any intermediate CAs. You can configure the value by passing --pathlen to init_ca:

$ python manage.py init_ca --pathlen=2 ...

When creating a sub-ca, you must name its parent using the --parent parameter:

$ python manage.py list_cas
BD:5B:AB:5B:A2:1C:49:0D:9A:B2:AA:BC:68:ED:ED:7D - Root CA
$ python manage.py init_ca --parent=BD:5B:AB:5B ...

Note

Just like throughout the system, you can always just give the start of the serial, as long as it still is a unique identifier for the CA.