Skip to content

Commit

Permalink
Fix ASGI TLS Extension to ease implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
grydz committed Jan 15, 2025
1 parent abc69a0 commit 8ff93d5
Showing 1 changed file with 27 additions and 134 deletions.
161 changes: 27 additions & 134 deletions specs/tls.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
ASGI TLS Extension
==================

**Version**: 0.2 (2020-10-02)
**Version**: 0.3 (2024-14-01)

This specification outlines how to report TLS (or SSL) connection information
in the ASGI *connection scope* object.
Expand Down Expand Up @@ -57,145 +57,38 @@ document. The value will be a dictionary with the following entries:
(e.g. if TLS is terminated by a separate proxy or load balancer); in that
case this shall be ``None``. Mandatory.

* ``client_cert_chain`` (*Iterable[Unicode string]*) -- An iterable of
Unicode strings, where each string is a PEM-encoded x509 certificate.
The first certificate is the client certificate. Any subsequent certificates
are part of the certificate chain sent by the client, with each certificate
signing the preceding one. If the client did not provide a client
certificate then it will be an empty iterable. Some web server
implementations may be unable to provide this (e.g. if TLS is terminated by a
separate proxy or load balancer); in that case this shall be an empty
iterable. Optional; if missing defaults to empty iterable.

* ``client_cert_name`` (*Unicode string or None*) -- The x509 Distinguished
Name of the Subject of the client certificate, as a single string encoded as
defined in `RFC4514 <https://tools.ietf.org/html/rfc4514>`_. If the client
did not provide a client certificate then it will be ``None``. Some web
server implementations may be unable to provide this (e.g. if TLS is
terminated by a separate proxy or load balancer); in that case this shall be
``None``. If ``client_cert_chain`` is provided and non-empty then this field
must be provided and must contain information that is consistent with
``client_cert_chain[0]``. Note that under some setups, (e.g. where TLS is
terminated by a separate proxy or load balancer and that device forwards the
client certificate name to the web server), this field may be set even where
``client_cert_chain`` is not set. Optional; if missing defaults to ``None``.

* ``client_cert_error`` (*Unicode string or None*) -- ``None`` if a client
certificate was provided and successfully verified, or was not provided.
If a client certificate was provided but verification failed, this is a
non-empty string containing an error message or error code indicating why
validation failed; the details are web server specific. Most web server
implementations will reject the connection if the client certificate
verification failed, instead of setting this value. However, some may be
configured to allow the connection anyway. This is especially useful when
testing that client certificates are supported properly by the client - it
allows a response containing an error message that can be presented to a
human, instead of just refusing the connection. Optional; if missing defaults
to ``None``.

* ``tls_version`` (*integer or None*) -- The TLS version in use. This is one of
the version numbers as defined in the TLS specifications, which is an
unsigned integer. Common values include ``0x0303`` for TLS 1.2 or ``0x0304``
for TLS 1.3. If TLS is not in use, set to ``None``. Some web server
implementations may be unable to provide this (e.g. if TLS is terminated by a
separate proxy or load balancer); in that case set to ``None``. Mandatory.

* ``cipher_suite`` (*integer or None*) -- The TLS cipher suite that is being
used. This is a 16-bit unsigned integer that encodes the pair of 8-bit
integers specified in the relevant RFC, in network byte order. For example
`RFC8446 section B.4 <https://tools.ietf.org/html/rfc8446#appendix-B.4>`_
defines that the cipher suite ``TLS_AES_128_GCM_SHA256`` is ``{0x13, 0x01}``;
that is encoded as a ``cipher_suite`` value of ``0x1301`` (equal to 4865
decimal). Some web server implementations may be unable to provide this
(e.g. if TLS is terminated by a separate proxy or load balancer); in that case
set to ``None``. Mandatory.
* ``client_cert_chain`` (*Unicode string or None*) -- The PEM-encoded x509
certificate sent by the client when establishing the TLS connection if
client certificate authentication is configured. If the client did not
provide a client certificate then it will ``None``. Some web server
implementations may be unable to provide this (e.g. if TLS is terminated by
a separate proxy or load balancer); in that case this shall be ``None``.
Mandatory.

* ``tls_version`` (*Unicode string or None*) -- The TLS version in use.
Common values include ``SSLv2``, ``SSLv3``, ``TLSv1.1``, ``TLSv1.2``, and
``TLSv1.3``. If TLS is not in use, set to ``None``. Some web server
implementations may be unable to provide this (e.g. if TLS is terminated by
a separate proxy or load balancer); in that case set to ``None``.
Mandatory.

