From b372b2e5bb2949a9e96f7f152a69f9db63862894 Mon Sep 17 00:00:00 2001 From: Ronald Cron Date: Wed, 13 Mar 2024 14:10:58 +0100 Subject: [PATCH] docs: Move TLS 1.3 early data doc to a dedicated file Signed-off-by: Ronald Cron --- docs/architecture/tls13-support.md | 172 ----------------------------- docs/tls13-early-data.md | 171 ++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 172 deletions(-) create mode 100644 docs/tls13-early-data.md diff --git a/docs/architecture/tls13-support.md b/docs/architecture/tls13-support.md index 95a0ba79a4..2ac3950295 100644 --- a/docs/architecture/tls13-support.md +++ b/docs/architecture/tls13-support.md @@ -433,175 +433,3 @@ outbound message on server side as well. * state change: the state change is done in the main state handler to ease the navigation of the state machine transitions. - - -Writing and reading early or 0-RTT 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 ) -{ - *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 been 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 ) -{ - *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 to - * 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; -``` - -Basically, the same holds for reading early data on the server side without the -complication of possible rejection. An application function to read early data -into a given buffer could plausibly look like: -``` -int read_early_data( mbedtls_ssl_context *ssl, - unsigned char *buffer, - size_t buffer_size, - size_t *data_len ) -{ - *data_len = 0; - - while( *data_len < buffer_size ) - { - ret = mbedtls_ssl_read_early_data( ssl, buffer + *data_len, - buffer_size - *data_len ); - - if( ret < 0 && - ret != MBEDTLS_ERR_SSL_WANT_READ && - ret != MBEDTLS_ERR_SSL_WANT_WRITE ) - { - return( ret ); - } - - *data_len += ret; - } - - return( 0 ); -} -``` -with again calls to read_early_data() expected to be done with a fresh SSL -context. diff --git a/docs/tls13-early-data.md b/docs/tls13-early-data.md new file mode 100644 index 0000000000..be05743556 --- /dev/null +++ b/docs/tls13-early-data.md @@ -0,0 +1,171 @@ + +Writing and reading early or 0-RTT 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 ) +{ + *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 been 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 ) +{ + *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 to + * 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; +``` + +Basically, the same holds for reading early data on the server side without the +complication of possible rejection. An application function to read early data +into a given buffer could plausibly look like: +``` +int read_early_data( mbedtls_ssl_context *ssl, + unsigned char *buffer, + size_t buffer_size, + size_t *data_len ) +{ + *data_len = 0; + + while( *data_len < buffer_size ) + { + ret = mbedtls_ssl_read_early_data( ssl, buffer + *data_len, + buffer_size - *data_len ); + + if( ret < 0 && + ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + return( ret ); + } + + *data_len += ret; + } + + return( 0 ); +} +``` +with again calls to read_early_data() expected to be done with a fresh SSL +context.