LCOV - code coverage report
Current view: top level - tls - s2n_quic_support.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 68 71 95.8 %
Date: 2025-08-15 07:28:39 Functions: 9 10 90.0 %
Branches: 73 112 65.2 %

           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_quic_support.h"
      17                 :            : 
      18                 :            : #include "tls/s2n_connection.h"
      19                 :            : #include "tls/s2n_tls.h"
      20                 :            : #include "tls/s2n_tls13.h"
      21                 :            : #include "utils/s2n_mem.h"
      22                 :            : #include "utils/s2n_safety.h"
      23                 :            : 
      24                 :            : /* When reading and writing records with TCP, S2N sets its input and output buffers
      25                 :            :  * to the maximum record fragment size to prevent resizing those buffers later.
      26                 :            :  *
      27                 :            :  * However, because S2N with QUIC reads and writes messages instead of records,
      28                 :            :  * the "maximum size" for the input and output buffers would be the maximum message size: 64k.
      29                 :            :  * Since most messages are MUCH smaller than that (<3k), setting the buffer that large is wasteful.
      30                 :            :  *
      31                 :            :  * Instead, we intentionally choose a smaller size and accept that an abnormally large message
      32                 :            :  * could cause the buffer to resize. */
      33                 :            : #define S2N_EXPECTED_QUIC_MESSAGE_SIZE S2N_DEFAULT_FRAGMENT_LENGTH
      34                 :            : 
      35                 :            : S2N_RESULT s2n_read_in_bytes(struct s2n_connection *conn, struct s2n_stuffer *output, uint32_t length);
      36                 :            : 
      37                 :            : int s2n_config_enable_quic(struct s2n_config *config)
      38                 :         21 : {
      39 [ +  + ][ +  - ]:         21 :     POSIX_ENSURE_REF(config);
      40                 :         20 :     config->quic_enabled = true;
      41                 :         20 :     return S2N_SUCCESS;
      42                 :         21 : }
      43                 :            : 
      44                 :            : int s2n_connection_enable_quic(struct s2n_connection *conn)
      45                 :         50 : {
      46 [ +  - ][ +  + ]:         50 :     POSIX_ENSURE_REF(conn);
      47         [ -  + ]:         49 :     POSIX_GUARD_RESULT(s2n_connection_validate_tls13_support(conn));
      48                 :            :     /* QUIC support is not currently compatible with recv_buffering */
      49 [ -  + ][ #  # ]:         49 :     POSIX_ENSURE(!conn->recv_buffering, S2N_ERR_INVALID_STATE);
      50                 :         49 :     conn->quic_enabled = true;
      51                 :         49 :     return S2N_SUCCESS;
      52                 :         49 : }
      53                 :            : 
      54                 :            : bool s2n_connection_is_quic_enabled(struct s2n_connection *conn)
      55                 :    1259255 : {
      56 [ +  + ][ +  + ]:    1259258 :     return (conn && conn->quic_enabled) || (conn && conn->config && conn->config->quic_enabled);
         [ +  - ][ +  + ]
                 [ +  + ]
      57                 :    1259255 : }
      58                 :            : 
      59                 :            : bool s2n_connection_are_session_tickets_enabled(struct s2n_connection *conn)
      60                 :          0 : {
      61 [ #  # ][ #  # ]:          0 :     return conn && conn->config && conn->config->use_tickets;
                 [ #  # ]
      62                 :          0 : }
      63                 :            : 
      64                 :            : int s2n_connection_set_quic_transport_parameters(struct s2n_connection *conn,
      65                 :            :         const uint8_t *data_buffer, uint16_t data_len)
      66                 :          9 : {
      67 [ +  + ][ +  - ]:          9 :     POSIX_ENSURE_REF(conn);
      68                 :            : 
      69         [ -  + ]:          8 :     POSIX_GUARD(s2n_free(&conn->our_quic_transport_parameters));
      70         [ -  + ]:          8 :     POSIX_GUARD(s2n_alloc(&conn->our_quic_transport_parameters, data_len));
      71 [ +  + ][ +  - ]:          8 :     POSIX_CHECKED_MEMCPY(conn->our_quic_transport_parameters.data, data_buffer, data_len);
                 [ +  + ]
      72                 :            : 
      73                 :          7 :     return S2N_SUCCESS;
      74                 :          8 : }
      75                 :            : 
      76                 :            : int s2n_connection_get_quic_transport_parameters(struct s2n_connection *conn,
      77                 :            :         const uint8_t **data_buffer, uint16_t *data_len)
      78                 :          7 : {
      79 [ +  + ][ +  - ]:          7 :     POSIX_ENSURE_REF(conn);
      80 [ +  + ][ +  - ]:          6 :     POSIX_ENSURE_REF(data_buffer);
      81 [ +  - ][ +  + ]:          5 :     POSIX_ENSURE_REF(data_len);
      82                 :            : 
      83                 :          4 :     *data_buffer = conn->peer_quic_transport_parameters.data;
      84                 :          4 :     *data_len = conn->peer_quic_transport_parameters.size;
      85                 :            : 
      86                 :          4 :     return S2N_SUCCESS;
      87                 :          5 : }
      88                 :            : 
      89                 :            : int s2n_connection_set_secret_callback(struct s2n_connection *conn, s2n_secret_cb cb_func, void *ctx)
      90                 :        312 : {
      91 [ +  + ][ +  - ]:        312 :     POSIX_ENSURE_REF(conn);
      92 [ +  + ][ +  - ]:        311 :     POSIX_ENSURE_REF(cb_func);
      93                 :            : 
      94                 :        310 :     conn->secret_cb = cb_func;
      95                 :        310 :     conn->secret_cb_context = ctx;
      96                 :            : 
      97                 :        310 :     return S2N_SUCCESS;
      98                 :        311 : }
      99                 :            : 
     100                 :            : /* Currently we need an API that quic can call to process post-handshake messages. Ideally
     101                 :            :  * we could re-use the s2n_recv API but that function needs to be refactored to support quic.
     102                 :            :  * For now we just call this API.
     103                 :            :  */
     104                 :            : int s2n_recv_quic_post_handshake_message(struct s2n_connection *conn, s2n_blocked_status *blocked)
     105                 :         45 : {
     106 [ +  + ][ +  - ]:         45 :     POSIX_ENSURE_REF(conn);
     107                 :            : 
     108                 :         44 :     *blocked = S2N_BLOCKED_ON_READ;
     109                 :            : 
     110                 :         44 :     uint8_t message_type = 0;
     111                 :            :     /* This function uses the stuffer conn->handshake.io to read in the header. This stuffer is also used 
     112                 :            :      * for sending post-handshake messages. This could cause a concurrency issue if we start both sending
     113                 :            :      * and receiving post-handshake messages while quic is enabled. Currently there's no post-handshake
     114                 :            :      * message that is both sent and received in quic (servers only send session tickets
     115                 :            :      * and clients only receive session tickets.) Therefore it is safe for us
     116                 :            :      * to use the stuffer here.
     117                 :            :      */
     118         [ +  + ]:         44 :     POSIX_GUARD_RESULT(s2n_quic_read_handshake_message(conn, &message_type));
     119                 :            : 
     120                 :            :     /* The only post-handshake messages we support from QUIC currently are session tickets */
     121 [ +  + ][ +  - ]:         23 :     POSIX_ENSURE(message_type == TLS_SERVER_NEW_SESSION_TICKET, S2N_ERR_UNSUPPORTED_WITH_QUIC);
     122         [ -  + ]:         22 :     POSIX_GUARD_RESULT(s2n_post_handshake_process(conn, &conn->in, message_type));
     123                 :            : 
     124                 :         22 :     *blocked = S2N_NOT_BLOCKED;
     125                 :            : 
     126                 :         22 :     return S2N_SUCCESS;
     127                 :         22 : }
     128                 :            : 
     129                 :            : /* When using QUIC, S2N reads unencrypted handshake messages instead of encrypted records.
     130                 :            :  * This method sets up the S2N input buffers to match the results of using s2n_read_full_record.
     131                 :            :  */
     132                 :            : S2N_RESULT s2n_quic_read_handshake_message(struct s2n_connection *conn, uint8_t *message_type)
     133                 :        245 : {
     134 [ +  + ][ +  - ]:        245 :     RESULT_ENSURE_REF(conn);
     135                 :            :     /* The use of handshake.io here would complicate recv_buffering, and there's
     136                 :            :      * no real use case for recv_buffering when QUIC is handling the IO.
     137                 :            :      */
     138 [ #  # ][ -  + ]:        244 :     RESULT_ENSURE(!conn->recv_buffering, S2N_ERR_INVALID_STATE);
     139                 :            : 
     140                 :            :     /* Allocate stuffer space now so that we don't have to realloc later in the handshake. */
     141         [ +  + ]:        244 :     RESULT_GUARD_POSIX(s2n_stuffer_resize_if_empty(&conn->buffer_in, S2N_EXPECTED_QUIC_MESSAGE_SIZE));
     142                 :            : 
     143         [ +  + ]:        243 :     RESULT_GUARD(s2n_read_in_bytes(conn, &conn->handshake.io, TLS_HANDSHAKE_HEADER_LENGTH));
     144                 :            : 
     145                 :        209 :     uint32_t message_len = 0;
     146         [ -  + ]:        209 :     RESULT_GUARD(s2n_handshake_parse_header(&conn->handshake.io, message_type, &message_len));
     147         [ -  + ]:        209 :     RESULT_GUARD_POSIX(s2n_stuffer_reread(&conn->handshake.io));
     148                 :            : 
     149 [ +  - ][ +  + ]:        209 :     RESULT_ENSURE(message_len < S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH, S2N_ERR_BAD_MESSAGE);
     150         [ +  + ]:        206 :     RESULT_GUARD(s2n_read_in_bytes(conn, &conn->buffer_in, message_len));
     151                 :            : 
     152                 :            :     /* Although we call s2n_read_in_bytes, recv_greedy is always disabled for quic.
     153                 :            :      * Therefore buffer_in will always contain exactly message_len bytes of data.
     154                 :            :      * So we don't need to handle the possibility of extra data in buffer_in.
     155                 :            :      */
     156 [ -  + ][ #  # ]:        183 :     RESULT_ENSURE_EQ(s2n_stuffer_data_available(&conn->buffer_in), message_len);
     157         [ -  + ]:        183 :     RESULT_GUARD(s2n_recv_in_init(conn, message_len, message_len));
     158                 :        183 :     return S2N_RESULT_OK;
     159                 :        183 : }
     160                 :            : 
     161                 :            : /* When using QUIC, S2N writes unencrypted handshake messages instead of encrypted records.
     162                 :            :  * This method sets up the S2N output buffer to match the result of using s2n_record_write.
     163                 :            :  */
     164                 :            : S2N_RESULT s2n_quic_write_handshake_message(struct s2n_connection *conn)
     165                 :         52 : {
     166 [ +  - ][ +  + ]:         52 :     RESULT_ENSURE_REF(conn);
     167                 :            : 
     168                 :            :     /* Allocate stuffer space now so that we don't have to realloc later in the handshake. */
     169         [ -  + ]:         51 :     RESULT_GUARD_POSIX(s2n_stuffer_resize_if_empty(&conn->out, S2N_EXPECTED_QUIC_MESSAGE_SIZE));
     170                 :            : 
     171         [ -  + ]:         51 :     RESULT_GUARD_POSIX(s2n_stuffer_copy(&conn->handshake.io, &conn->out,
     172                 :         51 :             s2n_stuffer_data_available(&conn->handshake.io)));
     173                 :         51 :     return S2N_RESULT_OK;
     174                 :         51 : }

Generated by: LCOV version 1.14