LCOV - code coverage report
Current view: top level - tls/extensions - s2n_client_psk.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 202 208 97.1 %
Date: 2025-08-14 07:26:07 Functions: 11 11 100.0 %
Branches: 112 248 45.2 %

           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_psk.h"
      17                 :            : 
      18                 :            : #include <stdint.h>
      19                 :            : #include <sys/param.h>
      20                 :            : 
      21                 :            : #include "crypto/s2n_hash.h"
      22                 :            : #include "tls/s2n_psk.h"
      23                 :            : #include "tls/s2n_tls.h"
      24                 :            : #include "tls/s2n_tls_parameters.h"
      25                 :            : #include "utils/s2n_bitmap.h"
      26                 :            : #include "utils/s2n_safety.h"
      27                 :            : 
      28                 :       1092 : #define SIZE_OF_BINDER_SIZE      sizeof(uint8_t)
      29                 :       2140 : #define SIZE_OF_BINDER_LIST_SIZE sizeof(uint16_t)
      30                 :            : 
      31                 :            : /* To avoid a DoS attack triggered by decrypting too many session tickets,
      32                 :            :  * set a limit on the number of tickets we will attempt to decrypt before giving up.
      33                 :            :  * We may want to make this configurable someday, but just set a reasonable maximum for now. */
      34                 :        113 : #define MAX_REJECTED_TICKETS 3
      35                 :            : 
      36                 :            : static int s2n_client_psk_send(struct s2n_connection *conn, struct s2n_stuffer *out);
      37                 :            : static int s2n_client_psk_recv(struct s2n_connection *conn, struct s2n_stuffer *extension);
      38                 :            : static int s2n_client_psk_is_missing(struct s2n_connection *conn);
      39                 :            : 
      40                 :            : const s2n_extension_type s2n_client_psk_extension = {
      41                 :            :     .iana_value = TLS_EXTENSION_PRE_SHARED_KEY,
      42                 :            :     .minimum_version = S2N_TLS13,
      43                 :            :     .is_response = false,
      44                 :            :     .send = s2n_client_psk_send,
      45                 :            :     .recv = s2n_client_psk_recv,
      46                 :            :     .should_send = s2n_client_psk_should_send,
      47                 :            :     .if_missing = s2n_client_psk_is_missing,
      48                 :            : };
      49                 :            : 
      50                 :            : int s2n_client_psk_is_missing(struct s2n_connection *conn)
      51                 :       3842 : {
      52 [ #  # ][ -  + ]:       3842 :     POSIX_ENSURE_REF(conn);
      53                 :            : 
      54                 :            :     /* If the PSK extension is missing, we must not have received
      55                 :            :      * a request for early data.
      56                 :            :      *
      57                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.10
      58                 :            :      *# When a PSK is used and early data is allowed for that PSK, the client
      59                 :            :      *# can send Application Data in its first flight of messages.  If the
      60                 :            :      *# client opts to do so, it MUST supply both the "pre_shared_key" and
      61                 :            :      *# "early_data" extensions.
      62                 :            :      */
      63 [ #  # ][ -  + ]:       3842 :     POSIX_ENSURE(conn->early_data_state != S2N_EARLY_DATA_REQUESTED, S2N_ERR_UNSUPPORTED_EXTENSION);
      64                 :       3842 :     return S2N_SUCCESS;
      65                 :       3842 : }
      66                 :            : 
      67                 :            : bool s2n_client_psk_should_send(struct s2n_connection *conn)
      68                 :       6094 : {
      69 [ +  + ][ -  + ]:       6094 :     if (!conn || !conn->secure) {
      70                 :          1 :         return false;
      71                 :          1 :     }
      72                 :            : 
      73                 :            :     /* If this is NOT the second ClientHello after a retry, then all PSKs are viable.
      74                 :            :      * Send the extension if any PSKs are configured.
      75                 :            :      */
      76         [ +  + ]:       6093 :     if (!s2n_is_hello_retry_handshake(conn)) {
      77                 :       5428 :         return conn->psk_params.psk_list.len > 0;
      78                 :       5428 :     }
      79                 :            : 
      80                 :            :     /* If this is the second ClientHello after a retry, then only PSKs that match the cipher suite
      81                 :            :      * are viable. Only send the extension if at least one configured PSK matches the cipher suite.
      82                 :            :      */
      83         [ +  + ]:        671 :     for (size_t i = 0; i < conn->psk_params.psk_list.len; i++) {
      84                 :        480 :         struct s2n_psk *psk = NULL;
      85         [ +  - ]:        480 :         if (s2n_result_is_ok(s2n_array_get(&conn->psk_params.psk_list, i, (void **) &psk))
      86         [ +  - ]:        480 :                 && psk != NULL
      87         [ +  + ]:        480 :                 && conn->secure->cipher_suite->prf_alg == psk->hmac_alg) {
      88                 :        474 :             return true;
      89                 :        474 :         }
      90                 :        480 :     }
      91                 :        191 :     return false;
      92                 :        665 : }
      93                 :            : 
      94                 :            : /**
      95                 :            :  *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.11.1
      96                 :            :  *# The "obfuscated_ticket_age"
      97                 :            :  *# field of each PskIdentity contains an obfuscated version of the
      98                 :            :  *# ticket age formed by taking the age in milliseconds and adding the
      99                 :            :  *# "ticket_age_add" value that was included with the ticket (see
     100                 :            :  *# Section 4.6.1), modulo 2^32.
     101                 :            : */
     102                 :            : static S2N_RESULT s2n_generate_obfuscated_ticket_age(struct s2n_psk *psk, uint64_t current_time, uint32_t *output)
     103                 :       1092 : {
     104 [ -  + ][ #  # ]:       1092 :     RESULT_ENSURE_REF(psk);
     105 [ -  + ][ #  # ]:       1092 :     RESULT_ENSURE_MUT(output);
     106                 :            : 
     107                 :            :     /**
     108                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.11
     109                 :            :      *# For identities
     110                 :            :      *# established externally, an obfuscated_ticket_age of 0 SHOULD be
     111                 :            :      *# used,
     112                 :            :      **/
     113         [ +  + ]:       1092 :     if (psk->type == S2N_PSK_TYPE_EXTERNAL) {
     114                 :        980 :         *output = 0;
     115                 :        980 :         return S2N_RESULT_OK;
     116                 :        980 :     }
     117                 :            : 
     118 [ -  + ][ #  # ]:        112 :     RESULT_ENSURE(current_time >= psk->ticket_issue_time, S2N_ERR_SAFETY);
     119                 :            : 
     120                 :            :     /* Calculate ticket age */
     121                 :        112 :     uint64_t ticket_age_in_nanos = current_time - psk->ticket_issue_time;
     122                 :            : 
     123                 :            :     /* Convert ticket age to milliseconds */
     124                 :        112 :     uint64_t ticket_age_in_millis = ticket_age_in_nanos / ONE_MILLISEC_IN_NANOS;
     125 [ -  + ][ #  # ]:        112 :     RESULT_ENSURE(ticket_age_in_millis <= UINT32_MAX, S2N_ERR_SAFETY);
     126                 :            : 
     127                 :            :     /* Add the ticket_age_add value to the ticket age in milliseconds. The resulting uint32_t value
     128                 :            :      * may wrap, resulting in the modulo 2^32 operation. */
     129                 :        112 :     *output = ticket_age_in_millis + psk->ticket_age_add;
     130                 :            : 
     131                 :        112 :     return S2N_RESULT_OK;
     132                 :        112 : }
     133                 :            : 
     134                 :            : static int s2n_client_psk_send(struct s2n_connection *conn, struct s2n_stuffer *out)
     135                 :       1076 : {
     136 [ -  + ][ #  # ]:       1076 :     POSIX_ENSURE_REF(conn);
     137 [ -  + ][ #  # ]:       1076 :     POSIX_ENSURE_REF(conn->secure);
     138                 :            : 
     139                 :       1076 :     struct s2n_psk_parameters *psk_params = &conn->psk_params;
     140                 :       1076 :     struct s2n_array *psk_list = &psk_params->psk_list;
     141                 :            : 
     142                 :       1076 :     struct s2n_stuffer_reservation identity_list_size;
     143         [ -  + ]:       1076 :     POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &identity_list_size));
     144                 :            : 
     145                 :       1076 :     uint16_t binder_list_size = SIZE_OF_BINDER_LIST_SIZE;
     146                 :            : 
     147         [ +  + ]:       2168 :     for (size_t i = 0; i < psk_list->len; i++) {
     148                 :       1092 :         struct s2n_psk *psk = NULL;
     149         [ -  + ]:       1092 :         POSIX_GUARD_RESULT(s2n_array_get(psk_list, i, (void **) &psk));
     150 [ -  + ][ #  # ]:       1092 :         POSIX_ENSURE_REF(psk);
     151                 :            : 
     152                 :            :         /**
     153                 :            :          *= https://www.rfc-editor.org/rfc/rfc8446#section-4.1.4
     154                 :            :          *# In addition, in its updated ClientHello, the client SHOULD NOT offer
     155                 :            :          *# any pre-shared keys associated with a hash other than that of the
     156                 :            :          *# selected cipher suite.
     157                 :            :          */
     158 [ +  + ][ -  + ]:       1092 :         if (s2n_is_hello_retry_handshake(conn) && conn->secure->cipher_suite->prf_alg != psk->hmac_alg) {
     159                 :          0 :             continue;
     160                 :          0 :         }
     161                 :            : 
     162                 :            :         /* Write the identity */
     163         [ -  + ]:       1092 :         POSIX_GUARD(s2n_stuffer_write_uint16(out, psk->identity.size));
     164         [ -  + ]:       1092 :         POSIX_GUARD(s2n_stuffer_write(out, &psk->identity));
     165                 :            : 
     166                 :            :         /* Write obfuscated ticket age */
     167                 :       1092 :         uint32_t obfuscated_ticket_age = 0;
     168                 :       1092 :         uint64_t current_time = 0;
     169         [ -  + ]:       1092 :         POSIX_GUARD_RESULT(s2n_config_wall_clock(conn->config, &current_time));
     170         [ -  + ]:       1092 :         POSIX_GUARD_RESULT(s2n_generate_obfuscated_ticket_age(psk, current_time, &obfuscated_ticket_age));
     171         [ -  + ]:       1092 :         POSIX_GUARD(s2n_stuffer_write_uint32(out, obfuscated_ticket_age));
     172                 :            : 
     173                 :            :         /* Calculate binder size */
     174                 :       1092 :         uint8_t hash_size = 0;
     175         [ -  + ]:       1092 :         POSIX_GUARD(s2n_hmac_digest_size(psk->hmac_alg, &hash_size));
     176                 :       1092 :         binder_list_size += hash_size + SIZE_OF_BINDER_SIZE;
     177                 :       1092 :     }
     178                 :            : 
     179         [ -  + ]:       1076 :     POSIX_GUARD(s2n_stuffer_write_vector_size(&identity_list_size));
     180                 :            : 
     181                 :            :     /* Calculating the binders requires a complete ClientHello, and at this point
     182                 :            :      * the extension size, extension list size, and message size are all blank.
     183                 :            :      *
     184                 :            :      * We'll write placeholder data to ensure the extension and extension list sizes
     185                 :            :      * are calculated correctly, then rewrite the binders with real data later. */
     186                 :       1076 :     psk_params->binder_list_size = binder_list_size;
     187         [ -  + ]:       1076 :     POSIX_GUARD(s2n_stuffer_skip_write(out, binder_list_size));
     188                 :            : 
     189                 :       1076 :     return S2N_SUCCESS;
     190                 :       1076 : }
     191                 :            : 
     192                 :            : /* Find the first of the server's PSK identities that matches the client's identities.
     193                 :            :  * This method compares all server identities to all client identities.
     194                 :            :  *
     195                 :            :  * While both the client's identities and whether a match was found are public, we should make an attempt
     196                 :            :  * to keep the server's identities a secret. We will make comparisons to the server's identities constant
     197                 :            :  * time (to hide partial matches) and not end the search early when a match is found (to hide the ordering).
     198                 :            :  *
     199                 :            :  * Keeping these comparisons constant time is not high priority. There's no known attack using these timings,
     200                 :            :  * and an attacker could probably guess the server's known identities just by observing the public identities
     201                 :            :  * sent by clients.
     202                 :            :  */
     203                 :            : static S2N_RESULT s2n_select_external_psk(struct s2n_connection *conn, struct s2n_offered_psk_list *client_identity_list)
     204                 :        958 : {
     205 [ -  + ][ #  # ]:        958 :     RESULT_ENSURE_REF(conn);
     206 [ -  + ][ #  # ]:        958 :     RESULT_ENSURE_REF(client_identity_list);
     207                 :            : 
     208                 :        958 :     struct s2n_array *server_psks = &conn->psk_params.psk_list;
     209                 :        958 :     conn->psk_params.chosen_psk = NULL;
     210                 :            : 
     211         [ +  + ]:       1929 :     for (size_t i = 0; i < server_psks->len; i++) {
     212                 :        971 :         struct s2n_psk *server_psk = NULL;
     213         [ -  + ]:        971 :         RESULT_GUARD(s2n_array_get(server_psks, i, (void **) &server_psk));
     214 [ -  + ][ #  # ]:        971 :         RESULT_ENSURE_REF(server_psk);
     215                 :            : 
     216                 :        971 :         struct s2n_offered_psk client_psk = { 0 };
     217                 :        971 :         uint16_t wire_index = 0;
     218                 :            : 
     219         [ -  + ]:        971 :         RESULT_GUARD_POSIX(s2n_offered_psk_list_reread(client_identity_list));
     220         [ +  + ]:       1980 :         while (s2n_offered_psk_list_has_next(client_identity_list)) {
     221         [ -  + ]:       1009 :             RESULT_GUARD_POSIX(s2n_offered_psk_list_next(client_identity_list, &client_psk));
     222                 :       1009 :             uint16_t compare_size = MIN(client_psk.identity.size, server_psk->identity.size);
     223         [ +  + ]:       1009 :             if (s2n_constant_time_equals(client_psk.identity.data, server_psk->identity.data, compare_size)
     224                 :       1009 :                     & (client_psk.identity.size == server_psk->identity.size)
     225                 :       1009 :                     & (conn->psk_params.chosen_psk == NULL)) {
     226                 :        955 :                 conn->psk_params.chosen_psk = server_psk;
     227                 :        955 :                 conn->psk_params.chosen_psk_wire_index = wire_index;
     228                 :        955 :             }
     229                 :       1009 :             wire_index++;
     230                 :       1009 :         };
     231                 :        971 :     }
     232 [ +  - ][ +  + ]:        958 :     RESULT_ENSURE_REF(conn->psk_params.chosen_psk);
     233                 :        955 :     return S2N_RESULT_OK;
     234                 :        958 : }
     235                 :            : 
     236                 :            : static S2N_RESULT s2n_select_resumption_psk(struct s2n_connection *conn, struct s2n_offered_psk_list *client_identity_list)
     237                 :        113 : {
     238 [ #  # ][ -  + ]:        113 :     RESULT_ENSURE_REF(conn);
     239 [ -  + ][ #  # ]:        113 :     RESULT_ENSURE_REF(client_identity_list);
     240                 :            : 
     241                 :        113 :     struct s2n_offered_psk client_psk = { 0 };
     242                 :        113 :     conn->psk_params.chosen_psk = NULL;
     243                 :            : 
     244                 :        113 :     uint8_t rejected_count = 0;
     245 [ +  + ][ +  - ]:        118 :     while (s2n_offered_psk_list_has_next(client_identity_list) && (rejected_count < MAX_REJECTED_TICKETS)) {
     246         [ -  + ]:        113 :         RESULT_GUARD_POSIX(s2n_offered_psk_list_next(client_identity_list, &client_psk));
     247                 :            :         /* Select the first resumption PSK that can be decrypted */
     248         [ +  + ]:        113 :         if (s2n_offered_psk_list_choose_psk(client_identity_list, &client_psk) == S2N_SUCCESS) {
     249                 :        108 :             return S2N_RESULT_OK;
     250                 :        108 :         }
     251                 :          5 :         rejected_count++;
     252                 :          5 :     }
     253                 :            : 
     254         [ +  - ]:          5 :     RESULT_BAIL(S2N_ERR_INVALID_SESSION_TICKET);
     255                 :          5 : }
     256                 :            : 
     257                 :            : static S2N_RESULT s2n_client_psk_recv_identity_list(struct s2n_connection *conn, struct s2n_stuffer *wire_identities_in)
     258                 :       1072 : {
     259 [ -  + ][ #  # ]:       1072 :     RESULT_ENSURE_REF(conn);
     260 [ -  + ][ #  # ]:       1072 :     RESULT_ENSURE_REF(conn->config);
     261 [ -  + ][ #  # ]:       1072 :     RESULT_ENSURE_REF(wire_identities_in);
     262                 :            : 
     263                 :       1072 :     struct s2n_offered_psk_list identity_list = {
     264                 :       1072 :         .conn = conn,
     265                 :       1072 :         .wire_data = *wire_identities_in,
     266                 :       1072 :     };
     267                 :            : 
     268         [ +  + ]:       1072 :     if (conn->config->psk_selection_cb) {
     269         [ -  + ]:          1 :         RESULT_GUARD_POSIX(conn->config->psk_selection_cb(conn, conn->config->psk_selection_ctx, &identity_list));
     270         [ +  + ]:       1071 :     } else if (conn->psk_params.type == S2N_PSK_TYPE_EXTERNAL) {
     271         [ +  + ]:        958 :         RESULT_GUARD(s2n_select_external_psk(conn, &identity_list));
     272         [ +  - ]:        958 :     } else if (conn->psk_params.type == S2N_PSK_TYPE_RESUMPTION) {
     273         [ +  + ]:        113 :         RESULT_GUARD(s2n_select_resumption_psk(conn, &identity_list));
     274                 :        113 :     }
     275                 :            : 
     276 [ #  # ][ -  + ]:       1064 :     RESULT_ENSURE_REF(conn->psk_params.chosen_psk);
     277                 :       1064 :     return S2N_RESULT_OK;
     278                 :       1064 : }
     279                 :            : 
     280                 :            : static S2N_RESULT s2n_client_psk_recv_binder_list(struct s2n_connection *conn, struct s2n_blob *partial_client_hello,
     281                 :            :         struct s2n_stuffer *wire_binders_in)
     282                 :       1064 : {
     283 [ -  + ][ #  # ]:       1064 :     RESULT_ENSURE_REF(conn);
     284 [ #  # ][ -  + ]:       1064 :     RESULT_ENSURE_REF(wire_binders_in);
     285                 :            : 
     286                 :       1064 :     uint16_t wire_index = 0;
     287         [ +  - ]:       1073 :     while (s2n_stuffer_data_available(wire_binders_in) > 0) {
     288                 :       1073 :         uint8_t wire_binder_size = 0;
     289         [ -  + ]:       1073 :         RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(wire_binders_in, &wire_binder_size));
     290                 :            : 
     291                 :       1073 :         uint8_t *wire_binder_data = NULL;
     292 [ #  # ][ -  + ]:       1073 :         RESULT_ENSURE_REF(wire_binder_data = s2n_stuffer_raw_read(wire_binders_in, wire_binder_size));
     293                 :            : 
     294                 :       1073 :         struct s2n_blob wire_binder = { 0 };
     295         [ -  + ]:       1073 :         RESULT_GUARD_POSIX(s2n_blob_init(&wire_binder, wire_binder_data, wire_binder_size));
     296                 :            : 
     297         [ +  + ]:       1073 :         if (wire_index == conn->psk_params.chosen_psk_wire_index) {
     298         [ -  + ]:       1064 :             RESULT_GUARD_POSIX(s2n_psk_verify_binder(conn, conn->psk_params.chosen_psk,
     299                 :       1064 :                     partial_client_hello, &wire_binder));
     300                 :       1064 :             return S2N_RESULT_OK;
     301                 :       1064 :         }
     302                 :          9 :         wire_index++;
     303                 :          9 :     }
     304         [ #  # ]:          0 :     RESULT_BAIL(S2N_ERR_BAD_MESSAGE);
     305                 :          0 : }
     306                 :            : 
     307                 :            : static S2N_RESULT s2n_client_psk_recv_identities(struct s2n_connection *conn, struct s2n_stuffer *extension)
     308                 :       1072 : {
     309 [ -  + ][ #  # ]:       1072 :     RESULT_ENSURE_REF(conn);
     310                 :            : 
     311                 :       1072 :     uint16_t identity_list_size = 0;
     312         [ -  + ]:       1072 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(extension, &identity_list_size));
     313                 :            : 
     314                 :       1072 :     uint8_t *identity_list_data = NULL;
     315 [ #  # ][ -  + ]:       1072 :     RESULT_ENSURE_REF(identity_list_data = s2n_stuffer_raw_read(extension, identity_list_size));
     316                 :            : 
     317                 :       1072 :     struct s2n_blob identity_list_blob = { 0 };
     318         [ -  + ]:       1072 :     RESULT_GUARD_POSIX(s2n_blob_init(&identity_list_blob, identity_list_data, identity_list_size));
     319                 :            : 
     320                 :       1072 :     struct s2n_stuffer identity_list = { 0 };
     321         [ -  + ]:       1072 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&identity_list, &identity_list_blob));
     322         [ -  + ]:       1072 :     RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&identity_list, identity_list_blob.size));
     323                 :            : 
     324                 :       1072 :     return s2n_client_psk_recv_identity_list(conn, &identity_list);
     325                 :       1072 : }
     326                 :            : 
     327                 :            : static S2N_RESULT s2n_client_psk_recv_binders(struct s2n_connection *conn, struct s2n_stuffer *extension)
     328                 :       1064 : {
     329 [ #  # ][ -  + ]:       1064 :     RESULT_ENSURE_REF(conn);
     330                 :            : 
     331                 :       1064 :     uint16_t binder_list_size = 0;
     332         [ -  + ]:       1064 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(extension, &binder_list_size));
     333                 :            : 
     334                 :       1064 :     uint8_t *binder_list_data = NULL;
     335 [ #  # ][ -  + ]:       1064 :     RESULT_ENSURE_REF(binder_list_data = s2n_stuffer_raw_read(extension, binder_list_size));
     336                 :            : 
     337                 :       1064 :     struct s2n_blob binder_list_blob = { 0 };
     338         [ -  + ]:       1064 :     RESULT_GUARD_POSIX(s2n_blob_init(&binder_list_blob, binder_list_data, binder_list_size));
     339                 :            : 
     340                 :       1064 :     struct s2n_stuffer binder_list = { 0 };
     341         [ -  + ]:       1064 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&binder_list, &binder_list_blob));
     342         [ -  + ]:       1064 :     RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&binder_list, binder_list_blob.size));
     343                 :            : 
     344                 :            :     /* Record the ClientHello message up to but not including the binder list.
     345                 :            :      * This is required to calculate the binder for the chosen PSK. */
     346                 :       1064 :     struct s2n_blob partial_client_hello = { 0 };
     347                 :       1064 :     const struct s2n_stuffer *client_hello = &conn->handshake.io;
     348                 :       1064 :     uint32_t binders_size = binder_list_blob.size + SIZE_OF_BINDER_LIST_SIZE;
     349 [ #  # ][ -  + ]:       1064 :     RESULT_ENSURE_GTE(client_hello->write_cursor, binders_size);
     350                 :       1064 :     uint16_t partial_client_hello_size = client_hello->write_cursor - binders_size;
     351         [ -  + ]:       1064 :     RESULT_GUARD_POSIX(s2n_blob_slice(&client_hello->blob, &partial_client_hello, 0, partial_client_hello_size));
     352                 :            : 
     353                 :       1064 :     return s2n_client_psk_recv_binder_list(conn, &partial_client_hello, &binder_list);
     354                 :       1064 : }
     355                 :            : 
     356                 :            : int s2n_client_psk_recv(struct s2n_connection *conn, struct s2n_stuffer *extension)
     357                 :       1072 : {
     358 [ #  # ][ -  + ]:       1072 :     POSIX_ENSURE_REF(conn);
     359                 :            : 
     360                 :            :     /**
     361                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.11
     362                 :            :      *# The "pre_shared_key" extension MUST be the last extension in the
     363                 :            :      *# ClientHello (this facilitates implementation as described below).
     364                 :            :      *# Servers MUST check that it is the last extension and otherwise fail
     365                 :            :      *# the handshake with an "illegal_parameter" alert.
     366                 :            :      */
     367                 :       1072 :     s2n_extension_type_id psk_ext_id = 0;
     368         [ -  + ]:       1072 :     POSIX_GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_PRE_SHARED_KEY, &psk_ext_id));
     369 [ #  # ][ -  + ]:       1072 :     POSIX_ENSURE_NE(conn->client_hello.extensions.count, 0);
     370                 :       1072 :     uint16_t last_wire_index = conn->client_hello.extensions.count - 1;
     371                 :       1072 :     uint16_t extension_wire_index = conn->client_hello.extensions.parsed_extensions[psk_ext_id].wire_index;
     372 [ -  + ][ #  # ]:       1072 :     POSIX_ENSURE(extension_wire_index == last_wire_index, S2N_ERR_UNSUPPORTED_EXTENSION);
     373                 :            : 
     374                 :            :     /**
     375                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.9
     376                 :            :      *# If clients offer "pre_shared_key" without a "psk_key_exchange_modes" extension,
     377                 :            :      *# servers MUST abort the handshake.
     378                 :            :      *
     379                 :            :      * We can safely do this check here because s2n_client_psk is
     380                 :            :      * required to be the last extension sent in the list.
     381                 :            :      */
     382                 :       1072 :     s2n_extension_type_id psk_ke_mode_ext_id = 0;
     383         [ -  + ]:       1072 :     POSIX_GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_PSK_KEY_EXCHANGE_MODES, &psk_ke_mode_ext_id));
     384 [ -  + ][ #  # ]:       1072 :     POSIX_ENSURE(S2N_CBIT_TEST(conn->extension_requests_received, psk_ke_mode_ext_id), S2N_ERR_MISSING_EXTENSION);
     385                 :            : 
     386         [ +  - ]:       1072 :     if (conn->psk_params.psk_ke_mode == S2N_PSK_DHE_KE) {
     387                 :       1072 :         s2n_extension_type_id key_share_ext_id = 0;
     388         [ -  + ]:       1072 :         POSIX_GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_KEY_SHARE, &key_share_ext_id));
     389                 :            :         /* A key_share extension must have been received in order to use a pre-shared key
     390                 :            :          * in (EC)DHE key exchange mode.
     391                 :            :          */
     392 [ #  # ][ -  + ]:       1072 :         POSIX_ENSURE(S2N_CBIT_TEST(conn->extension_requests_received, key_share_ext_id), S2N_ERR_MISSING_EXTENSION);
     393                 :       1072 :     } else {
     394                 :            :         /* s2n currently only supports pre-shared keys in (EC)DHE key exchange mode. If we receive keys with any other
     395                 :            :          * exchange mode we fall back to a full handshake.
     396                 :            :          */
     397                 :          0 :         return S2N_SUCCESS;
     398                 :          0 :     }
     399                 :            : 
     400         [ +  + ]:       1072 :     if (s2n_result_is_error(s2n_client_psk_recv_identities(conn, extension))) {
     401                 :            :         /**
     402                 :            :          *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.11
     403                 :            :          *# If no acceptable PSKs are found, the server SHOULD perform a non-PSK
     404                 :            :          *# handshake if possible.
     405                 :            :          */
     406                 :          8 :         conn->psk_params.chosen_psk = NULL;
     407                 :          8 :     }
     408                 :            : 
     409         [ +  + ]:       1072 :     if (conn->psk_params.chosen_psk) {
     410                 :            :         /**
     411                 :            :          *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.11
     412                 :            :          *# Prior to accepting PSK key establishment, the server MUST validate
     413                 :            :          *# the corresponding binder value (see Section 4.2.11.2 below).  If this
     414                 :            :          *# value is not present or does not validate, the server MUST abort the
     415                 :            :          *# handshake.
     416                 :            :          */
     417         [ -  + ]:       1064 :         POSIX_GUARD_RESULT(s2n_client_psk_recv_binders(conn, extension));
     418                 :       1064 :     }
     419                 :            : 
     420                 :            :     /* At this point, we have either chosen a PSK or fallen back to a full handshake. */
     421                 :       1072 :     return S2N_SUCCESS;
     422                 :       1072 : }

Generated by: LCOV version 1.14