Overview
Certify is a C++11, header only library, which provides an abstraction of platform-specific operations, such as using X.509 certificates from the Operating System’s keystore to perform peer authentication during a TLS handshake. This library is intended for use with Boost.ASIO’s SSL components. Users of this library are assumed to have at least a basic understanding of the implementation of the Networking TS in Boost.ASIO. Beginners are recommended to start with the ASIO tutorial in Boost.Beast documentation to be able to follow examples in this library.
Note: Certify is not yet part of Boost.
Getting started
Certify is header-only, so no build step is required to use it.
Requirements
-
C++11
-
Boost (mostly Boost.ASIO)
-
OpenSSL (OpenSSL 1.0.2 or higher)
Building tests and examples
Before building, you need to clone/copy Certify into the libs/
subdirectory and bootstrap the b2
build tool:
cd boost
cd libs/
git clone https://github.com/djarek/certify.git
cd ..
./b2 libs/certify/test libs/certify/examples
Tests and examples can be built using the following command:
cd boost
./b2 libs/certify/test libs/certify/examples
For more information about additional flags and configuration steps see the Boost Wiki.
Building tests and examples requires OpenSSL installed. If OpenSSL is installed in a non-system location, you will need to copy the user-config.jam file into your home directory and set the OPENSSL_ROOT environment variable to the path that contains an installation of OpenSSL.
-
Ubuntu/Debian
If installed into a system directory, OpenSSL will be automatically found and used.
sudo apt install libssl-dev
-
Windows
Replace path
in the following code snippets with the path you installed
vcpkg to. Examples assume a 32-bit build, if you build a 64-bit version replace
x32-windows
with x64-windows
in the path.
Using vcpkg and CMD:
vcpkg install openssl --triplet x32-windows
SET OPENSSL_ROOT=path\installed\x32-windows
Using vcpkg and PowerShell:
vcpkg install openssl --triplet x32-windows
$env:OPENSSL_ROOT = "path\x32-windows"
Using vcpkg and bash:
vcpkg.exe install openssl --triplet x32-windows
export OPENSSL_ROOT=path/x32-windows
-
MacOS
Using brew:
brew install openssl
export OPENSSL_ROOT=$(brew --prefix openssl)
TLS primer
TLS (Transport Layer Security, specified in
RFC8447) is a network protocol which provides
confidentiality and authentication between peers of a network connection. TLS sessions are
represented by instances of the boost::asio::ssl::stream<NextLayer>
class template.
TLS connections share a number of configuration variables and state, which are
stored in a boost::asio::ssl::context
. It is safe to use a
boost::asio::ssl::context
context for multiple connections that run in
parallel on different threads, however accessing the context directly may result
in data races or race conditions.
A TLS session lasts between the initial handshake and shutdown. A handshake is a bidirectional exchange of configuration information and credentials, during which both peers agree on protocol configuration such as version or cipher. Both handshake and shutdown are initiated by the client. If peers cannot agree on a common set of configuration values or authentication fails, the entire handshake operation will fail. In typical use cases, the client authenticates the server based on their X.509 certificate, by verifying it with the use of public certificates of trusted organizations, known as certificate authorities. In order to verify a peer’s certificate, the implementation retrieves (one or more) public certificates from its key store. If verification of a certificate chain fails, the chain will be considered to be self-signed and the user is presented with an option to either continue the handshake or discontinue with an error. The verification procedure of a certificate chain presented by an HTTPS server is specified in RFC2818.
Some servers serve multiple hostnames using the same TCP endpoint and usually cannot determine which hostname to serve to a particular client unless additional information is provided. TLS-SNI is an extension that enables a client to indicate to a server which hostname it is trying to connect to. Some servers require this an SNI hostname to be sent in a TLS handshake, because multiple hostnames may be served by the same public-facing IP, without requiring all those sites to use the same certificate.
A client that wants to indicate to the server that a session is to be terminated in a clean way, it performs a shutdown operation. Some servers optimize this step out, when they can determine ahead of time that a peer will no longer send any requests and close the connection without waiting for a shutdown to complete.
Reference
The contents of the library are in namespace boost::certify.
HTTPS verification, <boost/certify/https_verification.hpp>
enable_native_https_server_verification(context)
void
enable_native_https_server_verification(asio::ssl::context& context);
Enables the use of the native certificate validation mechanism during a TLS handshake. Certificate verification is first performed using CA certificates imported into OpenSSL. If that fails because of missing CA certificates, the library will utilize platform specific APIs to try and complete the process.
If verification, using the platform-specific API, fails, the handshake operation
will fail with an error indicating that the certificate chain was self-signed. A
more detailed error can be retrieved after the handshake operation completes,
using SSL_get_verify_result
.
The library uses SSL_CTX_set_cert_verify_callback
in order to override the
default certificate verification procedure. If a regular verification callback
is set using asio::ssl::stream::set_verify_callback
, it will be invoked during
the first phase of certificate verification, in the same way a
default-configured asio::ssl::context
would.
set_server_hostname(stream, string_view, error_code)
template<class NextLayer>
void
set_server_hostname(asio::ssl::stream<NextLayer>& stream,
string_view hostname,
system::error_code& ec);
Sets the expected server hostname, which will be checked during
the verification process. The hostname must not contain \0
characters.
If setting the hostname results in a failure, ec
will contain the error code.
set_server_hostname(stream, string_view)
template<class NextLayer>
void
set_server_hostname(asio::ssl::stream<NextLayer>& stream, string_view hostname);
Sets the expected server hostname, which will be checked during
the verification process. The hostname must not contain \0
characters.
If setting the hostname results in a failure, an instance of
system::system_error
will be thrown.
TLS extensions, <boost/certify/extensions.hpp>
This file contains extensions to the implementation of asio::ssl
.
sni_hostname(stream)
template<class AsyncStream>
boost::string_view
sni_hostname(boost::asio::asio::ssl::stream<AsyncStream> const& stream);
Returns the SNI hostname set on the provided stream or a default
constructed string_view
if none was set.
sni_hostname(stream, hostname, error_code)
template<class AsyncStream>
void
sni_hostname(boost::asio::asio::ssl::stream<AsyncStream>& stream,
std::string const& hostname,
boost::system::error_code& ec);
Sets the provided SNI hostname on the provided stream. On success, ec
is
cleared, on error it will contain an error.
sni_hostname(stream, hostname)
template<class AsyncStream>
void
sni_hostname(asio::ssl::stream<AsyncStream>& stream,
std::string const& hostname);
Sets the provided SNI hostname on the provided stream. On error a
boost::system::system_error
is thrown.