Skip to content

Commit

Permalink
QUIC: Control SSL option setting
Browse files Browse the repository at this point in the history
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from #20061)
  • Loading branch information
hlandau authored and paulidale committed Jul 4, 2023
1 parent 68dbff4 commit f0d9757
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 7 deletions.
5 changes: 4 additions & 1 deletion include/internal/quic_ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ __owur int ossl_quic_key_update(SSL *s, int update_type);
__owur int ossl_quic_get_key_update_type(const SSL *s);
__owur int ossl_quic_num_ciphers(void);
__owur const SSL_CIPHER *ossl_quic_get_cipher(unsigned int u);
__owur int ossl_quic_set_ssl_op(SSL *ssl, uint64_t op);
int ossl_quic_renegotiate_check(SSL *ssl, int initok);

typedef struct quic_conn_st QUIC_CONNECTION;
Expand Down Expand Up @@ -96,6 +95,10 @@ __owur int ossl_quic_get_conn_close_info(SSL *ssl,
SSL_CONN_CLOSE_INFO *info,
size_t info_len);

uint64_t ossl_quic_set_options(SSL *s, uint64_t opts);
uint64_t ossl_quic_clear_options(SSL *s, uint64_t opts);
uint64_t ossl_quic_get_options(const SSL *s);

/*
* Used to override ossl_time_now() for debug purposes. While this may be
* overridden at any time, expect strange results if you change it after
Expand Down
51 changes: 50 additions & 1 deletion ssl/quic/quic_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@ static void quic_unlock(QUIC_CONNECTION *qc)
* ossl_quic_deinit
* SSL_free => ossl_quic_free
*
* SSL_set_options => ossl_quic_set_options
* SSL_get_options => ossl_quic_get_options
* SSL_clear_options => ossl_quic_clear_options
*
*/

/* SSL_new */
Expand All @@ -322,10 +326,13 @@ SSL *ossl_quic_new(SSL_CTX *ctx)
qc->tls = ossl_ssl_connection_new_int(ctx, TLS_method());
if (qc->tls == NULL || (sc = SSL_CONNECTION_FROM_SSL(qc->tls)) == NULL)
goto err;

/* override the user_ssl of the inner connection */
sc->user_ssl = ssl_base;
sc->s3.flags |= TLS1_FLAGS_QUIC;

/* Restrict options derived from the SSL_CTX. */
sc->options &= OSSL_QUIC_PERMITTED_OPTIONS;

#if defined(OPENSSL_THREADS)
if ((qc->mutex = ossl_crypto_mutex_new()) == NULL)
goto err;
Expand Down Expand Up @@ -608,6 +615,48 @@ static void qc_set_default_xso(QUIC_CONNECTION *qc, QUIC_XSO *xso, int touch)
SSL_free(&old_xso->ssl);
}

/* SSL_set_options */
static uint64_t quic_mask_or_options(SSL *ssl, uint64_t mask_value, uint64_t or_value)
{
QCTX ctx;
uint64_t r, options;

if (!expect_quic_with_stream_lock(ssl, /*remote_init=*/-1, &ctx))
return 0;

/*
* Currently most options that we permit are handled in the handshake
* layer.
*/
options = (SSL_get_options(ctx.qc->tls) & ~mask_value) | or_value;
options &= OSSL_QUIC_PERMITTED_OPTIONS;
r = SSL_set_options(ctx.qc->tls, options);

if (ctx.xso->stream != NULL && ctx.xso->stream->rstream != NULL)
ossl_quic_rstream_set_cleanse(ctx.xso->stream->rstream,
(options & SSL_OP_CLEANSE_PLAINTEXT) != 0);

quic_unlock(ctx.qc);
return r;
}

uint64_t ossl_quic_set_options(SSL *ssl, uint64_t options)
{
return quic_mask_or_options(ssl, UINT64_MAX, options);
}

/* SSL_clear_options */
uint64_t ossl_quic_clear_options(SSL *ssl, uint64_t options)
{
return quic_mask_or_options(ssl, options, 0);
}

/* SSL_get_options */
uint64_t ossl_quic_get_options(const SSL *ssl)
{
return quic_mask_or_options((SSL *)ssl, 0, 0);
}

/*
* QUIC Front-End I/O API: Network BIO Configuration
* =================================================
Expand Down
20 changes: 15 additions & 5 deletions ssl/ssl_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,7 @@ SSL *ossl_ssl_connection_new_int(SSL_CTX *ctx, const SSL_METHOD *method)
RECORD_LAYER_init(&s->rlayer, s);

s->options = ctx->options;

s->dane.flags = ctx->dane.flags;
if (method->version == ctx->method->version) {
s->min_proto_version = ctx->min_proto_version;
Expand Down Expand Up @@ -5888,6 +5889,11 @@ uint64_t SSL_get_options(const SSL *s)
{
const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);

#ifndef OPENSSL_NO_QUIC
if (IS_QUIC(s))
return ossl_quic_get_options(s);
#endif

if (sc == NULL)
return 0;

Expand All @@ -5905,13 +5911,12 @@ uint64_t SSL_set_options(SSL *s, uint64_t op)
OSSL_PARAM options[2], *opts = options;

#ifndef OPENSSL_NO_QUIC
if (IS_QUIC(s) && ossl_quic_set_ssl_op(s, op))
/* Handled by QUIC, return as set */
return op;
if (IS_QUIC(s))
return ossl_quic_set_options(s, op);
#endif

sc = SSL_CONNECTION_FROM_SSL(s);
if (sc == NULL)
sc = SSL_CONNECTION_FROM_SSL(s);
if (sc == NULL)
return 0;

