tls13-early-data.md (5804B)
1 2 Writing early data 3 ------------------ 4 5 An application function to write and send a buffer of data to a server through 6 TLS may plausibly look like: 7 8 ``` 9 int 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 ``` 33 where ssl is the SSL context to use, data_to_write the address of the data 34 buffer and data_to_write_len the number of data bytes. The handshake may 35 not be completed, not even started for the SSL context ssl when the function is 36 called and in that case the mbedtls_ssl_write() API takes care transparently of 37 completing the handshake before to write and send data to the server. The 38 mbedtls_ssl_write() may not be able to write and send all data in one go thus 39 the need for a loop calling it as long as there are still data to write and 40 send. 41 42 An application function to write and send early data and only early data, 43 data sent during the first flight of client messages while the handshake is in 44 its initial phase, would look completely similar but the call to 45 mbedtls_ssl_write_early_data() instead of mbedtls_ssl_write(). 46 ``` 47 int 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 ``` 71 Note that compared to write_data(), write_early_data() can also return 72 MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA and that should be handled 73 specifically by the user of write_early_data(). A fresh SSL context (typically 74 just after a call to mbedtls_ssl_setup() or mbedtls_ssl_session_reset()) would 75 be expected when calling `write_early_data`. 76 77 All together, code to write and send a buffer of data as long as possible as 78 early data and then as standard post-handshake application data could 79 plausibly look like: 80 81 ``` 82 ret = write_early_data(ssl, 83 data_to_write, 84 data_to_write_len, 85 &early_data_written); 86 if (ret < 0 && 87 ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) { 88 goto error; 89 } 90 91 ret = write_data(ssl, 92 data_to_write + early_data_written, 93 data_to_write_len - early_data_written, 94 &data_written); 95 if (ret < 0) { 96 goto error; 97 } 98 99 data_written += early_data_written; 100 ``` 101 102 Finally, taking into account that the server may reject early data, application 103 code to write and send a buffer of data could plausibly look like: 104 ``` 105 ret = write_early_data(ssl, 106 data_to_write, 107 data_to_write_len, 108 &early_data_written); 109 if (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 */ 118 while (!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 127 ret = mbedtls_ssl_get_early_data_status(ssl); 128 if (ret < 0) { 129 goto error; 130 } 131 132 if (ret == MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED) { 133 early_data_written = 0; 134 } 135 136 ret = write_data(ssl, 137 data_to_write + early_data_written, 138 data_to_write_len - early_data_written, 139 &data_written); 140 if (ret < 0) { 141 goto error; 142 } 143 144 data_written += early_data_written; 145 ``` 146 147 Reading early data 148 ------------------ 149 Mbed TLS provides the mbedtls_ssl_read_early_data() API to read the early data 150 that a TLS 1.3 server might receive during the TLS 1.3 handshake. 151 152 While establishing a TLS 1.3 connection with a client using a combination 153 of the mbedtls_ssl_handshake(), mbedtls_ssl_read() and mbedtls_ssl_write() APIs, 154 the reception of early data is signaled by an API returning the 155 MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA error code. Early data can then be read 156 with the mbedtls_ssl_read_early_data() API. 157 158 For example, a typical code to establish a TLS connection, where ssl is the SSL 159 context to use: 160 ``` 161 while ((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 ``` 170 could be adapted to handle early data in the following way: 171 ``` 172 size_t data_read_len = 0; 173 while ((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 ```