quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

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 ```