blob: 4b6f5d305c65bcf5d6d289572d784d4adf4df781 [file] [log] [blame] [view]
Ronald Cronb372b2e2024-03-13 14:10:58 +01001
Ronald Crond514d9c2024-03-13 15:19:38 +01002Writing early data
3------------------
Ronald Cronb372b2e2024-03-13 14:10:58 +01004
5An application function to write and send a buffer of data to a server through
6TLS may plausibly look like:
7
8```
Ronald Cron0fce9582024-03-13 14:22:19 +01009int 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)
Ronald Cronb372b2e2024-03-13 14:10:58 +010013{
Ronald Cron0fce9582024-03-13 14:22:19 +010014 int ret;
Ronald Cronb372b2e2024-03-13 14:10:58 +010015 *data_written = 0;
16
Ronald Cron0fce9582024-03-13 14:22:19 +010017 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);
Ronald Cronb372b2e2024-03-13 14:10:58 +010020
Ronald Cron0fce9582024-03-13 14:22:19 +010021 if (ret < 0 &&
Ronald Cronb372b2e2024-03-13 14:10:58 +010022 ret != MBEDTLS_ERR_SSL_WANT_READ &&
Ronald Cron0fce9582024-03-13 14:22:19 +010023 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
24 return ret;
Ronald Cronb372b2e2024-03-13 14:10:58 +010025 }
26
27 *data_written += ret;
28 }
29
Ronald Cron0fce9582024-03-13 14:22:19 +010030 return 0;
Ronald Cronb372b2e2024-03-13 14:10:58 +010031}
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
Ronald Cron0fce9582024-03-13 14:22:19 +010038mbedtls_ssl_write() may not be able to write and send all data in one go thus
Ronald Cronb372b2e2024-03-13 14:10:58 +010039the 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```
Ronald Cron0fce9582024-03-13 14:22:19 +010047int 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)
Ronald Cronb372b2e2024-03-13 14:10:58 +010051{
Ronald Cron0fce9582024-03-13 14:22:19 +010052 int ret;
Ronald Cronb372b2e2024-03-13 14:10:58 +010053 *data_written = 0;
54
Ronald Cron0fce9582024-03-13 14:22:19 +010055 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);
Ronald Cronb372b2e2024-03-13 14:10:58 +010058
Ronald Cron0fce9582024-03-13 14:22:19 +010059 if (ret < 0 &&
Ronald Cronb372b2e2024-03-13 14:10:58 +010060 ret != MBEDTLS_ERR_SSL_WANT_READ &&
Ronald Cron0fce9582024-03-13 14:22:19 +010061 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
62 return ret;
Ronald Cronb372b2e2024-03-13 14:10:58 +010063 }
64
65 *data_written += ret;
66 }
67
Ronald Cron0fce9582024-03-13 14:22:19 +010068 return 0;
Ronald Cronb372b2e2024-03-13 14:10:58 +010069}
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```
Ronald Cron0fce9582024-03-13 14:22:19 +010082ret = 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) {
Ronald Cronb372b2e2024-03-13 14:10:58 +010088 goto error;
89}
90
Ronald Cron0fce9582024-03-13 14:22:19 +010091ret = write_data(ssl,
92 data_to_write + early_data_written,
93 data_to_write_len - early_data_written,
94 &data_written);
95if (ret < 0) {
Ronald Cronb372b2e2024-03-13 14:10:58 +010096 goto error;
Ronald Cron0fce9582024-03-13 14:22:19 +010097}
Ronald Cronb372b2e2024-03-13 14:10:58 +010098
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```
Ronald Cron0fce9582024-03-13 14:22:19 +0100105ret = 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) {
Ronald Cronb372b2e2024-03-13 14:10:58 +0100111 goto error;
112}
113
114/*
Ronald Cron0fce9582024-03-13 14:22:19 +0100115 * Make sure the handshake is completed as it is a requisite of
Ronald Cronb372b2e2024-03-13 14:10:58 +0100116 * mbedtls_ssl_get_early_data_status().
117 */
Ronald Cron0fce9582024-03-13 14:22:19 +0100118while (!mbedtls_ssl_is_handshake_over(ssl)) {
119 ret = mbedtls_ssl_handshake(ssl);
120 if (ret < 0 &&
Ronald Cronb372b2e2024-03-13 14:10:58 +0100121 ret != MBEDTLS_ERR_SSL_WANT_READ &&
Ronald Cron0fce9582024-03-13 14:22:19 +0100122 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Ronald Cronb372b2e2024-03-13 14:10:58 +0100123 goto error;
124 }
125}
126
Ronald Cron0fce9582024-03-13 14:22:19 +0100127ret = mbedtls_ssl_get_early_data_status(ssl);
128if (ret < 0) {
Ronald Cronb372b2e2024-03-13 14:10:58 +0100129 goto error;
Ronald Cron0fce9582024-03-13 14:22:19 +0100130}
Ronald Cronb372b2e2024-03-13 14:10:58 +0100131
Ronald Cron0fce9582024-03-13 14:22:19 +0100132if (ret == MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED) {
Ronald Cronb372b2e2024-03-13 14:10:58 +0100133 early_data_written = 0;
Ronald Cron0fce9582024-03-13 14:22:19 +0100134}
Ronald Cronb372b2e2024-03-13 14:10:58 +0100135
Ronald Cron0fce9582024-03-13 14:22:19 +0100136ret = write_data(ssl,
137 data_to_write + early_data_written,
138 data_to_write_len - early_data_written,
139 &data_written);
140if (ret < 0) {
Ronald Cronb372b2e2024-03-13 14:10:58 +0100141 goto error;
Ronald Cron0fce9582024-03-13 14:22:19 +0100142}
Ronald Cronb372b2e2024-03-13 14:10:58 +0100143
144data_written += early_data_written;
145```
146
Ronald Crond514d9c2024-03-13 15:19:38 +0100147Reading 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:
Ronald Cronb372b2e2024-03-13 14:10:58 +0100160```
Ronald Crond514d9c2024-03-13 15:19:38 +0100161while ((int ret = mbedtls_ssl_handshake(&ssl)) != 0) {
Ronald Cronb372b2e2024-03-13 14:10:58 +0100162
Ronald Crond514d9c2024-03-13 15:19:38 +0100163 if (ret < 0 &&
164 ret != MBEDTLS_ERR_SSL_WANT_READ &&
165 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
166 break;
Ronald Cronb372b2e2024-03-13 14:10:58 +0100167 }
Ronald Cronb372b2e2024-03-13 14:10:58 +0100168}
169```
Ronald Crond514d9c2024-03-13 15:19:38 +0100170could 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```