Skip to content

Commit

Permalink
Add initial QUIC setup (aws#2283)
Browse files Browse the repository at this point in the history
Add a new method to enable QUIC-mode for TLS1.3. For now,
QUIC-mode does not change any TLS1.3 behavior.
  • Loading branch information
lrstewart authored Sep 14, 2020
1 parent 062554b commit e6314dd
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 14 deletions.
2 changes: 1 addition & 1 deletion error/s2n_errno.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ static const char *no_such_error = "Internal s2n error";
ERR_ENTRY(S2N_ERR_CERT_TYPE_UNSUPPORTED, "Certificate Type is unsupported") \
ERR_ENTRY(S2N_ERR_INVALID_MAX_FRAG_LEN, "invalid Maximum Fragmentation Length encountered") \
ERR_ENTRY(S2N_ERR_MAX_FRAG_LEN_MISMATCH, "Negotiated Maximum Fragmentation Length from server does not match the requested length by client") \
ERR_ENTRY(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED, "TLS protocol version is not supported by selected cipher suite") \
ERR_ENTRY(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED, "TLS protocol version is not supported by configuration") \
ERR_ENTRY(S2N_ERR_BAD_KEY_SHARE, "Bad key share received") \
ERR_ENTRY(S2N_ERR_CANCELLED, "handshake was cancelled") \
ERR_ENTRY(S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED, "Protocol downgrade detected by client") \
Expand Down
57 changes: 57 additions & 0 deletions tests/unit/s2n_client_hello_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "tls/s2n_tls.h"
#include "tls/s2n_tls13.h"
#include "tls/s2n_connection.h"
#include "tls/s2n_quic_support.h"
#include "tls/s2n_security_policies.h"
#include "tls/s2n_client_hello.h"
#include "tls/s2n_handshake.h"
Expand Down Expand Up @@ -227,6 +228,62 @@ int main(int argc, char **argv)
}
}

/* Test that negotiating TLS1.2 with QUIC-enabled server fails */
{
struct s2n_config *config = s2n_config_new();
EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, "test_all"));
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, ecdsa_chain_and_key));

/* Succeeds when negotiating TLS1.3 */
{
EXPECT_SUCCESS(s2n_enable_tls13());

struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));
EXPECT_EQUAL(server_conn->server_protocol_version, S2N_TLS13);

struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
EXPECT_SUCCESS(s2n_connection_set_config(client_conn, config));
EXPECT_EQUAL(client_conn->client_protocol_version, S2N_TLS13);

EXPECT_SUCCESS(s2n_connection_enable_quic(server_conn));

EXPECT_SUCCESS(s2n_client_hello_send(client_conn));
EXPECT_SUCCESS(s2n_stuffer_copy(&client_conn->handshake.io,
&server_conn->handshake.io, s2n_stuffer_data_available(&client_conn->handshake.io)));
EXPECT_SUCCESS(s2n_client_hello_recv(server_conn));

EXPECT_SUCCESS(s2n_connection_free(client_conn));
EXPECT_SUCCESS(s2n_connection_free(server_conn));
}

/* Fails when negotiating TLS1.2 */
{
EXPECT_SUCCESS(s2n_disable_tls13());
struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
EXPECT_SUCCESS(s2n_connection_set_config(client_conn, config));
EXPECT_EQUAL(client_conn->client_protocol_version, S2N_TLS12);

EXPECT_SUCCESS(s2n_enable_tls13());
struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));
EXPECT_EQUAL(server_conn->server_protocol_version, S2N_TLS13);

EXPECT_SUCCESS(s2n_connection_enable_quic(server_conn));

EXPECT_SUCCESS(s2n_client_hello_send(client_conn));
EXPECT_SUCCESS(s2n_stuffer_copy(&client_conn->handshake.io,
&server_conn->handshake.io, s2n_stuffer_data_available(&client_conn->handshake.io)));
EXPECT_FAILURE_WITH_ERRNO(s2n_client_hello_recv(server_conn), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);

EXPECT_SUCCESS(s2n_connection_free(client_conn));
EXPECT_SUCCESS(s2n_connection_free(server_conn));
}

EXPECT_SUCCESS(s2n_config_free(config));
EXPECT_SUCCESS(s2n_disable_tls13());
}

/* Test that cipher suites enforce proper highest supported versions.
* Eg. server configs TLS 1.2 only ciphers should never negotiate TLS 1.3
*/
Expand Down
57 changes: 57 additions & 0 deletions tests/unit/s2n_quic_support_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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 "s2n_test.h"
#include "tls/s2n_quic_support.h"

#include "tls/s2n_connection.h"

