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: 2025-08-15 07:28:39 Functions: 12 12 100.0 %
Branches: 156 214 72.9 %

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

Generated by: LCOV version 1.14