Enforce the server ALPN protocol was advertised.
The server should not be allowed select a protocol that wasn't
advertised. Callers tend to not really notice and act as if some default
were chosen which is unlikely to work very well.
Change-Id: Ib6388db72f05386f854d275bab762ca79e8174e6
Reviewed-on: https://boringssl-review.googlesource.com/10284
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata
index 5800d41..7753f17 100644
--- a/crypto/err/ssl.errordata
+++ b/crypto/err/ssl.errordata
@@ -59,6 +59,7 @@
SSL,155,HTTPS_PROXY_REQUEST
SSL,156,HTTP_REQUEST
SSL,157,INAPPROPRIATE_FALLBACK
+SSL,259,INVALID_ALPN_PROTOCOL
SSL,158,INVALID_COMMAND
SSL,256,INVALID_COMPRESSION_LIST
SSL,159,INVALID_MESSAGE
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 931b100..fe6bac2 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -4803,6 +4803,7 @@
#define SSL_R_INVALID_COMPRESSION_LIST 256
#define SSL_R_DUPLICATE_EXTENSION 257
#define SSL_R_MISSING_KEY_SHARE 258
+#define SSL_R_INVALID_ALPN_PROTOCOL 259
#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 62f3824..5e790a4 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1517,6 +1517,32 @@
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;
+ return 0;
+ }
+
+ if (CBS_len(&client_protocol_name) == CBS_len(&protocol_name) &&
+ 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,
&ssl->s3->alpn_selected_len)) {
*out_alert = SSL_AD_INTERNAL_ERROR;
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index b6befe4..f3d57c7 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -875,8 +875,8 @@
NegotiateALPNAndNPN bool
// SendALPN, if non-empty, causes the server to send the specified
- // string in the ALPN extension regardless of whether the client
- // advertised it.
+ // string in the ALPN extension regardless of the content or presence of
+ // the client offer.
SendALPN string
// SendEmptySessionTicket, if true, causes the server to send an empty
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 4cb22b1..45d3e13 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -4317,6 +4317,22 @@
resumeSession: resumeSession,
})
testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ALPNClient-Mismatch-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendALPN: "baz",
+ },
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo\x03bar",
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_ALPN_PROTOCOL:",
+ expectedLocalError: "remote error: illegal parameter",
+ })
+ testCases = append(testCases, testCase{
testType: serverTest,
name: "ALPNServer-" + ver.name,
config: Config{