Merge pull request #2020 from nghttp2/remove-npn

Remove NPN
This commit is contained in:
Tatsuhiro Tsujikawa
2023-12-24 16:08:16 +09:00
committed by GitHub
37 changed files with 279 additions and 505 deletions

View File

@@ -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.
@@ -972,12 +972,15 @@ threads to avoid saturating a single core on client side.
servers.
If the experimental HTTP/3 is enabled, h2load can send requests to
HTTP/3 server. To do this, specify ``h3`` to ``--npn-list`` option
HTTP/3 server. To do this, specify ``h3`` to ``--alpn-list`` option
like so:
.. code-block:: text
$ h2load --npn-list h3 https://127.0.0.1:4433
$ h2load --alpn-list h3 https://127.0.0.1:4433
For nghttp2 v1.58 or earlier, use ``--npn-list`` instead of
``--alpn-list``.
HPACK tools
-----------

View File

@@ -86,6 +86,7 @@ APIDOCS= \
nghttp2_rcbuf_incref.rst \
nghttp2_rcbuf_is_static.rst \
nghttp2_select_next_protocol.rst \
nghttp2_select_alpn.rst \
nghttp2_session_callbacks_del.rst \
nghttp2_session_callbacks_new.rst \
nghttp2_session_callbacks_set_before_frame_send_callback.rst \

View File

