LCOV - code coverage report
Current view: top level - tls/extensions - s2n_client_supported_groups.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 90 117 76.9 %
Date: 2025-08-14 07:26:07 Functions: 6 7 85.7 %
Branches: 54 130 41.5 %

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

Generated by: LCOV version 1.14