Add ALPN to QUIC when using TLS
This CL makes our client send ALPN when using QUIC with TLS, makes the server echo the first ALPN value, and allows quic_client to override the ALPN for IETF interop events.
gfe-relnote: protected by disabled flag quic_supports_tls_handshake
PiperOrigin-RevId: 242682444
Change-Id: I7e60fb61c0afe02283e38598de29df9018b71ee8
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc
index adc2c81..5081a48 100644
--- a/quic/core/tls_client_handshaker.cc
+++ b/quic/core/tls_client_handshaker.cc
@@ -4,12 +4,14 @@
#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
+#include <cstring>
#include <string>
#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
namespace quic {
@@ -87,6 +89,27 @@
return false;
}
+ std::string alpn_string =
+ AlpnForVersion(session()->supported_versions().front());
+ if (alpn_string.length() > std::numeric_limits<uint8_t>::max()) {
+ QUIC_BUG << "ALPN too long: '" << alpn_string << "'";
+ CloseConnection(QUIC_HANDSHAKE_FAILED, "ALPN too long");
+ return false;
+ }
+ const uint8_t alpn_length = alpn_string.length();
+ // SSL_set_alpn_protos expects a sequence of one-byte-length-prefixed strings
+ // so we copy alpn_string to a new buffer that has the length in alpn[0].
+ uint8_t alpn[std::numeric_limits<uint8_t>::max() + 1];
+ alpn[0] = alpn_length;
+ memcpy(reinterpret_cast<char*>(alpn + 1), alpn_string.data(), alpn_length);
+ if (SSL_set_alpn_protos(ssl(), alpn,
+ static_cast<unsigned>(alpn_length) + 1) != 0) {
+ QUIC_BUG << "Failed to set ALPN: '" << alpn_string << "'";
+ CloseConnection(QUIC_HANDSHAKE_FAILED, "Failed to set ALPN");
+ return false;
+ }
+ QUIC_DLOG(INFO) << "Client using ALPN: '" << alpn_string << "'";
+
// Set the Transport Parameters to send in the ClientHello
if (!SetTransportParameters()) {
CloseConnection(QUIC_HANDSHAKE_FAILED,
@@ -248,6 +271,28 @@
return;
}
+ const uint8_t* alpn_data = nullptr;
+ unsigned alpn_length = 0;
+ SSL_get0_alpn_selected(ssl(), &alpn_data, &alpn_length);
+ // TODO(b/130164908) Act on ALPN.
+ if (alpn_length != 0) {
+ std::string received_alpn_string(reinterpret_cast<const char*>(alpn_data),
+ alpn_length);
+ std::string sent_alpn_string =
+ AlpnForVersion(session()->supported_versions().front());
+ if (received_alpn_string != sent_alpn_string) {
+ QUIC_LOG(ERROR) << "Client: received mismatched ALPN '"
+ << received_alpn_string << "', expected '"
+ << sent_alpn_string << "'";
+ CloseConnection(QUIC_HANDSHAKE_FAILED, "Mismatched ALPN");
+ return;
+ }
+ QUIC_DLOG(INFO) << "Client: server selected ALPN: '" << received_alpn_string
+ << "'";
+ } else {
+ QUIC_DLOG(INFO) << "Client: server did not select ALPN";
+ }
+
session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session()->NeuterUnencryptedData();
encryption_established_ = true;