Skip to content

Commit cb247c6

Browse files
authored
Generalize ALPN logic (#7555)
1 parent 8977a45 commit cb247c6

File tree

10 files changed

+107
-88
lines changed

10 files changed

+107
-88
lines changed

iocore/net/ALPNSupport.cc

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,35 @@
2525
#include "P_SSLNextProtocolSet.h"
2626
#include "records/I_RecHttp.h"
2727

28+
int ALPNSupport::_ex_data_index = -1;
29+
30+
void
31+
ALPNSupport::initialize()
32+
{
33+
ink_assert(_ex_data_index == -1);
34+
if (_ex_data_index == -1) {
35+
_ex_data_index = SSL_get_ex_new_index(0, (void *)"ALPNSupport index", nullptr, nullptr, nullptr);
36+
}
37+
}
38+
39+
ALPNSupport *
40+
ALPNSupport::getInstance(SSL *ssl)
41+
{
42+
return static_cast<ALPNSupport *>(SSL_get_ex_data(ssl, _ex_data_index));
43+
}
44+
45+
void
46+
ALPNSupport::bind(SSL *ssl, ALPNSupport *alpns)
47+
{
48+
SSL_set_ex_data(ssl, _ex_data_index, alpns);
49+
}
50+
51+
void
52+
ALPNSupport::unbind(SSL *ssl)
53+
{
54+
SSL_set_ex_data(ssl, _ex_data_index, nullptr);
55+
}
56+
2857
void
2958
ALPNSupport::clear()
3059
{
@@ -53,6 +82,36 @@ ALPNSupport::setSelectedProtocol(const unsigned char *proto, unsigned int len)
5382
return true;
5483
}
5584

85+
int
86+
ALPNSupport::advertise_next_protocol(SSL *ssl, const unsigned char **out, unsigned *outlen)
87+
{
88+
if (this->getNPN(out, outlen)) {
89+
// Successful return tells OpenSSL to advertise.
90+
return SSL_TLSEXT_ERR_OK;
91+
}
92+
return SSL_TLSEXT_ERR_NOACK;
93+
}
94+
95+
int
96+
ALPNSupport::select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in,
97+
unsigned inlen)
98+
{
99+
const unsigned char *npnptr = nullptr;
100+
unsigned int npnsize = 0;
101+
if (this->getNPN(&npnptr, &npnsize)) {
102+
// SSL_select_next_proto chooses the first server-offered protocol that appears in the clients protocol set, ie. the
103+
// server selects the protocol. This is a n^2 search, so it's preferable to keep the protocol set short.
104+
if (SSL_select_next_proto(const_cast<unsigned char **>(out), outlen, npnptr, npnsize, in, inlen) == OPENSSL_NPN_NEGOTIATED) {
105+
Debug("ssl", "selected ALPN protocol %.*s", (int)(*outlen), *out);
106+
return SSL_TLSEXT_ERR_OK;
107+
}
108+
}
109+
110+
*out = nullptr;
111+
*outlen = 0;
112+
return SSL_TLSEXT_ERR_NOACK;
113+
}
114+
56115
void
57116
ALPNSupport::disableProtocol(int idx)
58117
{

iocore/net/P_ALPNSupport.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#pragma once
2626
#include "records/I_RecHttp.h"
27+
#include <openssl/ssl.h>
2728

2829
class SSLNextProtocolSet;
2930
class SSLNextProtocolAccept;
@@ -32,12 +33,22 @@ class Continuation;
3233
class ALPNSupport
3334
{
3435
public:
36+
virtual ~ALPNSupport() = default;
37+
38+
static void initialize();
39+
static ALPNSupport *getInstance(SSL *ssl);
40+
static void bind(SSL *ssl, ALPNSupport *alpns);
41+
static void unbind(SSL *ssl);
42+
3543
void registerNextProtocolSet(SSLNextProtocolSet *, const SessionProtocolSet &protos);
3644
void disableProtocol(int idx);
3745
void enableProtocol(int idx);
3846
void clear();
3947
bool setSelectedProtocol(const unsigned char *proto, unsigned int len);
4048

49+
int advertise_next_protocol(SSL *ssl, const unsigned char **out, unsigned *outlen);
50+
int select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen);
51+
4152
Continuation *
4253
endpoint() const
4354
{
@@ -65,6 +76,8 @@ class ALPNSupport
6576
int get_negotiated_protocol_id() const;
6677

6778
private:
79+
static int _ex_data_index;
80+
6881
const SSLNextProtocolSet *npnSet = nullptr;
6982
SessionProtocolSet protoenabled;
7083
// Local copies of the npn strings

iocore/net/P_QUICNetVConnection.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,6 @@ class QUICNetVConnection : public UnixNetVConnection,
186186
int populate_protocol(std::string_view *results, int n) const override;
187187
const char *protocol_contains(std::string_view tag) const override;
188188

189-
int select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in,
190-
unsigned inlen) const override;
191-
192189
// QUICConnection
193190
QUICStreamManager *stream_manager() override;
194191
void close_quic_connection(QUICConnectionErrorUPtr error) override;

iocore/net/P_SSLNetVConnection.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,6 @@ class SSLNetVConnection : public UnixNetVConnection,
143143
////////////////////////////////////////////////////////////
144144
SSLNetVConnection();
145145
~SSLNetVConnection() override {}
146-
static int advertise_next_protocol(SSL *ssl, const unsigned char **out, unsigned *outlen, void *);
147-
static int select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in,
148-
unsigned inlen, void *);
149146

