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

Generated by: LCOV version 1.14