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