xref: /aosp_15_r20/external/pigweed/pw_tls_client/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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