int main(int argc, char **argv)
{
BEGIN_TEST();

/* Test s2n_connection_enable_quic */
{
struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT);
EXPECT_NOT_NULL(conn);
EXPECT_FALSE(conn->quic_enabled);

/* Check error handling */
{
EXPECT_SUCCESS(s2n_disable_tls13());
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_enable_quic(conn), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);
EXPECT_FALSE(conn->quic_enabled);

EXPECT_SUCCESS(s2n_enable_tls13());
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_enable_quic(NULL), S2N_ERR_NULL);
EXPECT_FALSE(conn->quic_enabled);
}

/* Check success */
{
EXPECT_SUCCESS(s2n_enable_tls13());
EXPECT_SUCCESS(s2n_connection_enable_quic(conn));
EXPECT_TRUE(conn->quic_enabled);

/* Enabling QUIC again still succeeds */
EXPECT_SUCCESS(s2n_connection_enable_quic(conn));
EXPECT_TRUE(conn->quic_enabled);
}

EXPECT_SUCCESS(s2n_connection_free(conn));
}

END_TEST();
}
79 changes: 77 additions & 2 deletions tests/unit/s2n_server_hello_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <s2n.h>

#include "tls/s2n_cipher_suites.h"
#include "tls/s2n_quic_support.h"
#include "tls/s2n_tls.h"
#include "tls/s2n_tls13.h"
#include "tls/s2n_security_policies.h"
Expand All @@ -43,10 +44,27 @@ const uint8_t tls11_downgrade_protection_check_bytes[] = {
0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x00
};

static S2N_RESULT s2n_test_client_hello(struct s2n_connection *client_conn, struct s2n_connection *server_conn)
{
GUARD_AS_RESULT(s2n_client_hello_send(client_conn));
GUARD_AS_RESULT(s2n_stuffer_copy(&client_conn->handshake.io,
&server_conn->handshake.io, s2n_stuffer_data_available(&client_conn->handshake.io)));
GUARD_AS_RESULT(s2n_client_hello_recv(server_conn));

GUARD_AS_RESULT(s2n_stuffer_wipe(&client_conn->handshake.io));
GUARD_AS_RESULT(s2n_stuffer_wipe(&server_conn->handshake.io));

return S2N_RESULT_OK;
}

int main(int argc, char **argv)
{
BEGIN_TEST();

struct s2n_cert_chain_and_key *chain_and_key;
EXPECT_SUCCESS(s2n_test_cert_chain_and_key_new(&chain_and_key,
S2N_DEFAULT_ECDSA_TEST_CERT_CHAIN, S2N_DEFAULT_ECDSA_TEST_PRIVATE_KEY));

/* Test basic Server Hello Send */
{
struct s2n_config *config;
Expand Down Expand Up @@ -480,7 +498,64 @@ int main(int argc, char **argv)
EXPECT_SUCCESS(s2n_connection_free(client_conn));
}

END_TEST();
/* Test that negotiating TLS1.2 with QUIC-enabled client fails */
{
struct s2n_config *config = s2n_config_new();
EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, "test_all"));
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key));

/* Succeeds when negotiating TLS1.3 */
{
EXPECT_SUCCESS(s2n_enable_tls13());

struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
EXPECT_SUCCESS(s2n_connection_set_config(client_conn, config));
EXPECT_EQUAL(client_conn->client_protocol_version, S2N_TLS13);

struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));
EXPECT_EQUAL(server_conn->server_protocol_version, S2N_TLS13);

EXPECT_OK(s2n_test_client_hello(client_conn, server_conn));
EXPECT_SUCCESS(s2n_connection_enable_quic(client_conn));

EXPECT_SUCCESS(s2n_server_hello_send(server_conn));
EXPECT_SUCCESS(s2n_stuffer_copy(&server_conn->handshake.io,
&client_conn->handshake.io, s2n_stuffer_data_available(&server_conn->handshake.io)));
EXPECT_SUCCESS(s2n_server_hello_recv(client_conn));

return 0;
EXPECT_SUCCESS(s2n_connection_free(client_conn));
EXPECT_SUCCESS(s2n_connection_free(server_conn));
}

/* Fails when negotiating TLS1.2 */
{
EXPECT_SUCCESS(s2n_disable_tls13());
struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));
EXPECT_EQUAL(server_conn->server_protocol_version, S2N_TLS12);

EXPECT_SUCCESS(s2n_enable_tls13());
struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
EXPECT_SUCCESS(s2n_connection_set_config(client_conn, config));
EXPECT_EQUAL(client_conn->client_protocol_version, S2N_TLS13);

EXPECT_OK(s2n_test_client_hello(client_conn, server_conn));
EXPECT_SUCCESS(s2n_connection_enable_quic(client_conn));

