LCOV - code coverage report
Current view: top level - tls - s2n_protocol_preferences.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 99 99 100.0 %
Date: 2025-08-15 07:28:39 Functions: 9 9 100.0 %
Branches: 78 140 55.7 %

           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 "error/s2n_errno.h"
      17                 :            : #include "tls/s2n_connection.h"
      18                 :            : #include "utils/s2n_safety.h"
      19                 :            : 
      20                 :            : S2N_RESULT s2n_protocol_preferences_read(struct s2n_stuffer *protocol_preferences, struct s2n_blob *protocol)
      21                 :        120 : {
      22 [ +  + ][ +  - ]:        120 :     RESULT_ENSURE_REF(protocol_preferences);
      23 [ +  - ][ +  + ]:        119 :     RESULT_ENSURE_REF(protocol);
      24                 :            : 
      25                 :        118 :     uint8_t length = 0;
      26         [ +  + ]:        118 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(protocol_preferences, &length));
      27 [ +  + ][ +  - ]:        117 :     RESULT_ENSURE_GT(length, 0);
      28                 :            : 
      29                 :        115 :     uint8_t *data = s2n_stuffer_raw_read(protocol_preferences, length);
      30 [ -  + ][ #  # ]:        115 :     RESULT_ENSURE_REF(data);
      31                 :            : 
      32         [ -  + ]:        115 :     RESULT_GUARD_POSIX(s2n_blob_init(protocol, data, length));
      33                 :        115 :     return S2N_RESULT_OK;
      34                 :        115 : }
      35                 :            : 
      36                 :            : S2N_RESULT s2n_protocol_preferences_contain(struct s2n_blob *protocol_preferences, struct s2n_blob *protocol, bool *contains)
      37                 :         51 : {
      38 [ +  + ][ +  - ]:         51 :     RESULT_ENSURE_REF(contains);
      39                 :         50 :     *contains = false;
      40 [ +  + ][ +  - ]:         50 :     RESULT_ENSURE_REF(protocol_preferences);
      41 [ +  + ][ +  - ]:         49 :     RESULT_ENSURE_REF(protocol);
      42                 :            : 
      43                 :         48 :     struct s2n_stuffer app_protocols_stuffer = { 0 };
      44         [ -  + ]:         48 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&app_protocols_stuffer, protocol_preferences));
      45         [ -  + ]:         48 :     RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&app_protocols_stuffer, protocol_preferences->size));
      46                 :            : 
      47         [ +  + ]:         72 :     while (s2n_stuffer_data_available(&app_protocols_stuffer) > 0) {
      48                 :         60 :         struct s2n_blob match_against = { 0 };
      49         [ -  + ]:         60 :         RESULT_GUARD(s2n_protocol_preferences_read(&app_protocols_stuffer, &match_against));
      50                 :            : 
      51 [ +  + ][ +  + ]:         60 :         if (match_against.size == protocol->size && memcmp(match_against.data, protocol->data, protocol->size) == 0) {
      52                 :         36 :             *contains = true;
      53                 :         36 :             return S2N_RESULT_OK;
      54                 :         36 :         }
      55                 :         60 :     }
      56                 :         12 :     return S2N_RESULT_OK;
      57                 :         48 : }
      58                 :            : 
      59                 :            : S2N_RESULT s2n_protocol_preferences_append(struct s2n_blob *application_protocols, const uint8_t *protocol, uint8_t protocol_len)
      60                 :        124 : {
      61 [ -  + ][ #  # ]:        124 :     RESULT_ENSURE_MUT(application_protocols);
      62 [ #  # ][ -  + ]:        124 :     RESULT_ENSURE_REF(protocol);
      63                 :            : 
      64                 :            :     /**
      65                 :            :      *= https://www.rfc-editor.org/rfc/rfc7301#section-3.1
      66                 :            :      *# Empty strings
      67                 :            :      *# MUST NOT be included and byte strings MUST NOT be truncated.
      68                 :            :      */
      69 [ +  + ][ +  - ]:        124 :     RESULT_ENSURE(protocol_len != 0, S2N_ERR_INVALID_APPLICATION_PROTOCOL);
      70                 :            : 
      71                 :        122 :     uint32_t prev_len = application_protocols->size;
      72                 :        122 :     uint32_t new_len = prev_len + /* len prefix */ 1 + protocol_len;
      73 [ -  + ][ #  # ]:        122 :     RESULT_ENSURE(new_len <= UINT16_MAX, S2N_ERR_INVALID_APPLICATION_PROTOCOL);
      74                 :            : 
      75         [ -  + ]:        122 :     RESULT_GUARD_POSIX(s2n_realloc(application_protocols, new_len));
      76                 :            : 
      77                 :        122 :     struct s2n_stuffer protocol_stuffer = { 0 };
      78         [ -  + ]:        122 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&protocol_stuffer, application_protocols));
      79         [ -  + ]:        122 :     RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&protocol_stuffer, prev_len));
      80         [ -  + ]:        122 :     RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(&protocol_stuffer, protocol_len));
      81         [ -  + ]:        122 :     RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&protocol_stuffer, protocol, protocol_len));
      82                 :            : 
      83                 :        122 :     return S2N_RESULT_OK;
      84                 :        122 : }
      85                 :            : 
      86                 :            : S2N_RESULT s2n_protocol_preferences_set(struct s2n_blob *application_protocols, const char *const *protocols, int protocol_count)
      87                 :         68 : {
      88 [ -  + ][ #  # ]:         68 :     RESULT_ENSURE_MUT(application_protocols);
      89                 :            : 
      90                 :            :     /* NULL value indicates no preference so free the previous blob */
      91 [ +  + ][ +  + ]:         68 :     if (protocols == NULL || protocol_count == 0) {
      92         [ -  + ]:          6 :         RESULT_GUARD_POSIX(s2n_free(application_protocols));
      93                 :          6 :         return S2N_RESULT_OK;
      94                 :          6 :     }
      95                 :            : 
      96                 :         62 :     DEFER_CLEANUP(struct s2n_blob new_protocols = { 0 }, s2n_free);
      97                 :            : 
      98                 :            :     /* Allocate enough space to avoid a reallocation for every entry
      99                 :            :      *
     100                 :            :      * We assume that each protocol is most likely 8 bytes or less.
     101                 :            :      * If it ends up being larger, we will expand the blob automatically
     102                 :            :      * in the append method.
     103                 :            :      */
     104         [ -  + ]:         62 :     RESULT_GUARD_POSIX(s2n_realloc(&new_protocols, protocol_count * 8));
     105                 :            : 
     106                 :            :     /* set the size back to 0 so we start at the beginning.
     107                 :            :      * s2n_realloc will just update the size field here
     108                 :            :      */
     109         [ -  + ]:         62 :     RESULT_GUARD_POSIX(s2n_realloc(&new_protocols, 0));
     110 [ -  + ][ #  # ]:         62 :     RESULT_ENSURE_GTE(protocol_count, 0);
     111                 :            : 
     112         [ +  + ]:        167 :     for (size_t i = 0; i < (size_t) protocol_count; i++) {
     113                 :        107 :         const uint8_t *protocol = (const uint8_t *) protocols[i];
     114                 :        107 :         size_t length = strlen(protocols[i]);
     115                 :            : 
     116                 :            :         /**
     117                 :            :          *= https://www.rfc-editor.org/rfc/rfc7301#section-3.1
     118                 :            :          *# Empty strings
     119                 :            :          *# MUST NOT be included and byte strings MUST NOT be truncated.
     120                 :            :          */
     121 [ +  + ][ +  - ]:        107 :         RESULT_ENSURE(length < 256, S2N_ERR_INVALID_APPLICATION_PROTOCOL);
     122                 :            : 
     123         [ -  + ]:        105 :         RESULT_GUARD(s2n_protocol_preferences_append(&new_protocols, protocol, (uint8_t) length));
     124                 :        105 :     }
     125                 :            : 
     126                 :            :     /* now we can free the previous list since we've validated all new input */
     127         [ -  + ]:         60 :     RESULT_GUARD_POSIX(s2n_free(application_protocols));
     128                 :            : 
     129                 :            :     /* update the connection/config application_protocols with the newly allocated blob */
     130                 :         60 :     *application_protocols = new_protocols;
     131                 :            : 
     132                 :         60 :     ZERO_TO_DISABLE_DEFER_CLEANUP(new_protocols);
     133                 :            : 
     134                 :         60 :     return S2N_RESULT_OK;
     135                 :         60 : }
     136                 :            : 
     137                 :            : S2N_RESULT s2n_select_server_preference_protocol(struct s2n_connection *conn, struct s2n_stuffer *server_list,
     138                 :            :         struct s2n_blob *client_list)
     139                 :         37 : {
     140 [ #  # ][ -  + ]:         37 :     RESULT_ENSURE_REF(conn);
     141 [ #  # ][ -  + ]:         37 :     RESULT_ENSURE_REF(server_list);
     142 [ #  # ][ -  + ]:         37 :     RESULT_ENSURE_REF(client_list);
     143                 :            : 
     144         [ +  + ]:         44 :     while (s2n_stuffer_data_available(server_list) > 0) {
     145                 :         41 :         struct s2n_blob protocol = { 0 };
     146 [ -  + ][ #  # ]:         41 :         RESULT_ENSURE_OK(s2n_protocol_preferences_read(server_list, &protocol), S2N_ERR_BAD_MESSAGE);
     147                 :            : 
     148                 :         41 :         bool match_found = false;
     149 [ -  + ][ #  # ]:         41 :         RESULT_ENSURE_OK(s2n_protocol_preferences_contain(client_list, &protocol, &match_found), S2N_ERR_BAD_MESSAGE);
     150                 :            : 
     151         [ +  + ]:         41 :         if (match_found) {
     152 [ -  + ][ #  # ]:         34 :             RESULT_ENSURE_LT(protocol.size, sizeof(conn->application_protocol));
     153 [ -  + ][ #  # ]:         34 :             RESULT_CHECKED_MEMCPY(conn->application_protocol, protocol.data, protocol.size);
                 [ +  - ]
     154                 :         34 :             conn->application_protocol[protocol.size] = '\0';
     155                 :         34 :             return S2N_RESULT_OK;
     156                 :         34 :         }
     157                 :         41 :     }
     158                 :            : 
     159                 :          3 :     return S2N_RESULT_OK;
     160                 :         37 : }
     161                 :            : 
     162                 :            : int s2n_config_set_protocol_preferences(struct s2n_config *config, const char *const *protocols, int protocol_count)
     163                 :         57 : {
     164         [ +  + ]:         57 :     POSIX_GUARD_RESULT(s2n_protocol_preferences_set(&config->application_protocols, protocols, protocol_count));
     165                 :         56 :     return S2N_SUCCESS;
     166                 :         57 : }
     167                 :            : 
     168                 :            : int s2n_config_append_protocol_preference(struct s2n_config *config, const uint8_t *protocol, uint8_t protocol_len)
     169                 :          4 : {
     170         [ +  + ]:          4 :     POSIX_GUARD_RESULT(s2n_protocol_preferences_append(&config->application_protocols, protocol, protocol_len));
     171                 :          3 :     return S2N_SUCCESS;
     172                 :          4 : }
     173                 :            : 
     174                 :            : int s2n_connection_set_protocol_preferences(struct s2n_connection *conn, const char *const *protocols, int protocol_count)
     175                 :         11 : {
     176         [ +  + ]:         11 :     POSIX_GUARD_RESULT(s2n_protocol_preferences_set(&conn->application_protocols_overridden, protocols, protocol_count));
     177                 :         10 :     return S2N_SUCCESS;
     178                 :         11 : }
     179                 :            : 
     180                 :            : int s2n_connection_append_protocol_preference(struct s2n_connection *conn, const uint8_t *protocol, uint8_t protocol_len)
     181                 :         15 : {
     182         [ +  + ]:         15 :     POSIX_GUARD_RESULT(s2n_protocol_preferences_append(&conn->application_protocols_overridden, protocol, protocol_len));
     183                 :         14 :     return S2N_SUCCESS;
     184                 :         15 : }

Generated by: LCOV version 1.14