diff options
author | David Benjamin <davidben@chromium.org> | 2014-09-06 12:58:58 -0400 |
---|---|---|
committer | Adam Langley <agl@google.com> | 2014-09-15 21:10:46 +0000 |
commit | ae2888fbdc21ac70652034b5bfc24953a56dbe57 (patch) | |
tree | 9c95d7a08aff2a9ba129acaa0e87e90c1d05cd0f | |
parent | fa055a2b77a10ff39dd45091e084a2234deb3e86 (diff) | |
download | src-ae2888fbdc21ac70652034b5bfc24953a56dbe57.tar.gz |
Add tests for ALPN support.
Both as client and as server. Also tests that ALPN causes False Start to kick
in.
Change-Id: Ib570346f3c511834152cd2df2ef29541946d3ab4
Reviewed-on: https://boringssl-review.googlesource.com/1753
Reviewed-by: Adam Langley <agl@google.com>
-rw-r--r-- | ssl/test/bssl_shim.cc | 48 | ||||
-rw-r--r-- | ssl/test/runner/runner.go | 61 | ||||
-rw-r--r-- | ssl/test/test_config.cc | 4 | ||||
-rw-r--r-- | ssl/test/test_config.h | 4 |
4 files changed, 112 insertions, 5 deletions
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc index 4ca7c58..846850c 100644 --- a/ssl/test/bssl_shim.cc +++ b/ssl/test/bssl_shim.cc @@ -139,6 +139,29 @@ static int next_proto_select_callback(SSL* ssl, return SSL_TLSEXT_ERR_OK; } +static int alpn_select_callback(SSL* ssl, + const uint8_t** out, + uint8_t* outlen, + const uint8_t* in, + unsigned inlen, + void* arg) { + const TestConfig *config = GetConfigPtr(ssl); + if (config->select_alpn.empty()) + return SSL_TLSEXT_ERR_NOACK; + + if (!config->expected_advertised_alpn.empty() && + (config->expected_advertised_alpn.size() != inlen || + memcmp(config->expected_advertised_alpn.data(), + in, inlen) != 0)) { + fprintf(stderr, "bad ALPN select callback inputs\n"); + exit(1); + } + + *out = (const uint8_t*)config->select_alpn.data(); + *outlen = config->select_alpn.size(); + return SSL_TLSEXT_ERR_OK; +} + static int cookie_generate_callback(SSL *ssl, uint8_t *cookie, size_t *cookie_len) { *cookie_len = 32; memset(cookie, 42, *cookie_len); @@ -213,8 +236,13 @@ static SSL_CTX *setup_ctx(const TestConfig *config) { SSL_CTX_set_next_protos_advertised_cb( ssl_ctx, next_protos_advertised_callback, NULL); - SSL_CTX_set_next_proto_select_cb( - ssl_ctx, next_proto_select_callback, NULL); + if (!config->select_next_proto.empty()) { + SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_callback, NULL); + } + + if (!config->select_alpn.empty()) { + SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_callback, NULL); + } SSL_CTX_set_cookie_generate_cb(ssl_ctx, cookie_generate_callback); SSL_CTX_set_cookie_verify_cb(ssl_ctx, cookie_verify_callback); @@ -339,6 +367,10 @@ static int do_exchange(SSL_SESSION **out_session, if (!config->host_name.empty()) { SSL_set_tlsext_host_name(ssl, config->host_name.c_str()); } + if (!config->advertise_alpn.empty()) { + SSL_set_alpn_protos(ssl, (const uint8_t *)config->advertise_alpn.data(), + config->advertise_alpn.size()); + } BIO *bio = BIO_new_fd(fd, 1 /* take ownership */); if (bio == NULL) { @@ -425,6 +457,18 @@ static int do_exchange(SSL_SESSION **out_session, } } + if (!config->expected_alpn.empty()) { + const uint8_t *alpn_proto; + unsigned alpn_proto_len; + SSL_get0_alpn_selected(ssl, &alpn_proto, &alpn_proto_len); + if (alpn_proto_len != config->expected_alpn.size() || + memcmp(alpn_proto, config->expected_alpn.data(), + alpn_proto_len) != 0) { + fprintf(stderr, "negotiated alpn proto mismatch\n"); + return 2; + } + } + if (!config->expected_channel_id.empty()) { uint8_t channel_id[64]; if (!SSL_get_tls_channel_id(ssl, channel_id, sizeof(channel_id))) { diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 0a5888c..25e7626 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -113,6 +113,9 @@ type testCase struct { // expectChannelID controls whether the connection should have // negotiated a Channel ID with channelIDKey. expectChannelID bool + // expectedNextProto controls whether the connection should + // negotiate a next protocol via NPN or ALPN. + expectedNextProto string // messageLen is the length, in bytes, of the test message that will be // sent. messageLen int @@ -514,6 +517,12 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) e } } + if expected := test.expectedNextProto; expected != "" { + if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected { + return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected) + } + } + if test.shimWritesFirst { var buf [5]byte _, err := io.ReadFull(tlsConn, buf[:]) @@ -1129,13 +1138,13 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) protocol: protocol, name: "NPN-Client" + suffix, config: Config{ - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - NextProtos: []string{"foo"}, + NextProtos: []string{"foo"}, Bugs: ProtocolBugs{ MaxHandshakeRecordLength: maxHandshakeRecordLength, }, }, - flags: append(flags, "-select-next-proto", "foo"), + flags: append(flags, "-select-next-proto", "foo"), + expectedNextProto: "foo", }) testCases = append(testCases, testCase{ protocol: protocol, @@ -1150,6 +1159,7 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) flags: append(flags, "-advertise-npn", "\x03foo\x03bar\x03baz", "-expect-next-proto", "bar"), + expectedNextProto: "bar", }) // Client does False Start and negotiates NPN. @@ -1171,6 +1181,25 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) resumeSession: true, }) + // Client does False Start and negotiates ALPN. + testCases = append(testCases, testCase{ + protocol: protocol, + name: "FalseStart-ALPN" + suffix, + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + NextProtos: []string{"foo"}, + Bugs: ProtocolBugs{ + ExpectFalseStart: true, + MaxHandshakeRecordLength: maxHandshakeRecordLength, + }, + }, + flags: append(flags, + "-false-start", + "-advertise-alpn", "\x03foo"), + shimWritesFirst: true, + resumeSession: true, + }) + // False Start without session tickets. testCases = append(testCases, testCase{ name: "FalseStart-SessionTicketsDisabled", @@ -1407,6 +1436,32 @@ func addExtensionTests() { flags: []string{"-expect-server-name", "example.com"}, resumeSession: true, }) + testCases = append(testCases, testCase{ + testType: clientTest, + name: "ALPNClient", + config: Config{ + NextProtos: []string{"foo"}, + }, + flags: []string{ + "-advertise-alpn", "\x03foo\x03bar\x03baz", + "-expect-alpn", "foo", + }, + expectedNextProto: "foo", + resumeSession: true, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ALPNServer", + config: Config{ + NextProtos: []string{"foo", "bar", "baz"}, + }, + flags: []string{ + "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", + "-select-alpn", "foo", + }, + expectedNextProto: "foo", + resumeSession: true, + }) } func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) { diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc index 77d51a1..e96b242 100644 --- a/ssl/test/test_config.cc +++ b/ssl/test/test_config.cc @@ -68,6 +68,10 @@ const StringFlag kStringFlags[] = { { "-select-next-proto", &TestConfig::select_next_proto }, { "-send-channel-id", &TestConfig::send_channel_id }, { "-host-name", &TestConfig::host_name }, + { "-advertise-alpn", &TestConfig::advertise_alpn }, + { "-expect-alpn", &TestConfig::expected_alpn }, + { "-expect-advertised-alpn", &TestConfig::expected_advertised_alpn }, + { "-select-alpn", &TestConfig::select_alpn }, }; const size_t kNumStringFlags = sizeof(kStringFlags) / sizeof(kStringFlags[0]); diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h index c3ba63f..62c5c9e 100644 --- a/ssl/test/test_config.h +++ b/ssl/test/test_config.h @@ -48,6 +48,10 @@ struct TestConfig { bool shim_writes_first; bool tls_d5_bug; std::string host_name; + std::string advertise_alpn; + std::string expected_alpn; + std::string expected_advertised_alpn; + std::string select_alpn; }; bool ParseConfig(int argc, char **argv, TestConfig *out_config); |