shim: rewrite MoveTestState() to use a serialized representation.
This helps with creating a separate binary to perform split
handshakes, in that the test state must be communicated to, and
retrieved from, the handshaker binary using a socket.
Change-Id: I9d70a9bb3d97dd339aab4f51c6de75f71e4fe72d
Reviewed-on: https://boringssl-review.googlesource.com/29704
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/test_state.cc b/ssl/test/test_state.cc
index 14bd4a1..83ab6bf 100644
--- a/ssl/test/test_state.cc
+++ b/ssl/test/test_state.cc
@@ -19,6 +19,8 @@
#include "../../crypto/internal.h"
#include "../internal.h"
+using namespace bssl;
+
static CRYPTO_once_t g_once = CRYPTO_ONCE_INIT;
static int g_state_index = 0;
// Some code treats the zero time special, so initialize the clock to a
@@ -62,19 +64,9 @@
return (TestState *)SSL_get_ex_data(ssl, g_state_index);
}
-bool MoveTestState(SSL *dest, SSL *src) {
- TestState *state = GetTestState(src);
- if (!SSL_set_ex_data(src, g_state_index, nullptr) ||
- !SSL_set_ex_data(dest, g_state_index, state)) {
- return false;
- }
-
- return true;
-}
-
static void ssl_ctx_add_session(SSL_SESSION *session, void *void_param) {
SSL_CTX *ctx = reinterpret_cast<SSL_CTX *>(void_param);
- bssl::UniquePtr<SSL_SESSION> new_session = bssl::SSL_SESSION_dup(
+ UniquePtr<SSL_SESSION> new_session = SSL_SESSION_dup(
session, SSL_SESSION_INCLUDE_NONAUTH | SSL_SESSION_INCLUDE_TICKET);
if (new_session != nullptr) {
SSL_CTX_add_session(ctx, new_session.get());
@@ -84,3 +76,115 @@
void CopySessions(SSL_CTX *dst, const SSL_CTX *src) {
lh_SSL_SESSION_doall_arg(src->sessions, ssl_ctx_add_session, dst);
}
+
+static void push_session(SSL_SESSION *session, void *arg) {
+ auto s = reinterpret_cast<std::vector<SSL_SESSION *> *>(arg);
+ s->push_back(session);
+}
+
+bool SerializeContextState(SSL_CTX *ctx, CBB *cbb) {
+ CBB out, ctx_sessions, ticket_keys;
+ uint8_t keys[48];
+ if (!CBB_add_u24_length_prefixed(cbb, &out) ||
+ !CBB_add_u16(&out, 0 /* version */) ||
+ !SSL_CTX_get_tlsext_ticket_keys(ctx, &keys, sizeof(keys)) ||
+ !CBB_add_u8_length_prefixed(&out, &ticket_keys) ||
+ !CBB_add_bytes(&ticket_keys, keys, sizeof(keys)) ||
+ !CBB_add_asn1(&out, &ctx_sessions, CBS_ASN1_SEQUENCE)) {
+ return false;
+ }
+ std::vector<SSL_SESSION *> sessions;
+ lh_SSL_SESSION_doall_arg(ctx->sessions, push_session, &sessions);
+ for (const auto &sess : sessions) {
+ if (!ssl_session_serialize(sess, &ctx_sessions)) {
+ return false;
+ }
+ }
+ return CBB_flush(cbb);
+}
+
+bool DeserializeContextState(CBS *cbs, SSL_CTX *ctx) {
+ CBS in, sessions, ticket_keys;
+ uint16_t version;
+ constexpr uint16_t kVersion = 0;
+ if (!CBS_get_u24_length_prefixed(cbs, &in) ||
+ !CBS_get_u16(&in, &version) ||
+ version > kVersion ||
+ !CBS_get_u8_length_prefixed(&in, &ticket_keys) ||
+ !SSL_CTX_set_tlsext_ticket_keys(ctx, CBS_data(&ticket_keys),
+ CBS_len(&ticket_keys)) ||
+ !CBS_get_asn1(&in, &sessions, CBS_ASN1_SEQUENCE)) {
+ return false;
+ }
+ while (CBS_len(&sessions)) {
+ UniquePtr<SSL_SESSION> session =
+ SSL_SESSION_parse(&sessions, ctx->x509_method, ctx->pool);
+ if (!session) {
+ return false;
+ }
+ SSL_CTX_add_session(ctx, session.get());
+ }
+ return true;
+}
+
+bool TestState::Serialize(CBB *cbb) const {
+ CBB out, pending, text;
+ if (!CBB_add_u24_length_prefixed(cbb, &out) ||
+ !CBB_add_u16(&out, 0 /* version */) ||
+ !CBB_add_u24_length_prefixed(&out, &pending) ||
+ (pending_session &&
+ !ssl_session_serialize(pending_session.get(), &pending)) ||
+ !CBB_add_u16_length_prefixed(&out, &text) ||
+ !CBB_add_bytes(
+ &text, reinterpret_cast<const uint8_t *>(msg_callback_text.data()),
+ msg_callback_text.length()) ||
+ !CBB_flush(cbb)) {
+ return false;
+ }
+ return true;
+}
+
+std::unique_ptr<TestState> TestState::Deserialize(CBS *cbs, SSL_CTX *ctx) {
+ CBS in, pending_session, text;
+ std::unique_ptr<TestState> out_state(new TestState());
+ uint16_t version;
+ constexpr uint16_t kVersion = 0;
+ if (!CBS_get_u24_length_prefixed(cbs, &in) ||
+ !CBS_get_u16(&in, &version) ||
+ version > kVersion ||
+ !CBS_get_u24_length_prefixed(&in, &pending_session) ||
+ !CBS_get_u16_length_prefixed(&in, &text)) {
+ return nullptr;
+ }
+ if (CBS_len(&pending_session)) {
+ out_state->pending_session = SSL_SESSION_parse(
+ &pending_session, ctx->x509_method, ctx->pool);
+ if (!out_state->pending_session) {
+ return nullptr;
+ }
+ }
+ out_state->msg_callback_text = std::string(
+ reinterpret_cast<const char *>(CBS_data(&text)), CBS_len(&text));
+ return out_state;
+}
+
+bool MoveTestState(SSL *dest, SSL *src) {
+ ScopedCBB out;
+ Array<uint8_t> serialized;
+ if (!CBB_init(out.get(), 512) ||
+ !SerializeContextState(src->ctx.get(), out.get()) ||
+ !GetTestState(src)->Serialize(out.get()) ||
+ !CBBFinishArray(out.get(), &serialized)) {
+ return false;
+ }
+ CBS in;
+ CBS_init(&in, serialized.data(), serialized.size());
+ if (!DeserializeContextState(&in, dest->ctx.get()) ||
+ !SetTestState(dest, TestState::Deserialize(&in, dest->ctx.get())) ||
+ !GetTestState(dest)) {
+ return false;
+ }
+ GetTestState(dest)->async_bio = GetTestState(src)->async_bio;
+ GetTestState(src)->async_bio = nullptr;
+ return true;
+}