150147
bool
151148
getSSLClientRenegotiationAbort() const

iocore/net/QUICMultiCertConfigLoader.cc

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,18 +119,6 @@ QUICMultiCertConfigLoader::_set_handshake_callbacks(SSL_CTX *ssl_ctx)
119119
// SSL_CTX_set_client_hello_cb(ctx, QUIC::ssl_client_hello_cb, nullptr);
120120
}
121121

122-
int
123-
QUICMultiCertConfigLoader::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen,
124-
const unsigned char *in, unsigned inlen, void *)
125-
{
126-
QUICConnection *qc = static_cast<QUICConnection *>(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index));
127-
128-
if (qc) {
129-
return qc->select_next_protocol(ssl, out, outlen, in, inlen);
130-
}
131-
return SSL_TLSEXT_ERR_NOACK;
132-
}
133-
134122
int
135123
QUICMultiCertConfigLoader::ssl_sni_cb(SSL *ssl, int * /*ad*/, void * /*arg*/)
136124
{

iocore/net/QUICMultiCertConfigLoader.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ class QUICMultiCertConfigLoader : public SSLMultiCertConfigLoader
5555
virtual bool _set_info_callback(SSL_CTX *ctx) override;
5656
virtual bool _set_npn_callback(SSL_CTX *ctx) override;
5757

58-
static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in,
59-
unsigned inlen, void *);
6058
static int ssl_cert_cb(SSL *ssl, void *arg);
6159
static int ssl_sni_cb(SSL *ssl, int *ad, void *arg);
6260
};

iocore/net/QUICNetVConnection.cc

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,28 +1079,6 @@ QUICNetVConnection::protocol_contains(std::string_view prefix) const
10791079
return retval;
10801080
}
10811081

1082-
// ALPN TLS extension callback. Given the client's set of offered
1083-
// protocols, we have to select a protocol to use for this session.
1084-
int
1085-
QUICNetVConnection::select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in,
1086-
unsigned inlen) const
1087-
{
1088-
const unsigned char *npnptr = nullptr;
1089-
unsigned int npnsize = 0;
1090-
if (this->getNPN(&npnptr, &npnsize)) {
1091-
// SSL_select_next_proto chooses the first server-offered protocol that appears in the clients protocol set, ie. the
1092-
// server selects the protocol. This is a n^2 search, so it's preferable to keep the protocol set short.
1093-
if (SSL_select_next_proto(const_cast<unsigned char **>(out), outlen, npnptr, npnsize, in, inlen) == OPENSSL_NPN_NEGOTIATED) {
1094-
Debug("ssl", "selected ALPN protocol %.*s", (int)(*outlen), *out);
1095-
return SSL_TLSEXT_ERR_OK;
1096-
}
1097-
}
1098-
1099-
*out = nullptr;
1100-
*outlen = 0;
1101-
return SSL_TLSEXT_ERR_NOACK;
1102-
}
1103-
11041082
bool
11051083
QUICNetVConnection::is_closed() const
11061084
{

iocore/net/SSLNetVConnection.cc

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ SSLNetVConnection::_bindSSLObject()
215215
{
216216
SSLNetVCAttach(this->ssl, this);
217217
TLSBasicSupport::bind(this->ssl, this);
218+
ALPNSupport::bind(this->ssl, this);
218219
TLSSessionResumptionSupport::bind(this->ssl, this);
219220
TLSSNISupport::bind(this->ssl, this);
220221
}
@@ -224,6 +225,7 @@ SSLNetVConnection::_unbindSSLObject()
224225
{
225226
SSLNetVCDetach(this->ssl);
226227
TLSBasicSupport::unbind(this->ssl);
228+
ALPNSupport::unbind(this->ssl);
227229
TLSSessionResumptionSupport::unbind(this->ssl);
228230
TLSSNISupport::unbind(this->ssl);
229231
}
@@ -1562,48 +1564,6 @@ SSLNetVConnection::sslClientHandShakeEvent(int &err)
15621564
return EVENT_CONT;
15631565
}
15641566

