mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-06 10:08:52 +08:00
Remove NPN
This commit is contained in:
12
README.rst
12
README.rst
@@ -29,10 +29,10 @@ Public Test Server
|
||||
The following endpoints are available to try out our nghttp2
|
||||
implementation.
|
||||
|
||||
* https://nghttp2.org/ (TLS + ALPN/NPN and HTTP/3)
|
||||
* https://nghttp2.org/ (TLS + ALPN and HTTP/3)
|
||||
|
||||
This endpoint supports ``h2``, ``h2-16``, ``h2-14``, and
|
||||
``http/1.1`` via ALPN/NPN and requires TLSv1.2 for HTTP/2
|
||||
``http/1.1`` via ALPN and requires TLSv1.2 for HTTP/2
|
||||
connection.
|
||||
|
||||
It also supports HTTP/3.
|
||||
@@ -537,7 +537,7 @@ nghttp - client
|
||||
+++++++++++++++
|
||||
|
||||
``nghttp`` is a HTTP/2 client. It can connect to the HTTP/2 server
|
||||
with prior knowledge, HTTP Upgrade and NPN/ALPN TLS extension.
|
||||
with prior knowledge, HTTP Upgrade and ALPN TLS extension.
|
||||
|
||||
It has verbose output mode for framing information. Here is sample
|
||||
output from ``nghttp`` client:
|
||||
@@ -763,8 +763,8 @@ nghttpd - server
|
||||
By default, it uses SSL/TLS connection. Use ``--no-tls`` option to
|
||||
disable it.
|
||||
|
||||
``nghttpd`` only accepts HTTP/2 connections via NPN/ALPN or direct
|
||||
HTTP/2 connections. No HTTP Upgrade is supported.
|
||||
``nghttpd`` only accepts HTTP/2 connections via ALPN or direct HTTP/2
|
||||
connections. No HTTP Upgrade is supported.
|
||||
|
||||
The ``-p`` option allows users to configure server push.
|
||||
|
||||
@@ -845,7 +845,7 @@ to know how to migrate from earlier releases.
|
||||
``nghttpx`` implements `important performance-oriented features
|
||||
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
|
||||
session IDs, session tickets (with automatic key rotation), OCSP
|
||||
stapling, dynamic record sizing, ALPN/NPN, forward secrecy and HTTP/2.
|
||||
stapling, dynamic record sizing, ALPN, forward secrecy and HTTP/2.
|
||||
``nghttpx`` also offers the functionality to share session cache and
|
||||
ticket keys among multiple ``nghttpx`` instances via memcached.
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ In order to set benchmark settings, specify following 3 options.
|
||||
:option:`-m`
|
||||
The max concurrent streams to issue per client. Default: 1
|
||||
|
||||
For SSL/TLS connection, the protocol will be negotiated via ALPN/NPN.
|
||||
You can set specific protocols in :option:`--npn-list` option. For
|
||||
For SSL/TLS connection, the protocol will be negotiated via ALPN. You
|
||||
can set specific protocols in :option:`--npn-list` option. For
|
||||
cleartext connection, the default protocol is HTTP/2. To change the
|
||||
protocol in cleartext connection, use :option:`--no-tls-proto` option.
|
||||
For convenience, :option:`--h1` option forces HTTP/1.1 for both
|
||||
|
||||
@@ -20,7 +20,7 @@ known as "HTTP/2 router".
|
||||
By default, frontend connection is encrypted using SSL/TLS. So
|
||||
server's private key and certificate must be supplied to the command
|
||||
line (or through configuration file). In this case, the frontend
|
||||
protocol selection will be done via ALPN or NPN.
|
||||
protocol selection will be done via ALPN.
|
||||
|
||||
To turn off encryption on frontend connection, use ``no-tls`` keyword
|
||||
in :option:`--frontend` option. HTTP/2 and HTTP/1 are available on
|
||||
|
||||
@@ -18,34 +18,8 @@ note that nghttp2 itself does not depend on libevent.
|
||||
|
||||
The client starts with some libevent and OpenSSL setup in the
|
||||
``main()`` and ``run()`` functions. This setup isn't specific to
|
||||
nghttp2, but one thing you should look at is setup of the NPN
|
||||
callback. The NPN callback is used by the client to select the next
|
||||
application protocol over TLS. In this tutorial, we use the
|
||||
`nghttp2_select_next_protocol()` helper function to select the HTTP/2
|
||||
protocol the library supports::
|
||||
|
||||
static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg _U_) {
|
||||
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
||||
errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
If you are following TLS related RFC, you know that NPN is not the
|
||||
standardized way to negotiate HTTP/2. NPN itself is not event
|
||||
published as RFC. The standard way to negotiate HTTP/2 is ALPN,
|
||||
Application-Layer Protocol Negotiation Extension, defined in `RFC 7301
|
||||
<https://tools.ietf.org/html/rfc7301>`_. The one caveat of ALPN is
|
||||
that OpenSSL >= 1.0.2 is required. We use macro to enable/disable
|
||||
ALPN support depending on OpenSSL version. OpenSSL's ALPN
|
||||
implementation does not require callback function like the above. But
|
||||
we have to instruct OpenSSL SSL_CTX to use ALPN, which we'll talk
|
||||
about soon.
|
||||
|
||||
The callback is added to the SSL_CTX object using
|
||||
``SSL_CTX_set_next_proto_select_cb()``::
|
||||
nghttp2, but one thing you should look at is setup of ALPN. Client
|
||||
tells application protocols that it supports to server via ALPN::
|
||||
|
||||
static SSL_CTX *create_ssl_ctx(void) {
|
||||
SSL_CTX *ssl_ctx;
|
||||
@@ -58,7 +32,6 @@ The callback is added to the SSL_CTX object using
|
||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||
|
||||
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
|
||||
|
||||
@@ -153,10 +126,7 @@ underlying network socket::
|
||||
|
||||
ssl = bufferevent_openssl_get_ssl(session_data->bev);
|
||||
|
||||
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
||||
if (alpn == NULL) {
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
}
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
|
||||
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
|
||||
fprintf(stderr, "h2 is not negotiated\n");
|
||||
|
||||
@@ -21,33 +21,11 @@ note that nghttp2 itself does not depend on libevent.
|
||||
|
||||
The server starts with some libevent and OpenSSL setup in the
|
||||
``main()`` and ``run()`` functions. This setup isn't specific to
|
||||
nghttp2, but one thing you should look at is setup of the NPN
|
||||
callback. The NPN callback is used by the server to advertise which
|
||||
application protocols the server supports to a client. In this
|
||||
example program, when creating the ``SSL_CTX`` object, we store the
|
||||
application protocol name in the wire format of NPN in a statically
|
||||
allocated buffer. This is safe because we only create one ``SSL_CTX``
|
||||
object in the program's entire lifetime.
|
||||
|
||||
If you are following TLS related RFC, you know that NPN is not the
|
||||
standardized way to negotiate HTTP/2. NPN itself is not even
|
||||
published as RFC. The standard way to negotiate HTTP/2 is ALPN,
|
||||
Application-Layer Protocol Negotiation Extension, defined in `RFC 7301
|
||||
<https://tools.ietf.org/html/rfc7301>`_. The one caveat of ALPN is
|
||||
that OpenSSL >= 1.0.2 is required. We use macro to enable/disable
|
||||
ALPN support depending on OpenSSL version. In ALPN, client sends the
|
||||
list of supported application protocols, and server selects one of
|
||||
them. We provide the callback for it::
|
||||
|
||||
static unsigned char next_proto_list[256];
|
||||
static size_t next_proto_list_len;
|
||||
|
||||
static int next_proto_cb(SSL *s _U_, const unsigned char **data,
|
||||
unsigned int *len, void *arg _U_) {
|
||||
*data = next_proto_list;
|
||||
*len = (unsigned int)next_proto_list_len;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
nghttp2, but one thing you should look at is setup of ALPN callback.
|
||||
The ALPN callback is used by the server to select application
|
||||
protocols offered by client. In ALPN, client sends the list of
|
||||
supported application protocols, and server selects one of them. We
|
||||
provide the callback for it::
|
||||
|
||||
static int alpn_select_proto_cb(SSL *ssl _U_, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
@@ -71,28 +49,11 @@ them. We provide the callback for it::
|
||||
|
||||
...
|
||||
|
||||
next_proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
|
||||
memcpy(&next_proto_list[1], NGHTTP2_PROTO_VERSION_ID,
|
||||
NGHTTP2_PROTO_VERSION_ID_LEN);
|
||||
next_proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN;
|
||||
|
||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL);
|
||||
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL);
|
||||
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
The wire format of NPN is a sequence of length prefixed strings, with
|
||||
exactly one byte used to specify the length of each protocol
|
||||
identifier. In this tutorial, we advertise the specific HTTP/2
|
||||
protocol version the current nghttp2 library supports, which is
|
||||
exported in the identifier :macro:`NGHTTP2_PROTO_VERSION_ID`. The
|
||||
``next_proto_cb()`` function is the server-side NPN callback. In the
|
||||
OpenSSL implementation, we just assign the pointer to the NPN buffers
|
||||
we filled in earlier. The NPN callback function is set to the
|
||||
``SSL_CTX`` object using ``SSL_CTX_set_next_protos_advertised_cb()``.
|
||||
|
||||
In ``alpn_select_proto_cb()``, we use `nghttp2_select_next_protocol()`
|
||||
to select application protocol. The `nghttp2_select_next_protocol()`
|
||||
returns 1 only if it selected h2 (ALPN identifier for HTTP/2), and out
|
||||
@@ -209,10 +170,7 @@ underlying network socket::
|
||||
|
||||
ssl = bufferevent_openssl_get_ssl(session_data->bev);
|
||||
|
||||
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
||||
if (alpn == NULL) {
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
}
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
|
||||
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
|
||||
fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr);
|
||||
|
||||
@@ -345,29 +345,6 @@ static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) {
|
||||
callbacks, on_data_chunk_recv_callback);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
/*
|
||||
* Callback function for TLS NPN. Since this program only supports
|
||||
* HTTP/2 protocol, if server does not offer HTTP/2 the nghttp2
|
||||
* library supports, we terminate program.
|
||||
*/
|
||||
static int select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
int rv;
|
||||
(void)ssl;
|
||||
(void)arg;
|
||||
|
||||
/* nghttp2_select_next_protocol() selects HTTP/2 protocol the
|
||||
nghttp2 library supports. */
|
||||
rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
|
||||
if (rv <= 0) {
|
||||
die("Server did not advertise HTTP/2 protocol");
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
/*
|
||||
* Setup SSL/TLS context.
|
||||
*/
|
||||
@@ -376,10 +353,6 @@ static void init_ssl_ctx(SSL_CTX *ssl_ctx) {
|
||||
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
/* Set NPN callback */
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
|
||||
}
|
||||
|
||||
@@ -308,23 +308,6 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
/* NPN TLS extension client callback. We check that server advertised
|
||||
the HTTP/2 protocol the nghttp2 library supports. If not, exit
|
||||
the program. */
|
||||
static int select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
(void)ssl;
|
||||
(void)arg;
|
||||
|
||||
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
||||
errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
/* Create SSL_CTX. */
|
||||
static SSL_CTX *create_ssl_ctx(void) {
|
||||
SSL_CTX *ssl_ctx;
|
||||
@@ -337,9 +320,6 @@ static SSL_CTX *create_ssl_ctx(void) {
|
||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
|
||||
|
||||
@@ -506,9 +486,6 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr) {
|
||||
|
||||
ssl = bufferevent_openssl_get_ssl(session_data->bev);
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
if (alpn == NULL) {
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
}
|
||||
|
||||
@@ -106,21 +106,6 @@ struct app_context {
|
||||
struct event_base *evbase;
|
||||
};
|
||||
|
||||
static unsigned char next_proto_list[256];
|
||||
static size_t next_proto_list_len;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
static int next_proto_cb(SSL *ssl, const unsigned char **data,
|
||||
unsigned int *len, void *arg) {
|
||||
(void)ssl;
|
||||
(void)arg;
|
||||
|
||||
*data = next_proto_list;
|
||||
*len = (unsigned int)next_proto_list_len;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
@@ -175,15 +160,6 @@ static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
|
||||
errx(1, "Could not read certificate file %s", cert_file);
|
||||
}
|
||||
|
||||
next_proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
|
||||
memcpy(&next_proto_list[1], NGHTTP2_PROTO_VERSION_ID,
|
||||
NGHTTP2_PROTO_VERSION_ID_LEN);
|
||||
next_proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL);
|
||||
|
||||
return ssl_ctx;
|
||||
@@ -698,12 +674,7 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr) {
|
||||
|
||||
ssl = bufferevent_openssl_get_ssl(session_data->bev);
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||
if (alpn == NULL) {
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
}
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
|
||||
if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
|
||||
fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr);
|
||||
|
||||
@@ -5022,11 +5022,10 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* A helper function for dealing with NPN in client side or ALPN in
|
||||
* server side. The |in| contains peer's protocol list in preferable
|
||||
* order. The format of |in| is length-prefixed and not
|
||||
* null-terminated. For example, ``h2`` and
|
||||
* ``http/1.1`` stored in |in| like this::
|
||||
* A helper function for dealing with ALPN in server side. The |in|
|
||||
* contains peer's protocol list in preferable order. The format of
|
||||
* |in| is length-prefixed and not null-terminated. For example,
|
||||
* ``h2`` and ``http/1.1`` stored in |in| like this::
|
||||
*
|
||||
* in[0] = 2
|
||||
* in[1..2] = "h2"
|
||||
@@ -5051,20 +5050,18 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
|
||||
*
|
||||
* For ALPN, refer to https://tools.ietf.org/html/rfc7301
|
||||
*
|
||||
* See http://technotes.googlecode.com/git/nextprotoneg.html for more
|
||||
* details about NPN.
|
||||
* To use this method you should do something like::
|
||||
*
|
||||
* For NPN, to use this method you should do something like::
|
||||
*
|
||||
* static int select_next_proto_cb(SSL* ssl,
|
||||
* unsigned char **out,
|
||||
* static int alpn_select_proto_cb(SSL* ssl,
|
||||
* const unsigned char **out,
|
||||
* unsigned char *outlen,
|
||||
* const unsigned char *in,
|
||||
* unsigned int inlen,
|
||||
* void *arg)
|
||||
* {
|
||||
* int rv;
|
||||
* rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
|
||||
* rv = nghttp2_select_next_protocol((unsigned char**)out, outlen,
|
||||
* in, inlen);
|
||||
* if (rv == -1) {
|
||||
* return SSL_TLSEXT_ERR_NOACK;
|
||||
* }
|
||||
@@ -5074,7 +5071,7 @@ NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
|
||||
* return SSL_TLSEXT_ERR_OK;
|
||||
* }
|
||||
* ...
|
||||
* SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, my_obj);
|
||||
* SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, my_obj);
|
||||
*
|
||||
*/
|
||||
NGHTTP2_EXTERN int nghttp2_select_next_protocol(unsigned char **out,
|
||||
|
||||
@@ -725,7 +725,7 @@ int Http2Handler::tls_handshake() {
|
||||
std::cerr << "SSL/TLS handshake completed" << std::endl;
|
||||
}
|
||||
|
||||
if (verify_npn_result() != 0) {
|
||||
if (verify_alpn_result() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -892,25 +892,18 @@ int Http2Handler::connection_made() {
|
||||
return on_write();
|
||||
}
|
||||
|
||||
int Http2Handler::verify_npn_result() {
|
||||
int Http2Handler::verify_alpn_result() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
// Check the negotiated protocol in NPN or ALPN
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (next_proto) {
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
if (sessions_->get_config()->verbose) {
|
||||
std::cout << "The negotiated protocol: " << proto << std::endl;
|
||||
}
|
||||
if (util::check_h2_is_selected(proto)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
SSL_get0_alpn_selected(ssl_, &next_proto, &next_proto_len);
|
||||
// Check the negotiated protocol in ALPN
|
||||
SSL_get0_alpn_selected(ssl_, &next_proto, &next_proto_len);
|
||||
if (next_proto) {
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
if (sessions_->get_config()->verbose) {
|
||||
std::cout << "The negotiated protocol: " << proto << std::endl;
|
||||
}
|
||||
if (util::check_h2_is_selected(proto)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (sessions_->get_config()->verbose) {
|
||||
@@ -1988,18 +1981,6 @@ HttpServer::HttpServer(const Config *config) : config_(config) {
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
namespace {
|
||||
int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
|
||||
void *arg) {
|
||||
auto next_proto = static_cast<std::vector<unsigned char> *>(arg);
|
||||
*data = next_proto->data();
|
||||
*len = next_proto->size();
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
namespace {
|
||||
int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
// We don't verify the client certificate. Just request it for the
|
||||
@@ -2222,9 +2203,6 @@ int HttpServer::run() {
|
||||
|
||||
next_proto = util::get_default_alpn();
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
// ALPN selection callback
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this);
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ public:
|
||||
int on_read();
|
||||
int on_write();
|
||||
int connection_made();
|
||||
int verify_npn_result();
|
||||
int verify_alpn_result();
|
||||
|
||||
int submit_file_response(const StringRef &status, Stream *stream,
|
||||
time_t last_modified, off_t file_length,
|
||||
|
||||
@@ -1095,12 +1095,7 @@ int Client::connection_made() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
if (next_proto == nullptr) {
|
||||
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
|
||||
|
||||
if (next_proto) {
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
@@ -1130,9 +1125,8 @@ int Client::connection_made() {
|
||||
|
||||
for (const auto &proto : config.npn_list) {
|
||||
if (util::streq(NGHTTP2_H1_1_ALPN, StringRef{proto})) {
|
||||
std::cout
|
||||
<< "Server does not support NPN/ALPN. Falling back to HTTP/1.1."
|
||||
<< std::endl;
|
||||
std::cout << "Server does not support ALPN. Falling back to HTTP/1.1."
|
||||
<< std::endl;
|
||||
session = std::make_unique<Http1Session>(this);
|
||||
selected_proto = NGHTTP2_H1_1.str();
|
||||
break;
|
||||
@@ -1882,23 +1876,6 @@ std::string get_reqline(const char *uri, const http_parser_url &u) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
namespace {
|
||||
int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
if (util::select_protocol(const_cast<const unsigned char **>(out), outlen, in,
|
||||
inlen, config.npn_list)) {
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
// OpenSSL will terminate handshake with fatal alert if we return
|
||||
// NOACK. So there is no way to fallback.
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
namespace {
|
||||
constexpr char UNIX_PATH_PREFIX[] = "unix:";
|
||||
} // namespace
|
||||
@@ -2273,10 +2250,9 @@ Options:
|
||||
--npn-list=<LIST>
|
||||
Comma delimited list of ALPN protocol identifier sorted
|
||||
in the order of preference. That means most desirable
|
||||
protocol comes first. This is used in both ALPN and
|
||||
NPN. The parameter must be delimited by a single comma
|
||||
only and any white spaces are treated as a part of
|
||||
protocol string.
|
||||
protocol comes first. The parameter must be delimited
|
||||
by a single comma only and any white spaces are treated
|
||||
as a part of protocol string.
|
||||
Default: )"
|
||||
<< DEFAULT_NPN_LIST << R"(
|
||||
--h1 Short hand for --npn-list=http/1.1
|
||||
@@ -2980,11 +2956,6 @@ int main(int argc, char **argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb,
|
||||
nullptr);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
std::vector<unsigned char> proto_list;
|
||||
for (const auto &proto : config.npn_list) {
|
||||
std::copy_n(proto.c_str(), proto.size(), std::back_inserter(proto_list));
|
||||
|
||||
@@ -127,7 +127,7 @@ struct Config {
|
||||
bool base_uri_unix;
|
||||
// used when UNIX domain socket is used (base_uri_unix is true).
|
||||
sockaddr_un unix_addr;
|
||||
// list of supported NPN/ALPN protocol strings in the order of
|
||||
// list of supported ALPN protocol strings in the order of
|
||||
// preference.
|
||||
std::vector<std::string> npn_list;
|
||||
// The number of request per second for each client.
|
||||
|
||||
@@ -1115,24 +1115,19 @@ int HttpClient::connection_made() {
|
||||
}
|
||||
|
||||
if (ssl) {
|
||||
// Check NPN or ALPN result
|
||||
// Check ALPN result
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (next_proto) {
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
if (config.verbose) {
|
||||
std::cout << "The negotiated protocol: " << proto << std::endl;
|
||||
}
|
||||
if (!util::check_h2_is_selected(proto)) {
|
||||
next_proto = nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
|
||||
if (next_proto) {
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
if (config.verbose) {
|
||||
std::cout << "The negotiated protocol: " << proto << std::endl;
|
||||
}
|
||||
if (!util::check_h2_is_selected(proto)) {
|
||||
next_proto = nullptr;
|
||||
}
|
||||
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
if (!next_proto) {
|
||||
print_protocol_nego_error();
|
||||
@@ -2242,32 +2237,6 @@ id responseEnd requestStart process code size request path)"
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
namespace {
|
||||
int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
if (config.verbose) {
|
||||
print_timer();
|
||||
std::cout << "[NPN] server offers:" << std::endl;
|
||||
}
|
||||
for (unsigned int i = 0; i < inlen; i += in[i] + 1) {
|
||||
if (config.verbose) {
|
||||
std::cout << " * ";
|
||||
std::cout.write(reinterpret_cast<const char *>(&in[i + 1]), in[i]);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
if (!util::select_h2(const_cast<const unsigned char **>(out), outlen, in,
|
||||
inlen)) {
|
||||
print_protocol_nego_error();
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
namespace {
|
||||
int communicate(
|
||||
const std::string &scheme, const std::string &host, uint16_t port,
|
||||
@@ -2338,10 +2307,6 @@ int communicate(
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb,
|
||||
nullptr);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
auto proto_list = util::get_default_alpn();
|
||||
|
||||
|
||||
@@ -2801,10 +2801,9 @@ SSL/TLS:
|
||||
--npn-list=<LIST>
|
||||
Comma delimited list of ALPN protocol identifier sorted
|
||||
in the order of preference. That means most desirable
|
||||
protocol comes first. This is used in both ALPN and
|
||||
NPN. The parameter must be delimited by a single comma
|
||||
only and any white spaces are treated as a part of
|
||||
protocol string.
|
||||
protocol comes first. The parameter must be delimited
|
||||
by a single comma only and any white spaces are treated
|
||||
as a part of protocol string.
|
||||
Default: )"
|
||||
<< DEFAULT_NPN_LIST
|
||||
<< R"(
|
||||
|
||||
@@ -616,12 +616,7 @@ int ClientHandler::validate_next_proto() {
|
||||
// First set callback for catch all cases
|
||||
on_read_ = &ClientHandler::upstream_read;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
if (next_proto == nullptr) {
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
|
||||
StringRef proto;
|
||||
|
||||
|
||||
@@ -753,7 +753,7 @@ struct TLSConfig {
|
||||
// The list of additional TLS certificate pair
|
||||
std::vector<TLSCertificate> subcerts;
|
||||
std::vector<unsigned char> alpn_prefs;
|
||||
// list of supported NPN/ALPN protocol strings in the order of
|
||||
// list of supported ALPN protocol strings in the order of
|
||||
// preference.
|
||||
std::vector<StringRef> npn_list;
|
||||
// list of supported SSL/TLS protocol strings.
|
||||
|
||||
@@ -794,12 +794,7 @@ int Connection::check_http2_requirement() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(tls.ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
if (next_proto == nullptr) {
|
||||
SSL_get0_alpn_selected(tls.ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
SSL_get0_alpn_selected(tls.ssl, &next_proto, &next_proto_len);
|
||||
if (next_proto == nullptr ||
|
||||
!util::check_h2_is_selected(StringRef{next_proto, next_proto_len})) {
|
||||
return 0;
|
||||
|
||||
@@ -265,7 +265,7 @@ int ConnectionHandler::create_single_worker() {
|
||||
nb_,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
tlsconf.cacert, memcachedconf.cert_file,
|
||||
memcachedconf.private_key_file, nullptr);
|
||||
memcachedconf.private_key_file);
|
||||
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
|
||||
#ifdef ENABLE_HTTP3
|
||||
quic_all_ssl_ctx_.push_back(nullptr);
|
||||
@@ -367,7 +367,7 @@ int ConnectionHandler::create_worker_thread(size_t num) {
|
||||
nb_,
|
||||
# endif // HAVE_NEVERBLEED
|
||||
tlsconf.cacert, memcachedconf.cert_file,
|
||||
memcachedconf.private_key_file, nullptr);
|
||||
memcachedconf.private_key_file);
|
||||
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
|
||||
# ifdef ENABLE_HTTP3
|
||||
quic_all_ssl_ctx_.push_back(nullptr);
|
||||
@@ -935,8 +935,7 @@ SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
nb_,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
tlsconf.cacert, memcachedconf.cert_file, memcachedconf.private_key_file,
|
||||
nullptr);
|
||||
tlsconf.cacert, memcachedconf.cert_file, memcachedconf.private_key_file);
|
||||
|
||||
all_ssl_ctx_.push_back(ssl_ctx);
|
||||
#ifdef ENABLE_HTTP3
|
||||
|
||||
@@ -1672,12 +1672,7 @@ int Http2Session::connection_made() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len = 0;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
if (!next_proto) {
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
|
||||
if (!next_proto) {
|
||||
downstream_failure(addr_, raddr_);
|
||||
|
||||
@@ -405,12 +405,7 @@ int LiveCheck::tls_handshake() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len = 0;
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
if (next_proto == nullptr) {
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
}
|
||||
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
||||
|
||||
auto proto = StringRef{next_proto, next_proto_len};
|
||||
|
||||
|
||||
@@ -96,18 +96,6 @@ namespace shrpx {
|
||||
|
||||
namespace tls {
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
namespace {
|
||||
int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
|
||||
void *arg) {
|
||||
auto &prefs = get_config()->tls.alpn_prefs;
|
||||
*data = prefs.data();
|
||||
*len = prefs.size();
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
namespace {
|
||||
int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
if (!preverify_ok) {
|
||||
@@ -1065,10 +1053,6 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
|
||||
SSL_CTX_set_early_data_enabled(ssl_ctx, 1);
|
||||
#endif // NGHTTP2_OPENSSL_IS_BORINGSSL
|
||||
|
||||
// NPN advertisement
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, nullptr);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
// ALPN selection callback
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, nullptr);
|
||||
|
||||
@@ -1384,62 +1368,12 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file,
|
||||
}
|
||||
#endif // ENABLE_HTTP3
|
||||
|
||||
namespace {
|
||||
int select_h2_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
if (!util::select_h2(const_cast<const unsigned char **>(out), outlen, in,
|
||||
inlen)) {
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int select_h1_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
auto end = in + inlen;
|
||||
for (; in < end;) {
|
||||
if (util::streq(NGHTTP2_H1_1_ALPN, StringRef{in, in + (in[0] + 1)})) {
|
||||
*out = const_cast<unsigned char *>(in) + 1;
|
||||
*outlen = in[0];
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
in += in[0] + 1;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int select_next_proto_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
void *arg) {
|
||||
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
|
||||
switch (conn->proto) {
|
||||
case Proto::HTTP1:
|
||||
return select_h1_next_proto_cb(ssl, out, outlen, in, inlen, arg);
|
||||
case Proto::HTTP2:
|
||||
return select_h2_next_proto_cb(ssl, out, outlen, in, inlen, arg);
|
||||
default:
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SSL_CTX *create_ssl_client_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
const StringRef &cacert, const StringRef &cert_file,
|
||||
const StringRef &private_key_file,
|
||||
int (*next_proto_select_cb)(SSL *s, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg)) {
|
||||
const StringRef &private_key_file) {
|
||||
auto ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||
if (!ssl_ctx) {
|
||||
LOG(FATAL) << ERR_error_string(ERR_get_error(), nullptr);
|
||||
@@ -1539,12 +1473,6 @@ SSL_CTX *create_ssl_client_context(
|
||||
SSL_CTX_set_psk_client_callback(ssl_ctx, psk_client_cb);
|
||||
#endif // !OPENSSL_NO_PSK
|
||||
|
||||
// NPN selection callback. This is required to set SSL_CTX because
|
||||
// OpenSSL does not offer SSL_set_next_proto_select_cb.
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_cb, nullptr);
|
||||
#endif // !OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
@@ -2249,8 +2177,8 @@ SSL_CTX *setup_downstream_client_ssl_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
nb,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
tlsconf.cacert, tlsconf.client.cert_file, tlsconf.client.private_key_file,
|
||||
select_next_proto_cb);
|
||||
tlsconf.cacert, tlsconf.client.cert_file,
|
||||
tlsconf.client.private_key_file);
|
||||
}
|
||||
|
||||
void setup_downstream_http2_alpn(SSL *ssl) {
|
||||
|
||||
@@ -89,28 +89,12 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
|
||||
);
|
||||
|
||||
// Create client side SSL_CTX. This does not configure ALPN settings.
|
||||
// |next_proto_select_cb| is for NPN.
|
||||
SSL_CTX *create_ssl_client_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
const StringRef &cacert, const StringRef &cert_file,
|
||||
const StringRef &private_key_file,
|
||||
int (*next_proto_select_cb)(SSL *s, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg));
|
||||
|
||||
#ifdef ENABLE_HTTP3
|
||||
SSL_CTX *create_quic_ssl_client_context(
|
||||
# ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb,
|
||||
# endif // HAVE_NEVERBLEED
|
||||
const StringRef &cacert, const StringRef &cert_file,
|
||||
const StringRef &private_key_file,
|
||||
int (*next_proto_select_cb)(SSL *s, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg));
|
||||
#endif // ENABLE_HTTP3
|
||||
const StringRef &private_key_file);
|
||||
|
||||
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
|
||||
int addrlen, const UpstreamAddr *faddr);
|
||||
|
||||
Reference in New Issue
Block a user