########
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
============== =============================================================================================
``client``     Certificate can be used for TLS client authentication.
``enduser``    Certificate can be used for TLS client authentication and code and email signing.
``ocsp``       Certificate can be used for a OCSP responder, marked as automatically generated by default.
``server``     Certificate can be used for both a TLS server and a TLS client.
``webserver``  **(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 :ref:`CA_DEFAULT_PROFILE <settings-ca-default-profile>`
setting. You can also add new profiles or modify existing ones using the :ref:`CA_PROFILES
<settings-ca-profiles>` setting.

**************
Using profiles
**************

You can use a profile when signing certificates:

* When you use the :doc:`command line </cli/certs>`:

   .. code-block:: console

      $ python manage.py sign_cert --client ...

* In the :doc:`web_interface` you can select a profile when adding a certificate.
* In the :doc:`Python API </python/intro>`::

      >>> from django_ca.models import Certificate
      >>> Certificate.objects.create_cert(ca, csr, profile='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)


******************
Configure profiles
******************

You can add new profiles with the :ref:`CA_PROFILES <settings-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']},
           },
       },
   }

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:

.. code-block:: console

   $ 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
=============================== ========= ====================================================================
``add_crl_url``                 ``True``  Set to ``False`` if you don't want the CAs CRL URL added.
``add_issuer_alternative_name`` ``True``  Set to ``False`` if you don't want the CAs Issuer Alternative Name
                                          added.
``add_issuer_url``              ``True``  Set to ``False`` if you don't want the CAs Issuer URL added.
``add_ocsp_url``                ``True``  Set to ``False`` if you don't want the CAs OCSP URLs added.
``algorithm``                             The algorithm used for signing, defaults to
                                          :ref:`CA_DEFAULT_SIGNATURE_HASH_ALGORITHM
                                          <settings-ca-default-signature-hash-algorithm>` for ``RSA``/``EC``
                                          keys.
``autogenerated``               ``False`` Set to ``True`` if you want to mark certificates from this profile
                                          as automatically generated by default.
``cn_in_san``                   ``True``  If the CommonName should be added as Subject Alternative Name.
``description``                 ``''``    Informal text explaining what the profile is.
``expires``                               A ``timedelta`` of when a certificate will expire, if you set an
                                          integer it will be interpreted as a number of days. This defaults to
                                          :ref:`CA_DEFAULT_EXPIRES <settings-ca-default-expires>`.
``extensions``                  ``{}``    A dictionary of extensions to add. Please see below for more
                                          details.
``issuer_name``                 ``None``  Set an alternative issuer name from the CA. Note that this will
                                          usually break any certificate validation, so this is definitely for
                                          experts only.
``subject``                               The default subject to use, overrides :ref:`CA_DEFAULT_SUBJECT
                                          <settings-ca-default-subject>`.
=============================== ========= ====================================================================

.. _profiles-subject:

Configure the subject
=====================

The subject in a profile serves as a default value for subjects when signing certificates. You can use the
:ref:`settings-ca-default-subject` setting to set a default value for all profiles. If a profile should not
use :ref:`settings-ca-default-subject` as a default, set ``False`` for the subject.

The value is used when signing certificates. When issuing certificates via ACMEv2, the subject of the
retrieved certificate will use the subject of the profile, with the first DNS name requested by the client
used as common name.

When issuing certificates via the command line or the admin interface, the given subject is merged with the
subject of the profile, with explicitly given values taking precedence. As an example, given a profile
defining this subject::

    "subject": {
        ("C", "AT"),
        ("ST", "Vienna"),
    }

... signing a certificate with ``manage.py sign_cert --subject=/CN=example.com`` will give the certificate
a subject of ``/C=AT/ST=Vienna/CN=example.com``. If you sign with
``--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.

As with :ref:`settings-ca-default-subject` , name types given here must be given in
:ref:`settings-ca-default-name-order`.

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 :py:attr:`~django_ca.constants.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
:py:attr:`~django_ca.constants.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.

Authority Information Access
============================

The ``value`` is a ``dict`` with two optional keys: ``ocsp`` and ``issuers``. Both are a list of general
names as described in :ref:`names_on_cli`.  Example::

   {'ocsp': 'URI:http://ocsp.example.com'}

It is unusual to specify this extension in a profile, as the values should come from the certificate
authority. If you do specify it, it will be merged with values from the certificate authority if you create a
certificate from the command line or via ACMEv2 (unless the profile specifies ``add_ocsp_url=False`` and/or
``add_issuer_url=False``). If you create a certificate via the admin interface, selecting the profile will set
the value for this extension (profiles are only used to fill the form, not when actually signing the
certificate).

Certificate Policies
====================

.. note::

   Configuring a Certificate Policies extension in a profile is currently the `only` way to add this extension
   to a certificate.

The ``value`` is a list of dicts describing the policy information. Each dict has the mandatory
``policy_identifier`` key that names an Object Identifier as dotted string. The ``policy_qualifiers`` object
is optional and a list of policy qualifiers.

A ``policy_qualifiers`` item is either a string, or a dict describing a user notice. A user notice is a dict
with the optional ``explicit_text`` key with a string value and the optional ``notice_reference`` key
describing a notice reference. A ``notice_reference`` is a dict with the optional ``organization`` key as a
string, and the ``notice_numbers`` key as a list of integers.

Example::

   [
      {"policy_identifier": "1.1.1"},
      {
         "policy_identifier": "1.3.3",
         "policy_qualifiers": [
             "A policy qualifier as a string",
             {
                 "explicit_text": "An explicit text",
                 "notice_reference": {
                     "organization": "some org",
                     "notice_numbers": [1, 2, 3],
                 }
             },
         ],
      },
   ]

CRL Distribution Points
=======================

The ``value`` is a list of dicts describing distribution points. Each distribution point has either a
``full_name`` or a ``relative_name`` key (they are mutually exclusive). ``full_name`` is a list of names as
described in :ref:`names_on_cli`, ``relative_name`` is a string with a relative name, e.g.
``/CN=example.com``. A distribution point may also have a list of names in ``crl_issuers`` and a list of
reasons in ``reasons`` as named in :py:class:`~cg:cryptography.x509.ReasonFlags`.

Please note that in practice, the extension typically `only` uses a single ``full_name`` entry, all other
values are not used::

   [{'full_name': ['URI:http://crl.example.com']}]

Here is a full example::

   [
      {
         'full_name': ['URI:http://crl1.example.com', 'URI:http://crl2.example.com'],
         'crl_issuer': ['URI:http://crl-issuer.example.com'],
         'reasons': ['key_compromise'],
      }
   ]

It is unusual to specify this extension in a profile, as the values should come from the certificate
authority. If you do specify it, it will be merged with values from the certificate authority if you create a
certificate from the command line or via ACMEv2 (unless the profile specifies ``add_crl_url=False``).
If you create a certificate via the admin interface, selecting the profile will set the value for this
extension (profiles are only used to fill the form, not when actually signing the certificate).

Extended Key Usage
==================

The ``value`` is a list of extended key usages as defined in `RFC 5280, section 4.2.1.12
<https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12>`_. Example::

   ["serverAuth", "clientAuth"]

Freshest CRL
============

The syntax is the same as for the CRL Distribution Points extension.

Key Usage
=========

The ``value`` is a list of key usages as defined in `RFC 5280, section 4.2.1.3
<https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3>`_. Example::

   ["digitalSignature", "keyEncipherment"]

OCSP No Check
=============

The ``value`` is optional, as the extension has no value (besides being present).

TLS Feature
===========

The ``value`` is a list of features as defined in `RFC 7633
<https://datatracker.ietf.org/doc/html/rfc7633.html` (so ``status_request`` and ``status_request_v2``). For
convenience, ``OCSPMustStaple`` and ``MultipleCertStatusRequest`` is also supported. Example::

   ["OCSPMustStaple"]


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
   }
