LCOV - code coverage report
Current view: top level - tls/extensions - s2n_client_early_data_indication.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 67 67 100.0 %
Date: 2025-08-14 07:26:07 Functions: 6 6 100.0 %
Branches: 57 100 57.0 %

           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 "api/s2n.h"
      17                 :            : #include "tls/extensions/s2n_client_psk.h"
      18                 :            : #include "tls/extensions/s2n_early_data_indication.h"
      19                 :            : #include "tls/s2n_cipher_suites.h"
      20                 :            : #include "tls/s2n_early_data.h"
      21                 :            : #include "tls/s2n_protocol_preferences.h"
      22                 :            : #include "tls/s2n_tls13.h"
      23                 :            : #include "utils/s2n_safety.h"
      24                 :            : 
      25                 :            : /* S2N determines the handshake type after the ServerHello, but that will be
      26                 :            :  * too late to handle the early data + middlebox compatibility case:
      27                 :            :  *
      28                 :            :  *= https://www.rfc-editor.org/rfc/rfc8446#appendix-D.4
      29                 :            :  *# -  If not offering early data, the client sends a dummy
      30                 :            :  *#    change_cipher_spec record (see the third paragraph of Section 5)
      31                 :            :  *#    immediately before its second flight.  This may either be before
      32                 :            :  *#    its second ClientHello or before its encrypted handshake flight.
      33                 :            :  *#    If offering early data, the record is placed immediately after the
      34                 :            :  *#    first ClientHello.
      35                 :            :  *
      36                 :            :  * We need to set the handshake type flags in question during the ClientHello.
      37                 :            :  * This will require special [INITIAL | MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS]
      38                 :            :  * entries in the handshake arrays.
      39                 :            :  */
      40                 :            : static S2N_RESULT s2n_setup_middlebox_compat_for_early_data(struct s2n_connection *conn)
      41                 :       1082 : {
      42 [ #  # ][ -  + ]:       1082 :     RESULT_ENSURE_REF(conn);
      43                 :            : 
      44         [ +  + ]:       1082 :     if (s2n_is_middlebox_compat_enabled(conn)) {
      45         [ -  + ]:       1076 :         RESULT_GUARD(s2n_handshake_type_set_tls13_flag(conn, MIDDLEBOX_COMPAT));
      46         [ -  + ]:       1076 :         RESULT_GUARD(s2n_handshake_type_set_tls13_flag(conn, EARLY_CLIENT_CCS));
      47                 :       1076 :     }
      48                 :       1082 :     return S2N_RESULT_OK;
      49                 :       1082 : }
      50                 :            : 
      51                 :            : static S2N_RESULT s2n_early_data_config_is_possible(struct s2n_connection *conn)
      52                 :       7371 : {
      53 [ +  + ][ +  - ]:       7371 :     RESULT_ENSURE_REF(conn);
      54                 :            : 
      55                 :       7370 :     struct s2n_psk *first_psk = NULL;
      56         [ +  + ]:       7370 :     RESULT_GUARD(s2n_array_get(&conn->psk_params.psk_list, 0, (void **) &first_psk));
      57 [ -  + ][ #  # ]:       1107 :     RESULT_ENSURE_REF(first_psk);
      58                 :            : 
      59                 :       1107 :     struct s2n_early_data_config *early_data_config = &first_psk->early_data_config;
      60                 :            : 
      61                 :            :     /* Must support early data */
      62 [ +  - ][ +  + ]:       1107 :     RESULT_ENSURE_GT(early_data_config->max_early_data_size, 0);
      63                 :            : 
      64                 :            :     /* Early data must require a protocol than we could negotiate */
      65 [ +  - ][ +  + ]:       1019 :     RESULT_ENSURE_GTE(s2n_connection_get_protocol_version(conn), early_data_config->protocol_version);
      66 [ -  + ][ #  # ]:       1014 :     RESULT_ENSURE_GTE(s2n_connection_get_protocol_version(conn), S2N_TLS13);
      67                 :            : 
      68                 :       1014 :     const struct s2n_cipher_preferences *cipher_preferences = NULL;
      69         [ -  + ]:       1014 :     RESULT_GUARD_POSIX(s2n_connection_get_cipher_preferences(conn, &cipher_preferences));
      70 [ #  # ][ -  + ]:       1014 :     RESULT_ENSURE_REF(cipher_preferences);
      71                 :            : 
      72                 :            :     /* Early data must require a supported cipher */
      73                 :       1014 :     bool match = false;
      74         [ +  + ]:       2014 :     for (size_t i = 0; i < cipher_preferences->count; i++) {
      75         [ +  + ]:       2013 :         if (cipher_preferences->suites[i] == early_data_config->cipher_suite) {
      76                 :       1013 :             match = true;
      77                 :       1013 :             break;
      78                 :       1013 :         }
      79                 :       2013 :     }
      80 [ +  + ][ +  - ]:       1014 :     RESULT_ENSURE_EQ(match, true);
      81                 :            : 
      82                 :            :     /* If early data specifies an application protocol, it must be supported by protocol preferences */
      83         [ +  + ]:       1013 :     if (early_data_config->application_protocol.size > 0) {
      84                 :          4 :         struct s2n_blob *application_protocols = NULL;
      85         [ -  + ]:          4 :         RESULT_GUARD_POSIX(s2n_connection_get_protocol_preferences(conn, &application_protocols));
      86 [ -  + ][ #  # ]:          4 :         RESULT_ENSURE_REF(application_protocols);
      87                 :            : 
      88                 :          4 :         match = false;
      89         [ -  + ]:          4 :         RESULT_GUARD(s2n_protocol_preferences_contain(application_protocols, &early_data_config->application_protocol, &match));
      90 [ +  - ][ +  + ]:          4 :         RESULT_ENSURE_EQ(match, true);
      91                 :          4 :     }
      92                 :            : 
      93                 :       1010 :     return S2N_RESULT_OK;
      94                 :       1013 : }
      95                 :            : 
      96                 :            : static bool s2n_client_early_data_indication_should_send(struct s2n_connection *conn)
      97                 :       7371 : {
      98         [ +  + ]:       7371 :     return s2n_result_is_ok(s2n_early_data_config_is_possible(conn))
      99 [ +  - ][ +  + ]:       7371 :             && conn && conn->early_data_expected
     100                 :            :             /**
     101                 :            :              *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.10
     102                 :            :              *# A client MUST NOT include the
     103                 :            :              *# "early_data" extension in its followup ClientHello.
     104                 :            :              **/
     105         [ +  + ]:       7371 :             && !s2n_is_hello_retry_handshake(conn)
     106                 :            :             /**
     107                 :            :              *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.10
     108                 :            :              *# When a PSK is used and early data is allowed for that PSK, the client
     109                 :            :              *# can send Application Data in its first flight of messages.  If the
     110                 :            :              *# client opts to do so, it MUST supply both the "pre_shared_key" and
     111                 :            :              *# "early_data" extensions.
     112                 :            :              */
     113         [ +  - ]:       7371 :             && s2n_client_psk_extension.should_send(conn);
     114                 :       7371 : }
     115                 :            : 
     116                 :            : static int s2n_client_early_data_indication_is_missing(struct s2n_connection *conn)
     117                 :       6832 : {
     118         [ +  + ]:       6832 :     if (conn->early_data_state != S2N_EARLY_DATA_REJECTED) {
     119         [ -  + ]:       6376 :         POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_NOT_REQUESTED));
     120                 :       6376 :     }
     121                 :       6832 :     return S2N_SUCCESS;
     122                 :       6832 : }
     123                 :            : 
     124                 :            : /**
     125                 :            :  * The client version of this extension is empty, so we don't read/write any data.
     126                 :            :  *
     127                 :            :  *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.10
     128                 :            :  *# The "extension_data" field of this extension contains an
     129                 :            :  *# "EarlyDataIndication" value.
     130                 :            :  *#
     131                 :            :  *#     struct {} Empty;
     132                 :            :  *#
     133                 :            :  *#     struct {
     134                 :            :  *#         select (Handshake.msg_type) {
     135                 :            :  **
     136                 :            :  *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.10
     137                 :            :  *#             case client_hello:         Empty;
     138                 :            :  **
     139                 :            :  *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.10
     140                 :            :  *#         };
     141                 :            :  *#     } EarlyDataIndication;
     142                 :            :  **/
     143                 :            : 
     144                 :            : static int s2n_client_early_data_indication_send(struct s2n_connection *conn, struct s2n_stuffer *out)
     145                 :        541 : {
     146 [ #  # ][ -  + ]:        541 :     POSIX_ENSURE_REF(conn);
     147 [ -  + ][ #  # ]:        541 :     POSIX_ENSURE_REF(conn->secure);
     148                 :            : 
     149         [ -  + ]:        541 :     POSIX_GUARD_RESULT(s2n_setup_middlebox_compat_for_early_data(conn));
     150         [ -  + ]:        541 :     POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_REQUESTED));
     151                 :            : 
     152                 :            :     /* Set the cipher suite for early data */
     153                 :        541 :     struct s2n_psk *first_psk = NULL;
     154         [ -  + ]:        541 :     POSIX_GUARD_RESULT(s2n_array_get(&conn->psk_params.psk_list, 0, (void **) &first_psk));
     155 [ -  + ][ #  # ]:        541 :     POSIX_ENSURE_REF(first_psk);
     156                 :        541 :     conn->secure->cipher_suite = first_psk->early_data_config.cipher_suite;
     157                 :            : 
     158                 :        541 :     return S2N_SUCCESS;
     159                 :        541 : }
     160                 :            : 
     161                 :            : static int s2n_client_early_data_indiction_recv(struct s2n_connection *conn, struct s2n_stuffer *in)
     162                 :        542 : {
     163                 :            :     /**
     164                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.10
     165                 :            :      *# A client MUST NOT include the
     166                 :            :      *# "early_data" extension in its followup ClientHello.
     167                 :            :      */
     168 [ +  + ][ +  - ]:        542 :     POSIX_ENSURE(conn->handshake.message_number == 0, S2N_ERR_UNSUPPORTED_EXTENSION);
     169                 :            : 
     170                 :            :     /* Although technically we could NOT set the [MIDDLEBOX_COMPAT | EARLY_CLIENT_CCS] handshake type
     171                 :            :      * for the server because the server ignores the Client CCS message state, doing so would mean that
     172                 :            :      * the client and server state machines would be out of sync and potentially cause confusion.
     173                 :            :      */
     174         [ -  + ]:        541 :     POSIX_GUARD_RESULT(s2n_setup_middlebox_compat_for_early_data(conn));
     175                 :            : 
     176         [ -  + ]:        541 :     POSIX_GUARD_RESULT(s2n_connection_set_early_data_state(conn, S2N_EARLY_DATA_REQUESTED));
     177                 :        541 :     return S2N_SUCCESS;
     178                 :        541 : }
     179                 :            : 
     180                 :            : const s2n_extension_type s2n_client_early_data_indication_extension = {
     181                 :            :     .iana_value = TLS_EXTENSION_EARLY_DATA,
     182                 :            :     .is_response = false,
     183                 :            :     .send = s2n_client_early_data_indication_send,
     184                 :            :     .recv = s2n_client_early_data_indiction_recv,
     185                 :            :     .should_send = s2n_client_early_data_indication_should_send,
     186                 :            :     .if_missing = s2n_client_early_data_indication_is_missing,
     187                 :            : };

Generated by: LCOV version 1.14