Forbid a server from negotiating both ALPN and NPN.
If the two extensions select different next protocols (quite possible since one
is server-selected and the other is client-selected), things will break. This
matches the behavior of NSS (Firefox) and Go.
Change-Id: Ie1da97bf062b91a370c85c12bc61423220a22f36
Reviewed-on: https://boringssl-review.googlesource.com/5780
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 2eeffab..40b9752 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1410,6 +1410,13 @@
assert(!SSL_IS_DTLS(ssl));
assert(ssl->ctx->next_proto_select_cb != NULL);
+ if (ssl->s3->alpn_selected != NULL) {
+ /* NPN and ALPN may not be negotiated in the same connection. */
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN);
+ return 0;
+ }
+
const uint8_t *const orig_contents = CBS_data(contents);
const size_t orig_len = CBS_len(contents);
@@ -1585,6 +1592,13 @@
assert(!ssl->s3->initial_handshake_complete);
assert(ssl->alpn_client_proto_list != NULL);
+ if (ssl->s3->next_proto_neg_seen) {
+ /* NPN and ALPN may not be negotiated in the same connection. */
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN);
+ return 0;
+ }
+
/* The extension data consists of a ProtocolNameList which must have
* exactly one ProtocolName. Each of these is length-prefixed. */
CBS protocol_name_list, protocol_name;