blob: be0574355602d42cc5e2587532c31783e43f31e4 [file] [log] [blame] [view]
Ronald Cronb372b2e2024-03-13 14:10:58 +01001
2Writing and reading early or 0-RTT 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 *data_written = 0;
15
16 while( *data_written < data_to_write_len )
17 {
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 {
25 return( ret );
26 }
27
28 *data_written += ret;
29 }
30
31 return( 0 );
32}
33```
34where ssl is the SSL context to use, data_to_write the address of the data
35buffer and data_to_write_len the number of data bytes. The handshake may
36not be completed, not even started for the SSL context ssl when the function is
37called and in that case the mbedtls_ssl_write() API takes care transparently of
38completing the handshake before to write and send data to the server. The
39mbedtls_ssl_write() may not been able to write and send all data in one go thus
40the need for a loop calling it as long as there are still data to write and
41send.
42
43An application function to write and send early data and only early data,
44data sent during the first flight of client messages while the handshake is in
45its initial phase, would look completely similar but the call to
46mbedtls_ssl_write_early_data() instead of mbedtls_ssl_write().
47```
48int write_early_data( mbedtls_ssl_context *ssl,
49 const unsigned char *data_to_write,
50 size_t data_to_write_len,
51 size_t *data_written )
52{
53 *data_written = 0;
54
55 while( *data_written < data_to_write_len )
56 {
57 ret = mbedtls_ssl_write_early_data( ssl, data_to_write + *data_written,
58 data_to_write_len - *data_written );
59
60 if( ret < 0 &&
61 ret != MBEDTLS_ERR_SSL_WANT_READ &&
62 ret != MBEDTLS_ERR_SSL_WANT_WRITE )
63 {
64 return( ret );
65 }
66
67 *data_written += ret;
68 }
69
70 return( 0 );
71}
72```
73Note that compared to write_data(), write_early_data() can also return
74MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA and that should be handled
75specifically by the user of write_early_data(). A fresh SSL context (typically
76just after a call to mbedtls_ssl_setup() or mbedtls_ssl_session_reset()) would
77be expected when calling `write_early_data`.
78
79All together, code to write and send a buffer of data as long as possible as
80early data and then as standard post-handshake application data could
81plausibly look like:
82
83```
84ret = write_early_data( ssl, data_to_write, data_to_write_len,
85 &early_data_written );
86if( ret < 0 &&
87 ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA )
88{
89 goto error;
90}
91
92ret = write_data( ssl, data_to_write + early_data_written,
93 data_to_write_len - early_data_written, &data_written );
94if( ret < 0 )
95 goto error;
96
97data_written += early_data_written;
98```
99
100Finally, taking into account that the server may reject early data, application
101code to write and send a buffer of data could plausibly look like:
102```
103ret = write_early_data( ssl, data_to_write, data_to_write_len,
104 &early_data_written );
105if( ret < 0 &&
106 ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA )
107{
108 goto error;
109}
110
111/*
112 * Make sure the handshake is completed as it is a requisite to
113 * mbedtls_ssl_get_early_data_status().
114 */
115while( !mbedtls_ssl_is_handshake_over( ssl ) )
116{
117 ret = mbedtls_ssl_handshake( ssl );
118 if( ret < 0 &&
119 ret != MBEDTLS_ERR_SSL_WANT_READ &&
120 ret != MBEDTLS_ERR_SSL_WANT_WRITE )
121 {
122 goto error;
123 }
124}
125
126ret = mbedtls_ssl_get_early_data_status( ssl );
127if( ret < 0 )
128 goto error;
129
130if( ret == MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED )
131 early_data_written = 0;
132
133ret = write_data( ssl, data_to_write + early_data_written,
134 data_to_write_len - early_data_written, &data_written );
135if( ret < 0 )
136 goto error;
137
138data_written += early_data_written;
139```
140
141Basically, the same holds for reading early data on the server side without the
142complication of possible rejection. An application function to read early data
143into a given buffer could plausibly look like:
144```
145int read_early_data( mbedtls_ssl_context *ssl,
146 unsigned char *buffer,
147 size_t buffer_size,
148 size_t *data_len )
149{
150 *data_len = 0;
151
152 while( *data_len < buffer_size )
153 {
154 ret = mbedtls_ssl_read_early_data( ssl, buffer + *data_len,
155 buffer_size - *data_len );
156
157 if( ret < 0 &&
158 ret != MBEDTLS_ERR_SSL_WANT_READ &&
159 ret != MBEDTLS_ERR_SSL_WANT_WRITE )
160 {
161 return( ret );
162 }
163
164 *data_len += ret;
165 }
166
167 return( 0 );
168}
169```
170with again calls to read_early_data() expected to be done with a fresh SSL
171context.