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:
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;
}
}
Objects
There are two types of objects for the certificates:
Object |
Description |
---|---|
|
The certificate used on the connection for TLS handshakes. |
|
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:
const auto tls = cripts::Certs::Client(cripts::Client::Connection::Get());
Or if you are using the convenience wrappers:
const auto tls = cripts::Certs::Client(client.connection);
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 |
---|---|
|
The raw X509 certificate in PEM format. |
|
The raw signature of the certificate. |
|
The subject of the certificate. |
|
The issuer of the certificate. |
|
The serial number of the certificate. |
|
The date and time when the certificate is valid from. |
|
The date and time when the certificate is valid until. |
|
The version of the certificate. |
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 |
---|---|---|
|
na |
An array of tuples with type and |
|
|
An array of |
|
|
An array of |
|
|
An array of |
|
|
An array of |
注釈
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:
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:
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:
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
}
}
}