Add an option to allow unknown ALPN protocols. We received an external request to add an option to undo the check added in 3e51757de2bf9beef7d249f22d255e4dd9ddb012. Change-Id: Ifdd4b07705f2fa3d781d775d5cd139ea72d36734 Reviewed-on: https://boringssl-review.googlesource.com/14644 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 75862fc..6a6cd85 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h
@@ -2586,6 +2586,13 @@ const uint8_t **out_data, unsigned *out_len); +/* SSL_CTX_set_allow_unknown_alpn_protos configures client connections on |ctx| + * to allow unknown ALPN protocols from the server. Otherwise, by default, the + * client will require that the protocol be advertised in + * |SSL_CTX_set_alpn_protos|. */ +OPENSSL_EXPORT void SSL_CTX_set_allow_unknown_alpn_protos(SSL_CTX *ctx, + int enabled); + /* Next protocol negotiation. * @@ -4280,6 +4287,10 @@ * that this currently requires post-handshake verification of * certificates. */ unsigned i_promise_to_verify_certs_after_the_handshake:1; + + /* allow_unknown_alpn_protos is one if the client allows unsolicited ALPN + * protocols from the peer. */ + unsigned allow_unknown_alpn_protos:1; };
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 17e6521..7adf103 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c
@@ -1753,6 +1753,9 @@ } } +void SSL_CTX_set_allow_unknown_alpn_protos(SSL_CTX *ctx, int enabled) { + ctx->allow_unknown_alpn_protos = !!enabled; +} void SSL_CTX_set_tls_channel_id_enabled(SSL_CTX *ctx, int enabled) { ctx->tlsext_channel_id_enabled = !!enabled;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 45a04c1..793e2d7 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c
@@ -1432,31 +1432,33 @@ return 0; } - /* Check that the protcol name is one of the ones we advertised. */ - int protocol_ok = 0; - CBS client_protocol_name_list, client_protocol_name; - CBS_init(&client_protocol_name_list, ssl->alpn_client_proto_list, - ssl->alpn_client_proto_list_len); - while (CBS_len(&client_protocol_name_list) > 0) { - if (!CBS_get_u8_length_prefixed(&client_protocol_name_list, - &client_protocol_name)) { - *out_alert = SSL_AD_INTERNAL_ERROR; + if (!ssl->ctx->allow_unknown_alpn_protos) { + /* Check that the protocol name is one of the ones we advertised. */ + int protocol_ok = 0; + CBS client_protocol_name_list, client_protocol_name; + CBS_init(&client_protocol_name_list, ssl->alpn_client_proto_list, + ssl->alpn_client_proto_list_len); + while (CBS_len(&client_protocol_name_list) > 0) { + if (!CBS_get_u8_length_prefixed(&client_protocol_name_list, + &client_protocol_name)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + + if (CBS_len(&client_protocol_name) == CBS_len(&protocol_name) && + OPENSSL_memcmp(CBS_data(&client_protocol_name), + CBS_data(&protocol_name), + CBS_len(&protocol_name)) == 0) { + protocol_ok = 1; + break; + } + } + + if (!protocol_ok) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ALPN_PROTOCOL); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } - - if (CBS_len(&client_protocol_name) == CBS_len(&protocol_name) && - OPENSSL_memcmp(CBS_data(&client_protocol_name), - CBS_data(&protocol_name), - CBS_len(&protocol_name)) == 0) { - protocol_ok = 1; - break; - } - } - - if (!protocol_ok) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ALPN_PROTOCOL); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; } if (!CBS_stow(&protocol_name, &ssl->s3->alpn_selected,
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc index 70ea664..b60c809 100644 --- a/ssl/test/bssl_shim.cc +++ b/ssl/test/bssl_shim.cc
@@ -1187,6 +1187,10 @@ SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1); } + if (config->allow_unknown_alpn_protos) { + SSL_CTX_set_allow_unknown_alpn_protos(ssl_ctx.get(), 1); + } + return ssl_ctx; }
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 8444c21..ed328b6 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go
@@ -4889,7 +4889,7 @@ }) testCases = append(testCases, testCase{ testType: clientTest, - name: "ALPNClient-Mismatch-" + ver.name, + name: "ALPNClient-RejectUnknown-" + ver.name, config: Config{ MaxVersion: ver.version, Bugs: ProtocolBugs{ @@ -4904,6 +4904,20 @@ expectedLocalError: "remote error: illegal parameter", }) testCases = append(testCases, testCase{ + testType: clientTest, + name: "ALPNClient-AllowUnknown-" + ver.name, + config: Config{ + MaxVersion: ver.version, + Bugs: ProtocolBugs{ + SendALPN: "baz", + }, + }, + flags: []string{ + "-advertise-alpn", "\x03foo\x03bar", + "-allow-unknown-alpn-protos", + }, + }) + testCases = append(testCases, testCase{ testType: serverTest, name: "ALPNServer-" + ver.name, config: Config{
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc index a8cf755..1b23b02 100644 --- a/ssl/test/test_config.cc +++ b/ssl/test/test_config.cc
@@ -130,6 +130,7 @@ { "-expect-no-resume-alpn", &TestConfig::expect_no_resume_alpn }, { "-no-op-extra-handshake", &TestConfig::no_op_extra_handshake }, { "-handshake-twice", &TestConfig::handshake_twice }, + { "-allow-unknown-alpn-protos", &TestConfig::allow_unknown_alpn_protos }, }; const Flag<std::string> kStringFlags[] = {
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h index ef14f15..839c0fc 100644 --- a/ssl/test/test_config.h +++ b/ssl/test/test_config.h
@@ -143,6 +143,7 @@ int expect_ticket_age_skew = 0; bool no_op_extra_handshake = false; bool handshake_twice = false; + bool allow_unknown_alpn_protos = false; }; bool ParseConfig(int argc, char **argv, TestConfig *out_config);