1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_tls_client: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker-------------- 4*61c4878aSAndroid Build Coastguard Workerpw_tls_client 5*61c4878aSAndroid Build Coastguard Worker-------------- 6*61c4878aSAndroid Build Coastguard Worker 7*61c4878aSAndroid Build Coastguard WorkerThis module provides a facade that defines the public APIs for establishing TLS 8*61c4878aSAndroid Build Coastguard Workersessions over arbitrary transports. Two options of backends, 9*61c4878aSAndroid Build Coastguard Workerpw_tls_client_mbedtls and pw_tls_client_boringssl, which are based on BoringSSL 10*61c4878aSAndroid Build Coastguard Workerand MbedTLS libraries, are under construction. 11*61c4878aSAndroid Build Coastguard Worker 12*61c4878aSAndroid Build Coastguard WorkerThe facade provides a class ``pw::tls_client::Session`` with Open(), Read(), 13*61c4878aSAndroid Build Coastguard WorkerWrite() and Close() methods for TLS communication. An instance is created by 14*61c4878aSAndroid Build Coastguard Worker``pw::tls_client::Session::Create`` method. The method takes a 15*61c4878aSAndroid Build Coastguard Worker``pw::tls_client::SessionOptions`` object, which is used to configure TLS 16*61c4878aSAndroid Build Coastguard Workerconnection options. The list of supported configurations currently include: 17*61c4878aSAndroid Build Coastguard Worker 18*61c4878aSAndroid Build Coastguard Worker1. Host name of the target server. This will be used as the Server Name 19*61c4878aSAndroid Build Coastguard Worker Indication(SNI) extension during TLS handshake. 20*61c4878aSAndroid Build Coastguard Worker 21*61c4878aSAndroid Build Coastguard Worker2. User-implemented transport. The underlying transport for the TLS 22*61c4878aSAndroid Build Coastguard Worker communication. It is an object that implements the interface of 23*61c4878aSAndroid Build Coastguard Worker ``pw::stream::ReaderWriter``. 24*61c4878aSAndroid Build Coastguard Worker 25*61c4878aSAndroid Build Coastguard WorkerThe module will also provide mechanisms/APIs for users to specify sources of 26*61c4878aSAndroid Build Coastguard Workertrust anchors, time and entropy. These are under construction. 27*61c4878aSAndroid Build Coastguard Worker 28*61c4878aSAndroid Build Coastguard Worker.. warning:: 29*61c4878aSAndroid Build Coastguard Worker This module is under construction, not ready for use, and the documentation 30*61c4878aSAndroid Build Coastguard Worker is incomplete. 31*61c4878aSAndroid Build Coastguard Worker 32*61c4878aSAndroid Build Coastguard WorkerPrerequisites 33*61c4878aSAndroid Build Coastguard Worker============= 34*61c4878aSAndroid Build Coastguard WorkerThis module requires the following dependencies: 35*61c4878aSAndroid Build Coastguard Worker 36*61c4878aSAndroid Build Coastguard Worker1. Entropy 37*61c4878aSAndroid Build Coastguard Worker----------- 38*61c4878aSAndroid Build Coastguard WorkerTLS requires an entropy source for generating random bytes. Users of this 39*61c4878aSAndroid Build Coastguard Workermodule should provide one by implementing a backend to the 40*61c4878aSAndroid Build Coastguard Worker``pw_tls_client:entropy`` facade. The backend defaults to 41*61c4878aSAndroid Build Coastguard Worker``pw_tls_client:fake_entropy`` that does nothing. 42*61c4878aSAndroid Build Coastguard Worker 43*61c4878aSAndroid Build Coastguard Worker2. Chromium Verifier 44*61c4878aSAndroid Build Coastguard Worker--------------------- 45*61c4878aSAndroid Build Coastguard WorkerBoringSSL backend uses chromium verifier for certication verification. If the 46*61c4878aSAndroid Build Coastguard Workerdownstream project uses BoringSSL as the backend, the sources of the verifier, 47*61c4878aSAndroid Build Coastguard Workerwhich is part of the chorimum sources, needs to be downloaded in order for 48*61c4878aSAndroid Build Coastguard Worker``//third_party/chromium_verifier`` to build. It is recommended to use our 49*61c4878aSAndroid Build Coastguard Workersupport in pw_package for downloading compatible and tested version: 50*61c4878aSAndroid Build Coastguard Worker 51*61c4878aSAndroid Build Coastguard Worker.. code-block:: sh 52*61c4878aSAndroid Build Coastguard Worker 53*61c4878aSAndroid Build Coastguard Worker pw package install chromium_verifier 54*61c4878aSAndroid Build Coastguard Worker 55*61c4878aSAndroid Build Coastguard WorkerThen follow instruction for setting ``dir_pw_third_party_chromium_verifier`` to 56*61c4878aSAndroid Build Coastguard Workerthe path of the downloaded repo. 57*61c4878aSAndroid Build Coastguard Worker 58*61c4878aSAndroid Build Coastguard Worker3. Date time 59*61c4878aSAndroid Build Coastguard Worker------------- 60*61c4878aSAndroid Build Coastguard WorkerTLS needs a trust-worthy source of wall clock time in order to check 61*61c4878aSAndroid Build Coastguard Workerexpiration. Provisioning of time source for TLS communication is very specific 62*61c4878aSAndroid Build Coastguard Workerto the TLS library in use. However, common TLS libraires, such as BoringSSL 63*61c4878aSAndroid Build Coastguard Workerand MbedTLS, support the use of C APIs ``time()`` and ``getimtofday()`` for 64*61c4878aSAndroid Build Coastguard Workerobtaining date time. To accomodate the use of these libraries, a facade target 65*61c4878aSAndroid Build Coastguard Worker``pw_tls_client:time`` is added that wraps these APIs. For GN builds, 66*61c4878aSAndroid Build Coastguard Workerspecify the backend target with variable ``pw_tls_client_TIME_BACKEND``. 67*61c4878aSAndroid Build Coastguard Worker``pw_tls_client_TIME_BACKEND`` defaults to the ``pw_chrono::wrap_time_build_time`` 68*61c4878aSAndroid Build Coastguard Workerbackend that returns build time. 69*61c4878aSAndroid Build Coastguard Worker 70*61c4878aSAndroid Build Coastguard WorkerIf downstream project chooses to use other TLS libraires that handle time source 71*61c4878aSAndroid Build Coastguard Workerdifferently, then it needs to be investigated separately. 72*61c4878aSAndroid Build Coastguard Worker 73*61c4878aSAndroid Build Coastguard Worker4. CRLSet 74*61c4878aSAndroid Build Coastguard Worker----------- 75*61c4878aSAndroid Build Coastguard WorkerThe module supports CRLSet based revocation check for certificates. A CRLSet 76*61c4878aSAndroid Build Coastguard Workerfile specifies a list of X509 certificates that either need to be blocked, or 77*61c4878aSAndroid Build Coastguard Workerhave been revoked by the issuer. It is introduced by chromium and primarily 78*61c4878aSAndroid Build Coastguard Workerused for certificate verification/revocation checks during TLS handshake. The 79*61c4878aSAndroid Build Coastguard Workerformat of a CRLSet file is available in 80*61c4878aSAndroid Build Coastguard Workerhttps://chromium.googlesource.com/chromium/src/+/refs/heads/main/net/cert/crl_set.cc#24. 81*61c4878aSAndroid Build Coastguard Worker 82*61c4878aSAndroid Build Coastguard WorkerDownstream projects need to provide a CRLSet file at build time. For GN builds, 83*61c4878aSAndroid Build Coastguard Workerspecify the path of the CRLSet file with the GN variable 84*61c4878aSAndroid Build Coastguard Worker``pw_tls_client_CRLSET_FILE``. This module converts the CRLSet file into 85*61c4878aSAndroid Build Coastguard Workersource code at build time and generates APIs for querying certificate 86*61c4878aSAndroid Build Coastguard Workerblock/revocation status. See ``pw_tls_client/crlset.h`` for more detail. 87*61c4878aSAndroid Build Coastguard Worker 88*61c4878aSAndroid Build Coastguard WorkerChromium maintains its own CRLSet that targets at the general Internet. To use it, 89*61c4878aSAndroid Build Coastguard Workerrun the following command to download the latest version: 90*61c4878aSAndroid Build Coastguard Worker 91*61c4878aSAndroid Build Coastguard Worker.. code-block:: sh 92*61c4878aSAndroid Build Coastguard Worker 93*61c4878aSAndroid Build Coastguard Worker pw package install crlset --force 94*61c4878aSAndroid Build Coastguard Worker 95*61c4878aSAndroid Build Coastguard WorkerThe `--force` option forces CRLSet to be always re-downloaded so that it is 96*61c4878aSAndroid Build Coastguard Workerup-to-date. Project that are concerned about up-to-date CRLSet should always 97*61c4878aSAndroid Build Coastguard Workerrun the above command before build. 98*61c4878aSAndroid Build Coastguard Worker 99*61c4878aSAndroid Build Coastguard WorkerToolings will be provided for generating custom CRLSet files from user-provided 100*61c4878aSAndroid Build Coastguard Workercertificate files. The functionality is under construction. 101*61c4878aSAndroid Build Coastguard Worker 102*61c4878aSAndroid Build Coastguard WorkerSetup 103*61c4878aSAndroid Build Coastguard Worker===== 104*61c4878aSAndroid Build Coastguard WorkerThis module requires the following setup: 105*61c4878aSAndroid Build Coastguard Worker 106*61c4878aSAndroid Build Coastguard Worker1. Choose a ``pw_tls_client`` backend, or write one yourself. 107*61c4878aSAndroid Build Coastguard Worker2. If using GN build, Specify the ``pw_tls_client_BACKEND`` GN build arg to 108*61c4878aSAndroid Build Coastguard Worker point the library that provides a ``pw_tls_client`` backend. To use the 109*61c4878aSAndroid Build Coastguard Worker MbedTLS backend, set variable ``pw_tls_client_BACKEND`` to 110*61c4878aSAndroid Build Coastguard Worker ``//pw_tls_client_mbedtls``. To use the BoringSSL backend, set it to 111*61c4878aSAndroid Build Coastguard Worker ``//pw_tls_client_boringssl``. 112*61c4878aSAndroid Build Coastguard Worker3. Provide a `pw_tls_client:entropy` backend. If using GN build, specify the 113*61c4878aSAndroid Build Coastguard Worker backend with variable ``pw_tls_client_ENTROPY_BACKEND``. 114*61c4878aSAndroid Build Coastguard Worker 115*61c4878aSAndroid Build Coastguard WorkerModule usage 116*61c4878aSAndroid Build Coastguard Worker============ 117*61c4878aSAndroid Build Coastguard WorkerFor GN build, add ``//pw_tls_client`` to the dependency list. 118*61c4878aSAndroid Build Coastguard Worker 119*61c4878aSAndroid Build Coastguard WorkerThe following gives an example code for using the module on host platform. 120*61c4878aSAndroid Build Coastguard WorkerThe example uses a Pigweed socket stream as the transport and performs TLS 121*61c4878aSAndroid Build Coastguard Workerconnection to www.google.com: 122*61c4878aSAndroid Build Coastguard Worker 123*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 124*61c4878aSAndroid Build Coastguard Worker 125*61c4878aSAndroid Build Coastguard Worker // Host domain name 126*61c4878aSAndroid Build Coastguard Worker constexpr char kHost[] = "www.google.com"; 127*61c4878aSAndroid Build Coastguard Worker 128*61c4878aSAndroid Build Coastguard Worker constexpr int kPort = 443; 129*61c4878aSAndroid Build Coastguard Worker 130*61c4878aSAndroid Build Coastguard Worker // Server Name Indication. 131*61c4878aSAndroid Build Coastguard Worker constexpr const char* kServerNameIndication = kHost; 132*61c4878aSAndroid Build Coastguard Worker 133*61c4878aSAndroid Build Coastguard Worker // An example message to send. 134*61c4878aSAndroid Build Coastguard Worker constexpr char kHTTPRequest[] = "GET / HTTP/1.1\r\n\r\n"; 135*61c4878aSAndroid Build Coastguard Worker 136*61c4878aSAndroid Build Coastguard Worker // pw::stream::SocketStream doesn't accept host domain name as input. Thus we 137*61c4878aSAndroid Build Coastguard Worker // introduce this helper function for getting the IP address 138*61c4878aSAndroid Build Coastguard Worker pw::Status GetIPAddrFromHostName(std::string_view host, pw::span<char> ip) { 139*61c4878aSAndroid Build Coastguard Worker char null_terminated_host_name[256] = {0}; 140*61c4878aSAndroid Build Coastguard Worker auto host_copy_status = pw::string::Copy(host, null_terminated_host_name); 141*61c4878aSAndroid Build Coastguard Worker if (!host_copy_status.ok()) { 142*61c4878aSAndroid Build Coastguard Worker return host_copy_status.status(); 143*61c4878aSAndroid Build Coastguard Worker } 144*61c4878aSAndroid Build Coastguard Worker 145*61c4878aSAndroid Build Coastguard Worker struct hostent* ent = gethostbyname(null_terminated_host_name); 146*61c4878aSAndroid Build Coastguard Worker if (ent == NULL) { 147*61c4878aSAndroid Build Coastguard Worker return PW_STATUS_INTERNAL; 148*61c4878aSAndroid Build Coastguard Worker } 149*61c4878aSAndroid Build Coastguard Worker 150*61c4878aSAndroid Build Coastguard Worker in_addr** addr_list = reinterpret_cast<in_addr**>(ent->h_addr_list); 151*61c4878aSAndroid Build Coastguard Worker if (addr_list[0] == nullptr) { 152*61c4878aSAndroid Build Coastguard Worker return PW_STATUS_INTERNAL; 153*61c4878aSAndroid Build Coastguard Worker } 154*61c4878aSAndroid Build Coastguard Worker 155*61c4878aSAndroid Build Coastguard Worker auto ip_copy_status = pw::string::Copy(inet_ntoa(*addr_list[0]), ip); 156*61c4878aSAndroid Build Coastguard Worker if (!ip_copy_status.ok()) { 157*61c4878aSAndroid Build Coastguard Worker return ip_copy_status.status(); 158*61c4878aSAndroid Build Coastguard Worker } 159*61c4878aSAndroid Build Coastguard Worker 160*61c4878aSAndroid Build Coastguard Worker return pw::OkStatus(); 161*61c4878aSAndroid Build Coastguard Worker } 162*61c4878aSAndroid Build Coastguard Worker 163*61c4878aSAndroid Build Coastguard Worker int main() { 164*61c4878aSAndroid Build Coastguard Worker // Get the IP address of the target host. 165*61c4878aSAndroid Build Coastguard Worker char ip_address[64] = {0}; 166*61c4878aSAndroid Build Coastguard Worker auto get_ip_status = GetIPAddrFromHostName(kHost, ip_address); 167*61c4878aSAndroid Build Coastguard Worker if (!get_ip_status.ok()) { 168*61c4878aSAndroid Build Coastguard Worker return 1; 169*61c4878aSAndroid Build Coastguard Worker } 170*61c4878aSAndroid Build Coastguard Worker 171*61c4878aSAndroid Build Coastguard Worker // Use a socket stream as the transport. 172*61c4878aSAndroid Build Coastguard Worker pw::stream::SocketStream socket_stream; 173*61c4878aSAndroid Build Coastguard Worker 174*61c4878aSAndroid Build Coastguard Worker // Connect the socket to the remote host. 175*61c4878aSAndroid Build Coastguard Worker auto socket_connect_status = socket_stream.Connect(ip_address, kPort); 176*61c4878aSAndroid Build Coastguard Worker if (!socket_connect_status.ok()) { 177*61c4878aSAndroid Build Coastguard Worker return 1; 178*61c4878aSAndroid Build Coastguard Worker } 179*61c4878aSAndroid Build Coastguard Worker 180*61c4878aSAndroid Build Coastguard Worker // Create a TLS session. Register the transport. 181*61c4878aSAndroid Build Coastguard Worker auto options = pw::tls_client::SessionOptions() 182*61c4878aSAndroid Build Coastguard Worker .set_server_name(kServerNameIndication) 183*61c4878aSAndroid Build Coastguard Worker .set_transport(socket_stream); 184*61c4878aSAndroid Build Coastguard Worker auto tls_conn = pw::tls_client::Session::Create(options); 185*61c4878aSAndroid Build Coastguard Worker if (!tls_conn.ok()) { 186*61c4878aSAndroid Build Coastguard Worker // Handle errors. 187*61c4878aSAndroid Build Coastguard Worker return 1; 188*61c4878aSAndroid Build Coastguard Worker } 189*61c4878aSAndroid Build Coastguard Worker 190*61c4878aSAndroid Build Coastguard Worker auto open_status = tls_conn.value()->Open(); 191*61c4878aSAndroid Build Coastguard Worker if (!open_status.ok()) { 192*61c4878aSAndroid Build Coastguard Worker // Inspect/handle error with open_status.code() and 193*61c4878aSAndroid Build Coastguard Worker // tls_conn.value()->GetLastTLSStatus(). 194*61c4878aSAndroid Build Coastguard Worker return 1; 195*61c4878aSAndroid Build Coastguard Worker } 196*61c4878aSAndroid Build Coastguard Worker 197*61c4878aSAndroid Build Coastguard Worker auto write_status = tls_conn.value()->Write(pw::as_bytes(pw::span{kHTTPRequest})); 198*61c4878aSAndroid Build Coastguard Worker if (!write_status.ok()) { 199*61c4878aSAndroid Build Coastguard Worker // Inspect/handle error with write_status.code() and 200*61c4878aSAndroid Build Coastguard Worker // tls_conn.value()->GetLastTLSStatus(). 201*61c4878aSAndroid Build Coastguard Worker return 0; 202*61c4878aSAndroid Build Coastguard Worker } 203*61c4878aSAndroid Build Coastguard Worker 204*61c4878aSAndroid Build Coastguard Worker // Listen for incoming data. 205*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, 4096> buffer; 206*61c4878aSAndroid Build Coastguard Worker while (true) { 207*61c4878aSAndroid Build Coastguard Worker auto res = tls_conn.value()->Read(buffer); 208*61c4878aSAndroid Build Coastguard Worker if (!res.ok()) { 209*61c4878aSAndroid Build Coastguard Worker // Inspect/handle error with res.status().code() and 210*61c4878aSAndroid Build Coastguard Worker // tls_conn.value()->GetLastTLSStatus(). 211*61c4878aSAndroid Build Coastguard Worker return 1; 212*61c4878aSAndroid Build Coastguard Worker } 213*61c4878aSAndroid Build Coastguard Worker 214*61c4878aSAndroid Build Coastguard Worker // Process data in |buffer|. res.value() gives the span of read bytes. 215*61c4878aSAndroid Build Coastguard Worker // The following simply print to console. 216*61c4878aSAndroid Build Coastguard Worker if (res.value().size()) { 217*61c4878aSAndroid Build Coastguard Worker auto print_status = pw::sys_io::WriteBytes(res.value()); 218*61c4878aSAndroid Build Coastguard Worker if (!print_status.ok()) { 219*61c4878aSAndroid Build Coastguard Worker return 1; 220*61c4878aSAndroid Build Coastguard Worker } 221*61c4878aSAndroid Build Coastguard Worker } 222*61c4878aSAndroid Build Coastguard Worker 223*61c4878aSAndroid Build Coastguard Worker } 224*61c4878aSAndroid Build Coastguard Worker } 225*61c4878aSAndroid Build Coastguard Worker 226*61c4878aSAndroid Build Coastguard WorkerA list of other demos will be provided in ``//pw_tls_client/examples/`` 227*61c4878aSAndroid Build Coastguard Worker 228*61c4878aSAndroid Build Coastguard Worker.. warning:: 229*61c4878aSAndroid Build Coastguard Worker Open()/Read() APIs are synchronous for now. Support for 230*61c4878aSAndroid Build Coastguard Worker non-blocking/asynchronous usage will be added in the future. 231*61c4878aSAndroid Build Coastguard Worker 232*61c4878aSAndroid Build Coastguard Worker 233*61c4878aSAndroid Build Coastguard Worker.. toctree:: 234*61c4878aSAndroid Build Coastguard Worker :hidden: 235*61c4878aSAndroid Build Coastguard Worker :maxdepth: 1 236*61c4878aSAndroid Build Coastguard Worker 237*61c4878aSAndroid Build Coastguard Worker Backends <backends> 238