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