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-08-14 07:26:07 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                 :     759331 : #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                 :        545 : {
      36                 :            :     /* Initialize to s2n_unsupported_extension */
      37         [ +  + ]:      33245 :     for (size_t i = 0; i < S2N_MAX_INDEXED_EXTENSION_IANA; i++) {
      38                 :      32700 :         s2n_extension_ianas_to_ids[i] = s2n_unsupported_extension;
      39                 :      32700 :     }
      40                 :            : 
      41                 :            :     /* Reverse the mapping */
      42         [ +  + ]:      11990 :     for (size_t i = 0; i < S2N_SUPPORTED_EXTENSIONS_COUNT; i++) {
      43                 :      11445 :         uint16_t iana_value = s2n_supported_extensions[i];
      44         [ +  + ]:      11445 :         if (iana_value < S2N_MAX_INDEXED_EXTENSION_IANA) {
      45                 :       9810 :             s2n_extension_ianas_to_ids[iana_value] = i;
      46                 :       9810 :         }
      47                 :      11445 :     }
      48                 :            : 
      49                 :        545 :     return S2N_SUCCESS;
      50                 :        545 : }
      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                 :     714641 : {
      57                 :            :     /* Check the lookup table */
      58         [ +  + ]:     714641 :     if (iana_value < S2N_MAX_INDEXED_EXTENSION_IANA) {
      59                 :     631166 :         return s2n_extension_ianas_to_ids[iana_value];
      60                 :     631166 :     }
      61                 :            : 
      62                 :            :     /* Fall back to the full list. We can handle this more
      63                 :            :      * efficiently later if our extension list gets long. */
      64         [ +  + ]:     670636 :     for (size_t i = 0; i < S2N_SUPPORTED_EXTENSIONS_COUNT; i++) {
      65         [ +  + ]:     670097 :         if (s2n_supported_extensions[i] == iana_value) {
      66                 :      82936 :             return i;
      67                 :      82936 :         }
      68                 :     670097 :     }
      69                 :            : 
      70                 :        539 :     return s2n_unsupported_extension;
      71                 :      83475 : }
      72                 :            : 
      73                 :            : int s2n_extension_supported_iana_value_to_id(const uint16_t iana_value, s2n_extension_type_id *internal_id)
      74                 :     714593 : {
      75 [ #  # ][ -  + ]:     714593 :     POSIX_ENSURE_REF(internal_id);
      76                 :            : 
      77                 :     714593 :     *internal_id = s2n_extension_iana_value_to_id(iana_value);
      78 [ +  + ][ +  - ]:     714593 :     S2N_ERROR_IF(*internal_id == s2n_unsupported_extension, S2N_ERR_UNRECOGNIZED_EXTENSION);
      79                 :     714014 :     return S2N_SUCCESS;
      80                 :     714593 : }
      81                 :            : 
      82                 :            : int s2n_extension_send(const s2n_extension_type *extension_type, struct s2n_connection *conn, struct s2n_stuffer *out)
      83                 :     215388 : {
      84 [ +  - ][ +  + ]:     215388 :     POSIX_ENSURE_REF(extension_type);
      85 [ +  - ][ +  + ]:     215387 :     POSIX_ENSURE_REF(extension_type->should_send);
      86 [ +  - ][ +  + ]:     215386 :     POSIX_ENSURE_REF(extension_type->send);
      87 [ +  + ][ +  - ]:     215385 :     POSIX_ENSURE_REF(conn);
      88                 :            : 
      89                 :     215384 :     s2n_extension_type_id extension_id = 0;
      90         [ -  + ]:     215384 :     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 [ +  + ][ +  + ]:     215384 :     if (extension_type->is_response && !S2N_CBIT_TEST(conn->extension_requests_received, extension_id)) {
      94                 :      52624 :         return S2N_SUCCESS;
      95                 :      52624 :     }
      96                 :            : 
      97                 :            :     /* Do not send an extension that is not valid for the protocol version */
      98         [ +  + ]:     162760 :     if (extension_type->minimum_version > conn->actual_protocol_version) {
      99                 :       8182 :         return S2N_SUCCESS;
     100                 :       8182 :     }
     101                 :            : 
     102                 :            :     /* Check if we need to send. Some extensions are only sent if specific conditions are met. */
     103         [ +  + ]:     154578 :     if (!extension_type->should_send(conn)) {
     104                 :      96586 :         return S2N_SUCCESS;
     105                 :      96586 :     }
     106                 :            : 
     107                 :            :     /* Write extension type */
     108         [ +  + ]:      57992 :     POSIX_GUARD(s2n_stuffer_write_uint16(out, extension_type->iana_value));
     109                 :            : 
     110                 :            :     /* Reserve space for extension size */
     111                 :      57989 :     struct s2n_stuffer_reservation extension_size_bytes = { 0 };
     112         [ -  + ]:      57989 :     POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &extension_size_bytes));
     113                 :            : 
     114                 :            :     /* Write extension data */
     115         [ +  + ]:      57989 :     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                 :      57984 :     out->tainted = false;
     129                 :            : 
     130                 :            :     /* Record extension size */
     131         [ +  + ]:      57984 :     POSIX_GUARD(s2n_stuffer_write_vector_size(&extension_size_bytes));
     132                 :            : 
     133                 :            :     /* Set request bit flag */
     134         [ +  + ]:      57983 :     if (!extension_type->is_response) {
     135                 :      43801 :         S2N_CBIT_SET(conn->extension_requests_sent, extension_id);
     136                 :      43801 :     }
     137                 :            : 
     138                 :      57983 :     return S2N_SUCCESS;
     139                 :      57984 : }
     140                 :            : 
     141                 :            : int s2n_extension_recv(const s2n_extension_type *extension_type, struct s2n_connection *conn, struct s2n_stuffer *in)
     142                 :      57824 : {
     143 [ +  + ][ +  - ]:      57824 :     POSIX_ENSURE_REF(extension_type);
     144 [ +  - ][ +  + ]:      57823 :     POSIX_ENSURE_REF(extension_type->recv);
     145 [ +  + ][ +  - ]:      57822 :     POSIX_ENSURE_REF(conn);
     146                 :            : 
     147                 :      57821 :     s2n_extension_type_id extension_id = 0;
     148         [ -  + ]:      57821 :     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 [ +  + ][ +  + ]:      57821 :     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         [ +  + ]:      57820 :     if (extension_type->minimum_version > conn->actual_protocol_version) {
     175                 :        415 :         return S2N_SUCCESS;
     176                 :        415 :     }
     177                 :            : 
     178         [ +  + ]:      57405 :     POSIX_GUARD(extension_type->recv(conn, in));
     179                 :            : 
     180                 :            :     /* Set request bit flag */
     181         [ +  + ]:      57391 :     if (extension_type->is_response) {
     182                 :      13948 :         S2N_CBIT_SET(conn->extension_responses_received, extension_id);
     183                 :      43443 :     } else {
     184                 :      43443 :         S2N_CBIT_SET(conn->extension_requests_received, extension_id);
     185                 :      43443 :     }
     186                 :            : 
     187                 :      57391 :     return S2N_SUCCESS;
     188                 :      57405 : }
     189                 :            : 
     190                 :            : int s2n_extension_is_missing(const s2n_extension_type *extension_type, struct s2n_connection *conn)
     191                 :     155995 : {
     192 [ +  - ][ +  + ]:     155995 :     POSIX_ENSURE_REF(extension_type);
     193 [ +  - ][ +  + ]:     155994 :     POSIX_ENSURE_REF(extension_type->if_missing);
     194 [ +  - ][ +  + ]:     155992 :     POSIX_ENSURE_REF(conn);
     195                 :            : 
     196                 :     155990 :     s2n_extension_type_id extension_id = 0;
     197         [ -  + ]:     155990 :     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 [ +  + ][ +  + ]:     155990 :     if (extension_type->is_response && !S2N_CBIT_TEST(conn->extension_requests_sent, extension_id)) {
     201                 :      50932 :         return S2N_SUCCESS;
     202                 :      50932 :     }
     203                 :            : 
     204                 :            :     /* Do not consider an extension missing if it is not valid for the protocol version */
     205         [ +  + ]:     105058 :     if (extension_type->minimum_version > conn->actual_protocol_version) {
     206                 :       9412 :         return S2N_SUCCESS;
     207                 :       9412 :     }
     208                 :            : 
     209         [ +  + ]:      95646 :     POSIX_GUARD(extension_type->if_missing(conn));
     210                 :            : 
     211                 :      95638 :     return S2N_SUCCESS;
     212                 :      95646 : }
     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                 :       9588 : {
     226                 :       9588 :     return S2N_SUCCESS;
     227                 :       9588 : }
     228                 :            : 
     229                 :            : int s2n_extension_recv_noop(struct s2n_connection *conn, struct s2n_stuffer *in)
     230                 :        790 : {
     231                 :        790 :     return S2N_SUCCESS;
     232                 :        790 : }
     233                 :            : 
     234                 :            : bool s2n_extension_always_send(struct s2n_connection *conn)
     235                 :      10288 : {
     236                 :      10288 :     return true;
     237                 :      10288 : }
     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                 :      12614 : {
     246                 :      12614 :     return s2n_connection_get_protocol_version(conn) >= S2N_TLS13;
     247                 :      12614 : }
     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                 :      68338 : {
     256                 :      68338 :     return S2N_SUCCESS;
     257                 :      68338 : }

Generated by: LCOV version 1.14