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

Generated by: LCOV version 1.14