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 : : };