LCOV - code coverage report
Current view: top level - tls - s2n_ktls.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 202 241 83.8 %
Date: 2025-09-30 07:28:05 Functions: 16 17 94.1 %
Branches: 148 314 47.1 %

           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_ktls.h"
      17                 :            : 
      18                 :            : #include "crypto/s2n_ktls_crypto.h"
      19                 :            : #include "crypto/s2n_sequence.h"
      20                 :            : #include "tls/s2n_key_update.h"
      21                 :            : #include "tls/s2n_prf.h"
      22                 :            : #include "tls/s2n_tls.h"
      23                 :            : #include "tls/s2n_tls13_handshake.h"
      24                 :            : #include "tls/s2n_tls13_key_schedule.h"
      25                 :            : 
      26                 :            : /* Used for overriding setsockopt calls in testing */
      27                 :            : s2n_setsockopt_fn s2n_setsockopt = setsockopt;
      28                 :            : 
      29                 :            : S2N_RESULT s2n_ktls_set_setsockopt_cb(s2n_setsockopt_fn cb)
      30                 :         24 : {
      31 [ -  + ][ #  # ]:         24 :     RESULT_ENSURE(s2n_in_test(), S2N_ERR_NOT_IN_TEST);
      32                 :         24 :     s2n_setsockopt = cb;
      33                 :         24 :     return S2N_RESULT_OK;
      34                 :         24 : }
      35                 :            : 
      36                 :            : bool s2n_ktls_is_supported_on_platform()
      37                 :         39 : {
      38                 :         39 : #if defined(S2N_KTLS_SUPPORTED)
      39                 :         39 :     return true;
      40                 :            : #else
      41                 :            :     return false;
      42                 :            : #endif
      43                 :         39 : }
      44                 :            : 
      45                 :            : static int s2n_ktls_disabled_read(void *io_context, uint8_t *buf, uint32_t len)
      46                 :          0 : {
      47         [ #  # ]:          0 :     POSIX_BAIL(S2N_ERR_IO);
      48                 :          0 : }
      49                 :            : 
      50                 :            : static S2N_RESULT s2n_ktls_validate(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
      51                 :         37 : {
      52 [ -  + ][ #  # ]:         37 :     RESULT_ENSURE_REF(conn);
      53                 :         37 :     const struct s2n_config *config = conn->config;
      54 [ -  + ][ #  # ]:         37 :     RESULT_ENSURE_REF(config);
      55                 :            : 
      56 [ #  # ][ -  + ]:         37 :     RESULT_ENSURE(s2n_ktls_is_supported_on_platform(), S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
      57                 :            : 
      58                 :            :     /* kTLS enable should only be called once the handshake has completed. */
      59 [ +  - ][ +  + ]:         37 :     RESULT_ENSURE(is_handshake_complete(conn), S2N_ERR_HANDSHAKE_NOT_COMPLETE);
      60                 :            : 
      61                 :            :     /* kTLS uses the prf_space to recalculate the keys, but the prf_space may be
      62                 :            :      * freed by s2n_connection_free_handshake to reduce the connection size.
      63                 :            :      * Explicitly check for prf_space here to avoid a confusing S2N_ERR_NULL later.
      64                 :            :      */
      65 [ #  # ][ -  + ]:         35 :     RESULT_ENSURE(conn->prf_space, S2N_ERR_INVALID_STATE);
      66                 :            : 
      67                 :            :     /* For now, only allow TlS1.3 if explicitly enabled.
      68                 :            :      *
      69                 :            :      * TLS1.3 is potentially more dangerous to enable than TLS1.2, since the kernel
      70                 :            :      * does not currently support updating TLS keys and therefore will fail if
      71                 :            :      * KeyUpdate messages are encountered.
      72                 :            :      */
      73         [ +  + ]:         35 :     bool version_supported = (conn->actual_protocol_version == S2N_TLS12)
      74 [ +  + ][ +  - ]:         35 :             || (conn->config->ktls_tls13_enabled && conn->actual_protocol_version == S2N_TLS13);
      75 [ +  + ][ +  - ]:         35 :     RESULT_ENSURE(version_supported, S2N_ERR_KTLS_UNSUPPORTED_CONN);
      76                 :            : 
      77                 :            :     /* Check if the cipher supports kTLS */
      78                 :         32 :     const struct s2n_cipher *cipher = NULL;
      79         [ -  + ]:         32 :     RESULT_GUARD(s2n_connection_get_secure_cipher(conn, &cipher));
      80 [ -  + ][ #  # ]:         32 :     RESULT_ENSURE_REF(cipher);
      81 [ +  - ][ +  + ]:         32 :     RESULT_ENSURE(cipher->set_ktls_info, S2N_ERR_KTLS_UNSUPPORTED_CONN);
      82                 :            : 
      83                 :            :     /* Renegotiation requires updating the keys, which kTLS doesn't currently support.
      84                 :            :      *
      85                 :            :      * Setting the renegotiation callback doesn't guarantee that a client will
      86                 :            :      * attempt to renegotiate. The callback can also be used to send warning alerts
      87                 :            :      * signaling that renegotiation was rejected. However, we can provide applications
      88                 :            :      * with a clearer signal earlier by preventing them from enabling ktls on a
      89                 :            :      * connection that MIGHT require renegotiation. We can relax this restriction
      90                 :            :      * later if necessary.
      91                 :            :      */
      92                 :         30 :     bool may_receive_hello_request = s2n_result_is_ok(s2n_client_hello_request_validate(conn));
      93 [ +  + ][ +  + ]:         30 :     bool may_renegotiate = may_receive_hello_request && config->renegotiate_request_cb;
      94 [ +  + ][ +  - ]:         30 :     RESULT_ENSURE(!may_renegotiate, S2N_ERR_KTLS_RENEG);
      95                 :            : 
      96                 :            :     /* Prevent kTLS from being enabled on connections that might be serialized.
      97                 :            :      *
      98                 :            :      * The socket takes over tracking sequence numbers when kTLS is enabled.
      99                 :            :      * We would need to call getsockopt to retrieve the current sequence numbers for
     100                 :            :      * serialization. This would complicate the serialization implementation so
     101                 :            :      * for now, do not support kTLS with serialization.
     102                 :            :      */
     103 [ +  - ][ +  + ]:         29 :     RESULT_ENSURE(config->serialized_connection_version == S2N_SERIALIZED_CONN_NONE,
     104                 :         28 :             S2N_ERR_KTLS_UNSUPPORTED_CONN);
     105                 :            : 
     106                 :            :     /* kTLS I/O functionality is managed by s2n-tls. kTLS cannot be enabled if the
     107                 :            :      * application sets custom I/O (managed_send_io == false means application has
     108                 :            :      * set custom I/O).
     109                 :            :      */
     110                 :         28 :     switch (ktls_mode) {
     111         [ +  + ]:         12 :         case S2N_KTLS_MODE_SEND:
     112 [ +  + ][ +  - ]:         12 :             RESULT_ENSURE(conn->managed_send_io, S2N_ERR_KTLS_MANAGED_IO);
     113                 :            :             /* The output stuffer should be empty before enabling kTLS. */
     114 [ +  + ][ +  - ]:         11 :             RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->out), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
     115                 :         10 :             break;
     116         [ +  + ]:         16 :         case S2N_KTLS_MODE_RECV:
     117 [ +  - ][ +  + ]:         16 :             RESULT_ENSURE(conn->managed_recv_io, S2N_ERR_KTLS_MANAGED_IO);
     118                 :            :             /* The input stuffers should be empty before enabling kTLS. */
     119 [ +  + ][ +  - ]:         15 :             RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->header_in), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
     120 [ +  - ][ +  + ]:         14 :             RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->in), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
     121 [ +  - ][ +  + ]:         13 :             RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->buffer_in), S2N_ERR_KTLS_UNSUPPORTED_CONN);
     122                 :         12 :             break;
     123         [ -  + ]:         12 :         default:
     124         [ #  # ]:          0 :             RESULT_BAIL(S2N_ERR_SAFETY);
     125                 :          0 :             break;
     126                 :         28 :     }
     127                 :            : 
     128                 :         22 :     return S2N_RESULT_OK;
     129                 :         28 : }
     130                 :            : 
     131                 :            : /* Enabling kTLS preserves the original *io_context; making this functions
     132                 :            :  * safe to call even after kTLS has been enabled on the connection.
     133                 :            :  *
     134                 :            :  * Retrieving fd assumes that the connection is using socket IO and has the
     135                 :            :  * send_io_context set. While kTLS overrides IO and essentially disables
     136                 :            :  * the socket conn->send function callback, it doesn't modify the
     137                 :            :  * send_io_context. */
     138                 :            : S2N_RESULT s2n_ktls_get_file_descriptor(struct s2n_connection *conn, s2n_ktls_mode ktls_mode, int *fd)
     139                 :       1506 : {
     140 [ #  # ][ -  + ]:       1506 :     RESULT_ENSURE_REF(conn);
     141 [ -  + ][ #  # ]:       1506 :     RESULT_ENSURE_REF(fd);
     142                 :            : 
     143         [ +  + ]:       1506 :     if (ktls_mode == S2N_KTLS_MODE_RECV) {
     144         [ -  + ]:         12 :         RESULT_GUARD_POSIX(s2n_connection_get_read_fd(conn, fd));
     145         [ +  - ]:       1494 :     } else if (ktls_mode == S2N_KTLS_MODE_SEND) {
     146         [ -  + ]:       1494 :         RESULT_GUARD_POSIX(s2n_connection_get_write_fd(conn, fd));
     147                 :       1494 :     }
     148                 :       1506 :     return S2N_RESULT_OK;
     149                 :       1506 : }
     150                 :            : 
     151                 :            : static S2N_RESULT s2n_ktls_get_io_mode(s2n_ktls_mode ktls_mode, int *tls_tx_rx_mode)
     152                 :         22 : {
     153 [ -  + ][ #  # ]:         22 :     RESULT_ENSURE_REF(tls_tx_rx_mode);
     154                 :            : 
     155         [ +  + ]:         22 :     if (ktls_mode == S2N_KTLS_MODE_SEND) {
     156                 :         10 :         *tls_tx_rx_mode = S2N_TLS_TX;
     157                 :         12 :     } else {
     158                 :         12 :         *tls_tx_rx_mode = S2N_TLS_RX;
     159                 :         12 :     }
     160                 :         22 :     return S2N_RESULT_OK;
     161                 :         22 : }
     162                 :            : 
     163                 :            : static S2N_RESULT s2n_ktls_crypto_info_init(struct s2n_connection *conn, s2n_ktls_mode ktls_mode,
     164                 :            :         struct s2n_ktls_crypto_info *crypto_info)
     165                 :         22 : {
     166 [ #  # ][ -  + ]:         22 :     RESULT_ENSURE_REF(conn);
     167                 :         22 :     struct s2n_crypto_parameters *secure = conn->secure;
     168 [ -  + ][ #  # ]:         22 :     RESULT_ENSURE_REF(secure);
     169                 :            : 
     170                 :            :     /* In order to avoid storing the encryption keys on the connection, we instead
     171                 :            :      * regenerate them when required by ktls.
     172                 :            :      *
     173                 :            :      * s2n_key_material also includes an IV, but we should use the IV stored
     174                 :            :      * on the connection instead. Some record algorithms (like CBC) mutate the
     175                 :            :      * "implicit_iv" when writing records, so the IV may change after generation.
     176                 :            :      */
     177                 :         22 :     struct s2n_key_material key_material = { 0 };
     178                 :            : 
     179                 :         22 :     bool is_sending_key = (ktls_mode == S2N_KTLS_MODE_SEND);
     180         [ +  + ]:         22 :     s2n_mode key_mode = (is_sending_key) ? conn->mode : S2N_PEER_MODE(conn->mode);
     181                 :            : 
     182                 :         22 :     switch (conn->actual_protocol_version) {
     183         [ +  + ]:         21 :         case S2N_TLS12:
     184         [ -  + ]:         21 :             RESULT_GUARD(s2n_prf_generate_key_material(conn, &key_material));
     185                 :         21 :             break;
     186         [ +  + ]:         21 :         case S2N_TLS13:
     187         [ -  + ]:          1 :             RESULT_GUARD(s2n_tls13_key_schedule_generate_key_material(
     188                 :          1 :                     conn, key_mode, &key_material));
     189                 :          1 :             break;
     190         [ -  + ]:          1 :         default:
     191         [ #  # ]:          0 :             RESULT_BAIL(S2N_ERR_KTLS_UNSUPPORTED_CONN);
     192                 :         22 :     }
     193                 :            : 
     194                 :         22 :     struct s2n_ktls_crypto_info_inputs inputs = { 0 };
     195         [ +  + ]:         22 :     if (key_mode == S2N_CLIENT) {
     196                 :         11 :         inputs.key = key_material.client_key;
     197         [ -  + ]:         11 :         RESULT_GUARD_POSIX(s2n_blob_init(&inputs.iv,
     198                 :         11 :                 secure->client_implicit_iv, sizeof(secure->client_implicit_iv)));
     199                 :         11 :     } else {
     200                 :         11 :         inputs.key = key_material.server_key;
     201         [ -  + ]:         11 :         RESULT_GUARD_POSIX(s2n_blob_init(&inputs.iv,
     202                 :         11 :                 secure->server_implicit_iv, sizeof(secure->server_implicit_iv)));
     203                 :         11 :     }
     204         [ -  + ]:         22 :     RESULT_GUARD(s2n_connection_get_sequence_number(conn, key_mode, &inputs.seq));
     205                 :            : 
     206                 :         22 :     const struct s2n_cipher *cipher = NULL;
     207         [ -  + ]:         22 :     RESULT_GUARD(s2n_connection_get_secure_cipher(conn, &cipher));
     208 [ -  + ][ #  # ]:         22 :     RESULT_ENSURE_REF(cipher);
     209 [ -  + ][ #  # ]:         22 :     RESULT_ENSURE_REF(cipher->set_ktls_info);
     210         [ -  + ]:         22 :     RESULT_GUARD(cipher->set_ktls_info(&inputs, crypto_info));
     211                 :         22 :     return S2N_RESULT_OK;
     212                 :         22 : }
     213                 :            : 
     214                 :            : /* This method intentionally returns void because it may NOT perform any fallible
     215                 :            :  * operations. See s2n_connection_ktls_enable.
     216                 :            :  */
     217                 :            : void s2n_ktls_configure_connection(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
     218                 :         41 : {
     219         [ -  + ]:         41 :     if (conn == NULL) {
     220                 :          0 :         return;
     221                 :          0 :     }
     222         [ +  + ]:         41 :     if (ktls_mode == S2N_KTLS_MODE_SEND) {
     223                 :         16 :         conn->ktls_send_enabled = true;
     224                 :         16 :         conn->send = s2n_ktls_send_cb;
     225                 :         25 :     } else {
     226                 :         25 :         conn->ktls_recv_enabled = true;
     227                 :         25 :         conn->recv = s2n_ktls_disabled_read;
     228                 :         25 :     }
     229                 :         41 : }
     230                 :            : 
     231                 :            : static S2N_RESULT s2n_connection_ktls_enable(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
     232                 :         37 : {
     233 [ #  # ][ -  + ]:         37 :     RESULT_ENSURE_REF(conn);
     234         [ +  + ]:         37 :     RESULT_GUARD(s2n_ktls_validate(conn, ktls_mode));
     235                 :            : 
     236                 :         22 :     int fd = 0;
     237         [ -  + ]:         22 :     RESULT_GUARD(s2n_ktls_get_file_descriptor(conn, ktls_mode, &fd));
     238                 :            : 
     239                 :            :     /* This call doesn't actually enable ktls or modify the IO behavior of the socket.
     240                 :            :      * Instead, this is just a prerequisite for calling setsockopt with SOL_TLS.
     241                 :            :      *
     242                 :            :      * We intentionally ignore the result of this call. It may fail because ktls
     243                 :            :      * is not supported, but it might also fail because ktls has already been enabled
     244                 :            :      * for the socket. If SOL_TLS isn't enabled on the socket, our next call to
     245                 :            :      * setsockopt with SOL_TLS will also fail, and we DO check that result.
     246                 :            :      */
     247                 :         22 :     s2n_setsockopt(fd, S2N_SOL_TCP, S2N_TCP_ULP, S2N_TLS_ULP_NAME, S2N_TLS_ULP_NAME_SIZE);
     248                 :            : 
     249                 :         22 :     int tls_tx_rx_mode = 0;
     250         [ -  + ]:         22 :     RESULT_GUARD(s2n_ktls_get_io_mode(ktls_mode, &tls_tx_rx_mode));
     251                 :            : 
     252                 :         22 :     struct s2n_ktls_crypto_info crypto_info = { 0 };
     253         [ -  + ]:         22 :     RESULT_GUARD(s2n_ktls_crypto_info_init(conn, ktls_mode, &crypto_info));
     254                 :            : 
     255                 :            :     /* If this call succeeds, then ktls is enabled for that io mode and will be offloaded */
     256                 :         22 :     int ret = s2n_setsockopt(fd, S2N_SOL_TLS, tls_tx_rx_mode, crypto_info.value.data, crypto_info.value.size);
     257 [ +  + ][ +  - ]:         22 :     RESULT_ENSURE(ret == 0, S2N_ERR_KTLS_ENABLE);
     258                 :            : 
     259                 :            :     /* At this point, ktls is enabled on the socket for the requested IO mode.
     260                 :            :      * No further fallible operations may be performed, or else the caller may
     261                 :            :      * incorrectly assume that enabling ktls failed and they should therefore
     262                 :            :      * fall back to using application layer TLS.
     263                 :            :      *
     264                 :            :      * That means no calls to RESULT_ENSURE, RESULT_GUARD, etc. after this point.
     265                 :            :      */
     266                 :            : 
     267                 :         18 :     s2n_ktls_configure_connection(conn, ktls_mode);
     268                 :         18 :     return S2N_RESULT_OK;
     269                 :         22 : }
     270                 :            : 
     271                 :            : int s2n_connection_ktls_enable_send(struct s2n_connection *conn)
     272                 :         18 : {
     273 [ #  # ][ -  + ]:         18 :     POSIX_ENSURE_REF(conn);
     274                 :            : 
     275                 :            :     /* If already enabled then return success */
     276         [ +  + ]:         18 :     if (conn->ktls_send_enabled) {
     277                 :          1 :         return S2N_SUCCESS;
     278                 :          1 :     }
     279                 :            : 
     280         [ +  + ]:         17 :     POSIX_GUARD_RESULT(s2n_connection_ktls_enable(conn, S2N_KTLS_MODE_SEND));
     281                 :          8 :     return S2N_SUCCESS;
     282                 :         17 : }
     283                 :            : 
     284                 :            : int s2n_connection_ktls_enable_recv(struct s2n_connection *conn)
     285                 :         21 : {
     286 [ -  + ][ #  # ]:         21 :     POSIX_ENSURE_REF(conn);
     287                 :            : 
     288                 :            :     /* If already enabled then return success */
     289         [ +  + ]:         21 :     if (conn->ktls_recv_enabled) {
     290                 :          1 :         return S2N_SUCCESS;
     291                 :          1 :     }
     292                 :            : 
     293         [ +  + ]:         20 :     POSIX_GUARD_RESULT(s2n_connection_ktls_enable(conn, S2N_KTLS_MODE_RECV));
     294                 :         10 :     return S2N_SUCCESS;
     295                 :         20 : }
     296                 :            : 
     297                 :            : int s2n_config_ktls_enable_unsafe_tls13(struct s2n_config *config)
     298                 :          6 : {
     299 [ +  - ][ +  + ]:          6 :     POSIX_ENSURE_REF(config);
     300                 :          5 :     config->ktls_tls13_enabled = true;
     301                 :          5 :     return S2N_SUCCESS;
     302                 :          6 : }
     303                 :            : 
     304                 :            : /* The RFC defines the encryption limits in terms of "full-size records" sent.
     305                 :            :  * We can estimate the number of "full-sized records" sent by assuming that
     306                 :            :  * all records are full-sized.
     307                 :            :  */
     308                 :            : static S2N_RESULT s2n_ktls_estimate_records(size_t bytes, uint64_t *estimate)
     309                 :         88 : {
     310 [ -  + ][ #  # ]:         88 :     RESULT_ENSURE_REF(estimate);
     311                 :         88 :     uint64_t records = bytes / S2N_TLS_MAXIMUM_FRAGMENT_LENGTH;
     312         [ +  + ]:         88 :     if (bytes % S2N_TLS_MAXIMUM_FRAGMENT_LENGTH) {
     313                 :         70 :         records++;
     314                 :         70 :     }
     315                 :         88 :     *estimate = records;
     316                 :         88 :     return S2N_RESULT_OK;
     317                 :         88 : }
     318                 :            : 
     319                 :            : S2N_RESULT s2n_ktls_set_estimated_sequence_number(
     320                 :            :         struct s2n_connection *conn, size_t bytes_written)
     321                 :      50693 : {
     322 [ -  + ][ #  # ]:      50693 :     RESULT_ENSURE_REF(conn);
     323         [ +  + ]:      50693 :     if (conn->actual_protocol_version < S2N_TLS13) {
     324                 :      50655 :         return S2N_RESULT_OK;
     325                 :      50655 :     }
     326                 :            : 
     327                 :         38 :     uint64_t new_records_sent = 0;
     328         [ -  + ]:         38 :     RESULT_GUARD(s2n_ktls_estimate_records(bytes_written, &new_records_sent));
     329                 :            : 
     330                 :         38 :     struct s2n_blob seq_num = { 0 };
     331         [ -  + ]:         38 :     RESULT_GUARD(s2n_connection_get_sequence_number(conn, conn->mode, &seq_num));
     332                 :            : 
     333         [ +  + ]:         97 :     for (size_t i = 0; i < new_records_sent; i++) {
     334         [ -  + ]:         59 :         RESULT_GUARD_POSIX(s2n_increment_sequence_number(&seq_num));
     335                 :         59 :     }
     336                 :         38 :     return S2N_RESULT_OK;
     337                 :         38 : }
     338                 :            : 
     339                 :            : /* We need to track when the key encryption limit is reached. We could get the current record
     340                 :            :  * sequence number from the kernel with getsockopt, but that requires a surprisingly
     341                 :            :  * expensive syscall.
     342                 :            :  *
     343                 :            :  * Instead, we track the estimated sequence number and enforce the limit based
     344                 :            :  * on that estimate.
     345                 :            :  */
     346                 :            : S2N_RESULT s2n_ktls_check_estimated_record_limit(struct s2n_connection *conn, size_t bytes_requested)
     347                 :      50710 : {
     348 [ #  # ][ -  + ]:      50710 :     RESULT_ENSURE_REF(conn);
     349         [ +  + ]:      50710 :     if (conn->actual_protocol_version < S2N_TLS13) {
     350                 :      50660 :         return S2N_RESULT_OK;
     351                 :      50660 :     }
     352                 :            : 
     353                 :         50 :     uint64_t new_records_sent = 0;
     354         [ -  + ]:         50 :     RESULT_GUARD(s2n_ktls_estimate_records(bytes_requested, &new_records_sent));
     355                 :            : 
     356                 :         50 :     uint64_t old_records_sent = 0;
     357                 :         50 :     struct s2n_blob seq_num = { 0 };
     358         [ -  + ]:         50 :     RESULT_GUARD(s2n_connection_get_sequence_number(conn, conn->mode, &seq_num));
     359         [ -  + ]:         50 :     RESULT_GUARD_POSIX(s2n_sequence_number_to_uint64(&seq_num, &old_records_sent));
     360                 :            : 
     361 [ #  # ][ +  - ]:         50 :     RESULT_ENSURE(S2N_ADD_IS_OVERFLOW_SAFE(old_records_sent, new_records_sent, UINT64_MAX),
                 [ +  - ]
     362                 :         50 :             S2N_ERR_KTLS_KEY_LIMIT);
     363                 :         50 :     uint64_t total_records_sent = old_records_sent + new_records_sent;
     364                 :            : 
     365 [ -  + ][ #  # ]:         50 :     RESULT_ENSURE_REF(conn->secure);
     366 [ -  + ][ #  # ]:         50 :     RESULT_ENSURE_REF(conn->secure->cipher_suite);
     367 [ -  + ][ #  # ]:         50 :     RESULT_ENSURE_REF(conn->secure->cipher_suite->record_alg);
     368                 :         50 :     uint64_t encryption_limit = conn->secure->cipher_suite->record_alg->encryption_limit;
     369         [ +  + ]:         50 :     if (total_records_sent > encryption_limit) {
     370 [ #  # ][ -  + ]:         12 :         RESULT_ENSURE_REF(conn->config);
     371 [ +  + ][ +  - ]:         12 :         RESULT_ENSURE(conn->config->ktls_tls13_enabled, S2N_ERR_KTLS_KEY_LIMIT);
     372                 :            : 
     373                 :            :         /* Check that the data requested for the ktls send call is not going over the encryption limit,
     374                 :            :          * as that would require multiple key updates.
     375                 :            :          * In TLS1.3, the key limit is 2^24.5 full-size records. (See S2N_TLS13_AES_GCM_MAXIMUM_RECORD_NUMBER)
     376                 :            :          * A full-sized record is 2^14 bytes. So essentially 2^24.5 * 2^14 bytes(388 GB) can be sent
     377                 :            :          * before you need to key update. We can add logic for multiple key updates in a single ktls
     378                 :            :          * send call in the future, but it's not required at the moment. */
     379 [ +  - ][ +  + ]:          5 :         RESULT_ENSURE(new_records_sent <= encryption_limit, S2N_ERR_INVALID_ARGUMENT);
     380                 :          2 :         s2n_atomic_flag_set(&conn->key_update_pending);
     381                 :          2 :     }
     382                 :            : 
     383                 :         40 :     return S2N_RESULT_OK;
     384                 :         50 : }
     385                 :            : 
     386                 :            : S2N_RESULT s2n_ktls_key_update_send(struct s2n_connection *conn, size_t bytes_requested)
     387                 :      50703 : {
     388 [ -  + ][ #  # ]:      50703 :     RESULT_ENSURE_REF(conn);
     389         [ +  + ]:      50703 :     RESULT_GUARD(s2n_ktls_check_estimated_record_limit(conn, bytes_requested));
     390                 :            : 
     391         [ -  + ]:      50696 :     if (s2n_atomic_flag_test(&conn->key_update_pending)) {
     392 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE_REF(conn->config);
     393 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE(conn->config->ktls_tls13_enabled, S2N_ERR_KTLS_KEYUPDATE);
     394                 :            : 
     395                 :          0 :         uint8_t key_update_data[S2N_KEY_UPDATE_MESSAGE_SIZE];
     396                 :          0 :         struct s2n_blob key_update_blob = { 0 };
     397         [ #  # ]:          0 :         RESULT_GUARD_POSIX(s2n_blob_init(&key_update_blob, key_update_data, sizeof(key_update_data)));
     398                 :            : 
     399                 :            :         /* Write Keyupdate message */
     400         [ #  # ]:          0 :         RESULT_GUARD_POSIX(s2n_key_update_write(&key_update_blob));
     401                 :            : 
     402                 :            :         /* Send Keyupdate message */
     403                 :          0 :         const struct iovec iov = {
     404                 :          0 :             .iov_base = (void *) (uintptr_t) key_update_data,
     405                 :          0 :             .iov_len = sizeof(key_update_data),
     406                 :          0 :         };
     407                 :          0 :         s2n_blocked_status blocked = S2N_NOT_BLOCKED;
     408                 :          0 :         size_t bytes_written = 0;
     409         [ #  # ]:          0 :         RESULT_GUARD(s2n_ktls_sendmsg(conn->send_io_context, TLS_HANDSHAKE, &iov, 1, &blocked, &bytes_written));
     410 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE_EQ(bytes_written, sizeof(key_update_data));
     411                 :            : 
     412                 :            :         /* Create new encryption key */
     413         [ #  # ]:          0 :         RESULT_GUARD_POSIX(s2n_update_application_traffic_keys(conn, conn->mode, SENDING));
     414                 :            : 
     415                 :          0 :         struct s2n_ktls_crypto_info crypto_info = { 0 };
     416         [ #  # ]:          0 :         RESULT_GUARD(s2n_ktls_crypto_info_init(conn, S2N_KTLS_MODE_SEND, &crypto_info));
     417                 :            : 
     418                 :          0 :         int fd = 0;
     419         [ #  # ]:          0 :         RESULT_GUARD(s2n_ktls_get_file_descriptor(conn, S2N_KTLS_MODE_SEND, &fd));
     420                 :            : 
     421                 :            :         /* Update the socket with new key */
     422                 :          0 :         int ret = s2n_setsockopt(fd, S2N_SOL_TLS, S2N_TLS_TX, crypto_info.value.data, crypto_info.value.size);
     423 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE(ret == 0, S2N_ERR_KTLS_SOCKOPT);
     424                 :            : 
     425                 :          0 :         s2n_atomic_flag_clear(&conn->key_update_pending);
     426                 :          0 :     }
     427                 :      50696 :     return S2N_RESULT_OK;
     428                 :      50696 : }
     429                 :            : 
     430                 :            : S2N_RESULT s2n_ktls_key_update_process(struct s2n_connection *conn)
     431                 :          1 : {
     432 [ #  # ][ -  + ]:          1 :     RESULT_ENSURE_REF(conn);
     433 [ -  + ][ #  # ]:          1 :     RESULT_ENSURE_REF(conn->config);
     434 [ +  - ][ +  - ]:          1 :     RESULT_ENSURE(conn->config->ktls_tls13_enabled, S2N_ERR_KTLS_KEYUPDATE);
     435                 :            : 
     436                 :          0 :     struct s2n_ktls_crypto_info crypto_info = { 0 };
     437         [ #  # ]:          0 :     RESULT_GUARD(s2n_ktls_crypto_info_init(conn, S2N_KTLS_MODE_RECV, &crypto_info));
     438                 :            : 
     439                 :          0 :     int fd = 0;
     440         [ #  # ]:          0 :     RESULT_GUARD(s2n_ktls_get_file_descriptor(conn, S2N_KTLS_MODE_RECV, &fd));
     441                 :            : 
     442                 :            :     /* Update the socket with new key */
     443                 :          0 :     int ret = s2n_setsockopt(fd, S2N_SOL_TLS, S2N_TLS_RX, crypto_info.value.data, crypto_info.value.size);
     444 [ #  # ][ #  # ]:          0 :     RESULT_ENSURE(ret == 0, S2N_ERR_KTLS_SOCKOPT);
     445                 :            : 
     446                 :          0 :     return S2N_RESULT_OK;
     447                 :          0 : }

Generated by: LCOV version 1.14