1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include "tls/s2n_quic_support.h"
#include "tls/s2n_connection.h"
#include "tls/s2n_tls.h"
#include "tls/s2n_tls13.h"
#include "utils/s2n_mem.h"
#include "utils/s2n_safety.h"
/* When reading and writing records with TCP, S2N sets its input and output buffers
* to the maximum record fragment size to prevent resizing those buffers later.
*
* However, because S2N with QUIC reads and writes messages instead of records,
* the "maximum size" for the input and output buffers would be the maximum message size: 64k.
* Since most messages are MUCH smaller than that (<3k), setting the buffer that large is wasteful.
*
* Instead, we intentionally choose a smaller size and accept that an abnormally large message
* could cause the buffer to resize. */
#define S2N_EXPECTED_QUIC_MESSAGE_SIZE S2N_DEFAULT_FRAGMENT_LENGTH
S2N_RESULT s2n_read_in_bytes(struct s2n_connection *conn, struct s2n_stuffer *output, uint32_t length);
int s2n_config_enable_quic(struct s2n_config *config)
{
POSIX_ENSURE_REF(config);
config->quic_enabled = true;
return S2N_SUCCESS;
}
int s2n_connection_enable_quic(struct s2n_connection *conn)
{
POSIX_ENSURE_REF(conn);
POSIX_GUARD_RESULT(s2n_connection_validate_tls13_support(conn));
conn->quic_enabled = true;
return S2N_SUCCESS;
}
bool s2n_connection_is_quic_enabled(struct s2n_connection *conn)
{
return (conn && conn->quic_enabled) || (conn && conn->config && conn->config->quic_enabled);
}
int s2n_connection_set_quic_transport_parameters(struct s2n_connection *conn,
const uint8_t *data_buffer, uint16_t data_len)
{
POSIX_ENSURE_REF(conn);
POSIX_GUARD(s2n_free(&conn->our_quic_transport_parameters));
POSIX_GUARD(s2n_alloc(&conn->our_quic_transport_parameters, data_len));
POSIX_CHECKED_MEMCPY(conn->our_quic_transport_parameters.data, data_buffer, data_len);
return S2N_SUCCESS;
}
int s2n_connection_get_quic_transport_parameters(struct s2n_connection *conn,
const uint8_t **data_buffer, uint16_t *data_len)
{
POSIX_ENSURE_REF(conn);
POSIX_ENSURE_REF(data_buffer);
POSIX_ENSURE_REF(data_len);
*data_buffer = conn->peer_quic_transport_parameters.data;
*data_len = conn->peer_quic_transport_parameters.size;
return S2N_SUCCESS;
}
int s2n_connection_set_secret_callback(struct s2n_connection *conn, s2n_secret_cb cb_func, void *ctx)
{
POSIX_ENSURE_REF(conn);
POSIX_ENSURE_REF(cb_func);
conn->secret_cb = cb_func;
conn->secret_cb_context = ctx;
return S2N_SUCCESS;
}
/* When using QUIC, S2N reads unencrypted handshake messages instead of encrypted records.
* This method sets up the S2N input buffers to match the results of using s2n_read_full_record.
*/
S2N_RESULT s2n_quic_read_handshake_message(struct s2n_connection *conn, uint8_t *message_type)
{
RESULT_ENSURE_REF(conn);
/* Allocate stuffer space now so that we don't have to realloc later in the handshake. */
RESULT_GUARD_POSIX(s2n_stuffer_resize_if_empty(&conn->in, S2N_EXPECTED_QUIC_MESSAGE_SIZE));
RESULT_GUARD(s2n_read_in_bytes(conn, &conn->handshake.io, TLS_HANDSHAKE_HEADER_LENGTH));
uint32_t message_len;
RESULT_GUARD(s2n_handshake_parse_header(&conn->handshake.io, message_type, &message_len));
RESULT_GUARD_POSIX(s2n_stuffer_reread(&conn->handshake.io));
RESULT_ENSURE(message_len < S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH, S2N_ERR_BAD_MESSAGE);
RESULT_GUARD(s2n_read_in_bytes(conn, &conn->in, message_len));
return S2N_RESULT_OK;
}
/* When using QUIC, S2N writes unencrypted handshake messages instead of encrypted records.
* This method sets up the S2N output buffer to match the result of using s2n_record_write.
*/
S2N_RESULT s2n_quic_write_handshake_message(struct s2n_connection *conn, struct s2n_blob *in)
{
RESULT_ENSURE_REF(conn);
/* Allocate stuffer space now so that we don't have to realloc later in the handshake. */
RESULT_GUARD_POSIX(s2n_stuffer_resize_if_empty(&conn->out, S2N_EXPECTED_QUIC_MESSAGE_SIZE));
RESULT_GUARD_POSIX(s2n_stuffer_write(&conn->out, in));
return S2N_RESULT_OK;
}
|