.. Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. include:: ../../common.defs .. highlight:: cpp .. default-domain:: cpp .. _cripts-certs: Certificates ************ Cripts provides a set of convenient classes for introspection into the various TLS certificates that are used. These include both the server certificates used to establish a TLS connections, as well as any client certificates used for mutual TLS. In the current implementation, these objects only work on X509 certificates as associated with the ``client`` and ``server`` connections. Let's start off with a simple example of how to use these objects: .. code-block:: cpp do_send_response() { if (client.connection.IsTLS()) { const auto tls = cripts::Certs::Server(client.connection); client.response["X-Subject"] = tls.subject; client.response["X-NotBefore"] = tls.notBefore; client.response["X-NotAfter"] = tls.notAfter; } } .. _cripts-certs-objects: Objects ======= There are two types of objects for the certificates: ================================= =============================================================== Object Description ================================= =============================================================== ``cripts::Certs::Server`` The certificate used on the connection for TLS handshakes. ``cripts::Certs::Client`` The mutual TLS (mTLS) certificate used on the connection. ================================= =============================================================== This combined with the two kinds of connections, ``cripts::Client::Connection`` and ``cripts::Server::Connection`` yields a total of four possible certificate objects. For example, to access the client mTLS provided certificate on a client connection, you would use: .. code-block:: cpp const auto tls = cripts::Certs::Client(cripts::Client::Connection::Get()); Or if you are using the convenience wrappers: .. code-block:: cpp const auto tls = cripts::Certs::Client(client.connection); .. _cripts-certs-x509: X509 Values =========== As part of the certificate objects, there are a number of values that can be accessed. These values are all based on the X509 standard and can be used to introspect the certificate. The following values are available: ================================= =============================================================== Value Description ================================= =============================================================== ``certificate`` The raw X509 certificate in PEM format. ``signature`` The raw signature of the certificate. ``subject`` The subject of the certificate. ``issuer`` The issuer of the certificate. ``serialNumber`` The serial number of the certificate. ``notBefore`` The date and time when the certificate is valid from. ``notAfter`` The date and time when the certificate is valid until. ``version`` The version of the certificate. ================================= =============================================================== .. _cripts-certs-san: SAN Values ========== We've made special provisions to access the Subject Alternative Name (SAN) values of the certificate. These values are often used to identify the hostnames or IP addresses that the certificate is valid for. Once you have the certificate object, you can access the SAN values as follows: ==================== =============== =============================================================== Field X509 field Description ==================== =============== =============================================================== ``.san`` na An array of tuples with type and ``string_view`` of all SANs. ``.san.email`` ``GEN_EMAIL`` An array of ``string_view`` of email addresses. ``.san.dns`` ``GEN_DNS`` An array of ``string_view`` of DNS names. ``.san.uri`` ``GEN_URI`` An array of ``string_view`` of URIs. ``.san.ipadd`` ``GEN_IPADD`` An array of ``string_view`` of IP addresses. ==================== =============== =============================================================== .. note:: These arrays are empty if no SAN values are present in the certificate. We also populate these arrays lazily, but they are kept for the lifetime of the certificate object. This means that you can access these values multiple times without incurring additional overhead. Remember that you can use the ``cripts::Net::IP`` class to convert the IP addresses into proper IP address objects if needed. Odds are that you will want to use one of the specific array values, such as ``.san.uri``, which is easily done in a simple loop: .. code-block:: cpp do_remap() { if (client.connection.IsTLS()) { const auto tls = cripts::Certs::Server(client.connection); for (auto uri : tls.san.uri) { // Check the URI string_view } } } You can of course loop over all SAN values, which is where the type of the value would come in handy, and why this is an array of tuples. In this scenario, you would iterate over the tuples like this: .. code-block:: cpp do_remap() { if (client.connection.IsTLS()) { const auto tls = cripts::Certs::Server(client.connection); for (const [type, san] : tls.san) { if (type == cripts::Certs::SAN::URI) { // Check the URI string here } else if (type == cripts::Certs::SAN::DNS) { // Check the DNS string here } } } } In addition to traditional C++ iterators, you can also access SAN values by index. Make sure you check the size of the array first, as accessing an out-of-bounds index will give you an empty tuple. Prefer the iterator above, unless you know you want to access a specific element. Example of an alternative way to loop over all SAN values: .. code-block:: cpp do_remap() { if (client.connection.IsTLS()) { const auto tls = cripts::Certs::Server(client.connection); size_t san_count = tls.san.size(); for (size_t i = 0; i < san_count; ++i) { const auto [type, san] = tls.san[i]; // Process the type and san as needed } } }