Skip to content

Commit

Permalink
Send "http/1.1" ALPN when connecting to an HTTPS server or peer
Browse files Browse the repository at this point in the history
... except when SslBump peeks at or splices the HTTPS server. In those
cases, Squid still sends ALPN protocols received from the TLS client, of
course. When peeking, Squid also configures OpenSSL with ALPN protocols
received from the TLS client.

Before these changes, non-peeking/splicing Squid was only sending ALPN
when SslBump was staring at the origin server. Without SslBump and with
SslBump that was bumping the origin server, no ALPN extension was
probably sent.

Sending ALPN is the right thing to do and works around bugs in popular
serves that respond with malformed NPN extensions when ClientHello has
NPN but not ALPN.

This draft implementation needs a lot of polishing (and GnuTLS support).
  • Loading branch information
rousskov committed Aug 4, 2021
1 parent c0a7aa1 commit 16a3534
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 10 deletions.
40 changes: 40 additions & 0 deletions src/security/PeerConnector.cc
Expand Up @@ -123,6 +123,8 @@ Security::PeerConnector::initialize(Security::SessionPointer &serverSession)
serverSession = fd_table[serverConnection()->fd].ssl;
debugs(83, 5, serverConnection() << ", session=" << (void*)serverSession.get());

offerClientApplicationProtocols(serverSession, clientApplicationProtocols());

#if USE_OPENSSL
// If CertValidation Helper used do not lookup checklist for errors,
// but keep a list of errors to send it to CertValidator
Expand All @@ -142,6 +144,44 @@ Security::PeerConnector::initialize(Security::SessionPointer &serverSession)
return true;
}

const SBuf &
Security::PeerConnector::clientApplicationProtocols() const
{
static const SBuf supportedProtocols("\x08http/1.1", 9);
return supportedProtocols;
}

/// configure the session to offer the given application-layer protos (RFC 7301)
/// \param protocolList a non-empty list of protocol names, in ALPN wire format
void
Security::PeerConnector::offerClientApplicationProtocols(SessionPointer &serverSession, const SBuf &protocolList)
{
assert(serverSession); // TODO: Use Security::Connection instead of this pointer
assert(protocolList.length());
debugs(83, 5, Raw("ALPN", protocolList.rawContent(), protocolList.length()).hex());
#if USE_OPENSSL

#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
SSL_set_alpn_protos(serverSession.get(),
reinterpret_cast<const unsigned char*>(protocolList.rawContent()),
protocolList.length());
// XXX: throw on errors
#endif

#elif USE_GNUTLS
// XXX: GnuTLS needs a different format:
// std::vector<gnutls_datum_t /* PoolingAllocator */> rawList(protoNames.size());
// for (const auto &proto: protoNames)
// rawList.emplace_back(proto.rawContent(), proto.length());
// if (!gnutls_alpn_set_protocols(serverSession, rawList.data(), rawList.size(), 0))
// throw ...
(void)serverSession;
#else
(void)serverSession;
assert(false); // unreachable
#endif // USE_OPENSSL
}

void
Security::PeerConnector::recordNegotiationDetails()
{
Expand Down
5 changes: 5 additions & 0 deletions src/security/PeerConnector.h
Expand Up @@ -104,6 +104,10 @@ class PeerConnector: virtual public AsyncJob
/// \returns true on successful TLS session initialization
virtual bool initialize(Security::SessionPointer &);

/// computes a list of application protocols we can support on serverConn
/// \returns a non-empty list of application protocols in ALPN wire format
virtual const SBuf &clientApplicationProtocols() const;

/// Performs a single secure connection negotiation step.
/// It is called multiple times untill the negotiation finishes or aborts.
void negotiate();
Expand Down Expand Up @@ -191,6 +195,7 @@ class PeerConnector: virtual public AsyncJob

static void NegotiateSsl(int fd, void *data);
void negotiateSsl();
void offerClientApplicationProtocols(SessionPointer &, const SBuf &protocolList);

/// The maximum allowed missing certificates downloads.
static const unsigned int MaxCertsDownloads = 10;
Expand Down
19 changes: 19 additions & 0 deletions src/ssl/PeekingPeerConnector.cc
Expand Up @@ -208,6 +208,25 @@ Ssl::PeekingPeerConnector::initialize(Security::SessionPointer &serverSession)
return true;
}

const SBuf &
Ssl::PeekingPeerConnector::clientApplicationProtocols() const
{
// when peeking at the server, use the client-sent list (if any)
if (const auto * const csd = request->clientConnectionManager.valid()) {
if (csd->sslBumpMode == Ssl::bumpPeek) {
if (const auto &details = csd->tlsParser.details) {
if (details->tlsVersion.protocol != AnyP::PROTO_NONE) {
if (!details->tlsAppLayerProtoNeg.isEmpty()) {
debugs(83, 5, "mimicking client ALPN");
return details->tlsAppLayerProtoNeg;
}
}
}
}
}
return Security::PeerConnector::clientApplicationProtocols();
}

void
Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState *error)
{
Expand Down
1 change: 1 addition & 0 deletions src/ssl/PeekingPeerConnector.h
Expand Up @@ -37,6 +37,7 @@ class PeekingPeerConnector: public Security::PeerConnector {

/* Security::PeerConnector API */
virtual bool initialize(Security::SessionPointer &);
virtual const SBuf &clientApplicationProtocols() const;
virtual Security::ContextPointer getTlsContext();
virtual void noteWantWrite();
virtual void noteNegotiationError(const int result, const int ssl_error, const int ssl_lib_error);
Expand Down
11 changes: 1 addition & 10 deletions src/ssl/bio.cc
Expand Up @@ -736,16 +736,7 @@ applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl
SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
#endif

#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
if (!details->tlsAppLayerProtoNeg.isEmpty()) {
if (bumpMode == Ssl::bumpPeek)
SSL_set_alpn_protos(ssl, (const unsigned char*)details->tlsAppLayerProtoNeg.rawContent(), details->tlsAppLayerProtoNeg.length());
else {
static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
SSL_set_alpn_protos(ssl, supported_protos, sizeof(supported_protos));
}
}
#endif
// Security::PeerConnec1tor::offerClientApplicationProtocols() mimics ALPN
}

#endif // USE_OPENSSL
Expand Down

0 comments on commit 16a3534

Please sign in to comment.