1565-
// NextProtocolNegotiation TLS extension callback. The NPN extension
1566-
// allows the client to select a preferred protocol, so all we have
1567-
// to do here is tell them what out protocol set is.
1568-
int
1569-
SSLNetVConnection::advertise_next_protocol(SSL *ssl, const unsigned char **out, unsigned int *outlen, void * /*arg ATS_UNUSED */)
1570-
{
1571-
SSLNetVConnection *netvc = SSLNetVCAccess(ssl);
1572-
1573-
ink_release_assert(netvc && netvc->ssl == ssl);
1574-
1575-
if (netvc->getNPN(out, outlen)) {
1576-
// Successful return tells OpenSSL to advertise.
1577-
return SSL_TLSEXT_ERR_OK;
1578-
}
1579-
return SSL_TLSEXT_ERR_NOACK;
1580-
}
1581-
1582-
// ALPN TLS extension callback. Given the client's set of offered
1583-
// protocols, we have to select a protocol to use for this session.
1584-
int
1585-
SSLNetVConnection::select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen,
1586-
const unsigned char *in ATS_UNUSED, unsigned inlen ATS_UNUSED, void *)
1587-
{
1588-
SSLNetVConnection *netvc = SSLNetVCAccess(ssl);
1589-
1590-
ink_release_assert(netvc && netvc->ssl == ssl);
1591-
const unsigned char *npnptr = nullptr;
1592-
unsigned int npnsize = 0;
1593-
if (netvc->getNPN(&npnptr, &npnsize)) {
1594-
// SSL_select_next_proto chooses the first server-offered protocol that appears in the clients protocol set, ie. the
1595-
// server selects the protocol. This is a n^2 search, so it's preferable to keep the protocol set short.
1596-
if (SSL_select_next_proto(const_cast<unsigned char **>(out), outlen, npnptr, npnsize, in, inlen) == OPENSSL_NPN_NEGOTIATED) {
1597-
Debug("ssl", "selected ALPN protocol %.*s", (int)(*outlen), *out);
1598-
return SSL_TLSEXT_ERR_OK;
1599-
}
1600-
}
1601-
1602-
*out = nullptr;
1603-
*outlen = 0;
1604-
return SSL_TLSEXT_ERR_NOACK;
1605-
}
1606-
16071567
void
16081568
SSLNetVConnection::reenable(NetHandler *nh, int event)
16091569
{

iocore/net/SSLUtils.cc

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,36 @@ ssl_servername_callback(SSL *ssl, int *al, void *arg)
463463
return SSL_TLSEXT_ERR_OK;
464464
}
465465

466+
// NextProtocolNegotiation TLS extension callback. The NPN extension
467+
// allows the client to select a preferred protocol, so all we have
468+
// to do here is tell them what out protocol set is.
469+
int
470+
ssl_next_protos_advertised_callback(SSL *ssl, const unsigned char **out, unsigned *outlen, void *)
471+
{
472+
ALPNSupport *alpns = ALPNSupport::getInstance(ssl);
473+
474+
ink_assert(alpns);
475+
if (alpns) {
476+
return alpns->advertise_next_protocol(ssl, out, outlen);
477+
}
478+
479+
return SSL_TLSEXT_ERR_NOACK;
480+
}
481+
482+
int
483+
ssl_alpn_select_callback(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen,
484+
void *)
485+
{
486+
ALPNSupport *alpns = ALPNSupport::getInstance(ssl);
487+
488+
ink_assert(alpns);
489+
if (alpns) {
490+
return alpns->select_next_protocol(ssl, out, outlen, in, inlen);
491+
}
492+
493+
return SSL_TLSEXT_ERR_NOACK;
494+
}
495+
466496
#if TS_USE_GET_DH_2048_256 == 0
467497
/* Build 2048-bit MODP Group with 256-bit Prime Order Subgroup from RFC 5114 */
468498
static DH *
@@ -873,6 +903,7 @@ SSLInitializeLibrary()
873903
ssl_vc_index = SSL_get_ex_new_index(0, (void *)"NetVC index", nullptr, nullptr, nullptr);
874904

875905
TLSBasicSupport::initialize();
906+
ALPNSupport::initialize();
876907
TLSSessionResumptionSupport::initialize();
877908
TLSSNISupport::initialize();
878909

@@ -1434,14 +1465,14 @@ SSLMultiCertConfigLoader::_set_info_callback(SSL_CTX *ctx)
14341465
bool
14351466
SSLMultiCertConfigLoader::_set_npn_callback(SSL_CTX *ctx)
14361467
{
1437-
SSL_CTX_set_next_protos_advertised_cb(ctx, SSLNetVConnection::advertise_next_protocol, nullptr);
1468+
SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_next_protos_advertised_callback, nullptr);
14381469
return true;
14391470
}
14401471

14411472
bool
14421473
SSLMultiCertConfigLoader::_set_alpn_callback(SSL_CTX *ctx)
14431474
{
1444-
SSL_CTX_set_alpn_select_cb(ctx, SSLNetVConnection::select_next_protocol, nullptr);
1475+
SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_callback, nullptr);
14451476
return true;
14461477
}
14471478

iocore/net/quic/QUICConnection.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ class QUICConnectionInfoProvider
5555

5656
virtual uint32_t pmtu() const = 0;
5757
virtual NetVConnectionContext_t direction() const = 0;
58-
virtual int select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in,
59-
unsigned inlen) const = 0;
6058
virtual bool is_closed() const = 0;
6159
virtual bool is_at_anti_amplification_limit() const = 0;
6260
virtual bool is_address_validation_completed() const = 0;

0 commit comments

Comments
 (0)