LCOV - code coverage report
Current view: top level - tls - s2n_record_read.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 110 112 98.2 %
Date: 2026-07-04 07:27:58 Functions: 6 6 100.0 %
Branches: 78 120 65.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/s2n_record_read.h"
      17                 :            : 
      18                 :            : #include "crypto/s2n_cipher.h"
      19                 :            : #include "crypto/s2n_hmac.h"
      20                 :            : #include "crypto/s2n_sequence.h"
      21                 :            : #include "error/s2n_errno.h"
      22                 :            : #include "stuffer/s2n_stuffer.h"
      23                 :            : #include "tls/s2n_cipher_suites.h"
      24                 :            : #include "tls/s2n_connection.h"
      25                 :            : #include "tls/s2n_crypto.h"
      26                 :            : #include "utils/s2n_blob.h"
      27                 :            : #include "utils/s2n_safety.h"
      28                 :            : 
      29                 :            : int s2n_sslv2_record_header_parse(
      30                 :            :         struct s2n_connection *conn,
      31                 :            :         uint8_t *record_type,
      32                 :            :         uint8_t *client_protocol_version,
      33                 :            :         uint16_t *fragment_length)
      34                 :        193 : {
      35                 :        193 :     struct s2n_stuffer *header_in = &conn->header_in;
      36                 :            : 
      37 [ #  # ][ -  + ]:        193 :     POSIX_ENSURE(s2n_stuffer_data_available(header_in) >= S2N_TLS_RECORD_HEADER_LENGTH,
      38                 :        193 :             S2N_ERR_BAD_MESSAGE);
      39                 :            : 
      40         [ -  + ]:        193 :     POSIX_GUARD(s2n_stuffer_read_uint16(header_in, fragment_length));
      41                 :            : 
      42                 :            :     /* The first bit of the SSLv2 message would usually indicate whether the
      43                 :            :      * length is 2 bytes long or 3 bytes long.
      44                 :            :      * See https://www.ietf.org/archive/id/draft-hickman-netscape-ssl-00.txt
      45                 :            :      *
      46                 :            :      * However, s2n-tls only supports SSLv2 for ClientHellos as defined in the
      47                 :            :      * TLS1.2 RFC. In that case, the first bit must always be set to distinguish
      48                 :            :      * SSLv2 from non-SSLv2 headers. The length is always 2 bytes.
      49                 :            :      * See https://datatracker.ietf.org/doc/html/rfc5246#appendix-E.2
      50                 :            :      *
      51                 :            :      * Since the first bit is not actually used to indicate length, we need to
      52                 :            :      * remove it from the length.
      53                 :            :      *
      54                 :            :      *= https://www.rfc-editor.org/rfc/rfc5246#appendix-E.2
      55                 :            :      *# msg_length
      56                 :            :      *#    The highest bit MUST be 1; the remaining bits contain the length
      57                 :            :      *#    of the following data in bytes.
      58                 :            :      */
      59 [ #  # ][ -  + ]:        193 :     POSIX_ENSURE(*fragment_length & S2N_TLS_SSLV2_HEADER_FLAG_UINT16, S2N_ERR_BAD_MESSAGE);
      60                 :        193 :     *fragment_length ^= S2N_TLS_SSLV2_HEADER_FLAG_UINT16;
      61                 :            : 
      62                 :            :     /* We read 5 bytes into header_in because we expected a standard, non-SSLv2 record header
      63                 :            :      * instead of an SSLv2 message. We have therefore already read 3 bytes of the payload.
      64                 :            :      * We need to adjust "fragment_length" to account for the bytes we have already
      65                 :            :      * read so that we will only attempt to read the remainder of the payload on
      66                 :            :      * our next call to conn->recv.
      67                 :            :      */
      68 [ +  + ][ +  - ]:        193 :     POSIX_ENSURE(*fragment_length >= s2n_stuffer_data_available(header_in), S2N_ERR_BAD_MESSAGE);
      69                 :        191 :     *fragment_length -= s2n_stuffer_data_available(header_in);
      70                 :            : 
      71                 :            :     /* By reading 5 bytes for a standard header we have also read the first
      72                 :            :      * 3 bytes of the SSLv2 ClientHello message.
      73                 :            :      * So we now need to parse those three bytes.
      74                 :            :      *
      75                 :            :      * The first field of an SSLv2 ClientHello is the msg_type.
      76                 :            :      * This is always '1', matching the ClientHello msg_type used by later
      77                 :            :      * handshake messages.
      78                 :            :      */
      79         [ -  + ]:        191 :     POSIX_GUARD(s2n_stuffer_read_uint8(header_in, record_type));
      80                 :            : 
      81                 :            :     /*
      82                 :            :      * The second field of an SSLv2 ClientHello is the version.
      83                 :            :      *
      84                 :            :      * The protocol version read here will likely not be SSLv2, since we only
      85                 :            :      * accept SSLv2 ClientHellos offering higher protocol versions.
      86                 :            :      * See s2n_sslv2_client_hello_parse.
      87                 :            :      */
      88                 :        191 :     uint8_t protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN] = { 0 };
      89         [ -  + ]:        191 :     POSIX_GUARD(s2n_stuffer_read_bytes(header_in, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN));
      90                 :        191 :     *client_protocol_version = (protocol_version[0] * 10) + protocol_version[1];
      91                 :            : 
      92         [ -  + ]:        191 :     POSIX_GUARD(s2n_stuffer_reread(header_in));
      93                 :        191 :     return 0;
      94                 :        191 : }
      95                 :            : 
      96                 :            : int s2n_record_header_parse(
      97                 :            :         struct s2n_connection *conn,
      98                 :            :         uint8_t *content_type,
      99                 :            :         uint16_t *fragment_length)
     100                 :    7323378 : {
     101                 :    7323378 :     struct s2n_stuffer *in = &conn->header_in;
     102                 :            : 
     103 [ -  + ][ #  # ]:    7323378 :     S2N_ERROR_IF(s2n_stuffer_data_available(in) < S2N_TLS_RECORD_HEADER_LENGTH, S2N_ERR_BAD_MESSAGE);
     104                 :            : 
     105         [ -  + ]:    7323378 :     POSIX_GUARD(s2n_stuffer_read_uint8(in, content_type));
     106                 :            : 
     107                 :    7323378 :     uint8_t protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN];
     108         [ -  + ]:    7323378 :     POSIX_GUARD(s2n_stuffer_read_bytes(in, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN));
     109                 :            : 
     110                 :    7323378 :     const uint8_t version = (protocol_version[0] * 10) + protocol_version[1];
     111                 :            :     /* We record the protocol version in the first record seen by the server for fingerprinting usecases */
     112         [ +  + ]:    7323378 :     if (!conn->client_hello.record_version_recorded) {
     113                 :    3307621 :         conn->client_hello.legacy_record_version = version;
     114                 :    3307621 :         conn->client_hello.record_version_recorded = 1;
     115                 :    3307621 :     }
     116                 :            : 
     117                 :            :     /* https://tools.ietf.org/html/rfc5246#appendix-E.1 states that servers must accept any value {03,XX} as the record
     118                 :            :      * layer version number for the first TLS record. There is some ambiguity here because the client does not know
     119                 :            :      * what version to use in the record header prior to receiving the ServerHello. Some client implementations may use
     120                 :            :      * a garbage value(not {03,XX}) in the ClientHello.
     121                 :            :      * Choose to be lenient to these clients. After protocol negotiation, we will enforce that all record versions
     122                 :            :      * match the negotiated version.
     123                 :            :      */
     124                 :            : 
     125 [ +  + ][ +  + ]:    7323378 :     S2N_ERROR_IF(conn->actual_protocol_version_established && S2N_MIN(conn->actual_protocol_version, S2N_TLS12) /* check against legacy record version (1.2) in tls 1.3 */
         [ +  + ][ +  - ]
     126                 :    7323378 :                             != version,
     127                 :    7323378 :             S2N_ERR_BAD_MESSAGE);
     128                 :            : 
     129                 :            :     /* Some servers send fragments that are above the maximum length (e.g.
     130                 :            :      * Openssl 1.0.1), so we don't check if the fragment length is >
     131                 :            :      * S2N_TLS_MAXIMUM_FRAGMENT_LENGTH. We allow up to 2^16.
     132                 :            :      *
     133                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-5.1
     134                 :            :      *= type=exception
     135                 :            :      *= reason=Incorrect implementations exist in the wild. Ignoring instead.
     136                 :            :      *# The length MUST NOT exceed 2^14 bytes.  An
     137                 :            :      *# endpoint that receives a record that exceeds this length MUST
     138                 :            :      *# terminate the connection with a "record_overflow" alert.
     139                 :            :      */
     140         [ -  + ]:    7323376 :     POSIX_GUARD(s2n_stuffer_read_uint16(in, fragment_length));
     141         [ -  + ]:    7323376 :     POSIX_GUARD(s2n_stuffer_reread(in));
     142                 :            : 
     143                 :    7323376 :     return 0;
     144                 :    7323376 : }
     145                 :            : 
     146                 :            : /* In TLS 1.3, handle CCS message as unprotected records all the time.
     147                 :            :  * https://tools.ietf.org/html/rfc8446#section-5
     148                 :            :  *
     149                 :            :  * In TLS 1.2 and TLS 1.3 Alert messages are plaintext or encrypted
     150                 :            :  * depending on the context of the connection. If we receive an encrypted
     151                 :            :  * alert, the record type is TLS_APPLICATION_DATA at this point. It will
     152                 :            :  * be decrypted and processed in s2n_handshake_io. We may receive a
     153                 :            :  * plaintext alert if we hit an error before the handshake completed
     154                 :            :  * (like a certificate failed to validate).
     155                 :            :  * https://tools.ietf.org/html/rfc8446#section-6
     156                 :            :  *
     157                 :            :  * This function is specific to TLS 1.3 to avoid changing the behavior
     158                 :            :  * of existing interpretation of TLS 1.2 alerts. */
     159                 :            : static bool s2n_is_tls13_plaintext_content(struct s2n_connection *conn, uint8_t content_type)
     160                 :    7224554 : {
     161 [ +  + ][ +  + ]:    7224554 :     return conn->actual_protocol_version == S2N_TLS13 && (content_type == TLS_ALERT || content_type == TLS_CHANGE_CIPHER_SPEC);
                 [ +  + ]
     162                 :    7224554 : }
     163                 :            : 
     164                 :            : int s2n_record_parse(struct s2n_connection *conn)
     165                 :    3612277 : {
     166                 :    3612277 :     uint8_t content_type = 0;
     167                 :    3612277 :     uint16_t encrypted_length = 0;
     168         [ -  + ]:    3612277 :     POSIX_GUARD(s2n_record_header_parse(conn, &content_type, &encrypted_length));
     169                 :            : 
     170                 :    3612277 :     struct s2n_crypto_parameters *current_client_crypto = conn->client;
     171                 :    3612277 :     struct s2n_crypto_parameters *current_server_crypto = conn->server;
     172         [ +  + ]:    3612277 :     if (s2n_is_tls13_plaintext_content(conn, content_type)) {
     173 [ -  + ][ #  # ]:      10167 :         POSIX_ENSURE_REF(conn->initial);
     174                 :      10167 :         conn->client = conn->initial;
     175                 :      10167 :         conn->server = conn->initial;
     176                 :      10167 :     }
     177                 :            : 
     178                 :    3612277 :     const struct s2n_cipher_suite *cipher_suite = conn->client->cipher_suite;
     179                 :    3612277 :     uint8_t *implicit_iv = conn->client->client_implicit_iv;
     180                 :    3612277 :     struct s2n_hmac_state *mac = &conn->client->client_record_mac;
     181                 :    3612277 :     uint8_t *sequence_number = conn->client->client_sequence_number;
     182                 :    3612277 :     struct s2n_session_key *session_key = &conn->client->client_key;
     183                 :            : 
     184         [ +  + ]:    3612277 :     if (conn->mode == S2N_CLIENT) {
     185                 :      94046 :         cipher_suite = conn->server->cipher_suite;
     186                 :      94046 :         implicit_iv = conn->server->server_implicit_iv;
     187                 :      94046 :         mac = &conn->server->server_record_mac;
     188                 :      94046 :         sequence_number = conn->server->server_sequence_number;
     189                 :      94046 :         session_key = &conn->server->server_key;
     190                 :      94046 :     }
     191                 :            : 
     192         [ +  + ]:    3612277 :     if (s2n_is_tls13_plaintext_content(conn, content_type)) {
     193                 :      10167 :         conn->client = current_client_crypto;
     194                 :      10167 :         conn->server = current_server_crypto;
     195                 :      10167 :     }
     196                 :            : 
     197                 :            :     /* The NULL stream cipher MUST NEVER be used for ApplicationData.
     198                 :            :      * If ApplicationData is unencrypted, we can't trust it. */
     199         [ +  + ]:    3612277 :     if (cipher_suite->record_alg->cipher == &s2n_null_cipher) {
     200 [ +  - ][ +  + ]:      76629 :         POSIX_ENSURE(content_type != TLS_APPLICATION_DATA, S2N_ERR_DECRYPT);
     201                 :      76629 :     }
     202                 :            : 
     203                 :    3611824 :     switch (cipher_suite->record_alg->cipher->type) {
     204         [ +  + ]:    3386224 :         case S2N_AEAD:
     205         [ +  + ]:    3386224 :             POSIX_GUARD(s2n_record_parse_aead(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key));
     206                 :     193682 :             break;
     207         [ +  + ]:     193682 :         case S2N_CBC:
     208         [ -  + ]:      41812 :             POSIX_GUARD(s2n_record_parse_cbc(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key));
     209                 :      41812 :             break;
     210         [ +  + ]:     107612 :         case S2N_COMPOSITE:
     211         [ -  + ]:     107612 :             POSIX_GUARD(s2n_record_parse_composite(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key));
     212                 :     107612 :             break;
     213         [ +  + ]:     107612 :         case S2N_STREAM:
     214         [ +  + ]:      76176 :             POSIX_GUARD(s2n_record_parse_stream(cipher_suite, conn, content_type, encrypted_length, implicit_iv, mac, sequence_number, session_key));
     215                 :      59998 :             break;
     216         [ -  + ]:      59998 :         default:
     217         [ #  # ]:          0 :             POSIX_BAIL(S2N_ERR_CIPHER_TYPE);
     218                 :          0 :             break;
     219                 :    3611824 :     }
     220                 :            : 
     221                 :     403104 :     return 0;
     222                 :    3611824 : }
     223                 :            : 
     224                 :            : int s2n_tls13_parse_record_type(struct s2n_stuffer *stuffer, uint8_t *record_type)
     225                 :      69200 : {
     226                 :      69200 :     uint32_t bytes_left = s2n_stuffer_data_available(stuffer);
     227                 :            : 
     228                 :            :     /* From rfc8446 Section 5.4
     229                 :            :      * The presence of padding does not change the overall record size
     230                 :            :      * limitations: the full encoded TLSInnerPlaintext MUST NOT exceed 2^14
     231                 :            :      * + 1 octets
     232                 :            :      *
     233                 :            :      * Certain versions of Java can generate inner plaintexts with lengths up to
     234                 :            :      * S2N_MAXIMUM_INNER_PLAINTEXT_LENGTH + 16 (See JDK-8221253)
     235                 :            :      * However, after the padding is stripped, the result will always be no more than
     236                 :            :      * S2N_MAXIMUM_INNER_PLAINTEXT_LENGTH - 1
     237                 :            :      */
     238 [ +  + ][ +  - ]:      69200 :     S2N_ERROR_IF(bytes_left > S2N_MAXIMUM_INNER_PLAINTEXT_LENGTH + 16, S2N_ERR_MAX_INNER_PLAINTEXT_SIZE);
     239                 :            : 
     240                 :            :     /* set cursor to the end of the stuffer */
     241         [ -  + ]:      69199 :     POSIX_GUARD(s2n_stuffer_skip_read(stuffer, bytes_left));
     242                 :            : 
     243                 :            :     /* Record type should have values greater than zero.
     244                 :            :      * If zero, treat as padding, keep reading and wiping from the back
     245                 :            :      * until a non-zero value is found
     246                 :            :      */
     247                 :      69199 :     *record_type = 0;
     248         [ +  + ]:     171215 :     while (*record_type == 0) {
     249                 :            :         /* back the cursor by one to read off the last byte */
     250         [ +  + ]:     102020 :         POSIX_GUARD(s2n_stuffer_rewind_read(stuffer, 1));
     251                 :            : 
     252                 :            :         /* set the record type */
     253         [ -  + ]:     102016 :         POSIX_GUARD(s2n_stuffer_read_uint8(stuffer, record_type));
     254                 :            : 
     255                 :            :         /* wipe the last byte at the end of the stuffer */
     256         [ -  + ]:     102016 :         POSIX_GUARD(s2n_stuffer_wipe_n(stuffer, 1));
     257                 :     102016 :     }
     258                 :            : 
     259                 :            :     /* only the original plaintext should remain */
     260                 :            :     /* now reset the read cursor at where it should be */
     261         [ -  + ]:      69195 :     POSIX_GUARD(s2n_stuffer_reread(stuffer));
     262                 :            : 
     263                 :            :     /* Even in the incorrect case above with up to 16 extra bytes, we should never see too much data after unpadding */
     264 [ +  + ][ +  - ]:      69195 :     S2N_ERROR_IF(s2n_stuffer_data_available(stuffer) > S2N_MAXIMUM_INNER_PLAINTEXT_LENGTH - 1, S2N_ERR_MAX_INNER_PLAINTEXT_SIZE);
     265                 :            : 
     266                 :      69194 :     return 0;
     267                 :      69195 : }
     268                 :            : 
     269                 :            : S2N_RESULT s2n_record_wipe(struct s2n_connection *conn)
     270                 :     239493 : {
     271 [ -  + ][ #  # ]:     239493 :     RESULT_ENSURE_REF(conn);
     272         [ -  + ]:     239493 :     RESULT_GUARD_POSIX(s2n_stuffer_wipe(&conn->header_in));
     273         [ -  + ]:     239493 :     RESULT_GUARD_POSIX(s2n_stuffer_wipe(&conn->in));
     274                 :     239493 :     conn->in_status = ENCRYPTED;
     275                 :            : 
     276                 :            :     /* Release the memory in conn->in, which un-taints buffer_in */
     277         [ -  + ]:     239493 :     RESULT_GUARD_POSIX(s2n_stuffer_free(&conn->in));
     278                 :     239493 :     conn->buffer_in.tainted = false;
     279                 :            : 
     280                 :            :     /* Reclaim any memory in buffer_in if possible.
     281                 :            :      * We want to avoid an expensive shift / copy later if possible.
     282                 :            :      */
     283         [ +  + ]:     239493 :     if (s2n_stuffer_is_consumed(&conn->buffer_in)) {
     284         [ -  + ]:     238997 :         RESULT_GUARD_POSIX(s2n_stuffer_rewrite(&conn->buffer_in));
     285                 :     238997 :     }
     286                 :     239493 :     return S2N_RESULT_OK;
     287                 :     239493 : }

Generated by: LCOV version 1.14