sc->options |= op;
Expand All @@ -5935,6 +5940,11 @@ uint64_t SSL_clear_options(SSL *s, uint64_t op)
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);

#ifndef OPENSSL_NO_QUIC
if (IS_QUIC(s))
return ossl_quic_clear_options(s, op);
#endif

if (sc == NULL)
return 0;

Expand Down
59 changes: 59 additions & 0 deletions ssl/ssl_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -2999,4 +2999,63 @@ void ossl_ssl_set_custom_record_layer(SSL_CONNECTION *s,
const OSSL_RECORD_METHOD *meth,
void *rlarg);

/*
* Options which no longer have any effect, but which can be implemented
* as no-ops for QUIC.
*/
#define OSSL_LEGACY_SSL_OPTIONS \
(SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG | \
SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER | \
SSL_OP_SSLEAY_080_CLIENT_DH_BUG | \
SSL_OP_TLS_D5_BUG | \
SSL_OP_TLS_BLOCK_PADDING_BUG | \
SSL_OP_MSIE_SSLV2_RSA_PADDING | \
SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG | \
SSL_OP_MICROSOFT_SESS_ID_BUG | \
SSL_OP_NETSCAPE_CHALLENGE_BUG | \
SSL_OP_PKCS1_CHECK_1 | \
SSL_OP_PKCS1_CHECK_2 | \
SSL_OP_SINGLE_DH_USE | \
SSL_OP_SINGLE_ECDH_USE | \
SSL_OP_EPHEMERAL_RSA )

/*
* Options which are no-ops under QUIC or TLSv1.3 and which are therefore
* allowed but ignored under QUIC.
*/
#define OSSL_TLS1_2_OPTIONS \
(SSL_OP_CRYPTOPRO_TLSEXT_BUG | \
SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS | \
SSL_OP_ALLOW_CLIENT_RENEGOTIATION | \
SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION | \
SSL_OP_NO_COMPRESSION | \
SSL_OP_NO_SSLv3 | \
SSL_OP_NO_TLSv1 | \
SSL_OP_NO_TLSv1_1 | \
SSL_OP_NO_TLSv1_2 | \
SSL_OP_NO_DTLSv1 | \
SSL_OP_NO_DTLSv1_2 | \
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | \
SSL_OP_CISCO_ANYCONNECT | \
SSL_OP_NO_RENEGOTIATION | \
SSL_OP_NO_EXTENDED_MASTER_SECRET | \
SSL_OP_NO_ENCRYPT_THEN_MAC | \
SSL_OP_COOKIE_EXCHANGE | \
SSL_OP_LEGACY_SERVER_CONNECT | \
SSL_OP_IGNORE_UNEXPECTED_EOF )

/* Total mask of options permitted or ignored under QUIC. */
#define OSSL_QUIC_PERMITTED_OPTIONS \
(OSSL_LEGACY_SSL_OPTIONS | \
OSSL_TLS1_2_OPTIONS | \
SSL_OP_CIPHER_SERVER_PREFERENCE | \
SSL_OP_DISABLE_TLSEXT_CA_NAMES | \
SSL_OP_NO_TX_CERTIFICATE_COMPRESSION | \
SSL_OP_NO_RX_CERTIFICATE_COMPRESSION | \
SSL_OP_PRIORITIZE_CHACHA | \
SSL_OP_CLEANSE_PLAINTEXT | \
SSL_OP_NO_QUERY_MTU | \
SSL_OP_NO_TICKET | \
SSL_OP_NO_ANTI_REPLAY )

#endif
43 changes: 43 additions & 0 deletions test/quicapitest.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "helpers/quictestlib.h"
#include "testutil.h"
#include "testutil/output.h"
#include "../ssl/ssl_local.h"

static OSSL_LIB_CTX *libctx = NULL;
static OSSL_PROVIDER *defctxnull = NULL;
Expand Down Expand Up @@ -416,6 +417,47 @@ static int test_quic_forbidden_apis(void)
return testresult;
}

static int test_quic_forbidden_options(void)
{
int testresult = 0;
SSL_CTX *ctx = NULL;
SSL *ssl = NULL;

if (!TEST_ptr(ctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method())))
goto err;

/* QUIC options restrictions do not affect SSL_CTX */
SSL_CTX_set_options(ctx, UINT64_MAX);

if (!TEST_uint64_t_eq(SSL_CTX_get_options(ctx), UINT64_MAX))
goto err;

if (!TEST_ptr(ssl = SSL_new(ctx)))
goto err;

/* Only permitted options get transferred to SSL object */
if (!TEST_uint64_t_eq(SSL_get_options(ssl), OSSL_QUIC_PERMITTED_OPTIONS))
goto err;

/* Try again using SSL_set_options */
SSL_set_options(ssl, UINT64_MAX);

if (!TEST_uint64_t_eq(SSL_get_options(ssl), OSSL_QUIC_PERMITTED_OPTIONS))
goto err;

/* Clear everything */
SSL_clear_options(ssl, UINT64_MAX);

if (!TEST_uint64_t_eq(SSL_get_options(ssl), 0))
goto err;

testresult = 1;
err:
SSL_free(ssl);
SSL_CTX_free(ctx);
return testresult;
}

OPT_TEST_DECLARE_USAGE("provider config certsdir datadir\n")

int setup_tests(void)
Expand Down Expand Up @@ -479,6 +521,7 @@ int setup_tests(void)
#endif
ADD_TEST(test_quic_forbidden_apis_ctx);
ADD_TEST(test_quic_forbidden_apis);
ADD_TEST(test_quic_forbidden_options);
return 1;
err:
cleanup_tests();
Expand Down

0 comments on commit f0d9757

Please sign in to comment.