Output a ClientHello during handoff.
This will allow edge servers to pass judgement on the ClientHello before
completing the handoff process. This also means that edge servers will
now enforce ClientHello well-formedness — previously that check didn't
occur until the handshaker tried to parse the handoff submission.
Change-Id: I9804ac0224632b4b4381c1a81f434d188e0b9376
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/35584
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 629f006..4240c29 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -4757,7 +4757,8 @@
OPENSSL_EXPORT void SSL_CTX_set_handoff_mode(SSL_CTX *ctx, bool on);
OPENSSL_EXPORT void SSL_set_handoff_mode(SSL *SSL, bool on);
-OPENSSL_EXPORT bool SSL_serialize_handoff(const SSL *ssl, CBB *out);
+OPENSSL_EXPORT bool SSL_serialize_handoff(const SSL *ssl, CBB *out,
+ SSL_CLIENT_HELLO *out_hello);
OPENSSL_EXPORT bool SSL_decline_handoff(SSL *ssl);
OPENSSL_EXPORT bool SSL_apply_handoff(SSL *ssl, Span<const uint8_t> handoff);
OPENSSL_EXPORT bool SSL_serialize_handback(const SSL *ssl, CBB *out);
diff --git a/ssl/d1_both.cc b/ssl/d1_both.cc
index d82852d..f68cd1c 100644
--- a/ssl/d1_both.cc
+++ b/ssl/d1_both.cc
@@ -405,7 +405,7 @@
return ssl_open_record_success;
}
-bool dtls1_get_message(SSL *ssl, SSLMessage *out) {
+bool dtls1_get_message(const SSL *ssl, SSLMessage *out) {
if (!dtls1_is_current_message_complete(ssl)) {
return false;
}
diff --git a/ssl/handoff.cc b/ssl/handoff.cc
index f9dbd13..0928015 100644
--- a/ssl/handoff.cc
+++ b/ssl/handoff.cc
@@ -49,7 +49,8 @@
return CBB_flush(out);
}
-bool SSL_serialize_handoff(const SSL *ssl, CBB *out) {
+bool SSL_serialize_handoff(const SSL *ssl, CBB *out,
+ SSL_CLIENT_HELLO *out_hello) {
const SSL3_STATE *const s3 = ssl->s3;
if (!ssl->server ||
s3->hs == nullptr ||
@@ -58,6 +59,7 @@
}
CBB seq;
+ SSLMessage msg;
Span<const uint8_t> transcript = s3->hs->transcript.buffer();
if (!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&seq, kHandoffVersion) ||
@@ -66,7 +68,9 @@
reinterpret_cast<uint8_t *>(s3->hs_buf->data),
s3->hs_buf->length) ||
!serialize_features(&seq) ||
- !CBB_flush(out)) {
+ !CBB_flush(out) ||
+ !ssl->method->get_message(ssl, &msg) ||
+ !ssl_client_hello_init(ssl, out_hello, msg)) {
return false;
}
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index cb4e9d1..4622ad0 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -515,10 +515,6 @@
return ssl_hs_error;
}
- if (hs->config->handoff) {
- return ssl_hs_handoff;
- }
-
SSL_CLIENT_HELLO client_hello;
if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
@@ -526,6 +522,10 @@
return ssl_hs_error;
}
+ if (hs->config->handoff) {
+ return ssl_hs_handoff;
+ }
+
// Run the early callback.
if (ssl->ctx->select_certificate_cb != NULL) {
switch (ssl->ctx->select_certificate_cb(&client_hello)) {
diff --git a/ssl/internal.h b/ssl/internal.h
index 16b2866..ee2952a 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1081,7 +1081,7 @@
void ssl_do_info_callback(const SSL *ssl, int type, int value);
// ssl_do_msg_callback calls |ssl|'s message callback, if set.
-void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type,
+void ssl_do_msg_callback(const SSL *ssl, int is_write, int content_type,
Span<const uint8_t> in);
@@ -1798,7 +1798,7 @@
// ClientHello functions.
-bool ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out,
+bool ssl_client_hello_init(const SSL *ssl, SSL_CLIENT_HELLO *out,
const SSLMessage &msg);
bool ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello,
@@ -1958,7 +1958,7 @@
void (*ssl_free)(SSL *ssl);
// get_message sets |*out| to the current handshake message and returns true
// if one has been received. It returns false if more input is needed.
- bool (*get_message)(SSL *ssl, SSLMessage *out);
+ bool (*get_message)(const SSL *ssl, SSLMessage *out);
// next_message is called to release the current handshake message.
void (*next_message)(SSL *ssl);
// Use the |ssl_open_handshake| wrapper.
@@ -2675,7 +2675,7 @@
void ssl_update_cache(SSL_HANDSHAKE *hs, int mode);
int ssl_send_alert(SSL *ssl, int level, int desc);
-bool ssl3_get_message(SSL *ssl, SSLMessage *out);
+bool ssl3_get_message(const SSL *ssl, SSLMessage *out);
ssl_open_record_t ssl3_open_handshake(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in);
void ssl3_next_message(SSL *ssl);
@@ -2741,7 +2741,7 @@
bool dtls1_new(SSL *ssl);
void dtls1_free(SSL *ssl);
-bool dtls1_get_message(SSL *ssl, SSLMessage *out);
+bool dtls1_get_message(const SSL *ssl, SSLMessage *out);
ssl_open_record_t dtls1_open_handshake(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in);
void dtls1_next_message(SSL *ssl);
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc
index aec6cae..27e9454 100644
--- a/ssl/s3_both.cc
+++ b/ssl/s3_both.cc
@@ -494,7 +494,7 @@
return true;
}
-bool ssl3_get_message(SSL *ssl, SSLMessage *out) {
+bool ssl3_get_message(const SSL *ssl, SSLMessage *out) {
size_t unused;
if (!parse_message(ssl, out, &unused)) {
return false;
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index d3e76d0..f9910f7 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -378,7 +378,7 @@
}
}
-void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type,
+void ssl_do_msg_callback(const SSL *ssl, int is_write, int content_type,
Span<const uint8_t> in) {
if (ssl->msg_callback == NULL) {
return;
@@ -399,8 +399,8 @@
version = SSL_version(ssl);
}
- ssl->msg_callback(is_write, version, content_type, in.data(), in.size(), ssl,
- ssl->msg_callback_arg);
+ ssl->msg_callback(is_write, version, content_type, in.data(), in.size(),
+ const_cast<SSL *>(ssl), ssl->msg_callback_arg);
}
void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock) {
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index cd6f389..d01b649 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -4050,8 +4050,9 @@
ScopedCBB cbb;
Array<uint8_t> handoff;
+ SSL_CLIENT_HELLO hello;
ASSERT_TRUE(CBB_init(cbb.get(), 256));
- ASSERT_TRUE(SSL_serialize_handoff(server.get(), cbb.get()));
+ ASSERT_TRUE(SSL_serialize_handoff(server.get(), cbb.get(), &hello));
ASSERT_TRUE(CBBFinishArray(cbb.get(), &handoff));
bssl::UniquePtr<SSL> handshaker(SSL_new(handshaker_ctx.get()));
@@ -4122,8 +4123,9 @@
ASSERT_EQ(server_err, SSL_ERROR_HANDOFF);
ScopedCBB cbb;
+ SSL_CLIENT_HELLO hello;
ASSERT_TRUE(CBB_init(cbb.get(), 256));
- ASSERT_TRUE(SSL_serialize_handoff(server.get(), cbb.get()));
+ ASSERT_TRUE(SSL_serialize_handoff(server.get(), cbb.get(), &hello));
ASSERT_TRUE(SSL_decline_handoff(server.get()));
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index c0452dc..87f1888 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -199,10 +199,10 @@
return true;
}
-bool ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out,
+bool ssl_client_hello_init(const SSL *ssl, SSL_CLIENT_HELLO *out,
const SSLMessage &msg) {
OPENSSL_memset(out, 0, sizeof(*out));
- out->ssl = ssl;
+ out->ssl = const_cast<SSL *>(ssl);
out->client_hello = CBS_data(&msg.body);
out->client_hello_len = CBS_len(&msg.body);
diff --git a/ssl/test/handshake_util.cc b/ssl/test/handshake_util.cc
index a36b41a..afead7f 100644
--- a/ssl/test/handshake_util.cc
+++ b/ssl/test/handshake_util.cc
@@ -413,8 +413,9 @@
}
ScopedCBB cbb;
+ SSL_CLIENT_HELLO hello;
if (!CBB_init(cbb.get(), 512) ||
- !SSL_serialize_handoff(ssl, cbb.get()) ||
+ !SSL_serialize_handoff(ssl, cbb.get(), &hello) ||
!writer->WriteHandoff({CBB_data(cbb.get()), CBB_len(cbb.get())}) ||
!SerializeContextState(ssl->ctx.get(), cbb.get()) ||
!GetTestState(ssl)->Serialize(cbb.get())) {