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/extensions/s2n_client_supported_groups.h" 17 : : 18 : : #include <stdint.h> 19 : : #include <sys/param.h> 20 : : 21 : : #include "crypto/s2n_pq.h" 22 : : #include "tls/extensions/s2n_ec_point_format.h" 23 : : #include "tls/s2n_security_policies.h" 24 : : #include "tls/s2n_tls.h" 25 : : #include "tls/s2n_tls13.h" 26 : : #include "tls/s2n_tls_parameters.h" 27 : : #include "utils/s2n_safety.h" 28 : : 29 : : static int s2n_client_supported_groups_send(struct s2n_connection *conn, struct s2n_stuffer *out); 30 : : static int s2n_client_supported_groups_recv(struct s2n_connection *conn, struct s2n_stuffer *extension); 31 : : 32 : : const s2n_extension_type s2n_client_supported_groups_extension = { 33 : : .iana_value = TLS_EXTENSION_SUPPORTED_GROUPS, 34 : : .is_response = false, 35 : : .send = s2n_client_supported_groups_send, 36 : : .recv = s2n_client_supported_groups_recv, 37 : : .should_send = s2n_extension_should_send_if_ecc_enabled, 38 : : .if_missing = s2n_extension_noop_if_missing, 39 : : }; 40 : : 41 : : bool s2n_extension_should_send_if_ecc_enabled(struct s2n_connection *conn) 42 : 14705 : { 43 : 14705 : const struct s2n_security_policy *security_policy = NULL; 44 [ + - ]: 14705 : return s2n_connection_get_security_policy(conn, &security_policy) == S2N_SUCCESS 45 [ + + ]: 14705 : && s2n_ecc_is_extension_required(security_policy); 46 : 14705 : } 47 : : 48 : : static int s2n_client_supported_groups_send(struct s2n_connection *conn, struct s2n_stuffer *out) 49 : 6259 : { 50 [ - + ][ # # ]: 6259 : POSIX_ENSURE_REF(conn); 51 : : 52 : 6259 : const struct s2n_ecc_preferences *ecc_pref = NULL; 53 [ - + ]: 6259 : POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); 54 [ # # ][ - + ]: 6259 : POSIX_ENSURE_REF(ecc_pref); 55 : : 56 : 6259 : const struct s2n_kem_preferences *kem_pref = NULL; 57 [ - + ]: 6259 : POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); 58 [ # # ][ - + ]: 6259 : POSIX_ENSURE_REF(kem_pref); 59 : : 60 : : /* Group list len */ 61 : 6259 : struct s2n_stuffer_reservation group_list_len = { 0 }; 62 [ - + ]: 6259 : POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &group_list_len)); 63 : : 64 : : /* Send KEM groups list first */ 65 [ + + ][ - + ]: 6259 : if (s2n_connection_get_protocol_version(conn) >= S2N_TLS13 && s2n_pq_is_enabled()) { 66 [ # # ]: 0 : for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { 67 [ # # ]: 0 : if (!s2n_kem_group_is_available(kem_pref->tls13_kem_groups[i])) { 68 : 0 : continue; 69 : 0 : } 70 [ # # ]: 0 : POSIX_GUARD(s2n_stuffer_write_uint16(out, kem_pref->tls13_kem_groups[i]->iana_id)); 71 : 0 : } 72 : 0 : } 73 : : 74 : : /* Then send curve list */ 75 [ + + ]: 31836 : for (size_t i = 0; i < ecc_pref->count; i++) { 76 [ - + ]: 25577 : POSIX_GUARD(s2n_stuffer_write_uint16(out, ecc_pref->ecc_curves[i]->iana_id)); 77 : 25577 : } 78 : : 79 [ - + ]: 6259 : POSIX_GUARD(s2n_stuffer_write_vector_size(&group_list_len)); 80 : : 81 : 6259 : return S2N_SUCCESS; 82 : 6259 : } 83 : : 84 : : S2N_RESULT s2n_supported_groups_parse_count(struct s2n_stuffer *extension, uint16_t *count) 85 : 6297 : { 86 [ # # ][ - + ]: 6297 : RESULT_ENSURE_REF(count); 87 : 6297 : *count = 0; 88 [ # # ][ - + ]: 6297 : RESULT_ENSURE_REF(extension); 89 : : 90 : 6297 : uint16_t supported_groups_list_size = 0; 91 [ - + ]: 6297 : RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(extension, &supported_groups_list_size)); 92 : : 93 [ + + ][ + - ]: 6297 : RESULT_ENSURE(supported_groups_list_size <= s2n_stuffer_data_available(extension), 94 : 6295 : S2N_ERR_INVALID_PARSED_EXTENSIONS); 95 [ + + ][ + - ]: 6295 : RESULT_ENSURE(supported_groups_list_size % S2N_SUPPORTED_GROUP_SIZE == 0, 96 : 6294 : S2N_ERR_INVALID_PARSED_EXTENSIONS); 97 : : 98 : 6294 : *count = supported_groups_list_size / S2N_SUPPORTED_GROUP_SIZE; 99 : : 100 : 6294 : return S2N_RESULT_OK; 101 : 6295 : } 102 : : 103 : : /* Populates the appropriate index of either the mutually_supported_curves or 104 : : * mutually_supported_kem_groups array based on the received IANA ID. Will 105 : : * ignore unrecognized IANA IDs (and return success). */ 106 : : static int s2n_client_supported_groups_recv_iana_id(struct s2n_connection *conn, uint16_t iana_id) 107 : 25254 : { 108 [ - + ][ # # ]: 25254 : POSIX_ENSURE_REF(conn); 109 : : 110 : 25254 : const struct s2n_ecc_preferences *ecc_pref = NULL; 111 [ - + ]: 25254 : POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); 112 [ # # ][ - + ]: 25254 : POSIX_ENSURE_REF(ecc_pref); 113 : : 114 [ + + ]: 65718 : for (size_t i = 0; i < ecc_pref->count; i++) { 115 : 64200 : const struct s2n_ecc_named_curve *supported_curve = ecc_pref->ecc_curves[i]; 116 [ + + ]: 64200 : if (iana_id == supported_curve->iana_id) { 117 : 23736 : conn->kex_params.mutually_supported_curves[i] = supported_curve; 118 : 23736 : return S2N_SUCCESS; 119 : 23736 : } 120 : 64200 : } 121 : : 122 : : /* Return early if PQ is disabled, or if TLS version is less than 1.3, so as to ignore PQ IDs */ 123 [ + - ][ # # ]: 1518 : if (!s2n_pq_is_enabled() || s2n_connection_get_protocol_version(conn) < S2N_TLS13) { 124 : 1518 : return S2N_SUCCESS; 125 : 1518 : } 126 : : 127 : 0 : const struct s2n_kem_preferences *kem_pref = NULL; 128 [ # # ]: 0 : POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); 129 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(kem_pref); 130 : : 131 [ # # ]: 0 : for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { 132 : 0 : const struct s2n_kem_group *supported_kem_group = kem_pref->tls13_kem_groups[i]; 133 [ # # ][ # # ]: 0 : if (s2n_kem_group_is_available(supported_kem_group) && iana_id == supported_kem_group->iana_id) { 134 : 0 : conn->kex_params.mutually_supported_kem_groups[i] = supported_kem_group; 135 : 0 : return S2N_SUCCESS; 136 : 0 : } 137 : 0 : } 138 : : 139 : 0 : return S2N_SUCCESS; 140 : 0 : } 141 : : 142 : : static int s2n_choose_supported_group(struct s2n_connection *conn) 143 : 6135 : { 144 [ # # ][ - + ]: 6135 : POSIX_ENSURE_REF(conn); 145 : : 146 : 6135 : const struct s2n_ecc_preferences *ecc_pref = NULL; 147 [ - + ]: 6135 : POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref)); 148 [ # # ][ - + ]: 6135 : POSIX_ENSURE_REF(ecc_pref); 149 : : 150 : 6135 : const struct s2n_kem_preferences *kem_pref = NULL; 151 [ - + ]: 6135 : POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref)); 152 [ - + ][ # # ]: 6135 : POSIX_ENSURE_REF(kem_pref); 153 : : 154 : : /* Ensure that only the intended group will be non-NULL (if no group is chosen, everything 155 : : * should be NULL). */ 156 : 6135 : conn->kex_params.server_kem_group_params.kem_group = NULL; 157 : 6135 : conn->kex_params.server_kem_group_params.ecc_params.negotiated_curve = NULL; 158 : 6135 : conn->kex_params.server_kem_group_params.kem_params.kem = NULL; 159 : 6135 : conn->kex_params.server_ecc_evp_params.negotiated_curve = NULL; 160 : : 161 : : /* Prefer to negotiate hybrid PQ over ECC. If PQ is disabled, we will never choose a 162 : : * PQ group because the mutually_supported_kem_groups array will not have been 163 : : * populated with anything. */ 164 [ + + ]: 11593 : for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) { 165 : 5458 : const struct s2n_kem_group *candidate_kem_group = conn->kex_params.mutually_supported_kem_groups[i]; 166 [ - + ][ # # ]: 5458 : if (candidate_kem_group != NULL && s2n_kem_group_is_available(candidate_kem_group)) { 167 : 0 : conn->kex_params.server_kem_group_params.kem_group = candidate_kem_group; 168 : 0 : conn->kex_params.server_kem_group_params.ecc_params.negotiated_curve = candidate_kem_group->curve; 169 : 0 : conn->kex_params.server_kem_group_params.kem_params.kem = candidate_kem_group->kem; 170 : 0 : return S2N_SUCCESS; 171 : 0 : } 172 : 5458 : } 173 : : 174 [ + + ]: 6191 : for (size_t i = 0; i < ecc_pref->count; i++) { 175 : 6188 : const struct s2n_ecc_named_curve *candidate_curve = conn->kex_params.mutually_supported_curves[i]; 176 [ + + ]: 6188 : if (candidate_curve != NULL) { 177 : 6132 : conn->kex_params.server_ecc_evp_params.negotiated_curve = candidate_curve; 178 : 6132 : return S2N_SUCCESS; 179 : 6132 : } 180 : 6188 : } 181 : : 182 : 3 : return S2N_SUCCESS; 183 : 6135 : } 184 : : 185 : : static int s2n_client_supported_groups_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) 186 : 6136 : { 187 [ - + ][ # # ]: 6136 : POSIX_ENSURE_REF(conn); 188 [ - + ][ # # ]: 6136 : POSIX_ENSURE_REF(extension); 189 : : 190 : 6136 : uint16_t supported_groups_count = 0; 191 [ + + ]: 6136 : if (s2n_result_is_error(s2n_supported_groups_parse_count(extension, &supported_groups_count))) { 192 : : /* Malformed length, ignore the extension */ 193 : 1 : return S2N_SUCCESS; 194 : 1 : } 195 : : 196 [ + + ]: 31389 : for (size_t i = 0; i < supported_groups_count; i++) { 197 : 25254 : uint16_t iana_id = 0; 198 [ - + ]: 25254 : POSIX_GUARD(s2n_stuffer_read_uint16(extension, &iana_id)); 199 [ - + ]: 25254 : POSIX_GUARD(s2n_client_supported_groups_recv_iana_id(conn, iana_id)); 200 : 25254 : } 201 : : 202 [ - + ]: 6135 : POSIX_GUARD(s2n_choose_supported_group(conn)); 203 : : 204 : 6135 : return S2N_SUCCESS; 205 : 6135 : } 206 : : 207 : : /* Old-style extension functions -- remove after extensions refactor is complete */ 208 : : 209 : : int s2n_recv_client_supported_groups(struct s2n_connection *conn, struct s2n_stuffer *extension) 210 : 0 : { 211 : 0 : return s2n_extension_recv(&s2n_client_supported_groups_extension, conn, extension); 212 : 0 : }