LCOV - code coverage report
Current view: top level - tls - s2n_record_write.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 355 359 98.9 %
Date: 2026-08-22 07:27:53 Functions: 9 9 100.0 %
Branches: 250 424 59.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 <stdint.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 "tls/s2n_ktls.h"
      27                 :            : #include "tls/s2n_record.h"
      28                 :            : #include "utils/s2n_blob.h"
      29                 :            : #include "utils/s2n_random.h"
      30                 :            : #include "utils/s2n_safety.h"
      31                 :            : 
      32                 :            : extern uint8_t s2n_unknown_protocol_version;
      33                 :            : 
      34                 :            : /* In TLS1.3 the record type is obfuscated as APPLICATION_DATA once the handshake begins to be encrypted.
      35                 :            :  * The real record type is encrypted and written in the final byte of the record.
      36                 :            :  * In TLS1.2 the record type is always cleartext. */
      37                 :    3608542 : #define RECORD_TYPE(is_tls13_record, content_type) (is_tls13_record ? TLS_APPLICATION_DATA : content_type)
      38                 :            : 
      39                 :            : /* How much overhead does the IV, MAC, TAG and padding bytes introduce ? */
      40                 :            : static S2N_RESULT s2n_tls_record_overhead(struct s2n_connection *conn, uint16_t *out)
      41                 :    3608867 : {
      42 [ -  + ][ #  # ]:    3608867 :     RESULT_ENSURE_REF(conn);
      43 [ #  # ][ -  + ]:    3608867 :     RESULT_ENSURE_MUT(out);
      44                 :    3608867 :     struct s2n_crypto_parameters *active = conn->server;
      45                 :            : 
      46         [ +  + ]:    3608867 :     if (conn->mode == S2N_CLIENT) {
      47                 :      85374 :         active = conn->client;
      48                 :      85374 :     }
      49                 :            : 
      50                 :    3608867 :     uint8_t extra = 0;
      51         [ -  + ]:    3608867 :     RESULT_GUARD_POSIX(s2n_hmac_digest_size(active->cipher_suite->record_alg->hmac_alg, &extra));
      52                 :            : 
      53         [ +  + ]:    3608867 :     if (active->cipher_suite->record_alg->cipher->type == S2N_CBC) {
      54                 :            :         /* Subtract one for the padding length byte */
      55                 :      41818 :         extra += 1;
      56                 :            : 
      57         [ +  + ]:      41818 :         if (conn->actual_protocol_version > S2N_TLS10) {
      58                 :      32922 :             extra += active->cipher_suite->record_alg->cipher->io.cbc.record_iv_size;
      59                 :      32922 :         }
      60         [ +  + ]:    3567049 :     } else if (active->cipher_suite->record_alg->cipher->type == S2N_AEAD) {
      61                 :    3348013 :         extra += active->cipher_suite->record_alg->cipher->io.aead.tag_size;
      62                 :    3348013 :         extra += active->cipher_suite->record_alg->cipher->io.aead.record_iv_size;
      63 [ +  + ][ +  + ]:    3348013 :     } else if (active->cipher_suite->record_alg->cipher->type == S2N_COMPOSITE && conn->actual_protocol_version > S2N_TLS10) {
      64                 :     131169 :         extra += active->cipher_suite->record_alg->cipher->io.comp.record_iv_size;
      65                 :     131169 :     }
      66                 :            : 
      67                 :    3608867 :     *out = extra;
      68                 :            : 
      69                 :    3608867 :     return S2N_RESULT_OK;
      70                 :    3608867 : }
      71                 :            : 
      72                 :            : /* This function returns maximum size of plaintext data to write for the payload.
      73                 :            :  * Record overheads are not included here.
      74                 :            :  */
      75                 :            : S2N_RESULT s2n_record_max_write_payload_size(struct s2n_connection *conn, uint16_t *max_fragment_size)
      76                 :    3632706 : {
      77 [ -  + ][ #  # ]:    3632706 :     RESULT_ENSURE_REF(conn);
      78 [ #  # ][ -  + ]:    3632706 :     RESULT_ENSURE_REF(conn->config);
      79 [ #  # ][ -  + ]:    3632706 :     RESULT_ENSURE_MUT(max_fragment_size);
      80 [ +  + ][ +  - ]:    3632706 :     RESULT_ENSURE(conn->max_outgoing_fragment_length > 0, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL);
      81                 :            : 
      82         [ +  + ]:    3632705 :     *max_fragment_size = S2N_MIN(conn->max_outgoing_fragment_length, S2N_TLS_MAXIMUM_FRAGMENT_LENGTH);
      83                 :            : 
      84                 :            :     /* If a custom send buffer is configured, ensure it will be large enough for the payload.
      85                 :            :      * That may mean we need a smaller fragment size.
      86                 :            :      */
      87                 :    3632705 :     uint32_t send_buffer_override = conn->config->send_buffer_size_override;
      88         [ +  + ]:    3632705 :     if (send_buffer_override) {
      89                 :         70 :         uint16_t max_record_size = 0;
      90         [ -  + ]:         70 :         RESULT_GUARD(s2n_record_max_write_size(conn, *max_fragment_size, &max_record_size));
      91         [ +  + ]:         70 :         if (send_buffer_override < max_record_size) {
      92                 :         10 :             size_t overhead = (max_record_size - *max_fragment_size);
      93 [ -  + ][ #  # ]:         10 :             RESULT_ENSURE_GT(send_buffer_override, overhead);
      94                 :         10 :             *max_fragment_size = send_buffer_override - overhead;
      95                 :         10 :         }
      96                 :         70 :     }
      97                 :            : 
      98                 :    3632705 :     return S2N_RESULT_OK;
      99                 :    3632705 : }
     100                 :            : 
     101                 :            : S2N_RESULT s2n_record_max_write_size(struct s2n_connection *conn, uint16_t max_fragment_size, uint16_t *max_record_size)
     102                 :    3307871 : {
     103 [ +  + ][ +  - ]:    3307871 :     RESULT_ENSURE_REF(conn);
     104 [ +  + ][ +  - ]:    3307870 :     RESULT_ENSURE_MUT(max_record_size);
     105                 :            : 
     106         [ +  + ]:    3307869 :     if (!IS_NEGOTIATED(conn)) {
     107                 :    3300748 :         *max_record_size = S2N_TLS_MAX_RECORD_LEN_FOR(max_fragment_size);
     108         [ +  + ]:    3300748 :     } else if (conn->actual_protocol_version < S2N_TLS13) {
     109                 :       2394 :         *max_record_size = S2N_TLS12_MAX_RECORD_LEN_FOR(max_fragment_size);
     110                 :       4727 :     } else {
     111                 :       4727 :         *max_record_size = S2N_TLS13_MAX_RECORD_LEN_FOR(max_fragment_size);
     112                 :       4727 :     }
     113                 :    3307869 :     return S2N_RESULT_OK;
     114                 :    3307870 : }
     115                 :            : 
     116                 :            : /* Find the largest size that will fit within an ethernet frame for a "small" payload */
     117                 :            : S2N_RESULT s2n_record_min_write_payload_size(struct s2n_connection *conn, uint16_t *payload_size)
     118                 :        325 : {
     119 [ #  # ][ -  + ]:        325 :     RESULT_ENSURE_REF(conn);
     120 [ #  # ][ -  + ]:        325 :     RESULT_ENSURE_MUT(payload_size);
     121                 :            : 
     122                 :            :     /* remove ethernet, TCP/IP and TLS header overheads */
     123                 :            :     /* We pessimistically assume that it's an Ipv6 header (40 bytes) vs an Ipv4
     124                 :            :      * header (20 bytes) to avoid having to care about the IP protocol. */
     125                 :        325 :     const uint16_t min_outgoing_fragment_length = ETH_MTU - IP_V6_HEADER_LENGTH
     126                 :        325 :             - TCP_HEADER_LENGTH - TCP_OPTIONS_LENGTH - S2N_TLS_RECORD_HEADER_LENGTH;
     127                 :            : 
     128         [ #  # ]:        325 :     RESULT_ENSURE(min_outgoing_fragment_length <= S2N_TLS_MAXIMUM_FRAGMENT_LENGTH, S2N_ERR_FRAGMENT_LENGTH_TOO_LARGE);
     129                 :        325 :     uint16_t size = min_outgoing_fragment_length;
     130                 :            : 
     131         [ +  + ]:        325 :     const struct s2n_crypto_parameters *active = conn->mode == S2N_CLIENT ? conn->client : conn->server;
     132                 :            : 
     133                 :            :     /* Round the fragment size down to be block aligned */
     134         [ +  + ]:        325 :     if (active->cipher_suite->record_alg->cipher->type == S2N_CBC) {
     135                 :          1 :         size -= size % active->cipher_suite->record_alg->cipher->io.cbc.block_size;
     136         [ +  + ]:        324 :     } else if (active->cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) {
     137                 :          1 :         size -= size % active->cipher_suite->record_alg->cipher->io.comp.block_size;
     138                 :            :         /* Composite digest length */
     139                 :          1 :         size -= active->cipher_suite->record_alg->cipher->io.comp.mac_key_size;
     140                 :            :         /* Padding length byte */
     141                 :          1 :         size -= 1;
     142                 :          1 :     }
     143                 :            : 
     144                 :            :     /* If TLS1.3, remove content type */
     145         [ +  + ]:        325 :     if (conn->actual_protocol_version >= S2N_TLS13) {
     146 [ -  + ][ #  # ]:         68 :         RESULT_ENSURE(size > S2N_TLS_CONTENT_TYPE_LENGTH, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL);
     147                 :         68 :         size -= S2N_TLS_CONTENT_TYPE_LENGTH;
     148                 :         68 :     }
     149                 :            : 
     150                 :            :     /* subtract overheads of a TLS record */
     151                 :        325 :     uint16_t overhead = 0;
     152         [ -  + ]:        325 :     RESULT_GUARD(s2n_tls_record_overhead(conn, &overhead));
     153 [ -  + ][ #  # ]:        325 :     RESULT_ENSURE(size > overhead, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL);
     154                 :        325 :     size -= overhead;
     155                 :            : 
     156 [ -  + ][ #  # ]:        325 :     RESULT_ENSURE(size > 0, S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL);
     157 [ #  # ][ -  + ]:        325 :     RESULT_ENSURE(size <= ETH_MTU, S2N_ERR_FRAGMENT_LENGTH_TOO_LARGE);
     158                 :            : 
     159                 :        325 :     *payload_size = size;
     160                 :            : 
     161                 :        325 :     return S2N_RESULT_OK;
     162                 :        325 : }
     163                 :            : 
     164                 :            : /**
     165                 :            :  * Return the protocol version that should be written into the record header.
     166                 :            :  * 
     167                 :            :  * This is the IANA version type (u16), not the internal s2n version type (u8).
     168                 :            :  * 
     169                 :            :  * This may not be the actual protocol version that was negotiated. For example
     170                 :            :  * TLS 1.3 records treat the record header protocol as an "opaque" value pinned
     171                 :            :  * to TLS 1.2 (0x0303)
     172                 :            :  */
     173                 :            : S2N_RESULT s2n_record_protocol_version(struct s2n_connection *conn, uint8_t record_type, uint16_t *out)
     174                 :    3608542 : {
     175                 :    3608542 :     uint8_t record_protocol_version = conn->actual_protocol_version;
     176                 :            : 
     177                 :            :     /**
     178                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-5.1
     179                 :            :      *# This version value is historical, deriving from the use of 0x0301 for
     180                 :            :      *# TLS 1.0 and 0x0300 for SSL 3.0.  In order to maximize backward
     181                 :            :      *# compatibility, a record containing an initial ClientHello SHOULD have
     182                 :            :      *# version 0x0301 (reflecting TLS 1.0)
     183                 :            :      *
     184                 :            :      * We set actual_protocol_version early for clients, but we do not
     185                 :            :      * use that assumed value here in case we are talking to a legacy
     186                 :            :      * server that expects TLS1.0.
     187                 :            :      *
     188                 :            :      * Both TLS 1.3 early data and a deserialized connection will
     189                 :            :      * send data without the server_protocol_version being known. However,
     190                 :            :      * the record type would be set to APPLICATION_DATA in their cases
     191                 :            :      * so this check is avoided.
     192                 :            :      **/
     193         [ +  + ]:    3608542 :     if (conn->server_protocol_version == s2n_unknown_protocol_version
     194         [ +  + ]:    3608542 :             && record_type == TLS_HANDSHAKE) {
     195         [ +  + ]:       8336 :         record_protocol_version = S2N_MIN(record_protocol_version, S2N_TLS10);
     196                 :       8336 :     }
     197                 :            : 
     198                 :            :     /**
     199                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-5.1
     200                 :            :      *# legacy_record_version:  MUST be set to 0x0303 for all records
     201                 :            :      *#    generated by a TLS 1.3 implementation other than an initial
     202                 :            :      *#    ClientHello (i.e., one not generated after a HelloRetryRequest),
     203                 :            :      *#    where it MAY also be 0x0301 for compatibility purposes.
     204                 :            :      **/
     205         [ +  + ]:    3608542 :     record_protocol_version = S2N_MIN(record_protocol_version, S2N_TLS12);
     206                 :            : 
     207                 :            :     /* Never send an empty protocol version.
     208                 :            :      * If the protocol version is unknown, default to TLS1.0 like we do for initial ClientHellos.
     209                 :            :      */
     210         [ +  + ]:    3608542 :     if (record_protocol_version == s2n_unknown_protocol_version) {
     211                 :         18 :         record_protocol_version = S2N_TLS10;
     212                 :         18 :     }
     213                 :            : 
     214                 :    3608542 :     uint16_t major_version = record_protocol_version / 10;
     215                 :    3608542 :     uint16_t minor_version = record_protocol_version % 10;
     216                 :    3608542 :     *out = (major_version << 8) | minor_version;
     217                 :            : 
     218                 :    3608542 :     return S2N_RESULT_OK;
     219                 :    3608542 : }
     220                 :            : 
     221                 :            : static inline int s2n_record_encrypt(
     222                 :            :         struct s2n_connection *conn,
     223                 :            :         const struct s2n_cipher_suite *cipher_suite,
     224                 :            :         struct s2n_session_key *session_key,
     225                 :            :         struct s2n_blob *iv,
     226                 :            :         struct s2n_blob *aad,
     227                 :            :         struct s2n_blob *en,
     228                 :            :         uint8_t *implicit_iv, uint16_t block_size)
     229                 :    3608541 : {
     230 [ #  # ][ -  + ]:    3608541 :     POSIX_ENSURE_REF(en->data);
     231                 :            : 
     232                 :    3608541 :     switch (cipher_suite->record_alg->cipher->type) {
     233         [ +  + ]:      55048 :         case S2N_STREAM:
     234         [ -  + ]:      55048 :             POSIX_GUARD(cipher_suite->record_alg->cipher->io.stream.encrypt(session_key, en, en));
     235                 :      55048 :             break;
     236         [ +  + ]:      55048 :         case S2N_CBC:
     237         [ -  + ]:      41817 :             POSIX_GUARD(cipher_suite->record_alg->cipher->io.cbc.encrypt(session_key, iv, en, en));
     238                 :            : 
     239                 :            :             /* Copy the last encrypted block to be the next IV */
     240         [ +  + ]:      41817 :             if (conn->actual_protocol_version < S2N_TLS11) {
     241 [ -  + ][ #  # ]:       8896 :                 POSIX_ENSURE_GTE(en->size, block_size);
     242 [ -  + ][ #  # ]:       8896 :                 POSIX_CHECKED_MEMCPY(implicit_iv, en->data + en->size - block_size, block_size);
                 [ +  - ]
     243                 :       8896 :             }
     244                 :      41817 :             break;
     245         [ +  + ]:    3347691 :         case S2N_AEAD:
     246         [ -  + ]:    3347691 :             POSIX_GUARD(cipher_suite->record_alg->cipher->io.aead.encrypt(session_key, iv, aad, en, en));
     247                 :    3347691 :             break;
     248         [ +  + ]:    3347691 :         case S2N_COMPOSITE:
     249                 :            :             /* This will: compute mac, append padding, append padding length, and encrypt */
     250         [ -  + ]:     163985 :             POSIX_GUARD(cipher_suite->record_alg->cipher->io.comp.encrypt(session_key, iv, en, en));
     251                 :            : 
     252                 :            :             /* Copy the last encrypted block to be the next IV */
     253 [ #  # ][ -  + ]:     163985 :             POSIX_ENSURE_GTE(en->size, block_size);
     254 [ -  + ][ #  # ]:     163985 :             POSIX_CHECKED_MEMCPY(implicit_iv, en->data + en->size - block_size, block_size);
                 [ +  - ]
     255                 :     163985 :             break;
     256         [ -  + ]:     163985 :         default:
     257         [ #  # ]:          0 :             POSIX_BAIL(S2N_ERR_CIPHER_TYPE);
     258                 :          0 :             break;
     259                 :    3608541 :     }
     260                 :            : 
     261                 :    3608541 :     return 0;
     262                 :    3608541 : }
     263                 :            : 
     264                 :            : static S2N_RESULT s2n_record_write_mac(struct s2n_connection *conn, struct s2n_blob *record_header,
     265                 :            :         struct s2n_blob *plaintext, struct s2n_stuffer *out, uint32_t *bytes_written)
     266                 :    3608542 : {
     267 [ -  + ][ #  # ]:    3608542 :     RESULT_ENSURE_REF(conn);
     268 [ #  # ][ -  + ]:    3608542 :     RESULT_ENSURE_REF(conn->server);
     269 [ -  + ][ #  # ]:    3608542 :     RESULT_ENSURE_REF(conn->client);
     270 [ -  + ][ #  # ]:    3608542 :     RESULT_ENSURE_REF(record_header);
     271 [ -  + ][ #  # ]:    3608542 :     RESULT_ENSURE_REF(plaintext);
     272 [ -  + ][ #  # ]:    3608542 :     RESULT_ENSURE_REF(out);
     273 [ #  # ][ -  + ]:    3608542 :     RESULT_ENSURE_REF(bytes_written);
     274                 :    3608542 :     *bytes_written = 0;
     275                 :            : 
     276                 :    3608542 :     struct s2n_hmac_state *mac = &conn->server->server_record_mac;
     277                 :    3608542 :     const struct s2n_cipher_suite *cipher_suite = conn->server->cipher_suite;
     278                 :    3608542 :     uint8_t *sequence_number = conn->server->server_sequence_number;
     279                 :            : 
     280         [ +  + ]:    3608542 :     if (conn->mode == S2N_CLIENT) {
     281                 :      85056 :         mac = &conn->client->client_record_mac;
     282                 :      85056 :         cipher_suite = conn->client->cipher_suite;
     283                 :      85056 :         sequence_number = conn->client->client_sequence_number;
     284                 :      85056 :     }
     285                 :            : 
     286 [ -  + ][ #  # ]:    3608542 :     RESULT_ENSURE_REF(cipher_suite);
     287 [ -  + ][ #  # ]:    3608542 :     RESULT_ENSURE_REF(cipher_suite->record_alg);
     288                 :            : 
     289         [ +  + ]:    3608542 :     if (cipher_suite->record_alg->hmac_alg == S2N_HMAC_NONE) {
     290                 :            :         /* If the S2N_HMAC_NONE algorithm is specified, a MAC should not be explicitly written.
     291                 :            :          * This is the case for AEAD and Composite cipher types, where the MAC is written as part
     292                 :            :          * of encryption. This is also the case for plaintext handshake records, where the null
     293                 :            :          * stream cipher is used.
     294                 :            :          */
     295                 :    3558634 :         return S2N_RESULT_OK;
     296                 :    3558634 :     }
     297                 :            : 
     298                 :            :     /**
     299                 :            :      *= https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1
     300                 :            :      *# The MAC is generated as:
     301                 :            :      *#
     302                 :            :      *#    MAC(MAC_write_key, seq_num +
     303                 :            :      */
     304         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_hmac_update(mac, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN));
     305                 :            : 
     306                 :      49908 :     struct s2n_stuffer header_stuffer = { 0 };
     307         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_stuffer_init_written(&header_stuffer, record_header));
     308                 :            : 
     309                 :            :     /**
     310                 :            :      *= https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1
     311                 :            :      *#     TLSCompressed.type +
     312                 :            :      */
     313                 :      49908 :     void *record_type_byte = s2n_stuffer_raw_read(&header_stuffer, sizeof(uint8_t));
     314 [ #  # ][ -  + ]:      49908 :     RESULT_ENSURE_REF(record_type_byte);
     315         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_hmac_update(mac, record_type_byte, sizeof(uint8_t)));
     316                 :            : 
     317                 :            :     /**
     318                 :            :      *= https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1
     319                 :            :      *#     TLSCompressed.version +
     320                 :            :      */
     321                 :      49908 :     void *protocol_version_bytes = s2n_stuffer_raw_read(&header_stuffer, S2N_TLS_PROTOCOL_VERSION_LEN);
     322 [ -  + ][ #  # ]:      49908 :     RESULT_ENSURE_REF(protocol_version_bytes);
     323         [ +  + ]:      49908 :     if (conn->actual_protocol_version > S2N_SSLv3) {
     324                 :            :         /* SSLv3 doesn't include the protocol version in the MAC. */
     325         [ -  + ]:      49242 :         RESULT_GUARD_POSIX(s2n_hmac_update(mac, protocol_version_bytes, S2N_TLS_PROTOCOL_VERSION_LEN));
     326                 :      49242 :     }
     327                 :            : 
     328                 :            :     /**
     329                 :            :      *= https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1
     330                 :            :      *#     TLSCompressed.length +
     331                 :            :      *
     332                 :            :      * Note that the length field refers to the length of the plaintext content, not the length of
     333                 :            :      * TLSCiphertext fragment written to the record header, which accounts for additional fields
     334                 :            :      * such as the padding and MAC.
     335                 :            :      */
     336                 :      49908 :     uint8_t content_length_bytes[sizeof(uint16_t)] = { 0 };
     337                 :      49908 :     struct s2n_blob content_length_blob = { 0 };
     338         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_blob_init(&content_length_blob, content_length_bytes, sizeof(content_length_bytes)));
     339                 :      49908 :     struct s2n_stuffer content_length_stuffer = { 0 };
     340         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&content_length_stuffer, &content_length_blob));
     341         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_stuffer_write_uint16(&content_length_stuffer, plaintext->size));
     342         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_hmac_update(mac, content_length_bytes, sizeof(content_length_bytes)));
     343                 :            : 
     344                 :            :     /**
     345                 :            :      *= https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1
     346                 :            :      *#     TLSCompressed.fragment);
     347                 :            :      *#
     348                 :            :      *# where "+" denotes concatenation.
     349                 :            :      */
     350         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_hmac_update(mac, plaintext->data, plaintext->size));
     351                 :            : 
     352                 :      49908 :     uint8_t mac_digest_size = 0;
     353         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_hmac_digest_size(mac->alg, &mac_digest_size));
     354                 :      49908 :     uint8_t *digest = s2n_stuffer_raw_write(out, mac_digest_size);
     355 [ -  + ][ #  # ]:      49908 :     RESULT_ENSURE_REF(digest);
     356         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_hmac_digest(mac, digest, mac_digest_size));
     357                 :      49908 :     *bytes_written = mac_digest_size;
     358                 :            : 
     359         [ -  + ]:      49908 :     RESULT_GUARD_POSIX(s2n_hmac_reset(mac));
     360                 :            : 
     361                 :      49908 :     return S2N_RESULT_OK;
     362                 :      49908 : }
     363                 :            : 
     364                 :            : int s2n_record_writev(struct s2n_connection *conn, uint8_t content_type, const struct iovec *in, int in_count, size_t offs, size_t to_write)
     365                 :    3608552 : {
     366         [ +  + ]:    3608552 :     if (conn->ktls_send_enabled) {
     367                 :          8 :         return s2n_ktls_record_writev(conn, content_type, in, in_count, offs, to_write);
     368                 :          8 :     }
     369                 :            : 
     370                 :    3608544 :     struct s2n_blob iv = { 0 };
     371                 :    3608544 :     uint8_t padding = 0;
     372                 :    3608544 :     uint16_t block_size = 0;
     373                 :    3608544 :     uint8_t aad_iv[S2N_TLS_MAX_IV_LEN] = { 0 };
     374                 :            : 
     375                 :            :     /* In TLS 1.3, handle CCS message as unprotected records */
     376                 :    3608544 :     struct s2n_crypto_parameters *current_client_crypto = conn->client;
     377                 :    3608544 :     struct s2n_crypto_parameters *current_server_crypto = conn->server;
     378 [ +  + ][ +  + ]:    3608544 :     if (conn->actual_protocol_version == S2N_TLS13 && content_type == TLS_CHANGE_CIPHER_SPEC) {
     379 [ #  # ][ -  + ]:       7859 :         POSIX_ENSURE_REF(conn->initial);
     380                 :       7859 :         conn->client = conn->initial;
     381                 :       7859 :         conn->server = conn->initial;
     382                 :       7859 :     }
     383                 :            : 
     384                 :    3608544 :     uint8_t *sequence_number = conn->server->server_sequence_number;
     385                 :    3608544 :     struct s2n_session_key *session_key = &conn->server->server_key;
     386                 :    3608544 :     const struct s2n_cipher_suite *cipher_suite = conn->server->cipher_suite;
     387                 :    3608544 :     uint8_t *implicit_iv = conn->server->server_implicit_iv;
     388                 :            : 
     389         [ +  + ]:    3608544 :     if (conn->mode == S2N_CLIENT) {
     390                 :      85056 :         sequence_number = conn->client->client_sequence_number;
     391                 :      85056 :         session_key = &conn->client->client_key;
     392                 :      85056 :         cipher_suite = conn->client->cipher_suite;
     393                 :      85056 :         implicit_iv = conn->client->client_implicit_iv;
     394                 :      85056 :     }
     395                 :            : 
     396                 :            :     /* The NULL stream cipher MUST NEVER be used for ApplicationData.
     397                 :            :      * Writing ApplicationData unencrypted defeats the purpose of TLS. */
     398         [ +  + ]:    3608544 :     if (cipher_suite->record_alg->cipher == &s2n_null_cipher) {
     399 [ +  - ][ +  + ]:      55050 :         POSIX_ENSURE(content_type != TLS_APPLICATION_DATA, S2N_ERR_ENCRYPT);
     400                 :      55050 :     }
     401                 :            : 
     402                 :    3608543 :     const int is_tls13_record = cipher_suite->record_alg->flags & S2N_TLS13_RECORD_AEAD_NONCE;
     403 [ -  + ][ #  # ]:    3608543 :     s2n_stack_blob(aad, is_tls13_record ? S2N_TLS13_AAD_LEN : S2N_TLS_MAX_AAD_LEN, S2N_TLS_MAX_AAD_LEN);
         [ -  + ][ +  + ]
     404                 :            : 
     405                 :            :     /* If we aren't buffering multiple records, then the output stuffer should be empty. */
     406         [ +  + ]:    3608543 :     if (!conn->multirecord_send) {
     407 [ +  + ][ +  - ]:    3608513 :         POSIX_ENSURE(s2n_stuffer_data_available(&conn->out) == 0, S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
     408                 :    3608513 :     }
     409                 :            : 
     410                 :            :     /* Before we do anything, we need to figure out what the length of the
     411                 :            :      * fragment is going to be.
     412                 :            :      */
     413                 :    3608542 :     uint16_t max_write_payload_size = 0;
     414         [ -  + ]:    3608542 :     POSIX_GUARD_RESULT(s2n_record_max_write_payload_size(conn, &max_write_payload_size));
     415         [ +  + ]:    3608542 :     const uint16_t data_bytes_to_take = S2N_MIN(to_write, max_write_payload_size);
     416                 :            : 
     417                 :    3608542 :     uint16_t extra = 0;
     418         [ -  + ]:    3608542 :     POSIX_GUARD_RESULT(s2n_tls_record_overhead(conn, &extra));
     419                 :            : 
     420                 :            :     /* If we have padding to worry about, figure that out too */
     421         [ +  + ]:    3608542 :     if (cipher_suite->record_alg->cipher->type == S2N_CBC) {
     422                 :      41817 :         block_size = cipher_suite->record_alg->cipher->io.cbc.block_size;
     423         [ +  + ]:      41817 :         if (((data_bytes_to_take + extra) % block_size)) {
     424                 :      38764 :             padding = block_size - ((data_bytes_to_take + extra) % block_size);
     425                 :      38764 :         }
     426         [ +  + ]:    3566725 :     } else if (cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) {
     427                 :     163985 :         block_size = cipher_suite->record_alg->cipher->io.comp.block_size;
     428                 :     163985 :     }
     429                 :            : 
     430         [ +  + ]:    3608542 :     if (s2n_stuffer_is_freed(&conn->out)) {
     431                 :            :         /* If the output buffer has not been allocated yet, allocate
     432                 :            :          * at least enough memory to hold a record with the local maximum fragment length.
     433                 :            :          *
     434                 :            :          * The local maximum fragment length is:
     435                 :            :          * 1) The local default configured for new connections
     436                 :            :          * 2) The local value set by the user via s2n_connection_prefer_throughput()
     437                 :            :          *    or s2n_connection_prefer_low_latency()
     438                 :            :          * 3) On the server, the minimum of the local value and the value negotiated with the
     439                 :            :          *    client via the max_fragment_length extension
     440                 :            :          *
     441                 :            :          * Because this only occurs if the output buffer has not been allocated,
     442                 :            :          * it does NOT resize existing buffers.
     443                 :            :          */
     444                 :    3307383 :         uint16_t max_wire_record_size = 0;
     445         [ -  + ]:    3307383 :         POSIX_GUARD_RESULT(s2n_record_max_write_size(conn, max_write_payload_size, &max_wire_record_size));
     446                 :            : 
     447         [ +  + ]:    3307383 :         uint32_t buffer_size = S2N_MAX(conn->config->send_buffer_size_override, max_wire_record_size);
     448         [ -  + ]:    3307383 :         POSIX_GUARD(s2n_stuffer_growable_alloc(&conn->out, buffer_size));
     449                 :    3307383 :     }
     450                 :            : 
     451                 :            :     /* A record only local stuffer used to avoid tainting the conn->out stuffer or overwriting
     452                 :            :      * previous records. It should be used to add an individual record to the out stuffer.
     453                 :            :      */
     454                 :    3608542 :     struct s2n_blob record_blob = { 0 };
     455                 :    3608542 :     struct s2n_stuffer record_stuffer = { 0 };
     456         [ -  + ]:    3608542 :     POSIX_GUARD(s2n_blob_init(&record_blob,
     457                 :    3608542 :             conn->out.blob.data + conn->out.write_cursor,
     458                 :    3608542 :             s2n_stuffer_space_remaining(&conn->out)));
     459         [ -  + ]:    3608542 :     POSIX_GUARD(s2n_stuffer_init(&record_stuffer, &record_blob));
     460                 :            : 
     461                 :            :     /* Now that we know the length, start writing the record */
     462         [ +  + ]:    3608542 :     uint8_t record_type = RECORD_TYPE(is_tls13_record, content_type);
     463         [ -  + ]:    3608542 :     POSIX_GUARD(s2n_stuffer_write_uint8(&record_stuffer, record_type));
     464                 :    3608542 :     uint16_t wire_protocol_version = 0;
     465         [ -  + ]:    3608542 :     POSIX_GUARD_RESULT(s2n_record_protocol_version(conn, record_type, &wire_protocol_version));
     466         [ -  + ]:    3608542 :     POSIX_GUARD(s2n_stuffer_write_uint16(&record_stuffer, wire_protocol_version));
     467                 :            : 
     468                 :            :     /* Compute non-payload parts of the MAC(seq num, type, proto vers, fragment length) for composite ciphers.
     469                 :            :      * Composite "encrypt" will MAC the payload data and fill in padding.
     470                 :            :      */
     471         [ +  + ]:    3608542 :     if (cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) {
     472                 :            :         /* Only fragment length is needed for MAC, but the EVP ctrl function needs fragment length + eiv len. */
     473                 :     163985 :         uint16_t payload_and_eiv_len = data_bytes_to_take;
     474         [ +  + ]:     163985 :         if (conn->actual_protocol_version > S2N_TLS10) {
     475                 :     131168 :             payload_and_eiv_len += block_size;
     476                 :     131168 :         }
     477                 :            : 
     478                 :            :         /* Outputs number of extra bytes required for MAC and padding */
     479                 :     163985 :         int pad_and_mac_len = 0;
     480         [ -  + ]:     163985 :         POSIX_GUARD(cipher_suite->record_alg->cipher->io.comp.initial_hmac(session_key, sequence_number, content_type, wire_protocol_version,
     481                 :     163985 :                 payload_and_eiv_len, &pad_and_mac_len));
     482                 :     163985 :         extra += pad_and_mac_len;
     483                 :     163985 :     }
     484                 :            : 
     485                 :            :     /* TLS 1.3 protected record occupies one extra byte for content type */
     486         [ +  + ]:    3608542 :     if (is_tls13_record) {
     487                 :     111360 :         extra += S2N_TLS_CONTENT_TYPE_LENGTH;
     488                 :     111360 :     }
     489                 :            : 
     490                 :            :     /* Rewrite the length to be the actual fragment length */
     491                 :    3608542 :     const uint16_t actual_fragment_length = data_bytes_to_take + padding + extra;
     492                 :            :     /* ensure actual_fragment_length + S2N_TLS_RECORD_HEADER_LENGTH <= max record length */
     493         [ +  + ]:    3608542 :     const uint16_t max_record_length = is_tls13_record ? S2N_TLS13_MAXIMUM_RECORD_LENGTH : S2N_TLS_MAXIMUM_RECORD_LENGTH;
     494 [ -  + ][ #  # ]:    3608542 :     S2N_ERROR_IF(actual_fragment_length + S2N_TLS_RECORD_HEADER_LENGTH > max_record_length, S2N_ERR_RECORD_LENGTH_TOO_LARGE);
     495         [ -  + ]:    3608542 :     POSIX_GUARD(s2n_stuffer_write_uint16(&record_stuffer, actual_fragment_length));
     496                 :            : 
     497                 :            :     /* If we're AEAD, write the sequence number as an IV, and generate the AAD */
     498         [ +  + ]:    3608542 :     if (cipher_suite->record_alg->cipher->type == S2N_AEAD) {
     499                 :    3347691 :         struct s2n_stuffer iv_stuffer = { 0 };
     500         [ -  + ]:    3347691 :         POSIX_GUARD(s2n_blob_init(&iv, aad_iv, sizeof(aad_iv)));
     501         [ -  + ]:    3347691 :         POSIX_GUARD(s2n_stuffer_init(&iv_stuffer, &iv));
     502                 :            : 
     503         [ +  + ]:    3347691 :         if (cipher_suite->record_alg->flags & S2N_TLS12_AES_GCM_AEAD_NONCE) {
     504                 :            :             /* Partially explicit nonce. See RFC 5288 Section 3 */
     505         [ -  + ]:    2178487 :             POSIX_GUARD(s2n_stuffer_write_bytes(&record_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN));
     506         [ -  + ]:    2178487 :             POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, implicit_iv, cipher_suite->record_alg->cipher->io.aead.fixed_iv_size));
     507         [ -  + ]:    2178487 :             POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN));
     508 [ +  + ][ +  - ]:    2178487 :         } else if (cipher_suite->record_alg->flags & S2N_TLS12_CHACHA_POLY_AEAD_NONCE || is_tls13_record) {
     509                 :            :             /* Fully implicit nonce. See RFC7905 Section 2 */
     510                 :    1169204 :             uint8_t four_zeroes[4] = { 0 };
     511         [ -  + ]:    1169204 :             POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, four_zeroes, 4));
     512         [ -  + ]:    1169204 :             POSIX_GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN));
     513         [ +  + ]:   15199652 :             for (int i = 0; i < cipher_suite->record_alg->cipher->io.aead.fixed_iv_size; i++) {
     514                 :   14030448 :                 aad_iv[i] = aad_iv[i] ^ implicit_iv[i];
     515                 :   14030448 :             }
     516                 :    1169204 :         } else {
     517         [ #  # ]:          0 :             POSIX_BAIL(S2N_ERR_INVALID_NONCE_TYPE);
     518                 :          0 :         }
     519                 :            : 
     520                 :            :         /* Set the IV size to the amount of data written */
     521                 :    3347691 :         iv.size = s2n_stuffer_data_available(&iv_stuffer);
     522         [ +  + ]:    3347691 :         if (is_tls13_record) {
     523                 :     111360 :             struct s2n_record_header header = {
     524                 :     111360 :                 .content_type = TLS_APPLICATION_DATA,
     525                 :     111360 :                 .version = 0x0303,
     526                 :     111360 :                 .length = data_bytes_to_take + S2N_TLS_CONTENT_TYPE_LENGTH + cipher_suite->record_alg->cipher->io.aead.tag_size
     527                 :     111360 :             };
     528         [ -  + ]:     111360 :             POSIX_GUARD_RESULT(s2n_tls13_aead_aad_init(&header, &aad));
     529                 :    3236331 :         } else {
     530         [ -  + ]:    3236331 :             POSIX_GUARD_RESULT(s2n_aead_aad_init(conn, sequence_number, content_type, data_bytes_to_take, &aad));
     531                 :    3236331 :         }
     532 [ +  + ][ +  + ]:    3347691 :     } else if (cipher_suite->record_alg->cipher->type == S2N_CBC || cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) {
     533         [ -  + ]:     205802 :         POSIX_GUARD(s2n_blob_init(&iv, implicit_iv, block_size));
     534                 :            : 
     535                 :            :         /* For TLS1.1/1.2; write the IV with random data */
     536         [ +  + ]:     205802 :         if (conn->actual_protocol_version > S2N_TLS10) {
     537         [ -  + ]:     164089 :             POSIX_GUARD_RESULT(s2n_get_public_random_data(&iv));
     538         [ +  + ]:     164089 :             if (cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) {
     539                 :            :                 /* Write a separate random block to the record. This will be used along with the previously generated
     540                 :            :                  * iv blob to generate the final explicit_iv for this record.
     541                 :            :                  *
     542                 :            :                  * How? Openssl's AES-CBC stitched encrypt populates the first block of application data with:
     543                 :            :                  * AES(Key, XOR(iv, initial_block))
     544                 :            :                  *
     545                 :            :                  * If we make initial_block a random block unrelated to random_iv, explicit IV for this record
     546                 :            :                  * is random value based on the two random blobs we just generated:
     547                 :            :                  * AES(Key, XOR(random_iv, explicit_iv_placeholder) == AES(Key, XOR(random_iv, random_iv2))
     548                 :            :                  *
     549                 :            :                  * NOTE: We can't use the same random IV blob as both the initial block and IV since it will result in:
     550                 :            :                  * AES(Key, XOR(random_iv, random_iv)) == AES(Key, 0), which will be shared by all records in this session.
     551                 :            :                  */
     552                 :     131168 :                 struct s2n_blob explicit_iv_placeholder = { 0 };
     553                 :     131168 :                 uint8_t zero_block[S2N_TLS_MAX_IV_LEN] = { 0 };
     554         [ -  + ]:     131168 :                 POSIX_GUARD(s2n_blob_init(&explicit_iv_placeholder, zero_block, block_size));
     555         [ -  + ]:     131168 :                 POSIX_GUARD_RESULT(s2n_get_public_random_data(&explicit_iv_placeholder));
     556         [ -  + ]:     131168 :                 POSIX_GUARD(s2n_stuffer_write(&record_stuffer, &explicit_iv_placeholder));
     557                 :     131168 :             } else {
     558                 :            :                 /* We can write the explicit IV directly to the record for non composite CBC because
     559                 :            :                  * s2n starts AES *after* the explicit IV.
     560                 :            :                  */
     561         [ -  + ]:      32921 :                 POSIX_GUARD(s2n_stuffer_write(&record_stuffer, &iv));
     562                 :      32921 :             }
     563                 :     164089 :         }
     564                 :     205802 :     }
     565                 :            : 
     566                 :            :     /* Write the plaintext data */
     567         [ -  + ]:    3608542 :     POSIX_GUARD(s2n_stuffer_writev_bytes(&record_stuffer, in, in_count, offs, data_bytes_to_take));
     568                 :    3608542 :     void *orig_write_ptr = record_stuffer.blob.data + record_stuffer.write_cursor - data_bytes_to_take;
     569                 :            : 
     570                 :            :     /* Write the MAC */
     571                 :    3608542 :     struct s2n_blob header_blob = { 0 };
     572         [ -  + ]:    3608542 :     POSIX_GUARD(s2n_blob_slice(&record_blob, &header_blob, 0, S2N_TLS_RECORD_HEADER_LENGTH));
     573                 :    3608542 :     struct s2n_blob plaintext_blob = { 0 };
     574         [ -  + ]:    3608542 :     POSIX_GUARD(s2n_blob_init(&plaintext_blob, orig_write_ptr, data_bytes_to_take));
     575                 :    3608542 :     uint32_t mac_digest_size = 0;
     576         [ -  + ]:    3608542 :     POSIX_GUARD_RESULT(s2n_record_write_mac(conn, &header_blob, &plaintext_blob, &record_stuffer, &mac_digest_size));
     577                 :            : 
     578                 :            :     /* We are done with this sequence number, so we can increment it */
     579                 :    3608542 :     struct s2n_blob seq = { 0 };
     580         [ -  + ]:    3608542 :     POSIX_GUARD(s2n_blob_init(&seq, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN));
     581         [ +  + ]:    3608542 :     POSIX_GUARD(s2n_increment_sequence_number(&seq));
     582                 :            : 
     583                 :            :     /* Write content type for TLS 1.3 record (RFC 8446 Section 5.2) */
     584         [ +  + ]:    3608541 :     if (is_tls13_record) {
     585         [ -  + ]:     111360 :         POSIX_GUARD(s2n_stuffer_write_uint8(&record_stuffer, content_type));
     586                 :     111360 :     }
     587                 :            : 
     588         [ +  + ]:    3608541 :     if (cipher_suite->record_alg->cipher->type == S2N_CBC) {
     589                 :            :         /* Include padding bytes, each with the value 'p', and
     590                 :            :          * include an extra padding length byte, also with the value 'p'.
     591                 :            :          */
     592         [ +  + ]:     363189 :         for (int i = 0; i <= padding; i++) {
     593         [ -  + ]:     321372 :             POSIX_GUARD(s2n_stuffer_write_uint8(&record_stuffer, padding));
     594                 :     321372 :         }
     595                 :      41817 :     }
     596                 :            : 
     597                 :            :     /* Rewind to rewrite/encrypt the packet */
     598         [ -  + ]:    3608541 :     POSIX_GUARD(s2n_stuffer_rewrite(&record_stuffer));
     599                 :            : 
     600                 :            :     /* Skip the header */
     601         [ -  + ]:    3608541 :     POSIX_GUARD(s2n_stuffer_skip_write(&record_stuffer, S2N_TLS_RECORD_HEADER_LENGTH));
     602                 :            : 
     603                 :    3608541 :     uint16_t encrypted_length = data_bytes_to_take + mac_digest_size;
     604                 :    3608541 :     switch (cipher_suite->record_alg->cipher->type) {
     605         [ +  + ]:    3347691 :         case S2N_AEAD:
     606         [ -  + ]:    3347691 :             POSIX_GUARD(s2n_stuffer_skip_write(&record_stuffer, cipher_suite->record_alg->cipher->io.aead.record_iv_size));
     607                 :    3347691 :             encrypted_length += cipher_suite->record_alg->cipher->io.aead.tag_size;
     608         [ +  + ]:    3347691 :             if (is_tls13_record) {
     609                 :            :                 /* one extra byte for content type */
     610                 :     111360 :                 encrypted_length += S2N_TLS_CONTENT_TYPE_LENGTH;
     611                 :     111360 :             }
     612                 :    3347691 :             break;
     613         [ +  + ]:      41817 :         case S2N_CBC:
     614         [ +  + ]:      41817 :             if (conn->actual_protocol_version > S2N_TLS10) {
     615                 :            :                 /* Leave the IV alone and unencrypted */
     616         [ -  + ]:      32921 :                 POSIX_GUARD(s2n_stuffer_skip_write(&record_stuffer, iv.size));
     617                 :      32921 :             }
     618                 :            :             /* Encrypt the padding and the padding length byte too */
     619                 :      41817 :             encrypted_length += padding + 1;
     620                 :      41817 :             break;
     621         [ +  + ]:     163985 :         case S2N_COMPOSITE:
     622                 :            :             /* Composite CBC expects a pointer starting at explicit IV: [Explicit IV | fragment | MAC | padding | padding len ]
     623                 :            :         * extra will account for the explicit IV len(if applicable), MAC digest len, padding len + padding byte.
     624                 :            :         */
     625                 :     163985 :             encrypted_length += extra;
     626                 :     163985 :             break;
     627         [ +  + ]:      55048 :         default:
     628                 :      55048 :             break;
     629                 :    3608541 :     }
     630                 :            : 
     631                 :            :     /* Check that stuffer have enough space to write encrypted record, because raw_write cannot expand tainted stuffer */
     632 [ -  + ][ #  # ]:    3608541 :     S2N_ERROR_IF(s2n_stuffer_space_remaining(&record_stuffer) < encrypted_length, S2N_ERR_RECORD_STUFFER_SIZE);
     633                 :            : 
     634                 :            :     /* Do the encryption */
     635                 :    3608541 :     struct s2n_blob en = { .size = encrypted_length, .data = s2n_stuffer_raw_write(&record_stuffer, encrypted_length) };
     636         [ -  + ]:    3608541 :     POSIX_GUARD(s2n_record_encrypt(conn, cipher_suite, session_key, &iv, &aad, &en, implicit_iv, block_size));
     637                 :            : 
     638                 :            :     /* Sync the out stuffer write cursor with the record stuffer. */
     639         [ -  + ]:    3608541 :     POSIX_GUARD(s2n_stuffer_skip_write(&conn->out, s2n_stuffer_data_available(&record_stuffer)));
     640                 :            : 
     641 [ +  + ][ +  + ]:    3608541 :     if (conn->actual_protocol_version == S2N_TLS13 && content_type == TLS_CHANGE_CIPHER_SPEC) {
     642                 :       7859 :         conn->client = current_client_crypto;
     643                 :       7859 :         conn->server = current_server_crypto;
     644                 :       7859 :     }
     645                 :            : 
     646                 :    3608541 :     return data_bytes_to_take;
     647                 :    3608541 : }
     648                 :            : 
     649                 :            : S2N_RESULT s2n_record_write(struct s2n_connection *conn, uint8_t content_type, struct s2n_blob *in)
     650                 :    3392058 : {
     651                 :    3392058 :     struct iovec iov;
     652                 :    3392058 :     iov.iov_base = in->data;
     653                 :    3392058 :     iov.iov_len = in->size;
     654                 :    3392058 :     int written = s2n_record_writev(conn, content_type, &iov, 1, 0, in->size);
     655         [ +  + ]:    3392058 :     RESULT_GUARD_POSIX(written);
     656 [ +  - ][ +  + ]:    3392055 :     RESULT_ENSURE((uint32_t) written == in->size, S2N_ERR_FRAGMENT_LENGTH_TOO_LARGE);
     657                 :    3392035 :     return S2N_RESULT_OK;
     658                 :    3392055 : }

Generated by: LCOV version 1.14