mirror of
				https://github.com/Mbed-TLS/mbedtls.git
				synced 2025-10-30 10:45:34 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			193 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
 | |
| Writing early data
 | |
| ------------------
 | |
| 
 | |
| An application function to write and send a buffer of data to a server through
 | |
| TLS may plausibly look like:
 | |
| 
 | |
| ```
 | |
| int write_data(mbedtls_ssl_context *ssl,
 | |
|                const unsigned char *data_to_write,
 | |
|                size_t data_to_write_len,
 | |
|                size_t *data_written)
 | |
| {
 | |
|     int ret;
 | |
|     *data_written = 0;
 | |
| 
 | |
|     while (*data_written < data_to_write_len) {
 | |
|         ret = mbedtls_ssl_write(ssl, data_to_write + *data_written,
 | |
|                                 data_to_write_len - *data_written);
 | |
| 
 | |
|         if (ret < 0 &&
 | |
|             ret != MBEDTLS_ERR_SSL_WANT_READ &&
 | |
|             ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
 | |
|             return ret;
 | |
|         }
 | |
| 
 | |
|         *data_written += ret;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| ```
 | |
| where ssl is the SSL context to use, data_to_write the address of the data
 | |
| buffer and data_to_write_len the number of data bytes. The handshake may
 | |
| not be completed, not even started for the SSL context ssl when the function is
 | |
| called and in that case the mbedtls_ssl_write() API takes care transparently of
 | |
| completing the handshake before to write and send data to the server. The
 | |
| mbedtls_ssl_write() may not be able to write and send all data in one go thus
 | |
| the need for a loop calling it as long as there are still data to write and
 | |
| send.
 | |
| 
 | |
| An application function to write and send early data and only early data,
 | |
| data sent during the first flight of client messages while the handshake is in
 | |
| its initial phase, would look completely similar but the call to
 | |
| mbedtls_ssl_write_early_data() instead of mbedtls_ssl_write().
 | |
| ```
 | |
| int write_early_data(mbedtls_ssl_context *ssl,
 | |
|                      const unsigned char *data_to_write,
 | |
|                      size_t data_to_write_len,
 | |
|                      size_t *data_written)
 | |
| {
 | |
|     int ret;
 | |
|     *data_written = 0;
 | |
| 
 | |
|     while (*data_written < data_to_write_len) {
 | |
|         ret = mbedtls_ssl_write_early_data(ssl, data_to_write + *data_written,
 | |
|                                            data_to_write_len - *data_written);
 | |
| 
 | |
|         if (ret < 0 &&
 | |
|             ret != MBEDTLS_ERR_SSL_WANT_READ &&
 | |
|             ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
 | |
|             return ret;
 | |
|         }
 | |
| 
 | |
|         *data_written += ret;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| ```
 | |
| Note that compared to write_data(), write_early_data() can also return
 | |
| MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA and that should be handled
 | |
| specifically by the user of write_early_data(). A fresh SSL context (typically
 | |
| just after a call to mbedtls_ssl_setup() or mbedtls_ssl_session_reset()) would
 | |
| be expected when calling `write_early_data`.
 | |
| 
 | |
| All together, code to write and send a buffer of data as long as possible as
 | |
| early data and then as standard post-handshake application data could
 | |
| plausibly look like:
 | |
| 
 | |
| ```
 | |
| ret = write_early_data(ssl,
 | |
|                        data_to_write,
 | |
|                        data_to_write_len,
 | |
|                        &early_data_written);
 | |
| if (ret < 0 &&
 | |
|     ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) {
 | |
|     goto error;
 | |
| }
 | |
| 
 | |
| ret = write_data(ssl,
 | |
|                  data_to_write + early_data_written,
 | |
|                  data_to_write_len - early_data_written,
 | |
|                  &data_written);
 | |
| if (ret < 0) {
 | |
|     goto error;
 | |
| }
 | |
| 
 | |
| data_written += early_data_written;
 | |
| ```
 | |
| 
 | |
| Finally, taking into account that the server may reject early data, application
 | |
| code to write and send a buffer of data could plausibly look like:
 | |
| ```
 | |
| ret = write_early_data(ssl,
 | |
|                        data_to_write,
 | |
|                        data_to_write_len,
 | |
|                        &early_data_written);
 | |
| if (ret < 0 &&
 | |
|     ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) {
 | |
|     goto error;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Make sure the handshake is completed as it is a requisite of
 | |
|  * mbedtls_ssl_get_early_data_status().
 | |
|  */
 | |
| while (!mbedtls_ssl_is_handshake_over(ssl)) {
 | |
|     ret = mbedtls_ssl_handshake(ssl);
 | |
|     if (ret < 0 &&
 | |
|         ret != MBEDTLS_ERR_SSL_WANT_READ &&
 | |
|         ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
 | |
|         goto error;
 | |
|     }
 | |
| }
 | |
| 
 | |
| ret = mbedtls_ssl_get_early_data_status(ssl);
 | |
| if (ret < 0) {
 | |
|     goto error;
 | |
| }
 | |
| 
 | |
| if (ret == MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED) {
 | |
|    early_data_written = 0;
 | |
| }
 | |
| 
 | |
| ret = write_data(ssl,
 | |
|                  data_to_write + early_data_written,
 | |
|                  data_to_write_len - early_data_written,
 | |
|                  &data_written);
 | |
| if (ret < 0) {
 | |
|     goto error;
 | |
| }
 | |
| 
 | |
| data_written += early_data_written;
 | |
| ```
 | |
| 
 | |
| Reading early data
 | |
| ------------------
 | |
| Mbed TLS provides the mbedtls_ssl_read_early_data() API to read the early data
 | |
| that a TLS 1.3 server might receive during the TLS 1.3 handshake.
 | |
| 
 | |
| While establishing a TLS 1.3 connection with a client using a combination
 | |
| of the mbedtls_ssl_handshake(), mbedtls_ssl_read() and mbedtls_ssl_write() APIs,
 | |
| the reception of early data is signaled by an API returning the
 | |
| MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA error code. Early data can then be read
 | |
| with the mbedtls_ssl_read_early_data() API.
 | |
| 
 | |
| For example, a typical code to establish a TLS connection, where ssl is the SSL
 | |
| context to use:
 | |
| ```
 | |
| while ((int ret = mbedtls_ssl_handshake(&ssl)) != 0) {
 | |
| 
 | |
|     if (ret < 0 &&
 | |
|         ret != MBEDTLS_ERR_SSL_WANT_READ &&
 | |
|         ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
 | |
|         break;
 | |
|     }
 | |
| }
 | |
| ```
 | |
| could be adapted to handle early data in the following way:
 | |
| ```
 | |
| size_t data_read_len = 0;
 | |
| while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
 | |
| 
 | |
|     if (ret == MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA) {
 | |
|         ret = mbedtls_ssl_read_early_data(&ssl,
 | |
|                                           buffer + data_read_len,
 | |
|                                           sizeof(buffer) - data_read_len);
 | |
|         if (ret < 0) {
 | |
|             break;
 | |
|         }
 | |
|         data_read_len += ret;
 | |
|         continue;
 | |
|     }
 | |
| 
 | |
|     if (ret < 0 &&
 | |
|         ret != MBEDTLS_ERR_SSL_WANT_READ &&
 | |
|         ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
 | |
|         break;
 | |
|     }
 | |
| }
 | |
| ```
 |