LCOV - code coverage report
Current view: top level - tls - s2n_early_data_io.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 168 168 100.0 %
Date: 2026-07-04 07:27:58 Functions: 12 12 100.0 %
Branches: 158 216 73.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License").
       5                 :            :  * You may not use this file except in compliance with the License.
       6                 :            :  * A copy of the License is located at
       7                 :            :  *
       8                 :            :  *  http://aws.amazon.com/apache2.0
       9                 :            :  *
      10                 :            :  * or in the "license" file accompanying this file. This file is distributed
      11                 :            :  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
      12                 :            :  * express or implied. See the License for the specific language governing
      13                 :            :  * permissions and limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "tls/s2n_connection.h"
      17                 :            : #include "tls/s2n_early_data.h"
      18                 :            : #include "utils/s2n_mem.h"
      19                 :            : #include "utils/s2n_safety.h"
      20                 :            : 
      21                 :            : int s2n_end_of_early_data_send(struct s2n_connection *conn)
      22                 :         78 : {
      23         [ +  + ]:         78 :     if (conn->early_data_expected) {
      24         [ -  + ]:         40 :         POSIX_GUARD(s2n_stuffer_wipe(&conn->handshake.io));
      25         [ +  - ]:         40 :         POSIX_BAIL(S2N_ERR_EARLY_DATA_BLOCKED);
      26                 :         40 :     }
      27                 :            : 
      28         [ -  + ]:         38 :     POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_END_OF_EARLY_DATA));
      29                 :         38 :     return S2N_SUCCESS;
      30                 :         38 : }
      31                 :            : 
      32                 :            : int s2n_end_of_early_data_recv(struct s2n_connection *conn)
      33                 :         37 : {
      34 [ #  # ][ -  + ]:         37 :     POSIX_ENSURE(!s2n_connection_is_quic_enabled(conn), S2N_ERR_BAD_MESSAGE);
      35         [ -  + ]:         37 :     POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_END_OF_EARLY_DATA));
      36                 :         37 :     return S2N_SUCCESS;
      37                 :         37 : }
      38                 :            : 
      39                 :            : /**
      40                 :            :  *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.10
      41                 :            :  *# If the client attempts a 0-RTT handshake but the server
      42                 :            :  *# rejects it, the server will generally not have the 0-RTT record
      43                 :            :  *# protection keys and must instead use trial decryption (either with
      44                 :            :  *# the 1-RTT handshake keys or by looking for a cleartext ClientHello in
      45                 :            :  *# the case of a HelloRetryRequest) to find the first non-0-RTT message.
      46                 :            :  */
      47                 :            : bool s2n_early_data_is_trial_decryption_allowed(struct s2n_connection *conn, uint8_t record_type)
      48                 :     246518 : {
      49 [ +  - ][ +  + ]:     246518 :     return conn && (conn->early_data_state == S2N_EARLY_DATA_REJECTED)
      50         [ +  + ]:     246518 :             && record_type == TLS_APPLICATION_DATA
      51                 :            :             /* Only servers receive early data. */
      52         [ +  + ]:     246518 :             && (conn->mode == S2N_SERVER)
      53                 :            :             /* Early data is only expected during the handshake. */
      54         [ +  + ]:     246518 :             && (s2n_conn_get_current_message_type(conn) != APPLICATION_DATA);
      55                 :     246518 : }
      56                 :            : 
      57                 :            : static bool s2n_is_early_data_io(struct s2n_connection *conn)
      58                 :     651742 : {
      59         [ +  + ]:     651742 :     if (s2n_conn_get_current_message_type(conn) == APPLICATION_DATA) {
      60                 :     524207 :         return false;
      61                 :     524207 :     }
      62                 :            : 
      63                 :            :     /* It would be more accurate to not include this check.
      64                 :            :      * However, before the early data feature was added, s2n_send and s2n_recv
      65                 :            :      * did not verify that they were being called after a complete handshake.
      66                 :            :      * Enforcing that broke several S2N tests, and might have broken customers too.
      67                 :            :      *
      68                 :            :      * Therefore, only consider this early data if the customer has indicated that
      69                 :            :      * they are aware of early data, either because early data is currently expected
      70                 :            :      * or early data is in a state that indicates that early data was previously expected.
      71                 :            :      */
      72         [ +  + ]:     127535 :     if (conn->early_data_expected
      73 [ +  + ][ +  + ]:     127535 :             || (conn->mode == S2N_CLIENT && conn->early_data_state == S2N_EARLY_DATA_REQUESTED)
      74         [ +  + ]:     127535 :             || conn->early_data_state == S2N_EARLY_DATA_ACCEPTED
      75         [ +  + ]:     127535 :             || conn->early_data_state == S2N_END_OF_EARLY_DATA) {
      76                 :       1937 :         return true;
      77                 :       1937 :     }
      78                 :     125598 :     return false;
      79                 :     127535 : }
      80                 :            : 
      81                 :            : S2N_RESULT s2n_early_data_record_bytes(struct s2n_connection *conn, ssize_t data_len)
      82                 :     653816 : {
      83 [ +  + ][ +  - ]:     653816 :     RESULT_ENSURE_REF(conn);
      84 [ +  + ][ +  + ]:     653815 :     if (data_len < 0 || !s2n_is_early_data_io(conn)) {
      85                 :     653403 :         return S2N_RESULT_OK;
      86                 :     653403 :     }
      87                 :            : 
      88                 :            :     /* Ensure the bytes read are within the bounds of what we can actually record. */
      89         [ +  + ]:        412 :     if ((size_t) data_len > (UINT64_MAX - conn->early_data_bytes)) {
      90                 :          1 :         conn->early_data_bytes = UINT64_MAX;
      91         [ +  - ]:          1 :         RESULT_BAIL(S2N_ERR_INTEGER_OVERFLOW);
      92                 :          1 :     }
      93                 :            : 
      94                 :            :     /* Record the early data bytes read, even if they exceed the max_early_data_size.
      95                 :            :      * This will ensure that if this method is called again, it will fail again:
      96                 :            :      * Once we receive too many bytes, we can't proceed with the connection. */
      97                 :        411 :     conn->early_data_bytes += data_len;
      98                 :            : 
      99                 :        411 :     uint32_t max_early_data_size = 0;
     100         [ -  + ]:        411 :     RESULT_GUARD_POSIX(s2n_connection_get_max_early_data_size(conn, &max_early_data_size));
     101 [ +  + ][ +  - ]:        411 :     RESULT_ENSURE(conn->early_data_bytes <= max_early_data_size, S2N_ERR_MAX_EARLY_DATA_SIZE);
     102                 :            : 
     103                 :        405 :     return S2N_RESULT_OK;
     104                 :        411 : }
     105                 :            : 
     106                 :            : S2N_RESULT s2n_early_data_validate_send(struct s2n_connection *conn, uint32_t bytes_to_send)
     107                 :      23246 : {
     108 [ +  - ][ +  + ]:      23246 :     RESULT_ENSURE_REF(conn);
     109         [ +  + ]:      23245 :     if (!s2n_is_early_data_io(conn)) {
     110                 :      22614 :         return S2N_RESULT_OK;
     111                 :      22614 :     }
     112                 :            : 
     113 [ +  + ][ +  - ]:        631 :     RESULT_ENSURE(conn->early_data_expected, S2N_ERR_EARLY_DATA_NOT_ALLOWED);
     114 [ +  + ][ +  - ]:        627 :     RESULT_ENSURE(conn->mode == S2N_CLIENT, S2N_ERR_EARLY_DATA_NOT_ALLOWED);
     115 [ +  - ][ +  + ]:        626 :     RESULT_ENSURE(conn->early_data_state == S2N_EARLY_DATA_REQUESTED
                 [ +  + ]
     116                 :        623 :                     || conn->early_data_state == S2N_EARLY_DATA_ACCEPTED,
     117                 :        623 :             S2N_ERR_EARLY_DATA_NOT_ALLOWED);
     118                 :            : 
     119                 :        623 :     uint32_t allowed_early_data_size = 0;
     120         [ -  + ]:        623 :     RESULT_GUARD_POSIX(s2n_connection_get_remaining_early_data_size(conn, &allowed_early_data_size));
     121 [ +  - ][ +  + ]:        623 :     RESULT_ENSURE(bytes_to_send <= allowed_early_data_size, S2N_ERR_MAX_EARLY_DATA_SIZE);
     122                 :            : 
     123                 :        621 :     return S2N_RESULT_OK;
     124                 :        623 : }
     125                 :            : 
     126                 :            : S2N_RESULT s2n_early_data_validate_recv(struct s2n_connection *conn)
     127                 :     418443 : {
     128 [ +  + ][ +  - ]:     418443 :     RESULT_ENSURE_REF(conn);
     129         [ +  + ]:     418442 :     if (!s2n_is_early_data_io(conn)) {
     130                 :     418308 :         return S2N_RESULT_OK;
     131                 :     418308 :     }
     132                 :            : 
     133 [ -  + ][ #  # ]:        134 :     RESULT_ENSURE(conn->early_data_expected, S2N_ERR_EARLY_DATA_NOT_ALLOWED);
     134 [ +  - ][ +  + ]:        134 :     RESULT_ENSURE(conn->mode == S2N_SERVER, S2N_ERR_EARLY_DATA_NOT_ALLOWED);
     135 [ +  + ][ +  - ]:        133 :     RESULT_ENSURE(conn->early_data_state == S2N_EARLY_DATA_ACCEPTED, S2N_ERR_EARLY_DATA_NOT_ALLOWED);
     136 [ +  - ][ +  + ]:        128 :     RESULT_ENSURE(s2n_conn_get_current_message_type(conn) == END_OF_EARLY_DATA, S2N_ERR_EARLY_DATA_NOT_ALLOWED);
     137                 :        126 :     return S2N_RESULT_OK;
     138                 :        128 : }
     139                 :            : 
     140                 :            : static bool s2n_early_data_can_continue(struct s2n_connection *conn)
     141                 :       9701 : {
     142                 :       9701 :     uint32_t remaining_early_data_size = 0;
     143         [ +  - ]:       9701 :     return s2n_connection_get_remaining_early_data_size(conn, &remaining_early_data_size) >= S2N_SUCCESS
     144         [ +  + ]:       9701 :             && remaining_early_data_size > 0;
     145                 :       9701 : }
     146                 :            : 
     147                 :            : S2N_RESULT s2n_send_early_data_impl(struct s2n_connection *conn, const uint8_t *data, ssize_t data_len_signed,
     148                 :            :         ssize_t *data_sent, s2n_blocked_status *blocked)
     149                 :       1484 : {
     150 [ #  # ][ -  + ]:       1484 :     RESULT_ENSURE_GTE(data_len_signed, 0);
     151                 :       1484 :     size_t data_len = data_len_signed;
     152 [ -  + ][ #  # ]:       1484 :     RESULT_ENSURE_REF(conn);
     153 [ +  - ][ +  + ]:       1484 :     RESULT_ENSURE_REF(blocked);
     154                 :       1483 :     *blocked = S2N_NOT_BLOCKED;
     155 [ +  - ][ +  + ]:       1483 :     RESULT_ENSURE_REF(data_sent);
     156                 :       1482 :     *data_sent = 0;
     157                 :            : 
     158 [ +  + ][ +  - ]:       1482 :     RESULT_ENSURE(conn->mode == S2N_CLIENT, S2N_ERR_SERVER_MODE);
     159 [ -  + ][ #  # ]:       1481 :     RESULT_ENSURE(s2n_connection_supports_tls13(conn), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);
     160                 :            : 
     161         [ +  + ]:       1481 :     if (!s2n_early_data_can_continue(conn)) {
     162                 :         68 :         return S2N_RESULT_OK;
     163                 :         68 :     }
     164                 :            : 
     165                 :            :     /* Attempt to make progress in the handshake even if s2n_send eventually fails.
     166                 :            :      * We only care about the result of this call if it would prevent us from calling s2n_send. */
     167                 :       1413 :     int negotiate_result = s2n_negotiate(conn, blocked);
     168         [ +  + ]:       1413 :     if (negotiate_result < S2N_SUCCESS) {
     169         [ +  + ]:       1392 :         if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) {
     170         [ +  - ]:          1 :             RESULT_GUARD_POSIX(negotiate_result);
     171 [ +  + ][ +  + ]:       1391 :         } else if (*blocked != S2N_BLOCKED_ON_EARLY_DATA && *blocked != S2N_BLOCKED_ON_READ) {
     172         [ +  - ]:       1246 :             RESULT_GUARD_POSIX(negotiate_result);
     173                 :       1246 :         }
     174                 :       1392 :     }
     175                 :            :     /* Save the error status for later */
     176                 :        166 :     int negotiate_error = s2n_errno;
     177                 :        166 :     s2n_blocked_status negotiate_blocked = *blocked;
     178                 :            : 
     179                 :            :     /* Attempt to send the early data.
     180                 :            :      * We only care about the result of this call if it fails. */
     181                 :        166 :     uint32_t early_data_to_send = 0;
     182         [ -  + ]:        166 :     RESULT_GUARD_POSIX(s2n_connection_get_remaining_early_data_size(conn, &early_data_to_send));
     183         [ +  + ]:        166 :     early_data_to_send = S2N_MIN(data_len, early_data_to_send);
     184         [ +  + ]:        166 :     if (early_data_to_send) {
     185                 :         71 :         ssize_t send_result = s2n_send(conn, data, early_data_to_send, blocked);
     186         [ +  + ]:         71 :         RESULT_GUARD_POSIX(send_result);
     187                 :         61 :         *data_sent = send_result;
     188                 :         61 :     }
     189                 :        156 :     *blocked = S2N_NOT_BLOCKED;
     190                 :            : 
     191                 :            :     /* Since the send was successful, report the result of the original negotiate call.
     192                 :            :      * If we got this far, the result must have been success or a blocking error. */
     193         [ +  + ]:        156 :     if (negotiate_result < S2N_SUCCESS) {
     194 [ #  # ][ -  + ]:        135 :         RESULT_ENSURE_EQ(s2n_error_get_type(negotiate_error), S2N_ERR_T_BLOCKED);
     195         [ +  + ]:        135 :         if (negotiate_blocked == S2N_BLOCKED_ON_EARLY_DATA) {
     196                 :         30 :             return S2N_RESULT_OK;
     197         [ +  + ]:        105 :         } else if (s2n_early_data_can_continue(conn)) {
     198                 :         90 :             *blocked = negotiate_blocked;
     199         [ +  - ]:         90 :             RESULT_BAIL(negotiate_error);
     200                 :         90 :         } else {
     201                 :         15 :             return S2N_RESULT_OK;
     202                 :         15 :         }
     203                 :        135 :     }
     204                 :         21 :     return S2N_RESULT_OK;
     205                 :        156 : }
     206                 :            : 
     207                 :            : int s2n_send_early_data(struct s2n_connection *conn, const uint8_t *data, ssize_t data_len,
     208                 :            :         ssize_t *data_sent, s2n_blocked_status *blocked)
     209                 :       1485 : {
     210 [ +  + ][ +  - ]:       1485 :     POSIX_ENSURE_REF(conn);
     211                 :            : 
     212                 :            :     /* Calling this method indicates that we expect early data. */
     213         [ -  + ]:       1484 :     POSIX_GUARD(s2n_connection_set_early_data_expected(conn));
     214                 :            : 
     215                 :       1484 :     s2n_result result = s2n_send_early_data_impl(conn, data, data_len, data_sent, blocked);
     216                 :            : 
     217                 :            :     /* Unless s2n_send_early_data is called again (undoing this), we are done sending early data.
     218                 :            :      * If s2n_negotiate is called next, we could send the EndOfEarlyData message. */
     219         [ -  + ]:       1484 :     POSIX_GUARD(s2n_connection_set_end_of_early_data(conn));
     220                 :            : 
     221         [ +  + ]:       1484 :     POSIX_GUARD_RESULT(result);
     222                 :        134 :     return S2N_SUCCESS;
     223                 :       1484 : }
     224                 :            : 
     225                 :            : S2N_RESULT s2n_recv_early_data_impl(struct s2n_connection *conn, uint8_t *data, ssize_t max_data_len,
     226                 :            :         ssize_t *data_received, s2n_blocked_status *blocked)
     227                 :       4126 : {
     228 [ #  # ][ -  + ]:       4126 :     RESULT_ENSURE_REF(conn);
     229 [ +  + ][ +  - ]:       4126 :     RESULT_ENSURE_REF(blocked);
     230                 :       4125 :     *blocked = S2N_NOT_BLOCKED;
     231 [ +  - ][ +  + ]:       4125 :     RESULT_ENSURE_REF(data_received);
     232                 :       4124 :     *data_received = 0;
     233                 :            : 
     234 [ +  + ][ +  - ]:       4124 :     RESULT_ENSURE(conn->mode == S2N_SERVER, S2N_ERR_CLIENT_MODE);
     235                 :            : 
     236         [ +  + ]:       4123 :     if (!s2n_early_data_can_continue(conn)) {
     237                 :         79 :         return S2N_RESULT_OK;
     238                 :         79 :     }
     239                 :            : 
     240                 :       4044 :     int negotiate_result = S2N_SUCCESS;
     241         [ +  + ]:       4093 :     while ((negotiate_result = s2n_negotiate(conn, blocked)) != S2N_SUCCESS) {
     242         [ +  + ]:       4072 :         if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) {
     243         [ +  - ]:          1 :             RESULT_GUARD_POSIX(negotiate_result);
     244         [ +  + ]:       4071 :         } else if (max_data_len <= *data_received) {
     245         [ +  - ]:         29 :             RESULT_GUARD_POSIX(negotiate_result);
     246         [ +  + ]:       4042 :         } else if (*blocked != S2N_BLOCKED_ON_EARLY_DATA) {
     247         [ +  + ]:       3992 :             if (s2n_early_data_can_continue(conn)) {
     248         [ +  - ]:       3959 :                 RESULT_GUARD_POSIX(negotiate_result);
     249                 :       3959 :             } else {
     250                 :         33 :                 *blocked = S2N_NOT_BLOCKED;
     251                 :         33 :                 return S2N_RESULT_OK;
     252                 :         33 :             }
     253                 :       3992 :         }
     254                 :            : 
     255                 :         50 :         ssize_t recv_result = s2n_recv(conn, data + *data_received,
     256                 :         50 :                 max_data_len - *data_received, blocked);
     257         [ +  + ]:         50 :         RESULT_GUARD_POSIX(recv_result);
     258                 :         49 :         *data_received += recv_result;
     259                 :         49 :     }
     260                 :         21 :     return S2N_RESULT_OK;
     261                 :       4044 : }
     262                 :            : 
     263                 :            : int s2n_recv_early_data(struct s2n_connection *conn, uint8_t *data, ssize_t max_data_len,
     264                 :            :         ssize_t *data_received, s2n_blocked_status *blocked)
     265                 :       4127 : {
     266                 :            :     /* Calling this method indicates that we expect early data. */
     267         [ +  + ]:       4127 :     POSIX_GUARD(s2n_connection_set_early_data_expected(conn));
     268                 :            : 
     269                 :       4126 :     s2n_result result = s2n_recv_early_data_impl(conn, data, max_data_len, data_received, blocked);
     270                 :            : 
     271                 :            :     /* Unless s2n_recv_early_data is called again (undoing this), we are done accepting early data. */
     272         [ -  + ]:       4126 :     POSIX_GUARD(s2n_connection_set_end_of_early_data(conn));
     273                 :            : 
     274         [ +  + ]:       4126 :     POSIX_GUARD_RESULT(result);
     275                 :        133 :     return S2N_SUCCESS;
     276                 :       4126 : }

Generated by: LCOV version 1.14