LCOV - code coverage report
Current view: top level - tls/extensions - s2n_extension_type.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 119 119 100.0 %
Date: 2025-09-30 07:28:05 Functions: 15 15 100.0 %
Branches: 88 110 80.0 %

           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_extension_type.h"
      17                 :            : 
      18                 :            : #include "api/s2n.h"
      19                 :            : #include "error/s2n_errno.h"
      20                 :            : #include "tls/s2n_connection.h"
      21                 :            : #include "tls/s2n_tls13.h"
      22                 :            : #include "utils/s2n_bitmap.h"
      23                 :            : #include "utils/s2n_safety.h"
      24                 :            : 
      25                 :            : #define TLS_EXTENSION_DATA_LENGTH_BYTES 2
      26                 :            : 
      27                 :            : /* Because there are 65536 possible extension IANAs, we will only
      28                 :            :  * put the lowest (and most common) in a lookup table to conserve space. */
      29                 :     787532 : #define S2N_MAX_INDEXED_EXTENSION_IANA 60
      30                 :            : 
      31                 :            : const s2n_extension_type_id s2n_unsupported_extension = S2N_SUPPORTED_EXTENSIONS_COUNT;
      32                 :            : s2n_extension_type_id s2n_extension_ianas_to_ids[S2N_MAX_INDEXED_EXTENSION_IANA];
      33                 :            : 
      34                 :            : int s2n_extension_type_init()
      35                 :        549 : {
      36                 :            :     /* Initialize to s2n_unsupported_extension */
      37         [ +  + ]:      33489 :     for (size_t i = 0; i < S2N_MAX_INDEXED_EXTENSION_IANA; i++) {
      38                 :      32940 :         s2n_extension_ianas_to_ids[i] = s2n_unsupported_extension;
      39                 :      32940 :     }
      40                 :            : 
      41                 :            :     /* Reverse the mapping */
      42         [ +  + ]:      12078 :     for (size_t i = 0; i < S2N_SUPPORTED_EXTENSIONS_COUNT; i++) {
      43                 :      11529 :         uint16_t iana_value = s2n_supported_extensions[i];
      44         [ +  + ]:      11529 :         if (iana_value < S2N_MAX_INDEXED_EXTENSION_IANA) {
      45                 :       9882 :             s2n_extension_ianas_to_ids[iana_value] = i;
      46                 :       9882 :         }
      47                 :      11529 :     }
      48                 :            : 
      49                 :        549 :     return S2N_SUCCESS;
      50                 :        549 : }
      51                 :            : 
      52                 :            : /* Convert the IANA value (which ranges from 0->65535) to an id with a more
      53                 :            :  * constrained range. That id can be used for bitfields, array indexes, etc.
      54                 :            :  * to avoid allocating too much memory. */
      55                 :            : s2n_extension_type_id s2n_extension_iana_value_to_id(const uint16_t iana_value)
      56                 :     742514 : {
      57                 :            :     /* Check the lookup table */
      58         [ +  + ]:     742514 :     if (iana_value < S2N_MAX_INDEXED_EXTENSION_IANA) {
      59                 :     656134 :         return s2n_extension_ianas_to_ids[iana_value];
      60                 :     656134 :     }
      61                 :            : 
      62                 :            :     /* Fall back to the full list. We can handle this more
      63                 :            :      * efficiently later if our extension list gets long. */
      64         [ +  + ]:     693476 :     for (size_t i = 0; i < S2N_SUPPORTED_EXTENSIONS_COUNT; i++) {
      65         [ +  + ]:     692937 :         if (s2n_supported_extensions[i] == iana_value) {
      66                 :      85841 :             return i;
      67                 :      85841 :         }
      68                 :     692937 :     }
      69                 :            : 
      70                 :        539 :     return s2n_unsupported_extension;
      71                 :      86380 : }
      72                 :            : 
      73                 :            : int s2n_extension_supported_iana_value_to_id(const uint16_t iana_value, s2n_extension_type_id *internal_id)
      74                 :     742466 : {
      75 [ #  # ][ -  + ]:     742466 :     POSIX_ENSURE_REF(internal_id);
      76                 :            : 
      77                 :     742466 :     *internal_id = s2n_extension_iana_value_to_id(iana_value);
      78 [ +  + ][ +  - ]:     742466 :     S2N_ERROR_IF(*internal_id == s2n_unsupported_extension, S2N_ERR_UNRECOGNIZED_EXTENSION);
      79                 :     741887 :     return S2N_SUCCESS;
      80                 :     742466 : }
      81                 :            : 
      82                 :            : int s2n_extension_send(const s2n_extension_type *extension_type, struct s2n_connection *conn, struct s2n_stuffer *out)
      83                 :     223834 : {
      84 [ +  - ][ +  + ]:     223834 :     POSIX_ENSURE_REF(extension_type);
      85 [ +  - ][ +  + ]:     223833 :     POSIX_ENSURE_REF(extension_type->should_send);
      86 [ +  - ][ +  + ]:     223832 :     POSIX_ENSURE_REF(extension_type->send);
      87 [ +  + ][ +  - ]:     223831 :     POSIX_ENSURE_REF(conn);
      88                 :            : 
      89                 :     223830 :     s2n_extension_type_id extension_id = 0;
      90         [ -  + ]:     223830 :     POSIX_GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id));
      91                 :            : 
      92                 :            :     /* Do not send response if request not received. */
      93 [ +  + ][ +  + ]:     223830 :     if (extension_type->is_response && !S2N_CBIT_TEST(conn->extension_requests_received, extension_id)) {
      94                 :      54824 :         return S2N_SUCCESS;
      95                 :      54824 :     }
      96                 :            : 
      97                 :            :     /* Do not send an extension that is not valid for the protocol version */
      98         [ +  + ]:     169006 :     if (extension_type->minimum_version > conn->actual_protocol_version) {
      99                 :       8402 :         return S2N_SUCCESS;
     100                 :       8402 :     }
     101                 :            : 
     102                 :            :     /* Check if we need to send. Some extensions are only sent if specific conditions are met. */
     103         [ +  + ]:     160604 :     if (!extension_type->should_send(conn)) {
     104                 :     100373 :         return S2N_SUCCESS;
     105                 :     100373 :     }
     106                 :            : 
     107                 :            :     /* Write extension type */
     108         [ +  + ]:      60231 :     POSIX_GUARD(s2n_stuffer_write_uint16(out, extension_type->iana_value));
     109                 :            : 
     110                 :            :     /* Reserve space for extension size */
     111                 :      60228 :     struct s2n_stuffer_reservation extension_size_bytes = { 0 };
     112         [ -  + ]:      60228 :     POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &extension_size_bytes));
     113                 :            : 
     114                 :            :     /* Write extension data */
     115         [ +  + ]:      60228 :     POSIX_GUARD(extension_type->send(conn, out));
     116                 :            : 
     117                 :            :     /**
     118                 :            :      * Reset the tainted flag in the out stuffer (handshake.io stuffer).
     119                 :            :      * 
     120                 :            :      * Some extension send functions call s2n_stuffer_raw_write(), which
     121                 :            :      * makes the stuffer tainted, preventing further resizing of the handshake.io stuffer.
     122                 :            :      * We need to reset this flag after each extension is sent, because handshake.io
     123                 :            :      * might need to be resized to send subsequent extensions.
     124                 :            :      * 
     125                 :            :      * This is safe because the outstanding pointer from s2n_stuffer_raw_write() is scoped to
     126                 :            :      * the send function of each extension, and it is never stored in s2n_connection.
     127                 :            :      */
     128                 :      60223 :     out->tainted = false;
     129                 :            : 
     130                 :            :     /* Record extension size */
     131         [ +  + ]:      60223 :     POSIX_GUARD(s2n_stuffer_write_vector_size(&extension_size_bytes));
     132                 :            : 
     133                 :            :     /* Set request bit flag */
     134         [ +  + ]:      60222 :     if (!extension_type->is_response) {
     135                 :      45469 :         S2N_CBIT_SET(conn->extension_requests_sent, extension_id);
     136                 :      45469 :     }
     137                 :            : 
     138                 :      60222 :     return S2N_SUCCESS;
     139                 :      60223 : }
     140                 :            : 
     141                 :            : int s2n_extension_recv(const s2n_extension_type *extension_type, struct s2n_connection *conn, struct s2n_stuffer *in)
     142                 :      60063 : {
     143 [ +  + ][ +  - ]:      60063 :     POSIX_ENSURE_REF(extension_type);
     144 [ +  - ][ +  + ]:      60062 :     POSIX_ENSURE_REF(extension_type->recv);
     145 [ +  + ][ +  - ]:      60061 :     POSIX_ENSURE_REF(conn);
     146                 :            : 
     147                 :      60060 :     s2n_extension_type_id extension_id = 0;
     148         [ -  + ]:      60060 :     POSIX_GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id));
     149                 :            : 
     150                 :            :     /**
     151                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2
     152                 :            :      *# Implementations MUST NOT send extension responses if the remote
     153                 :            :      *# endpoint did not send the corresponding extension requests, with the
     154                 :            :      *# exception of the "cookie" extension in the HelloRetryRequest.  Upon
     155                 :            :      *# receiving such an extension, an endpoint MUST abort the handshake
     156                 :            :      *# with an "unsupported_extension" alert.
     157                 :            :      *
     158                 :            :      *= https://www.rfc-editor.org/rfc/rfc7627#section-5.3
     159                 :            :      *# If the original session did not use the "extended_master_secret"
     160                 :            :      *# extension but the new ServerHello contains the extension, the
     161                 :            :      *# client MUST abort the handshake.
     162                 :            :      *
     163                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#4.1.4
     164                 :            :      *# As with the ServerHello, a HelloRetryRequest MUST NOT contain any
     165                 :            :      *# extensions that were not first offered by the client in its
     166                 :            :      *# ClientHello, with the exception of optionally the "cookie" (see
     167                 :            :      *# Section 4.2.2) extension.
     168                 :            :      **/
     169 [ +  + ][ +  + ]:      60060 :     if (extension_type->is_response && !S2N_CBIT_TEST(conn->extension_requests_sent, extension_id)) {
     170         [ +  - ]:          1 :         POSIX_BAIL(S2N_ERR_UNSUPPORTED_EXTENSION);
     171                 :          1 :     }
     172                 :            : 
     173                 :            :     /* Do not process an extension not valid for the protocol version */
     174         [ +  + ]:      60059 :     if (extension_type->minimum_version > conn->actual_protocol_version) {
     175                 :        415 :         return S2N_SUCCESS;
     176                 :        415 :     }
     177                 :            : 
     178         [ +  + ]:      59644 :     POSIX_GUARD(extension_type->recv(conn, in));
     179                 :            : 
     180                 :            :     /* Set request bit flag */
     181         [ +  + ]:      59630 :     if (extension_type->is_response) {
     182                 :      14519 :         S2N_CBIT_SET(conn->extension_responses_received, extension_id);
     183                 :      45111 :     } else {
     184                 :      45111 :         S2N_CBIT_SET(conn->extension_requests_received, extension_id);
     185                 :      45111 :     }
     186                 :            : 
     187                 :      59630 :     return S2N_SUCCESS;
     188                 :      59644 : }
     189                 :            : 
     190                 :            : int s2n_extension_is_missing(const s2n_extension_type *extension_type, struct s2n_connection *conn)
     191                 :     162202 : {
     192 [ +  - ][ +  + ]:     162202 :     POSIX_ENSURE_REF(extension_type);
     193 [ +  - ][ +  + ]:     162201 :     POSIX_ENSURE_REF(extension_type->if_missing);
     194 [ +  - ][ +  + ]:     162199 :     POSIX_ENSURE_REF(conn);
     195                 :            : 
     196                 :     162197 :     s2n_extension_type_id extension_id = 0;
     197         [ -  + ]:     162197 :     POSIX_GUARD(s2n_extension_supported_iana_value_to_id(extension_type->iana_value, &extension_id));
     198                 :            : 
     199                 :            :     /* Do not consider an extension missing if we did not send a request */
     200 [ +  + ][ +  + ]:     162197 :     if (extension_type->is_response && !S2N_CBIT_TEST(conn->extension_requests_sent, extension_id)) {
     201                 :      53132 :         return S2N_SUCCESS;
     202                 :      53132 :     }
     203                 :            : 
     204                 :            :     /* Do not consider an extension missing if it is not valid for the protocol version */
     205         [ +  + ]:     109065 :     if (extension_type->minimum_version > conn->actual_protocol_version) {
     206                 :       9632 :         return S2N_SUCCESS;
     207                 :       9632 :     }
     208                 :            : 
     209         [ +  + ]:      99433 :     POSIX_GUARD(extension_type->if_missing(conn));
     210                 :            : 
     211                 :      99425 :     return S2N_SUCCESS;
     212                 :      99433 : }
     213                 :            : 
     214                 :            : int s2n_extension_send_unimplemented(struct s2n_connection *conn, struct s2n_stuffer *out)
     215                 :          2 : {
     216         [ +  - ]:          2 :     POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
     217                 :          2 : }
     218                 :            : 
     219                 :            : int s2n_extension_recv_unimplemented(struct s2n_connection *conn, struct s2n_stuffer *in)
     220                 :          3 : {
     221         [ +  - ]:          3 :     POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
     222                 :          3 : }
     223                 :            : 
     224                 :            : int s2n_extension_send_noop(struct s2n_connection *conn, struct s2n_stuffer *out)
     225                 :       9923 : {
     226                 :       9923 :     return S2N_SUCCESS;
     227                 :       9923 : }
     228                 :            : 
     229                 :            : int s2n_extension_recv_noop(struct s2n_connection *conn, struct s2n_stuffer *in)
     230                 :        844 : {
     231                 :        844 :     return S2N_SUCCESS;
     232                 :        844 : }
     233                 :            : 
     234                 :            : bool s2n_extension_always_send(struct s2n_connection *conn)
     235                 :      10759 : {
     236                 :      10759 :     return true;
     237                 :      10759 : }
     238                 :            : 
     239                 :            : bool s2n_extension_never_send(struct s2n_connection *conn)
     240                 :          2 : {
     241                 :          2 :     return false;
     242                 :          2 : }
     243                 :            : 
     244                 :            : bool s2n_extension_send_if_tls13_connection(struct s2n_connection *conn)
     245                 :      13119 : {
     246                 :      13119 :     return s2n_connection_get_protocol_version(conn) >= S2N_TLS13;
     247                 :      13119 : }
     248                 :            : 
     249                 :            : int s2n_extension_error_if_missing(struct s2n_connection *conn)
     250                 :          8 : {
     251         [ +  - ]:          8 :     POSIX_BAIL(S2N_ERR_MISSING_EXTENSION);
     252                 :          8 : }
     253                 :            : 
     254                 :            : int s2n_extension_noop_if_missing(struct s2n_connection *conn)
     255                 :      70906 : {
     256                 :      70906 :     return S2N_SUCCESS;
     257                 :      70906 : }

Generated by: LCOV version 1.14