* ``cipher_suite`` (*Unicode string or None*) -- The TLS cipher suite that is
being used. For example with TLSv1.3
(`RFC8446 section B.4 <https://tools.ietf.org/html/rfc8446#appendix-B.4>`_),
the following cipher suites are available: ``TLS_AES_128_GCM_SHA256``,
``TLS_AES_256_GCM_SHA384``, ``TLS_CHACHA20_POLY1305_SHA256``,
``TLS_AES_128_CCM_SHA256`` and ``TLS_AES_128_CCM_8_SHA256``. See
`IANA TLS Parameters <https://www.iana.org/assignments/tls-parameters/tls-parameters.xml>`_
for a complete list of cipher suites. Some web server
implementations may be unable to provide this (e.g. if TLS is terminated by
a separate proxy or load balancer); in that case set to ``None``.
Mandatory.

Events
------

All events are as defined in the *base protocol specification*.

Rationale (Informative)
-----------------------

This section explains the choices that led to this specification.

Providing the entire TLS certificates in ``client_cert_chain``, rather than a
parsed subset:

* Makes it easier for web servers to implement, as they do not have to
include a parser for the entirety of the x509 certificate specifications
(which are huge and complicated). They just have to convert the binary
DER format certificate from the wire, to the text PEM format. That is
supported by many off-the-shelf libraries.
* Makes it easier for web servers to maintain, as they do not have to update
their parser when new certificate fields are defined.
* Makes it easier for clients as there are plenty of existing x509 libraries
available that they can use to parse the certificate; they don't need to
do some special ASGI-specific thing.
* Improves interoperability as this is a simple, well-defined encoding, that
clients and servers are unlikely to get wrong.
* Makes it much easier to write this specification. There is no standard
documented format for a parsed certificate in Python, and we would need to
write one.
* Makes it much easier to maintain this specification. There is no need
to update a parsed certificate specification when new certificate fields
are defined.
* Allows the client to support new certificate fields without requiring
any server changes, so long as the fields are marked as "non-critical" in
the certificate. (A x509 parser is allowed to ignore non-critical fields
it does not understand. Critical fields that are not understood cause
certificate parsing to fail).
* Allows the client to do weird and wonderful things with the raw certificate,
instead of placing arbitrary limits on it.

Specifying ``tls_version`` as an integer, not a string or float:

* Avoids maintenance effort in this specification. If a new version of TLS is
defined, then no changes are needed in this specification.
* Does not significantly affect servers. Whatever format we specified, servers
would likely need a lookup table from what their TLS library reports to what
this API needs. (Unless their TLS library provides access to the raw value,
in which case it can be reported via this API directly).
* Does not significantly affect clients. Whatever format we specified, clients
would likely need a lookup table from what this API reports to the values
they support and wish to use internally.

Specifying ``cipher_suite`` as an integer, not a string:

* Avoids significant effort to compile a list of cipher suites in this
specification. There are a huge number of existing TLS cipher suites, many
of which are not widely used, even listing them all would be a huge effort.
* Avoids maintenance effort in this specification. If a new cipher suite is
defined, then no changes are needed in this specification.
* Avoids dependencies on nonstandard TLS-library-specific names. E.g. the
cipher names used by OpenSSL are different from the cipher names used by the
RFCs.
* Does not significantly affect servers. Whatever format we specified, (unless
it was a nonstandard library-specific name and the server happened to use
that library), servers would likely need a lookup table from what their
TLS library reports to what this API needs. (Unless their TLS library
provides access to the raw value, in which case it can be reported via this
API directly).
* Does not significantly affect clients. Whatever format we specified, clients
would likely need a lookup table from what this API reports to the values
they support and wish to use internally.
* Using a single integer, rather than a pair of integers, makes handling this
value simpler and faster.

``client_cert_name`` duplicates information that is also available in
``client_cert_chain``. However, many ASGI applications will probably find
that information is sufficient for their application - it provides a simple
string that identifies the user. It is simpler to use than parsing the x509
certificate. For the server, this information is readily available.

There are theoretical interoperability problems with ``client_cert_name``,
since it depends on a list of object ID names that is maintained by IANA and
theoretically can change. In practice, this is not a real problem, since the
object IDs that are actually used in certificates have not changed in many
years. So in practice it will be fine.


Copyright
---------

Expand Down

0 comments on commit 8ff93d5

Please sign in to comment.