1a8e1175bSopenharmony_ci
2a8e1175bSopenharmony_ciWriting early data
3a8e1175bSopenharmony_ci------------------
4a8e1175bSopenharmony_ci
5a8e1175bSopenharmony_ciAn application function to write and send a buffer of data to a server through
6a8e1175bSopenharmony_ciTLS may plausibly look like:
7a8e1175bSopenharmony_ci
8a8e1175bSopenharmony_ci```
9a8e1175bSopenharmony_ciint write_data(mbedtls_ssl_context *ssl,
10a8e1175bSopenharmony_ci               const unsigned char *data_to_write,
11a8e1175bSopenharmony_ci               size_t data_to_write_len,
12a8e1175bSopenharmony_ci               size_t *data_written)
13a8e1175bSopenharmony_ci{
14a8e1175bSopenharmony_ci    int ret;
15a8e1175bSopenharmony_ci    *data_written = 0;
16a8e1175bSopenharmony_ci
17a8e1175bSopenharmony_ci    while (*data_written < data_to_write_len) {
18a8e1175bSopenharmony_ci        ret = mbedtls_ssl_write(ssl, data_to_write + *data_written,
19a8e1175bSopenharmony_ci                                data_to_write_len - *data_written);
20a8e1175bSopenharmony_ci
21a8e1175bSopenharmony_ci        if (ret < 0 &&
22a8e1175bSopenharmony_ci            ret != MBEDTLS_ERR_SSL_WANT_READ &&
23a8e1175bSopenharmony_ci            ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
24a8e1175bSopenharmony_ci            return ret;
25a8e1175bSopenharmony_ci        }
26a8e1175bSopenharmony_ci
27a8e1175bSopenharmony_ci        *data_written += ret;
28a8e1175bSopenharmony_ci    }
29a8e1175bSopenharmony_ci
30a8e1175bSopenharmony_ci    return 0;
31a8e1175bSopenharmony_ci}
32a8e1175bSopenharmony_ci```
33a8e1175bSopenharmony_ciwhere ssl is the SSL context to use, data_to_write the address of the data
34a8e1175bSopenharmony_cibuffer and data_to_write_len the number of data bytes. The handshake may
35a8e1175bSopenharmony_cinot be completed, not even started for the SSL context ssl when the function is
36a8e1175bSopenharmony_cicalled and in that case the mbedtls_ssl_write() API takes care transparently of
37a8e1175bSopenharmony_cicompleting the handshake before to write and send data to the server. The
38a8e1175bSopenharmony_cimbedtls_ssl_write() may not be able to write and send all data in one go thus
39a8e1175bSopenharmony_cithe need for a loop calling it as long as there are still data to write and
40a8e1175bSopenharmony_cisend.
41a8e1175bSopenharmony_ci
42a8e1175bSopenharmony_ciAn application function to write and send early data and only early data,
43a8e1175bSopenharmony_cidata sent during the first flight of client messages while the handshake is in
44a8e1175bSopenharmony_ciits initial phase, would look completely similar but the call to
45a8e1175bSopenharmony_cimbedtls_ssl_write_early_data() instead of mbedtls_ssl_write().
46a8e1175bSopenharmony_ci```
47a8e1175bSopenharmony_ciint write_early_data(mbedtls_ssl_context *ssl,
48a8e1175bSopenharmony_ci                     const unsigned char *data_to_write,
49a8e1175bSopenharmony_ci                     size_t data_to_write_len,
50a8e1175bSopenharmony_ci                     size_t *data_written)
51a8e1175bSopenharmony_ci{
52a8e1175bSopenharmony_ci    int ret;
53a8e1175bSopenharmony_ci    *data_written = 0;
54a8e1175bSopenharmony_ci
55a8e1175bSopenharmony_ci    while (*data_written < data_to_write_len) {
56a8e1175bSopenharmony_ci        ret = mbedtls_ssl_write_early_data(ssl, data_to_write + *data_written,
57a8e1175bSopenharmony_ci                                           data_to_write_len - *data_written);
58a8e1175bSopenharmony_ci
59a8e1175bSopenharmony_ci        if (ret < 0 &&
60a8e1175bSopenharmony_ci            ret != MBEDTLS_ERR_SSL_WANT_READ &&
61a8e1175bSopenharmony_ci            ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
62a8e1175bSopenharmony_ci            return ret;
63a8e1175bSopenharmony_ci        }
64a8e1175bSopenharmony_ci
65a8e1175bSopenharmony_ci        *data_written += ret;
66a8e1175bSopenharmony_ci    }
67a8e1175bSopenharmony_ci
68a8e1175bSopenharmony_ci    return 0;
69a8e1175bSopenharmony_ci}
70a8e1175bSopenharmony_ci```
71a8e1175bSopenharmony_ciNote that compared to write_data(), write_early_data() can also return
72a8e1175bSopenharmony_ciMBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA and that should be handled
73a8e1175bSopenharmony_cispecifically by the user of write_early_data(). A fresh SSL context (typically
74a8e1175bSopenharmony_cijust after a call to mbedtls_ssl_setup() or mbedtls_ssl_session_reset()) would
75a8e1175bSopenharmony_cibe expected when calling `write_early_data`.
76a8e1175bSopenharmony_ci
77a8e1175bSopenharmony_ciAll together, code to write and send a buffer of data as long as possible as
78a8e1175bSopenharmony_ciearly data and then as standard post-handshake application data could
79a8e1175bSopenharmony_ciplausibly look like:
80a8e1175bSopenharmony_ci
81a8e1175bSopenharmony_ci```
82a8e1175bSopenharmony_ciret = write_early_data(ssl,
83a8e1175bSopenharmony_ci                       data_to_write,
84a8e1175bSopenharmony_ci                       data_to_write_len,
85a8e1175bSopenharmony_ci                       &early_data_written);
86a8e1175bSopenharmony_ciif (ret < 0 &&
87a8e1175bSopenharmony_ci    ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) {
88a8e1175bSopenharmony_ci    goto error;
89a8e1175bSopenharmony_ci}
90a8e1175bSopenharmony_ci
91a8e1175bSopenharmony_ciret = write_data(ssl,
92a8e1175bSopenharmony_ci                 data_to_write + early_data_written,
93a8e1175bSopenharmony_ci                 data_to_write_len - early_data_written,
94a8e1175bSopenharmony_ci                 &data_written);
95a8e1175bSopenharmony_ciif (ret < 0) {
96a8e1175bSopenharmony_ci    goto error;
97a8e1175bSopenharmony_ci}
98a8e1175bSopenharmony_ci
99a8e1175bSopenharmony_cidata_written += early_data_written;
100a8e1175bSopenharmony_ci```
101a8e1175bSopenharmony_ci
102a8e1175bSopenharmony_ciFinally, taking into account that the server may reject early data, application
103a8e1175bSopenharmony_cicode to write and send a buffer of data could plausibly look like:
104a8e1175bSopenharmony_ci```
105a8e1175bSopenharmony_ciret = write_early_data(ssl,
106a8e1175bSopenharmony_ci                       data_to_write,
107a8e1175bSopenharmony_ci                       data_to_write_len,
108a8e1175bSopenharmony_ci                       &early_data_written);
109a8e1175bSopenharmony_ciif (ret < 0 &&
110a8e1175bSopenharmony_ci    ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) {
111a8e1175bSopenharmony_ci    goto error;
112a8e1175bSopenharmony_ci}
113a8e1175bSopenharmony_ci
114a8e1175bSopenharmony_ci/*
115a8e1175bSopenharmony_ci * Make sure the handshake is completed as it is a requisite of
116a8e1175bSopenharmony_ci * mbedtls_ssl_get_early_data_status().
117a8e1175bSopenharmony_ci */
118a8e1175bSopenharmony_ciwhile (!mbedtls_ssl_is_handshake_over(ssl)) {
119a8e1175bSopenharmony_ci    ret = mbedtls_ssl_handshake(ssl);
120a8e1175bSopenharmony_ci    if (ret < 0 &&
121a8e1175bSopenharmony_ci        ret != MBEDTLS_ERR_SSL_WANT_READ &&
122a8e1175bSopenharmony_ci        ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
123a8e1175bSopenharmony_ci        goto error;
124a8e1175bSopenharmony_ci    }
125a8e1175bSopenharmony_ci}
126a8e1175bSopenharmony_ci
127a8e1175bSopenharmony_ciret = mbedtls_ssl_get_early_data_status(ssl);
128a8e1175bSopenharmony_ciif (ret < 0) {
129a8e1175bSopenharmony_ci    goto error;
130a8e1175bSopenharmony_ci}
131a8e1175bSopenharmony_ci
132a8e1175bSopenharmony_ciif (ret == MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED) {
133a8e1175bSopenharmony_ci   early_data_written = 0;
134a8e1175bSopenharmony_ci}
135a8e1175bSopenharmony_ci
136a8e1175bSopenharmony_ciret = write_data(ssl,
137a8e1175bSopenharmony_ci                 data_to_write + early_data_written,
138a8e1175bSopenharmony_ci                 data_to_write_len - early_data_written,
139a8e1175bSopenharmony_ci                 &data_written);
140a8e1175bSopenharmony_ciif (ret < 0) {
141a8e1175bSopenharmony_ci    goto error;
142a8e1175bSopenharmony_ci}
143a8e1175bSopenharmony_ci
144a8e1175bSopenharmony_cidata_written += early_data_written;
145a8e1175bSopenharmony_ci```
146a8e1175bSopenharmony_ci
147a8e1175bSopenharmony_ciReading early data
148a8e1175bSopenharmony_ci------------------
149a8e1175bSopenharmony_ciMbed TLS provides the mbedtls_ssl_read_early_data() API to read the early data
150a8e1175bSopenharmony_cithat a TLS 1.3 server might receive during the TLS 1.3 handshake.
151a8e1175bSopenharmony_ci
152a8e1175bSopenharmony_ciWhile establishing a TLS 1.3 connection with a client using a combination
153a8e1175bSopenharmony_ciof the mbedtls_ssl_handshake(), mbedtls_ssl_read() and mbedtls_ssl_write() APIs,
154a8e1175bSopenharmony_cithe reception of early data is signaled by an API returning the
155a8e1175bSopenharmony_ciMBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA error code. Early data can then be read
156a8e1175bSopenharmony_ciwith the mbedtls_ssl_read_early_data() API.
157a8e1175bSopenharmony_ci
158a8e1175bSopenharmony_ciFor example, a typical code to establish a TLS connection, where ssl is the SSL
159a8e1175bSopenharmony_cicontext to use:
160a8e1175bSopenharmony_ci```
161a8e1175bSopenharmony_ciwhile ((int ret = mbedtls_ssl_handshake(&ssl)) != 0) {
162a8e1175bSopenharmony_ci
163a8e1175bSopenharmony_ci    if (ret < 0 &&
164a8e1175bSopenharmony_ci        ret != MBEDTLS_ERR_SSL_WANT_READ &&
165a8e1175bSopenharmony_ci        ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
166a8e1175bSopenharmony_ci        break;
167a8e1175bSopenharmony_ci    }
168a8e1175bSopenharmony_ci}
169a8e1175bSopenharmony_ci```
170a8e1175bSopenharmony_cicould be adapted to handle early data in the following way:
171a8e1175bSopenharmony_ci```
172a8e1175bSopenharmony_cisize_t data_read_len = 0;
173a8e1175bSopenharmony_ciwhile ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
174a8e1175bSopenharmony_ci
175a8e1175bSopenharmony_ci    if (ret == MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA) {
176a8e1175bSopenharmony_ci        ret = mbedtls_ssl_read_early_data(&ssl,
177a8e1175bSopenharmony_ci                                          buffer + data_read_len,
178a8e1175bSopenharmony_ci                                          sizeof(buffer) - data_read_len);
179a8e1175bSopenharmony_ci        if (ret < 0) {
180a8e1175bSopenharmony_ci            break;
181a8e1175bSopenharmony_ci        }
182a8e1175bSopenharmony_ci        data_read_len += ret;
183a8e1175bSopenharmony_ci        continue;
184a8e1175bSopenharmony_ci    }
185a8e1175bSopenharmony_ci
186a8e1175bSopenharmony_ci    if (ret < 0 &&
187a8e1175bSopenharmony_ci        ret != MBEDTLS_ERR_SSL_WANT_READ &&
188a8e1175bSopenharmony_ci        ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
189a8e1175bSopenharmony_ci        break;
190a8e1175bSopenharmony_ci    }
191a8e1175bSopenharmony_ci}
192a8e1175bSopenharmony_ci```
193