EXPECT_SUCCESS(s2n_server_hello_send(server_conn));
EXPECT_SUCCESS(s2n_stuffer_copy(&server_conn->handshake.io,
&client_conn->handshake.io, s2n_stuffer_data_available(&server_conn->handshake.io)));
EXPECT_FAILURE_WITH_ERRNO(s2n_server_hello_recv(client_conn), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);

EXPECT_SUCCESS(s2n_connection_free(client_conn));
EXPECT_SUCCESS(s2n_connection_free(server_conn));
}

EXPECT_SUCCESS(s2n_config_free(config));
}

EXPECT_SUCCESS(s2n_cert_chain_and_key_free(chain_and_key));

END_TEST();
}
3 changes: 2 additions & 1 deletion tls/s2n_client_hello.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@ int s2n_process_client_hello(struct s2n_connection *conn)
}

/* for pre TLS 1.3 connections, protocol selection is not done in supported_versions extensions, so do it here */
if (conn->actual_protocol_version != S2N_TLS13) {
if (conn->actual_protocol_version < S2N_TLS13) {
ENSURE_POSIX(!conn->quic_enabled, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);
conn->actual_protocol_version = MIN(conn->server_protocol_version, conn->client_protocol_version);
}

Expand Down
24 changes: 14 additions & 10 deletions tls/s2n_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,6 @@ struct s2n_connection {
/* Was the EC point formats sent by the client */
unsigned ec_point_formats:1;

/* Track request extensions to ensure correct response extension behavior.
*
* We need to track client and server extensions separately because some
* extensions (like request_status and other Certificate extensions) can
* be requested by the client, the server, or both.
*/
s2n_extension_bitfield extension_requests_sent;
s2n_extension_bitfield extension_requests_received;

/* whether the connection address is ipv6 or not */
unsigned ipv6:1;

Expand All @@ -114,7 +105,16 @@ struct s2n_connection {

/* If write fd is broken */
unsigned write_fd_broken:1;


/* Track request extensions to ensure correct response extension behavior.
*
* We need to track client and server extensions separately because some
* extensions (like request_status and other Certificate extensions) can
* be requested by the client, the server, or both.
*/
s2n_extension_bitfield extension_requests_sent;
s2n_extension_bitfield extension_requests_received;

/* Is this connection a client or a server connection */
s2n_mode mode;

Expand Down Expand Up @@ -305,6 +305,10 @@ struct s2n_connection {
/* Key update data */
unsigned key_update_pending:1;

/* Whether this connection can be used by a QUIC implementation.
* See s2n_quic_support.h */
unsigned quic_enabled:1;

/* Bitmap to represent preferred list of keyshare for client to generate and send keyshares in the ClientHello message.
* The least significant bit (lsb), if set, indicates that the client must send an empty keyshare list.
* Each bit value in the bitmap indiciates the corresponding curve in the ecc_preferences list for which a key share needs to be generated.
Expand Down
30 changes: 30 additions & 0 deletions tls/s2n_quic_support.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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_tls13.h"
#include "utils/s2n_safety.h"

int s2n_connection_enable_quic(struct s2n_connection *conn)
{
/* The QUIC protocol doesn't use pre-1.3 TLS */
ENSURE_POSIX(s2n_is_tls13_enabled(), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);

notnull_check(conn);
conn->quic_enabled = true;
return S2N_SUCCESS;
}
32 changes: 32 additions & 0 deletions tls/s2n_quic_support.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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.
*/

#pragma once

#include "api/s2n.h"

/*
* APIs intended to support an external implementation of the QUIC protocol:
* https://datatracker.ietf.org/wg/quic/about/
*
* QUIC requires access to parts of S2N not usually surfaced to customers. These APIs change
* the behavior of S2N in potentially dangerous ways and should only be used by implementations
* of the QUIC protocol.
*
* Additionally, the QUIC RFC is not yet finalized, so all QUIC APIs are considered experimental
* and are subject to change without notice. They should only be used for testing purposes.
*/

S2N_API int s2n_connection_enable_quic(struct s2n_connection *conn);
1 change: 1 addition & 0 deletions tls/s2n_server_hello.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ static int s2n_server_hello_parse(struct s2n_connection *conn)
conn->server_protocol_version = (uint8_t)(protocol_version[0] * 10) + protocol_version[1];

S2N_ERROR_IF(s2n_client_detect_downgrade_mechanism(conn), S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED);
ENSURE_POSIX(!conn->quic_enabled, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);

const struct s2n_security_policy *security_policy;
GUARD(s2n_connection_get_security_policy(conn, &security_policy));
Expand Down

0 comments on commit e6314dd

Please sign in to comment.