@@ -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:`--alpn-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
@@ -139,4 +139,4 @@ h2load supports HTTP/3 if it is built with HTTP/3 enabled. HTTP/3
support is experimental.
In order to send HTTP/3 request, specify ``h3`` to
:option:`--npn-list`.
:option:`--alpn-list`.

View File

@@ -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

View File

@@ -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");

View File

@@ -21,40 +21,18 @@ 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,
unsigned int inlen, void *arg _U_) {
int rv;
rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen);
rv = nghttp2_select_alpn(out, outlen, in, inlen);
if (rv != 1) {
return SSL_TLSEXT_ERR_NOACK;
@@ -71,31 +49,14 @@ 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
In ``alpn_select_proto_cb()``, we use `nghttp2_select_alpn()` to
select application protocol. The `nghttp2_select_alpn()` returns 1
only if it selected h2 (ALPN identifier for HTTP/2), and out
parameters were assigned accordingly.
Next, let's take a look at the main structures used by the example
@@ -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);

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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) {
@@ -128,7 +113,7 @@ static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
(void)ssl;
(void)arg;
rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen);
rv = nghttp2_select_alpn(out, outlen, in, inlen);
if (rv != 1) {
return SSL_TLSEXT_ERR_NOACK;
@@ -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);

View File

@@ -200,6 +200,7 @@ OPTIONS = [
"frontend-quic-initial-rtt",
"require-http-scheme",
"tls-ktls",
"alpn-list",
]
LOGVARS = [

View File

@@ -14,7 +14,7 @@ set(NGHTTP2_SOURCES
nghttp2_stream.c nghttp2_outbound_item.c
nghttp2_session.c nghttp2_submit.c
nghttp2_helper.c
nghttp2_npn.c
nghttp2_alpn.c
nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c
nghttp2_version.c
nghttp2_priority_spec.c

View File

@@ -41,7 +41,7 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_stream.c nghttp2_outbound_item.c \
nghttp2_session.c nghttp2_submit.c \
nghttp2_helper.c \
nghttp2_npn.c \
nghttp2_alpn.c \
nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c \
nghttp2_version.c \
nghttp2_priority_spec.c \
@@ -60,7 +60,7 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_frame.h \
nghttp2_buf.h \
nghttp2_session.h nghttp2_helper.h nghttp2_stream.h nghttp2_int.h \
nghttp2_npn.h \
nghttp2_alpn.h \
nghttp2_submit.h nghttp2_outbound_item.h \
nghttp2_net.h \
nghttp2_hd.h nghttp2_hd_huffman.h \

View File

@@ -74,7 +74,7 @@ NGHTTP2_SRC := nghttp2_pq.c \
nghttp2_session.c \
nghttp2_submit.c \
nghttp2_helper.c \
nghttp2_npn.c \
nghttp2_alpn.c \
nghttp2_hd.c \
nghttp2_hd_huffman.c \
nghttp2_hd_huffman_data.c \

View File

@@ -5022,11 +5022,14 @@ 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::
* .. warning::
*
* Deprecated. Use `nghttp2_select_alpn` instead.
*
* 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 +5054,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 +5075,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,
@@ -5082,6 +5083,65 @@ NGHTTP2_EXTERN int nghttp2_select_next_protocol(unsigned char **out,
const unsigned char *in,
unsigned int inlen);
/**
* @function
*
* 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"
* in[3] = 8
* in[4..11] = "http/1.1"
* inlen = 12
*
* The selection algorithm is as follows:
*
* 1. If peer's list contains HTTP/2 protocol the library supports,
* it is selected and returns 1. The following step is not taken.
*
* 2. If peer's list contains ``http/1.1``, this function selects
* ``http/1.1`` and returns 0. The following step is not taken.
*
* 3. This function selects nothing and returns -1 (So called
* non-overlap case). In this case, |out| and |outlen| are left
* untouched.
*
* Selecting ``h2`` means that ``h2`` is written into |*out| and its
* length (which is 2) is assigned to |*outlen|.
*
* For ALPN, refer to https://tools.ietf.org/html/rfc7301
*
* To use this method you should do something like::
*
* 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_alpn(out, outlen, in, inlen);
* if (rv == -1) {
* return SSL_TLSEXT_ERR_NOACK;
* }
* if (rv == 1) {
* ((MyType*)arg)->http2_selected = 1;
* }
* return SSL_TLSEXT_ERR_OK;
* }
* ...
* SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, my_obj);
*
*/
NGHTTP2_EXTERN int nghttp2_select_alpn(const unsigned char **out,
unsigned char *outlen,
const unsigned char *in,
unsigned int inlen);
/**
* @function
*

View File

@@ -22,13 +22,13 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nghttp2_npn.h"
#include "nghttp2_alpn.h"
#include <string.h>
static int select_next_protocol(unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen,
const char *key, unsigned int keylen) {
static int select_alpn(const unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen,
const char *key, unsigned int keylen) {
unsigned int i;
for (i = 0; i + keylen <= inlen; i += (unsigned int)(in[i] + 1)) {
if (memcmp(&in[i], key, keylen) == 0) {
@@ -45,12 +45,25 @@ static int select_next_protocol(unsigned char **out, unsigned char *outlen,
int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen) {
if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN,
NGHTTP2_PROTO_ALPN_LEN) == 0) {
if (select_alpn((const unsigned char **)out, outlen, in, inlen,
NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN) == 0) {
return 1;
}
if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_HTTP_1_1_ALPN,
NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) {
if (select_alpn((const unsigned char **)out, outlen, in, inlen,
NGHTTP2_HTTP_1_1_ALPN, NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) {
return 0;
}
return -1;
}
int nghttp2_select_alpn(const unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen) {
if (select_alpn(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN,
NGHTTP2_PROTO_ALPN_LEN) == 0) {
return 1;
}
if (select_alpn(out, outlen, in, inlen, NGHTTP2_HTTP_1_1_ALPN,
NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) {
return 0;
}
return -1;

View File

@@ -22,8 +22,8 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_NPN_H
#define NGHTTP2_NPN_H
#ifndef NGHTTP2_ALPN_H
#define NGHTTP2_ALPN_H
#ifdef HAVE_CONFIG_H
# include <config.h>
@@ -31,4 +31,4 @@
#include <nghttp2/nghttp2.h>
#endif /* NGHTTP2_NPN_H */
#endif /* NGHTTP2_ALPN_H */

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -155,8 +155,8 @@ bool Config::has_base_uri() const { return (!this->base_uri.empty()); }
bool Config::rps_enabled() const { return this->rps > 0.0; }
bool Config::is_quic() const {
#ifdef ENABLE_HTTP3
return !npn_list.empty() &&
(npn_list[0] == NGHTTP3_ALPN_H3 || npn_list[0] == "\x5h3-29");
return !alpn_list.empty() &&
(alpn_list[0] == NGHTTP3_ALPN_H3 || alpn_list[0] == "\x5h3-29");
#else // !ENABLE_HTTP3
return false;
#endif // !ENABLE_HTTP3
@@ -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};
@@ -1128,11 +1123,10 @@ int Client::connection_made() {
std::cout << "No protocol negotiated. Fallback behaviour may be activated"
<< std::endl;
for (const auto &proto : config.npn_list) {
for (const auto &proto : config.alpn_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;
@@ -1148,7 +1142,7 @@ int Client::connection_made() {
std::cout
<< "No supported protocol was negotiated. Supported protocols were:"
<< std::endl;
for (const auto &proto : config.npn_list) {
for (const auto &proto : config.alpn_list) {
std::cout << proto.substr(1) << std::endl;
}
disconnect();
@@ -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
@@ -2110,7 +2087,7 @@ benchmarking tool for HTTP/2 server)"
} // namespace
namespace {
constexpr char DEFAULT_NPN_LIST[] = "h2,h2-16,h2-14,http/1.1";
constexpr char DEFAULT_ALPN_LIST[] = "h2,h2-16,h2-14,http/1.1";
} // namespace
namespace {
@@ -2270,16 +2247,15 @@ Options:
instead of TCP. In this case, scheme is inferred from
the first URI appeared in the command line or inside
input files as usual.
--npn-list=<LIST>
--alpn-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
<< DEFAULT_ALPN_LIST << R"(
--h1 Short hand for --alpn-list=http/1.1
--no-tls-proto=http/1.1, which effectively force
http/1.1 for both http and https URI.
--header-table-size=<SIZE>
@@ -2383,6 +2359,7 @@ int main(int argc, char **argv) {
{"qlog-file-base", required_argument, &flag, 16},
{"max-udp-payload-size", required_argument, &flag, 17},
{"ktls", no_argument, &flag, 18},
{"alpn-list", required_argument, &flag, 19},
{nullptr, 0, nullptr, 0}};
int option_index = 0;
auto c = getopt_long(argc, argv,
@@ -2610,10 +2587,6 @@ int main(int argc, char **argv) {
config.ifile = optarg;
config.timing_script = true;
break;
case 4:
// npn-list option
config.npn_list = util::parse_config_str_list(StringRef{optarg});
break;
case 5:
// rate-period
config.rate_period = util::parse_duration_with_unit(optarg);
@@ -2624,7 +2597,7 @@ int main(int argc, char **argv) {
break;
case 6:
// --h1
config.npn_list =
config.alpn_list =
util::parse_config_str_list(StringRef::from_lit("http/1.1"));
config.no_tls_proto = Config::PROTO_HTTP1_1;
break;
@@ -2714,6 +2687,15 @@ int main(int argc, char **argv) {
// --ktls
config.ktls = true;
break;
case 4:
// npn-list option
std::cerr << "--npn-list: deprecated. Use --alpn-list instead."
<< std::endl;
// fall through
case 19:
// alpn-list option
config.alpn_list = util::parse_config_str_list(StringRef{optarg});
break;
}
break;
default:
@@ -2734,13 +2716,13 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE);
}
if (config.npn_list.empty()) {
config.npn_list =
util::parse_config_str_list(StringRef::from_lit(DEFAULT_NPN_LIST));
if (config.alpn_list.empty()) {
config.alpn_list =
util::parse_config_str_list(StringRef::from_lit(DEFAULT_ALPN_LIST));
}
// serialize the APLN tokens
for (auto &proto : config.npn_list) {
for (auto &proto : config.alpn_list) {
proto.insert(proto.begin(), static_cast<unsigned char>(proto.size()));
}
@@ -2980,13 +2962,8 @@ 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) {
for (const auto &proto : config.alpn_list) {
std::copy_n(proto.c_str(), proto.size(), std::back_inserter(proto_list));
}

View File

@@ -127,9 +127,9 @@ 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;
std::vector<std::string> alpn_list;
// The number of request per second for each client.
double rps;
// Disables GSO for UDP connections.

View File

@@ -438,11 +438,11 @@ int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
},
};
assert(config->npn_list.size());
assert(config->alpn_list.size());
uint32_t quic_version;
if (config->npn_list[0] == NGHTTP3_ALPN_H3) {
if (config->alpn_list[0] == NGHTTP3_ALPN_H3) {
quic_version = NGTCP2_PROTO_VER_V1;
} else {
quic_version = NGTCP2_PROTO_VER_MIN;

View File

@@ -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();

View File

@@ -1911,7 +1911,7 @@ bool conf_exists(const char *path) {
} // namespace
namespace {
constexpr auto DEFAULT_NPN_LIST =
constexpr auto DEFAULT_ALPN_LIST =
StringRef::from_lit("h2,h2-16,h2-14,http/1.1");
} // namespace
@@ -2798,15 +2798,14 @@ SSL/TLS:
Path to file that contains DH parameters in PEM format.
Without this option, DHE cipher suites are not
available.
--npn-list=<LIST>
--alpn-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
<< DEFAULT_ALPN_LIST
<< R"(
--verify-client
Require and verify client certificate.
@@ -3750,8 +3749,8 @@ int process_options(Config *config,
auto &tlsconf = config->tls;
if (tlsconf.npn_list.empty()) {
tlsconf.npn_list = util::split_str(DEFAULT_NPN_LIST, ',');
if (tlsconf.alpn_list.empty()) {
tlsconf.alpn_list = util::split_str(DEFAULT_ALPN_LIST, ',');
}
if (!tlsconf.tls_proto_list.empty()) {
@@ -3766,7 +3765,7 @@ int process_options(Config *config,
return -1;
}
if (tls::set_alpn_prefs(tlsconf.alpn_prefs, tlsconf.npn_list) != 0) {
if (tls::set_alpn_prefs(tlsconf.alpn_prefs, tlsconf.alpn_list) != 0) {
return -1;
}
@@ -4377,6 +4376,7 @@ int main(int argc, char **argv) {
190},
{SHRPX_OPT_REQUIRE_HTTP_SCHEME.c_str(), no_argument, &flag, 191},
{SHRPX_OPT_TLS_KTLS.c_str(), no_argument, &flag, 192},
{SHRPX_OPT_ALPN_LIST.c_str(), required_argument, &flag, 193},
{nullptr, 0, nullptr, 0}};
int option_index = 0;
@@ -5290,6 +5290,10 @@ int main(int argc, char **argv) {
// --tls-ktls
cmdcfgs.emplace_back(SHRPX_OPT_TLS_KTLS, StringRef::from_lit("yes"));
break;
case 193:
// --alpn-list
cmdcfgs.emplace_back(SHRPX_OPT_ALPN_LIST, StringRef{optarg});
break;
default:
break;
}

View File

@@ -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;
@@ -639,7 +634,7 @@ int ClientHandler::validate_next_proto() {
proto = StringRef::from_lit("http/1.1");
}
if (!tls::in_proto_list(get_config()->tls.npn_list, proto)) {
if (!tls::in_proto_list(get_config()->tls.alpn_list, proto)) {
if (LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "The negotiated protocol is not supported: " << proto;
}

View File

@@ -1912,6 +1912,11 @@ int option_lookup_token(const char *name, size_t namelen) {
return SHRPX_OPTID_LOG_LEVEL;
}
break;
case 't':
if (util::strieq_l("alpn-lis", name, 8)) {
return SHRPX_OPTID_ALPN_LIST;
}
break;
}
break;
case 10:
@@ -3341,15 +3346,6 @@ int parse_config(Config *config, int optid, const StringRef &opt,
case SHRPX_OPTID_WORKER_WRITE_BURST:
LOG(WARN) << opt << ": not implemented yet";
return 0;
case SHRPX_OPTID_NPN_LIST: {
auto list = util::split_str(optarg, ',');
config->tls.npn_list.resize(list.size());
for (size_t i = 0; i < list.size(); ++i) {
config->tls.npn_list[i] = make_string_ref(config->balloc, list[i]);
}
return 0;
}
case SHRPX_OPTID_TLS_PROTO_LIST: {
LOG(WARN) << opt
<< ": deprecated. Use tls-min-proto-version and "
@@ -4174,6 +4170,18 @@ int parse_config(Config *config, int optid, const StringRef &opt,
case SHRPX_OPTID_TLS_KTLS:
config->tls.ktls = util::strieq_l("yes", optarg);
return 0;
case SHRPX_OPTID_NPN_LIST:
LOG(WARN) << opt << ": deprecated. Use alpn-list instead.";
// fall through
case SHRPX_OPTID_ALPN_LIST: {
auto list = util::split_str(optarg, ',');
config->tls.alpn_list.resize(list.size());
for (size_t i = 0; i < list.size(); ++i) {
config->tls.alpn_list[i] = make_string_ref(config->balloc, list[i]);
}
return 0;
}
case SHRPX_OPTID_CONF:
LOG(WARN) << "conf: ignored";

View File

@@ -405,6 +405,7 @@ constexpr auto SHRPX_OPT_FRONTEND_QUIC_INITIAL_RTT =
constexpr auto SHRPX_OPT_REQUIRE_HTTP_SCHEME =
StringRef::from_lit("require-http-scheme");
constexpr auto SHRPX_OPT_TLS_KTLS = StringRef::from_lit("tls-ktls");
constexpr auto SHRPX_OPT_ALPN_LIST = StringRef::from_lit("alpn-list");
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
@@ -753,9 +754,9 @@ 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;
std::vector<StringRef> alpn_list;
// list of supported SSL/TLS protocol strings.
std::vector<StringRef> tls_proto_list;
std::vector<uint8_t> sct_data;
@@ -1183,6 +1184,7 @@ enum {
SHRPX_OPTID_ADD_REQUEST_HEADER,
SHRPX_OPTID_ADD_RESPONSE_HEADER,
SHRPX_OPTID_ADD_X_FORWARDED_FOR,
SHRPX_OPTID_ALPN_LIST,
SHRPX_OPTID_ALTSVC,
SHRPX_OPTID_API_MAX_REQUEST_BODY,
SHRPX_OPTID_BACKEND,

View File

@@ -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;

View File

@@ -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

View File

@@ -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_);

View File

@@ -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};

View File

@@ -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) {
@@ -650,10 +638,10 @@ namespace {
int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg) {
// We assume that get_config()->npn_list contains ALPN protocol
// We assume that get_config()->alpn_list contains ALPN protocol
// identifier sorted by preference order. So we just break when we
// found the first overlap.
for (const auto &target_proto_id : get_config()->tls.npn_list) {
for (const auto &target_proto_id : get_config()->tls.alpn_list) {
for (auto p = in, end = in + inlen; p < end;) {
auto proto_id = p + 1;
auto proto_len = *p;
@@ -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) {

View File

@@ -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);

View File

@@ -17,7 +17,7 @@ if(HAVE_CUNIT)
nghttp2_stream_test.c
nghttp2_session_test.c
nghttp2_hd_test.c
nghttp2_npn_test.c
nghttp2_alpn_test.c
nghttp2_helper_test.c
nghttp2_buf_test.c
nghttp2_http_test.c

View File

@@ -38,7 +38,7 @@ OBJECTS = main.c nghttp2_pq_test.c nghttp2_map_test.c nghttp2_queue_test.c \
nghttp2_stream_test.c \
nghttp2_session_test.c \
nghttp2_hd_test.c \
nghttp2_npn_test.c \
nghttp2_alpn_test.c \
nghttp2_helper_test.c \
nghttp2_buf_test.c \
nghttp2_http_test.c \
@@ -48,7 +48,7 @@ OBJECTS = main.c nghttp2_pq_test.c nghttp2_map_test.c nghttp2_queue_test.c \
HFILES = nghttp2_pq_test.h nghttp2_map_test.h nghttp2_queue_test.h \
nghttp2_session_test.h \
nghttp2_frame_test.h nghttp2_stream_test.h nghttp2_hd_test.h \
nghttp2_npn_test.h nghttp2_helper_test.h \
nghttp2_alpn_test.h nghttp2_helper_test.h \
nghttp2_test_helper.h \
nghttp2_buf_test.h \
nghttp2_http_test.h \

View File

@@ -37,7 +37,7 @@
#include "nghttp2_frame_test.h"
#include "nghttp2_stream_test.h"
#include "nghttp2_hd_test.h"
#include "nghttp2_npn_test.h"
#include "nghttp2_alpn_test.h"
#include "nghttp2_helper_test.h"
#include "nghttp2_buf_test.h"
#include "nghttp2_http_test.h"
@@ -75,7 +75,7 @@ int main(void) {
!CU_add_test(pSuite, "map_functional", test_nghttp2_map_functional) ||
!CU_add_test(pSuite, "map_each_free", test_nghttp2_map_each_free) ||
!CU_add_test(pSuite, "queue", test_nghttp2_queue) ||
!CU_add_test(pSuite, "npn", test_nghttp2_npn) ||
!CU_add_test(pSuite, "alpn", test_nghttp2_alpn) ||
!CU_add_test(pSuite, "session_recv", test_nghttp2_session_recv) ||
!CU_add_test(pSuite, "session_recv_invalid_stream_id",
test_nghttp2_session_recv_invalid_stream_id) ||

View File

@@ -22,7 +22,7 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nghttp2_npn_test.h"
#include "nghttp2_alpn_test.h"
#include <stdio.h>
#include <string.h>
@@ -34,8 +34,16 @@ static void http2(void) {
const unsigned char p[] = {8, 'h', 't', 't', 'p', '/', '1', '.', '1', 2,
'h', '2', 6, 's', 'p', 'd', 'y', '/', '3'};
unsigned char outlen;
unsigned char *out;
CU_ASSERT(1 == nghttp2_select_next_protocol(&out, &outlen, p, sizeof(p)));
const unsigned char *out;
CU_ASSERT(1 == nghttp2_select_next_protocol((unsigned char **)&out, &outlen,
p, sizeof(p)));
CU_ASSERT(NGHTTP2_PROTO_VERSION_ID_LEN == outlen);
CU_ASSERT(memcmp(NGHTTP2_PROTO_VERSION_ID, out, outlen) == 0);
outlen = 0;
out = NULL;
CU_ASSERT(1 == nghttp2_select_alpn(&out, &outlen, p, sizeof(p)));
CU_ASSERT(NGHTTP2_PROTO_VERSION_ID_LEN == outlen);
CU_ASSERT(memcmp(NGHTTP2_PROTO_VERSION_ID, out, outlen) == 0);
}
@@ -46,9 +54,16 @@ static void http11(void) {
'2', '.', '1', 8, 'h', 't', 't', 'p', '/', '1', '.', '1',
};
unsigned char outlen;
unsigned char *out;
CU_ASSERT(0 ==
nghttp2_select_next_protocol(&out, &outlen, spdy, sizeof(spdy)));
const unsigned char *out;
CU_ASSERT(0 == nghttp2_select_next_protocol((unsigned char **)&out, &outlen,
spdy, sizeof(spdy)));
CU_ASSERT(8 == outlen);
CU_ASSERT(memcmp("http/1.1", out, outlen) == 0);
outlen = 0;
out = NULL;
CU_ASSERT(0 == nghttp2_select_alpn(&out, &outlen, spdy, sizeof(spdy)));
CU_ASSERT(8 == outlen);
CU_ASSERT(memcmp("http/1.1", out, outlen) == 0);
}
@@ -59,14 +74,21 @@ static void no_overlap(void) {
'2', '.', '1', 8, 'h', 't', 't', 'p', '/', '1', '.', '0',
};
unsigned char outlen = 0;
unsigned char *out = NULL;
CU_ASSERT(-1 ==
nghttp2_select_next_protocol(&out, &outlen, spdy, sizeof(spdy)));
const unsigned char *out = NULL;
CU_ASSERT(-1 == nghttp2_select_next_protocol((unsigned char **)&out, &outlen,
spdy, sizeof(spdy)));
CU_ASSERT(0 == outlen);
CU_ASSERT(NULL == out);
outlen = 0;
out = NULL;
CU_ASSERT(-1 == nghttp2_select_alpn(&out, &outlen, spdy, sizeof(spdy)));
CU_ASSERT(0 == outlen);
CU_ASSERT(NULL == out);
}
void test_nghttp2_npn(void) {
void test_nghttp2_alpn(void) {
http2();
http11();
no_overlap();

View File

@@ -22,13 +22,13 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_NPN_TEST_H
#define NGHTTP2_NPN_TEST_H
#ifndef NGHTTP2_ALPN_TEST_H
#define NGHTTP2_ALPN_TEST_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
void test_nghttp2_npn(void);
void test_nghttp2_alpn(void);
#endif /* NGHTTP2_NPN_TEST_H */
#endif /* NGHTTP2_ALPN_TEST_H */