Allow configuring QUIC method per-connection
This allows sharing SSL_CTX between TCP and QUIC connections, such that
common settings can be configured without having to duplicate the
context.
Change-Id: Ie920e7f2a772dd6c6c7b63fdac243914ac5b7b26
Reviewed-on: https://boringssl-review.googlesource.com/c/33904
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index c128605..a011e0f 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -3170,6 +3170,12 @@
OPENSSL_EXPORT int SSL_CTX_set_quic_method(SSL_CTX *ctx,
const SSL_QUIC_METHOD *quic_method);
+// SSL_set_quic_method configures the QUIC hooks. This should only be
+// configured with a minimum version of TLS 1.3. |quic_method| must remain valid
+// for the lifetime of |ssl|. It returns one on success and zero on error.
+OPENSSL_EXPORT int SSL_set_quic_method(SSL *ssl,
+ const SSL_QUIC_METHOD *quic_method);
+
// Early data.
//
diff --git a/ssl/handshake.cc b/ssl/handshake.cc
index 058a793..091ed44 100644
--- a/ssl/handshake.cc
+++ b/ssl/handshake.cc
@@ -544,7 +544,7 @@
case ssl_hs_read_server_hello:
case ssl_hs_read_message:
case ssl_hs_read_change_cipher_spec: {
- if (ssl->ctx->quic_method) {
+ if (ssl->quic_method) {
hs->wait = ssl_hs_ok;
// The change cipher spec is omitted in QUIC.
if (hs->wait != ssl_hs_read_change_cipher_spec) {
diff --git a/ssl/internal.h b/ssl/internal.h
index 07e1b89..1116bad 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -3170,6 +3170,9 @@
uint32_t max_cert_list = 0;
bssl::UniquePtr<char> hostname;
+ // quic_method is the method table corresponding to the QUIC hooks.
+ const SSL_QUIC_METHOD *quic_method = nullptr;
+
// renegotiate_mode controls how peer renegotiation attempts are handled.
ssl_renegotiate_mode_t renegotiate_mode = ssl_renegotiate_never;
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc
index 02bc3bb..aec6cae 100644
--- a/ssl/s3_both.cc
+++ b/ssl/s3_both.cc
@@ -192,7 +192,7 @@
//
// TODO(davidben): See if we can do this uniformly.
Span<const uint8_t> rest = msg;
- if (ssl->ctx->quic_method == nullptr &&
+ if (ssl->quic_method == nullptr &&
ssl->s3->aead_write_ctx->is_null_cipher()) {
while (!rest.empty()) {
Span<const uint8_t> chunk = rest.subspan(0, ssl->max_send_fragment);
@@ -248,9 +248,9 @@
auto data =
MakeConstSpan(reinterpret_cast<const uint8_t *>(pending_hs_data->data),
pending_hs_data->length);
- if (ssl->ctx->quic_method) {
- if (!ssl->ctx->quic_method->add_handshake_data(ssl, ssl->s3->write_level,
- data.data(), data.size())) {
+ if (ssl->quic_method) {
+ if (!ssl->quic_method->add_handshake_data(ssl, ssl->s3->write_level,
+ data.data(), data.size())) {
OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
return false;
}
@@ -267,7 +267,7 @@
return false;
}
- if (!ssl->ctx->quic_method &&
+ if (!ssl->quic_method &&
!add_record_to_flight(ssl, SSL3_RT_CHANGE_CIPHER_SPEC,
kChangeCipherSpec)) {
return false;
@@ -283,13 +283,13 @@
return -1;
}
- if (ssl->ctx->quic_method) {
+ if (ssl->quic_method) {
if (ssl->s3->write_shutdown != ssl_shutdown_none) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
return -1;
}
- if (!ssl->ctx->quic_method->flush_flight(ssl)) {
+ if (!ssl->quic_method->flush_flight(ssl)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
return -1;
}
diff --git a/ssl/s3_pkt.cc b/ssl/s3_pkt.cc
index f1d67d0..abc6798 100644
--- a/ssl/s3_pkt.cc
+++ b/ssl/s3_pkt.cc
@@ -410,9 +410,9 @@
}
int ssl3_dispatch_alert(SSL *ssl) {
- if (ssl->ctx->quic_method) {
- if (!ssl->ctx->quic_method->send_alert(ssl, ssl->s3->write_level,
- ssl->s3->send_alert[1])) {
+ if (ssl->quic_method) {
+ if (!ssl->quic_method->send_alert(ssl, ssl->s3->write_level,
+ ssl->s3->send_alert[1])) {
OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
return 0;
}
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index bbc3758..f3d92a6 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -714,6 +714,7 @@
ssl->config->ocsp_stapling_enabled = ctx->ocsp_stapling_enabled;
ssl->config->handoff = ctx->handoff;
ssl->config->ignore_tls13_downgrade = ctx->ignore_tls13_downgrade;
+ ssl->quic_method = ctx->quic_method;
if (!ssl->method->ssl_new(ssl.get()) ||
!ssl->ctx->x509_method->ssl_new(ssl->s3->hs.get())) {
@@ -850,7 +851,7 @@
int SSL_provide_quic_data(SSL *ssl, enum ssl_encryption_level_t level,
const uint8_t *data, size_t len) {
- if (ssl->ctx->quic_method == nullptr) {
+ if (ssl->quic_method == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
@@ -1077,7 +1078,7 @@
}
int SSL_peek(SSL *ssl, void *buf, int num) {
- if (ssl->ctx->quic_method != nullptr) {
+ if (ssl->quic_method != nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
@@ -1098,7 +1099,7 @@
int SSL_write(SSL *ssl, const void *buf, int num) {
ssl_reset_error_state(ssl);
- if (ssl->ctx->quic_method != nullptr) {
+ if (ssl->quic_method != nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
@@ -1342,7 +1343,7 @@
return SSL_ERROR_HANDBACK;
case SSL_READING: {
- if (ssl->ctx->quic_method) {
+ if (ssl->quic_method) {
return SSL_ERROR_WANT_READ;
}
BIO *bio = SSL_get_rbio(ssl);
@@ -2459,6 +2460,14 @@
return 1;
}
+int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) {
+ if (ssl->method->is_dtls) {
+ return 0;
+ }
+ ssl->quic_method = quic_method;
+ return 1;
+}
+
int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
CRYPTO_EX_dup *dup_unused, CRYPTO_EX_free *free_func) {
int index;
diff --git a/ssl/ssl_versions.cc b/ssl/ssl_versions.cc
index 39540f1..e6dbc8d 100644
--- a/ssl/ssl_versions.cc
+++ b/ssl/ssl_versions.cc
@@ -192,7 +192,7 @@
uint16_t max_version = hs->config->conf_max_version;
// QUIC requires TLS 1.3.
- if (hs->ssl->ctx->quic_method && min_version < TLS1_3_VERSION) {
+ if (hs->ssl->quic_method && min_version < TLS1_3_VERSION) {
min_version = TLS1_3_VERSION;
}
diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc
index 605942a..7674d99 100644
--- a/ssl/tls13_both.cc
+++ b/ssl/tls13_both.cc
@@ -655,7 +655,7 @@
bool tls13_post_handshake(SSL *ssl, const SSLMessage &msg) {
if (msg.type == SSL3_MT_KEY_UPDATE) {
ssl->s3->key_update_count++;
- if (ssl->ctx->quic_method != nullptr ||
+ if (ssl->quic_method != nullptr ||
ssl->s3->key_update_count > kMaxKeyUpdates) {
OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_KEY_UPDATES);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
diff --git a/ssl/tls13_enc.cc b/ssl/tls13_enc.cc
index a59686f..7353561 100644
--- a/ssl/tls13_enc.cc
+++ b/ssl/tls13_enc.cc
@@ -144,7 +144,7 @@
}
UniquePtr<SSLAEADContext> traffic_aead;
- if (ssl->ctx->quic_method == nullptr) {
+ if (ssl->quic_method == nullptr) {
// Look up cipher suite properties.
const EVP_AEAD *aead;
size_t discard;
@@ -237,16 +237,16 @@
}
ssl->s3->early_exporter_secret_len = hs->hash_len;
- if (ssl->ctx->quic_method != nullptr) {
+ if (ssl->quic_method != nullptr) {
if (ssl->server) {
- if (!ssl->ctx->quic_method->set_encryption_secrets(
+ if (!ssl->quic_method->set_encryption_secrets(
ssl, ssl_encryption_early_data, nullptr, hs->early_traffic_secret,
hs->hash_len)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
return false;
}
} else {
- if (!ssl->ctx->quic_method->set_encryption_secrets(
+ if (!ssl->quic_method->set_encryption_secrets(
ssl, ssl_encryption_early_data, hs->early_traffic_secret, nullptr,
hs->hash_len)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
@@ -273,16 +273,16 @@
return false;
}
- if (ssl->ctx->quic_method != nullptr) {
+ if (ssl->quic_method != nullptr) {
if (ssl->server) {
- if (!ssl->ctx->quic_method->set_encryption_secrets(
+ if (!ssl->quic_method->set_encryption_secrets(
ssl, ssl_encryption_handshake, hs->client_handshake_secret,
hs->server_handshake_secret, hs->hash_len)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
return false;
}
} else {
- if (!ssl->ctx->quic_method->set_encryption_secrets(
+ if (!ssl->quic_method->set_encryption_secrets(
ssl, ssl_encryption_handshake, hs->server_handshake_secret,
hs->client_handshake_secret, hs->hash_len)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
@@ -314,16 +314,16 @@
return false;
}
- if (ssl->ctx->quic_method != nullptr) {
+ if (ssl->quic_method != nullptr) {
if (ssl->server) {
- if (!ssl->ctx->quic_method->set_encryption_secrets(
+ if (!ssl->quic_method->set_encryption_secrets(
ssl, ssl_encryption_application, hs->client_traffic_secret_0,
hs->server_traffic_secret_0, hs->hash_len)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
return false;
}
} else {
- if (!ssl->ctx->quic_method->set_encryption_secrets(
+ if (!ssl->quic_method->set_encryption_secrets(
ssl, ssl_encryption_application, hs->server_traffic_secret_0,
hs->client_traffic_secret_0, hs->hash_len)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);