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