mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-08 11:08:52 +08:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c13e63a501 | ||
|
|
c6d89dd0ba | ||
|
|
d134ccd35d | ||
|
|
3a6f83394c | ||
|
|
acf36f3d1a | ||
|
|
63e6a8bab2 | ||
|
|
5361cc6bd1 | ||
|
|
cabac55394 | ||
|
|
db7483ef10 | ||
|
|
4b51ccbefe | ||
|
|
74c2f1257a | ||
|
|
1428a5e3ae | ||
|
|
fe021c1524 | ||
|
|
c57bf21306 | ||
|
|
1743b7d92d | ||
|
|
7f31278c4c | ||
|
|
8401e16a15 | ||
|
|
07fb5854f3 | ||
|
|
b56a99bfba | ||
|
|
b91e4e4df1 | ||
|
|
52a4d6ac31 | ||
|
|
796ab87b14 | ||
|
|
ed1fad3bd4 | ||
|
|
9c1876f542 | ||
|
|
7d111d9963 | ||
|
|
8c2ce0cf3f | ||
|
|
1b442cb16f | ||
|
|
2bf3680d87 | ||
|
|
0d4f0f0db5 | ||
|
|
e17ff8fd32 |
3
AUTHORS
3
AUTHORS
@@ -21,6 +21,7 @@ Amir Pakdel
|
||||
Anders Bakken
|
||||
Andreas Pohl
|
||||
Andy Davies
|
||||
Angus Gratton
|
||||
Ant Bryan
|
||||
Benedikt Christoph Wolters
|
||||
Benedikt Christoph Wolters
|
||||
@@ -66,11 +67,13 @@ Remo E
|
||||
Reza Tavakoli
|
||||
Ross Smith II
|
||||
Scott Mitchell
|
||||
Soham Sinha
|
||||
Stefan Eissing
|
||||
Stephen Ludin
|
||||
Sunpoet Po-Chuan Hsieh
|
||||
Svante Signell
|
||||
Syohei YOSHIDA
|
||||
Tapanito
|
||||
Tatsuhiko Kubo
|
||||
Tatsuhiro Tsujikawa
|
||||
Tom Harwood
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
# XXX using 1.8.90 instead of 1.9.0-DEV
|
||||
project(nghttp2 VERSION 1.22.90)
|
||||
project(nghttp2 VERSION 1.23.1)
|
||||
|
||||
# See versioning rule:
|
||||
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
set(LT_CURRENT 27)
|
||||
set(LT_REVISION 2)
|
||||
set(LT_REVISION 3)
|
||||
set(LT_AGE 13)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
@@ -25,7 +25,7 @@ dnl Do not change user variables!
|
||||
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([nghttp2], [1.23.0-DEV], [t-tujikawa@users.sourceforge.net])
|
||||
AC_INIT([nghttp2], [1.23.1], [t-tujikawa@users.sourceforge.net])
|
||||
AC_CONFIG_AUX_DIR([.])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
@@ -45,7 +45,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
dnl See versioning rule:
|
||||
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
AC_SUBST(LT_CURRENT, 27)
|
||||
AC_SUBST(LT_REVISION, 2)
|
||||
AC_SUBST(LT_REVISION, 3)
|
||||
AC_SUBST(LT_AGE, 13)
|
||||
|
||||
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
|
||||
|
||||
@@ -8,7 +8,7 @@ _nghttp()
|
||||
_get_comp_words_by_ref cur prev
|
||||
case $cur in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W '--no-push --verbose --no-dep --get-assets --har --header-table-size --multiply --encoder-header-table-size --padding --hexdump --max-concurrent-streams --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --trailer --weight --help --key --null-out --window-bits --expect-continue --stat --header ' -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W '--no-push --verbose --no-dep --get-assets --har --header-table-size --multiply --encoder-header-table-size --padding --hexdump --max-concurrent-streams --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --trailer --weight --help --key --null-out --window-bits --expect-continue --stat --no-verify-peer --header ' -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
_filedir
|
||||
|
||||
@@ -8,7 +8,7 @@ _nghttpx()
|
||||
_get_comp_words_by_ref cur prev
|
||||
case $cur in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W '--worker-read-rate --include --frontend-http2-dump-response-header --tls-ticket-key-file --verify-client-cacert --max-response-header-fields --backend-http2-window-size --frontend-keep-alive-timeout --backend-request-buffer --max-request-header-fields --fastopen --backend-connect-timeout --tls-max-proto-version --conf --dns-lookup-timeout --backend-http2-max-concurrent-streams --worker-write-burst --npn-list --dns-max-try --fetch-ocsp-response-file --no-via --tls-session-cache-memcached-cert-file --no-http2-cipher-black-list --mruby-file --client-no-http2-cipher-black-list --stream-read-timeout --client-ciphers --forwarded-for --accesslog-syslog --dns-cache-timeout --frontend-http2-read-timeout --listener-disable-timeout --ciphers --client-psk-secrets --strip-incoming-x-forwarded-for --no-server-rewrite --private-key-passwd-file --backend-keep-alive-timeout --backend-http-proxy-uri --frontend-max-requests --rlimit-nofile --no-strip-incoming-x-forwarded-proto --tls-ticket-key-memcached-cert-file --ocsp-update-interval --forwarded-by --tls-session-cache-memcached-private-key-file --error-page --backend-write-timeout --tls-dyn-rec-warmup-threshold --tls-ticket-key-memcached-max-retry --frontend-http2-window-size --http2-no-cookie-crumbling --worker-read-burst --dh-param-file --accesslog-format --errorlog-syslog --redirect-https-port --request-header-field-buffer --api-max-request-body --frontend-http2-decoder-dynamic-table-size --errorlog-file --frontend-http2-max-concurrent-streams --psk-secrets --frontend-write-timeout --tls-ticket-key-cipher --read-burst --no-add-x-forwarded-proto --backend --server-name --insecure --backend-max-backoff --log-level --host-rewrite --tls-ticket-key-memcached-interval --frontend-http2-setting-timeout --frontend-http2-connection-window-size --worker-frontend-connections --syslog-facility --no-server-push --no-location-rewrite --single-thread --tls-session-cache-memcached --no-ocsp --backend-response-buffer --tls-min-proto-version --workers --add-forwarded --worker-write-rate --add-request-header --backend-http2-settings-timeout --subcert --ecdh-curves --no-kqueue --help --frontend-frame-debug --tls-sct-dir --pid-file --frontend-http2-dump-request-header --daemon --write-rate --altsvc --backend-http2-decoder-dynamic-table-size --user --add-x-forwarded-for --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --backend-connections-per-host --response-header-field-buffer --tls-ticket-key-memcached-address-family --padding --tls-session-cache-memcached-address-family --stream-write-timeout --cacert --tls-ticket-key-memcached-private-key-file --accesslog-write-early --backend-address-family --backend-http2-connection-window-size --version --add-response-header --backend-read-timeout --frontend-http2-optimize-window-size --frontend --accesslog-file --http2-proxy --backend-http2-encoder-dynamic-table-size --client-private-key-file --single-process --client-cert-file --tls-ticket-key-memcached --tls-dyn-rec-idle-timeout --frontend-http2-optimize-write-buffer-size --verify-client --frontend-http2-encoder-dynamic-table-size --read-rate --backend-connections-per-frontend --strip-incoming-forwarded ' -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W '--worker-read-rate --include --frontend-http2-dump-response-header --tls-ticket-key-file --verify-client-cacert --max-response-header-fields --backend-http2-window-size --frontend-keep-alive-timeout --backend-request-buffer --max-request-header-fields --fastopen --backend-connect-timeout --tls-max-proto-version --conf --dns-lookup-timeout --backend-http2-max-concurrent-streams --worker-write-burst --npn-list --dns-max-try --fetch-ocsp-response-file --no-via --tls-session-cache-memcached-cert-file --no-http2-cipher-black-list --mruby-file --client-no-http2-cipher-black-list --stream-read-timeout --client-ciphers --ocsp-update-interval --forwarded-for --accesslog-syslog --dns-cache-timeout --frontend-http2-read-timeout --listener-disable-timeout --ciphers --client-psk-secrets --strip-incoming-x-forwarded-for --no-server-rewrite --private-key-passwd-file --backend-keep-alive-timeout --backend-http-proxy-uri --frontend-max-requests --rlimit-nofile --no-strip-incoming-x-forwarded-proto --tls-ticket-key-memcached-cert-file --no-verify-ocsp --forwarded-by --tls-session-cache-memcached-private-key-file --error-page --ocsp-startup --backend-write-timeout --tls-dyn-rec-warmup-threshold --tls-ticket-key-memcached-max-retry --frontend-http2-window-size --http2-no-cookie-crumbling --worker-read-burst --dh-param-file --accesslog-format --errorlog-syslog --redirect-https-port --request-header-field-buffer --api-max-request-body --frontend-http2-decoder-dynamic-table-size --errorlog-file --frontend-http2-max-concurrent-streams --psk-secrets --frontend-write-timeout --tls-ticket-key-cipher --read-burst --no-add-x-forwarded-proto --backend --server-name --insecure --backend-max-backoff --log-level --host-rewrite --tls-ticket-key-memcached-interval --frontend-http2-setting-timeout --frontend-http2-connection-window-size --worker-frontend-connections --syslog-facility --no-server-push --no-location-rewrite --single-thread --tls-session-cache-memcached --no-ocsp --backend-response-buffer --tls-min-proto-version --workers --add-forwarded --worker-write-rate --add-request-header --backend-http2-settings-timeout --subcert --ecdh-curves --no-kqueue --help --frontend-frame-debug --tls-sct-dir --pid-file --frontend-http2-dump-request-header --daemon --write-rate --altsvc --backend-http2-decoder-dynamic-table-size --user --add-x-forwarded-for --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --backend-connections-per-host --response-header-field-buffer --tls-ticket-key-memcached-address-family --padding --tls-session-cache-memcached-address-family --stream-write-timeout --cacert --tls-ticket-key-memcached-private-key-file --accesslog-write-early --backend-address-family --backend-http2-connection-window-size --version --add-response-header --backend-read-timeout --frontend-http2-optimize-window-size --frontend --accesslog-file --http2-proxy --backend-http2-encoder-dynamic-table-size --client-private-key-file --single-process --client-cert-file --tls-ticket-key-memcached --tls-dyn-rec-idle-timeout --frontend-http2-optimize-write-buffer-size --verify-client --frontend-http2-encoder-dynamic-table-size --read-rate --backend-connections-per-frontend --strip-incoming-forwarded ' -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
_filedir
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "H2LOAD" "1" "Apr 24, 2017" "1.22.0" "nghttp2"
|
||||
.TH "H2LOAD" "1" "May 30, 2017" "1.23.1" "nghttp2"
|
||||
.SH NAME
|
||||
h2load \- HTTP/2 benchmarking tool
|
||||
.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "NGHTTP" "1" "Apr 24, 2017" "1.22.0" "nghttp2"
|
||||
.TH "NGHTTP" "1" "May 30, 2017" "1.23.1" "nghttp2"
|
||||
.SH NAME
|
||||
nghttp \- HTTP/2 client
|
||||
.
|
||||
@@ -236,6 +236,12 @@ combined with the \fI\%\-d\fP option.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-y, \-\-no\-verify\-peer
|
||||
Suppress warning on server certificate verification
|
||||
failure.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-version
|
||||
Display version information and exit.
|
||||
.UNINDENT
|
||||
|
||||
@@ -186,6 +186,11 @@ OPTIONS
|
||||
Continue interim response. This option is ignored unless
|
||||
combined with the :option:`-d` option.
|
||||
|
||||
.. option:: -y, --no-verify-peer
|
||||
|
||||
Suppress warning on server certificate verification
|
||||
failure.
|
||||
|
||||
.. option:: --version
|
||||
|
||||
Display version information and exit.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "NGHTTPD" "1" "Apr 24, 2017" "1.22.0" "nghttp2"
|
||||
.TH "NGHTTPD" "1" "May 30, 2017" "1.23.1" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpd \- HTTP/2 server
|
||||
.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "NGHTTPX" "1" "Apr 24, 2017" "1.22.0" "nghttp2"
|
||||
.TH "NGHTTPX" "1" "May 30, 2017" "1.23.1" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpx \- HTTP/2 proxy
|
||||
.
|
||||
@@ -96,6 +96,18 @@ host pattern "*.nghttp2.org" matches against
|
||||
match against "nghttp2.org". The exact hosts match
|
||||
takes precedence over the wildcard hosts match.
|
||||
.sp
|
||||
If path part ends with "*", it is treated as wildcard
|
||||
path. The wildcard path behaves differently from the
|
||||
normal path. For normal path, match is made around the
|
||||
boundary of path component separator,"\fI/\fP". On the other
|
||||
hand, the wildcard path does not take into account the
|
||||
path component separator. All paths which include the
|
||||
wildcard path without last "*" as prefix, and are
|
||||
strictly longer than wildcard path without last "*" are
|
||||
matched. "*" must match at least one character. For
|
||||
example, the pattern "\fI/foo*\fP" matches "\fI/foo/\fP" and
|
||||
"\fI/foobar\fP". But it does not match "\fI/foo\fP", or "\fI/fo\fP".
|
||||
.sp
|
||||
If <PATTERN> is omitted or empty string, "\fI/\fP" is used as
|
||||
pattern, which matches all request paths (catch\-all
|
||||
pattern). The catch\-all backend must be given.
|
||||
@@ -611,12 +623,12 @@ password protected it\(aqll be requested interactively.
|
||||
Specify additional certificate and private key file.
|
||||
nghttpx will choose certificates based on the hostname
|
||||
indicated by client using TLS SNI extension. If nghttpx
|
||||
is built with OpenSSL >= 1.0.2, signature algorithms
|
||||
(e.g., ECDSA+SHA256, RSA+SHA256) presented by client are
|
||||
also taken into consideration. This allows nghttpx to
|
||||
send ECDSA certificate to modern clients, while sending
|
||||
RSA based certificate to older clients. This option can
|
||||
be used multiple times. To make OCSP stapling work,
|
||||
is built with OpenSSL >= 1.0.2, the shared elliptic
|
||||
curves (e.g., P\-256) between client and server are also
|
||||
taken into consideration. This allows nghttpx to send
|
||||
ECDSA certificate to modern clients, while sending RSA
|
||||
based certificate to older clients. This option can be
|
||||
used multiple times. To make OCSP stapling work,
|
||||
<CERTPATH> must be absolute path.
|
||||
.sp
|
||||
Additional parameter can be specified in <PARAM>. The
|
||||
@@ -812,6 +824,20 @@ Default: \fB4h\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-ocsp\-startup
|
||||
Start accepting connections after initial attempts to
|
||||
get OCSP responses finish. It does not matter some of
|
||||
the attempts fail. This feature is useful if OCSP
|
||||
responses must be available before accepting
|
||||
connections.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-no\-verify\-ocsp
|
||||
nghttpx does not verify OCSP response.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-no\-ocsp
|
||||
Disable OCSP stapling.
|
||||
.UNINDENT
|
||||
@@ -1730,6 +1756,22 @@ be customized using \fI\%\-\-fetch\-ocsp\-response\-file\fP option.
|
||||
.sp
|
||||
If OCSP query is failed, previous OCSP response, if any, is continued
|
||||
to be used.
|
||||
.sp
|
||||
\fI\%\-\-fetch\-ocsp\-response\-file\fP option provides wide range of
|
||||
possibility to manage OCSP response. It can take an arbitrary script
|
||||
or executable. The requirement is that it supports the command\-line
|
||||
interface of \fBfetch\-ocsp\-response\fP script, and it must return a
|
||||
valid DER encoded OCSP response on success. It must return exit code
|
||||
0 on success, and 75 for temporary error, and the other error code for
|
||||
generic failure. For large cluster of servers, it is not efficient
|
||||
for each server to perform OCSP query using \fBfetch\-ocsp\-response\fP\&.
|
||||
Instead, you can retrieve OCSP response in some way, and store it in a
|
||||
disk or a shared database. Then specify a program in
|
||||
\fI\%\-\-fetch\-ocsp\-response\-file\fP to fetch it from those stores.
|
||||
This could provide a way to share the OCSP response between fleet of
|
||||
servers, and also any OCSP query strategy can be applied which may be
|
||||
beyond the ability of nghttpx itself or \fBfetch\-ocsp\-response\fP
|
||||
script.
|
||||
.SH TLS SESSION RESUMPTION
|
||||
.sp
|
||||
nghttpx supports TLS session resumption through both session ID and
|
||||
|
||||
@@ -80,6 +80,18 @@ Connections
|
||||
match against "nghttp2.org". The exact hosts match
|
||||
takes precedence over the wildcard hosts match.
|
||||
|
||||
If path part ends with "\*", it is treated as wildcard
|
||||
path. The wildcard path behaves differently from the
|
||||
normal path. For normal path, match is made around the
|
||||
boundary of path component separator,"*/*". On the other
|
||||
hand, the wildcard path does not take into account the
|
||||
path component separator. All paths which include the
|
||||
wildcard path without last "\*" as prefix, and are
|
||||
strictly longer than wildcard path without last "\*" are
|
||||
matched. "\*" must match at least one character. For
|
||||
example, the pattern "*/foo\**" matches "*/foo/*" and
|
||||
"*/foobar*". But it does not match "*/foo*", or "*/fo*".
|
||||
|
||||
If <PATTERN> is omitted or empty string, "*/*" is used as
|
||||
pattern, which matches all request paths (catch-all
|
||||
pattern). The catch-all backend must be given.
|
||||
@@ -563,12 +575,12 @@ SSL/TLS
|
||||
Specify additional certificate and private key file.
|
||||
nghttpx will choose certificates based on the hostname
|
||||
indicated by client using TLS SNI extension. If nghttpx
|
||||
is built with OpenSSL >= 1.0.2, signature algorithms
|
||||
(e.g., ECDSA+SHA256, RSA+SHA256) presented by client are
|
||||
also taken into consideration. This allows nghttpx to
|
||||
send ECDSA certificate to modern clients, while sending
|
||||
RSA based certificate to older clients. This option can
|
||||
be used multiple times. To make OCSP stapling work,
|
||||
is built with OpenSSL >= 1.0.2, the shared elliptic
|
||||
curves (e.g., P-256) between client and server are also
|
||||
taken into consideration. This allows nghttpx to send
|
||||
ECDSA certificate to modern clients, while sending RSA
|
||||
based certificate to older clients. This option can be
|
||||
used multiple times. To make OCSP stapling work,
|
||||
<CERTPATH> must be absolute path.
|
||||
|
||||
Additional parameter can be specified in <PARAM>. The
|
||||
@@ -743,6 +755,18 @@ SSL/TLS
|
||||
|
||||
Default: ``4h``
|
||||
|
||||
.. option:: --ocsp-startup
|
||||
|
||||
Start accepting connections after initial attempts to
|
||||
get OCSP responses finish. It does not matter some of
|
||||
the attempts fail. This feature is useful if OCSP
|
||||
responses must be available before accepting
|
||||
connections.
|
||||
|
||||
.. option:: --no-verify-ocsp
|
||||
|
||||
nghttpx does not verify OCSP response.
|
||||
|
||||
.. option:: --no-ocsp
|
||||
|
||||
Disable OCSP stapling.
|
||||
@@ -1581,6 +1605,22 @@ be customized using :option:`--fetch-ocsp-response-file` option.
|
||||
If OCSP query is failed, previous OCSP response, if any, is continued
|
||||
to be used.
|
||||
|
||||
:option:`--fetch-ocsp-response-file` option provides wide range of
|
||||
possibility to manage OCSP response. It can take an arbitrary script
|
||||
or executable. The requirement is that it supports the command-line
|
||||
interface of ``fetch-ocsp-response`` script, and it must return a
|
||||
valid DER encoded OCSP response on success. It must return exit code
|
||||
0 on success, and 75 for temporary error, and the other error code for
|
||||
generic failure. For large cluster of servers, it is not efficient
|
||||
for each server to perform OCSP query using ``fetch-ocsp-response``.
|
||||
Instead, you can retrieve OCSP response in some way, and store it in a
|
||||
disk or a shared database. Then specify a program in
|
||||
:option:`--fetch-ocsp-response-file` to fetch it from those stores.
|
||||
This could provide a way to share the OCSP response between fleet of
|
||||
servers, and also any OCSP query strategy can be applied which may be
|
||||
beyond the ability of nghttpx itself or ``fetch-ocsp-response``
|
||||
script.
|
||||
|
||||
TLS SESSION RESUMPTION
|
||||
----------------------
|
||||
|
||||
|
||||
@@ -171,6 +171,22 @@ be customized using :option:`--fetch-ocsp-response-file` option.
|
||||
If OCSP query is failed, previous OCSP response, if any, is continued
|
||||
to be used.
|
||||
|
||||
:option:`--fetch-ocsp-response-file` option provides wide range of
|
||||
possibility to manage OCSP response. It can take an arbitrary script
|
||||
or executable. The requirement is that it supports the command-line
|
||||
interface of ``fetch-ocsp-response`` script, and it must return a
|
||||
valid DER encoded OCSP response on success. It must return exit code
|
||||
0 on success, and 75 for temporary error, and the other error code for
|
||||
generic failure. For large cluster of servers, it is not efficient
|
||||
for each server to perform OCSP query using ``fetch-ocsp-response``.
|
||||
Instead, you can retrieve OCSP response in some way, and store it in a
|
||||
disk or a shared database. Then specify a program in
|
||||
:option:`--fetch-ocsp-response-file` to fetch it from those stores.
|
||||
This could provide a way to share the OCSP response between fleet of
|
||||
servers, and also any OCSP query strategy can be applied which may be
|
||||
beyond the ability of nghttpx itself or ``fetch-ocsp-response``
|
||||
script.
|
||||
|
||||
TLS SESSION RESUMPTION
|
||||
----------------------
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Compiling from source
|
||||
---------------------
|
||||
|
||||
h2load is compiled alongside nghttp2 and requires that the
|
||||
``--enable-apps`` flag is passed to ``./configure`` and `required
|
||||
``--enable-app`` flag is passed to ``./configure`` and `required
|
||||
dependencies <https://github.com/nghttp2/nghttp2#requirements>`_ are
|
||||
available during compilation. For details on compiling, see `nghttp2:
|
||||
Building from Git
|
||||
|
||||
@@ -62,11 +62,11 @@ ASIOCPPFLAGS = ${AM_CPPFLAGS} ${BOOST_CPPFLAGS}
|
||||
ASIOLDADD = $(top_builddir)/lib/libnghttp2.la \
|
||||
$(top_builddir)/src/libnghttp2_asio.la @JEMALLOC_LIBS@ \
|
||||
$(top_builddir)/third-party/libhttp-parser.la \
|
||||
@OPENSSL_LIBS@ \
|
||||
${BOOST_LDFLAGS} \
|
||||
${BOOST_ASIO_LIB} \
|
||||
${BOOST_THREAD_LIB} \
|
||||
${BOOST_SYSTEM_LIB} \
|
||||
@OPENSSL_LIBS@ \
|
||||
@APPLDFLAGS@
|
||||
|
||||
asio_sv_SOURCES = asio-sv.cc
|
||||
|
||||
@@ -166,6 +166,8 @@ OPTIONS = [
|
||||
"single-process",
|
||||
"no-add-x-forwarded-proto",
|
||||
"no-strip-incoming-x-forwarded-proto",
|
||||
"ocsp-startup",
|
||||
"no-verify-ocsp",
|
||||
]
|
||||
|
||||
LOGVARS = [
|
||||
|
||||
@@ -672,6 +672,9 @@ int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
|
||||
nghttp2_buf *buf;
|
||||
nghttp2_ext_altsvc *altsvc;
|
||||
|
||||
/* This is required with --disable-assert. */
|
||||
(void)rv;
|
||||
|
||||
altsvc = frame->payload;
|
||||
|
||||
buf = &bufs->head->buf;
|
||||
|
||||
@@ -7150,6 +7150,7 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
|
||||
}
|
||||
|
||||
assert(0);
|
||||
abort(); /* if NDEBUG is set */
|
||||
}
|
||||
|
||||
uint32_t nghttp2_session_get_local_settings(nghttp2_session *session,
|
||||
@@ -7170,6 +7171,7 @@ uint32_t nghttp2_session_get_local_settings(nghttp2_session *session,
|
||||
}
|
||||
|
||||
assert(0);
|
||||
abort(); /* if NDEBUG is set */
|
||||
}
|
||||
|
||||
static int nghttp2_session_upgrade_internal(nghttp2_session *session,
|
||||
|
||||
@@ -180,6 +180,9 @@ ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
|
||||
void Http2Session::on_connect() {
|
||||
int rv;
|
||||
|
||||
// This is required with --disable-assert.
|
||||
(void)rv;
|
||||
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
@@ -50,23 +50,21 @@ namespace nghttp2 {
|
||||
#endif // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
|
||||
|
||||
template <size_t N> struct Memchunk {
|
||||
Memchunk(std::unique_ptr<Memchunk> next_chunk)
|
||||
: pos(std::begin(buf)),
|
||||
last(pos),
|
||||
knext(std::move(next_chunk)),
|
||||
next(nullptr) {}
|
||||
Memchunk(Memchunk *next_chunk)
|
||||
: pos(std::begin(buf)), last(pos), knext(next_chunk), next(nullptr) {}
|
||||
size_t len() const { return last - pos; }
|
||||
size_t left() const { return std::end(buf) - last; }
|
||||
void reset() { pos = last = std::begin(buf); }
|
||||
std::array<uint8_t, N> buf;
|
||||
uint8_t *pos, *last;
|
||||
std::unique_ptr<Memchunk> knext;
|
||||
Memchunk *knext;
|
||||
Memchunk *next;
|
||||
static const size_t size = N;
|
||||
};
|
||||
|
||||
template <typename T> struct Pool {
|
||||
Pool() : pool(nullptr), freelist(nullptr), poolsize(0) {}
|
||||
~Pool() { clear(); }
|
||||
T *get() {
|
||||
if (freelist) {
|
||||
auto m = freelist;
|
||||
@@ -76,9 +74,9 @@ template <typename T> struct Pool {
|
||||
return m;
|
||||
}
|
||||
|
||||
pool = make_unique<T>(std::move(pool));
|
||||
pool = new T{pool};
|
||||
poolsize += T::size;
|
||||
return pool.get();
|
||||
return pool;
|
||||
}
|
||||
void recycle(T *m) {
|
||||
m->next = freelist;
|
||||
@@ -86,11 +84,16 @@ template <typename T> struct Pool {
|
||||
}
|
||||
void clear() {
|
||||
freelist = nullptr;
|
||||
for (auto p = pool; p;) {
|
||||
auto knext = p->knext;
|
||||
delete p;
|
||||
p = knext;
|
||||
}
|
||||
pool = nullptr;
|
||||
poolsize = 0;
|
||||
}
|
||||
using value_type = T;
|
||||
std::unique_ptr<T> pool;
|
||||
T *pool;
|
||||
T *freelist;
|
||||
size_t poolsize;
|
||||
};
|
||||
|
||||
@@ -42,34 +42,34 @@ void test_pool_recycle(void) {
|
||||
|
||||
auto m1 = pool.get();
|
||||
|
||||
CU_ASSERT(m1 == pool.pool.get());
|
||||
CU_ASSERT(m1 == pool.pool);
|
||||
CU_ASSERT(MemchunkPool::value_type::size == pool.poolsize);
|
||||
CU_ASSERT(nullptr == pool.freelist);
|
||||
|
||||
auto m2 = pool.get();
|
||||
|
||||
CU_ASSERT(m2 == pool.pool.get());
|
||||
CU_ASSERT(m2 == pool.pool);
|
||||
CU_ASSERT(2 * MemchunkPool::value_type::size == pool.poolsize);
|
||||
CU_ASSERT(nullptr == pool.freelist);
|
||||
CU_ASSERT(m1 == m2->knext.get());
|
||||
CU_ASSERT(nullptr == m1->knext.get());
|
||||
CU_ASSERT(m1 == m2->knext);
|
||||
CU_ASSERT(nullptr == m1->knext);
|
||||
|
||||
auto m3 = pool.get();
|
||||
|
||||
CU_ASSERT(m3 == pool.pool.get());
|
||||
CU_ASSERT(m3 == pool.pool);
|
||||
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
|
||||
CU_ASSERT(nullptr == pool.freelist);
|
||||
|
||||
pool.recycle(m3);
|
||||
|
||||
CU_ASSERT(m3 == pool.pool.get());
|
||||
CU_ASSERT(m3 == pool.pool);
|
||||
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
|
||||
CU_ASSERT(m3 == pool.freelist);
|
||||
|
||||
auto m4 = pool.get();
|
||||
|
||||
CU_ASSERT(m3 == m4);
|
||||
CU_ASSERT(m4 == pool.pool.get());
|
||||
CU_ASSERT(m4 == pool.pool);
|
||||
CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize);
|
||||
CU_ASSERT(nullptr == pool.freelist);
|
||||
|
||||
|
||||
@@ -172,6 +172,8 @@ Request::~Request() { nghttp2_gzip_inflate_del(inflater); }
|
||||
|
||||
void Request::init_inflater() {
|
||||
int rv;
|
||||
// This is required with --disable-assert.
|
||||
(void)rv;
|
||||
rv = nghttp2_gzip_inflate_new(&inflater);
|
||||
assert(rv == 0);
|
||||
}
|
||||
|
||||
@@ -43,14 +43,14 @@ static size_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in,
|
||||
zst.opaque = Z_NULL;
|
||||
|
||||
rv = deflateInit(&zst, Z_DEFAULT_COMPRESSION);
|
||||
assert(rv == Z_OK);
|
||||
CU_ASSERT(rv == Z_OK);
|
||||
|
||||
zst.avail_in = (unsigned int)inlen;
|
||||
zst.next_in = (uint8_t *)in;
|
||||
zst.avail_out = (unsigned int)outlen;
|
||||
zst.next_out = out;
|
||||
rv = deflate(&zst, Z_SYNC_FLUSH);
|
||||
assert(rv == Z_OK);
|
||||
CU_ASSERT(rv == Z_OK);
|
||||
|
||||
deflateEnd(&zst);
|
||||
|
||||
|
||||
32
src/shrpx.cc
32
src/shrpx.cc
@@ -2084,12 +2084,12 @@ SSL/TLS:
|
||||
Specify additional certificate and private key file.
|
||||
nghttpx will choose certificates based on the hostname
|
||||
indicated by client using TLS SNI extension. If nghttpx
|
||||
is built with OpenSSL >= 1.0.2, signature algorithms
|
||||
(e.g., ECDSA+SHA256, RSA+SHA256) presented by client are
|
||||
also taken into consideration. This allows nghttpx to
|
||||
send ECDSA certificate to modern clients, while sending
|
||||
RSA based certificate to older clients. This option can
|
||||
be used multiple times. To make OCSP stapling work,
|
||||
is built with OpenSSL >= 1.0.2, the shared elliptic
|
||||
curves (e.g., P-256) between client and server are also
|
||||
taken into consideration. This allows nghttpx to send
|
||||
ECDSA certificate to modern clients, while sending RSA
|
||||
based certificate to older clients. This option can be
|
||||
used multiple times. To make OCSP stapling work,
|
||||
<CERTPATH> must be absolute path.
|
||||
|
||||
Additional parameter can be specified in <PARAM>. The
|
||||
@@ -2234,6 +2234,14 @@ SSL/TLS:
|
||||
Set interval to update OCSP response cache.
|
||||
Default: )"
|
||||
<< util::duration_str(config->tls.ocsp.update_interval) << R"(
|
||||
--ocsp-startup
|
||||
Start accepting connections after initial attempts to
|
||||
get OCSP responses finish. It does not matter some of
|
||||
the attempts fail. This feature is useful if OCSP
|
||||
responses must be available before accepting
|
||||
connections.
|
||||
--no-verify-ocsp
|
||||
nghttpx does not verify OCSP response.
|
||||
--no-ocsp Disable OCSP stapling.
|
||||
--tls-session-cache-memcached=<HOST>,<PORT>[;tls]
|
||||
Specify address of memcached server to store session
|
||||
@@ -3183,7 +3191,9 @@ int main(int argc, char **argv) {
|
||||
{SHRPX_OPT_BACKEND_HTTP_PROXY_URI.c_str(), required_argument, &flag,
|
||||
26},
|
||||
{SHRPX_OPT_BACKEND_NO_TLS.c_str(), no_argument, &flag, 27},
|
||||
{SHRPX_OPT_OCSP_STARTUP.c_str(), no_argument, &flag, 28},
|
||||
{SHRPX_OPT_FRONTEND_NO_TLS.c_str(), no_argument, &flag, 29},
|
||||
{SHRPX_OPT_NO_VERIFY_OCSP.c_str(), no_argument, &flag, 30},
|
||||
{SHRPX_OPT_BACKEND_TLS_SNI_FIELD.c_str(), required_argument, &flag, 31},
|
||||
{SHRPX_OPT_DH_PARAM_FILE.c_str(), required_argument, &flag, 33},
|
||||
{SHRPX_OPT_READ_RATE.c_str(), required_argument, &flag, 34},
|
||||
@@ -3533,11 +3543,21 @@ int main(int argc, char **argv) {
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_NO_TLS,
|
||||
StringRef::from_lit("yes"));
|
||||
break;
|
||||
case 28:
|
||||
// --ocsp-startup
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_OCSP_STARTUP,
|
||||
StringRef::from_lit("yes"));
|
||||
break;
|
||||
case 29:
|
||||
// --frontend-no-tls
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_NO_TLS,
|
||||
StringRef::from_lit("yes"));
|
||||
break;
|
||||
case 30:
|
||||
// --no-verify-ocsp
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_NO_VERIFY_OCSP,
|
||||
StringRef::from_lit("yes"));
|
||||
break;
|
||||
case 31:
|
||||
// --backend-tls-sni-field
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SNI_FIELD,
|
||||
|
||||
@@ -1591,6 +1591,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||
return SHRPX_OPTID_HTTP2_BRIDGE;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if (util::strieq_l("ocsp-startu", name, 11)) {
|
||||
return SHRPX_OPTID_OCSP_STARTUP;
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (util::strieq_l("client-prox", name, 11)) {
|
||||
return SHRPX_OPTID_CLIENT_PROXY;
|
||||
@@ -1646,6 +1651,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||
return SHRPX_OPTID_NO_SERVER_PUSH;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if (util::strieq_l("no-verify-ocs", name, 13)) {
|
||||
return SHRPX_OPTID_NO_VERIFY_OCSP;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (util::strieq_l("backend-no-tl", name, 13)) {
|
||||
return SHRPX_OPTID_BACKEND_NO_TLS;
|
||||
@@ -3420,6 +3430,14 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
||||
case SHRPX_OPTID_NO_STRIP_INCOMING_X_FORWARDED_PROTO:
|
||||
config->http.xfp.strip_incoming = !util::strieq_l("yes", optarg);
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_OCSP_STARTUP:
|
||||
config->tls.ocsp.startup = util::strieq_l("yes", optarg);
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_NO_VERIFY_OCSP:
|
||||
config->tls.ocsp.no_verify = util::strieq_l("yes", optarg);
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_CONF:
|
||||
LOG(WARN) << "conf: ignored";
|
||||
@@ -3613,6 +3631,7 @@ StringRef strproto(shrpx_proto proto) {
|
||||
|
||||
// gcc needs this.
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -341,6 +341,8 @@ constexpr auto SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO =
|
||||
StringRef::from_lit("no-add-x-forwarded-proto");
|
||||
constexpr auto SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO =
|
||||
StringRef::from_lit("no-strip-incoming-x-forwarded-proto");
|
||||
constexpr auto SHRPX_OPT_OCSP_STARTUP = StringRef::from_lit("ocsp-startup");
|
||||
constexpr auto SHRPX_OPT_NO_VERIFY_OCSP = StringRef::from_lit("no-verify-ocsp");
|
||||
|
||||
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||
|
||||
@@ -561,6 +563,8 @@ struct TLSConfig {
|
||||
ev_tstamp update_interval;
|
||||
StringRef fetch_ocsp_response_file;
|
||||
bool disabled;
|
||||
bool startup;
|
||||
bool no_verify;
|
||||
} ocsp;
|
||||
|
||||
// Client verification configurations
|
||||
@@ -1043,8 +1047,10 @@ enum {
|
||||
SHRPX_OPTID_NO_SERVER_PUSH,
|
||||
SHRPX_OPTID_NO_SERVER_REWRITE,
|
||||
SHRPX_OPTID_NO_STRIP_INCOMING_X_FORWARDED_PROTO,
|
||||
SHRPX_OPTID_NO_VERIFY_OCSP,
|
||||
SHRPX_OPTID_NO_VIA,
|
||||
SHRPX_OPTID_NPN_LIST,
|
||||
SHRPX_OPTID_OCSP_STARTUP,
|
||||
SHRPX_OPTID_OCSP_UPDATE_INTERVAL,
|
||||
SHRPX_OPTID_PADDING,
|
||||
SHRPX_OPTID_PID_FILE,
|
||||
|
||||
@@ -163,14 +163,14 @@ void test_shrpx_config_parse_log_format(void) {
|
||||
void test_shrpx_config_read_tls_ticket_key_file(void) {
|
||||
char file1[] = "/tmp/nghttpx-unittest.XXXXXX";
|
||||
auto fd1 = mkstemp(file1);
|
||||
assert(fd1 != -1);
|
||||
assert(48 ==
|
||||
write(fd1, "0..............12..............34..............5", 48));
|
||||
CU_ASSERT(fd1 != -1);
|
||||
CU_ASSERT(48 ==
|
||||
write(fd1, "0..............12..............34..............5", 48));
|
||||
char file2[] = "/tmp/nghttpx-unittest.XXXXXX";
|
||||
auto fd2 = mkstemp(file2);
|
||||
assert(fd2 != -1);
|
||||
assert(48 ==
|
||||
write(fd2, "6..............78..............9a..............b", 48));
|
||||
CU_ASSERT(fd2 != -1);
|
||||
CU_ASSERT(48 ==
|
||||
write(fd2, "6..............78..............9a..............b", 48));
|
||||
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
@@ -204,16 +204,18 @@ void test_shrpx_config_read_tls_ticket_key_file(void) {
|
||||
void test_shrpx_config_read_tls_ticket_key_file_aes_256(void) {
|
||||
char file1[] = "/tmp/nghttpx-unittest.XXXXXX";
|
||||
auto fd1 = mkstemp(file1);
|
||||
assert(fd1 != -1);
|
||||
assert(80 == write(fd1, "0..............12..............................34..."
|
||||
"...........................5",
|
||||
80));
|
||||
CU_ASSERT(fd1 != -1);
|
||||
CU_ASSERT(80 == write(fd1,
|
||||
"0..............12..............................34..."
|
||||
"...........................5",
|
||||
80));
|
||||
char file2[] = "/tmp/nghttpx-unittest.XXXXXX";
|
||||
auto fd2 = mkstemp(file2);
|
||||
assert(fd2 != -1);
|
||||
assert(80 == write(fd2, "6..............78..............................9a..."
|
||||
"...........................b",
|
||||
80));
|
||||
CU_ASSERT(fd2 != -1);
|
||||
CU_ASSERT(80 == write(fd2,
|
||||
"6..............78..............................9a..."
|
||||
"...........................b",
|
||||
80));
|
||||
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
|
||||
@@ -381,6 +381,8 @@ int Connection::tls_handshake() {
|
||||
break;
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
auto rv = SSL_do_handshake(tls.ssl);
|
||||
|
||||
if (rv <= 0) {
|
||||
@@ -615,6 +617,8 @@ ssize_t Connection::write_tls(const void *data, size_t len) {
|
||||
|
||||
tls.last_write_idle = -1.;
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
auto rv = SSL_write(tls.ssl, data, len);
|
||||
|
||||
if (rv <= 0) {
|
||||
@@ -667,6 +671,8 @@ ssize_t Connection::read_tls(void *data, size_t len) {
|
||||
tls.last_readlen = 0;
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
auto rv = SSL_read(tls.ssl, data, len);
|
||||
|
||||
if (rv <= 0) {
|
||||
|
||||
@@ -118,7 +118,8 @@ ConnectionHandler::ConnectionHandler(struct ev_loop *loop, std::mt19937 &gen)
|
||||
tls_ticket_key_memcached_get_retry_count_(0),
|
||||
tls_ticket_key_memcached_fail_count_(0),
|
||||
worker_round_robin_cnt_(get_config()->api.enabled ? 1 : 0),
|
||||
graceful_shutdown_(false) {
|
||||
graceful_shutdown_(false),
|
||||
enable_acceptor_on_ocsp_completion_(false) {
|
||||
ev_timer_init(&disable_acceptor_timer_, acceptor_disable_cb, 0., 0.);
|
||||
disable_acceptor_timer_.data = this;
|
||||
|
||||
@@ -504,6 +505,9 @@ bool ConnectionHandler::get_graceful_shutdown() const {
|
||||
}
|
||||
|
||||
void ConnectionHandler::cancel_ocsp_update() {
|
||||
enable_acceptor_on_ocsp_completion_ = false;
|
||||
ev_timer_stop(loop_, &ocsp_timer_);
|
||||
|
||||
if (ocsp_.proc.pid == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -616,8 +620,13 @@ void ConnectionHandler::handle_ocsp_complete() {
|
||||
<< " finished successfully";
|
||||
}
|
||||
|
||||
auto config = get_config();
|
||||
auto &tlsconf = config->tls;
|
||||
|
||||
if (tlsconf.ocsp.no_verify ||
|
||||
tls::verify_ocsp_response(ssl_ctx, ocsp_.resp.data(),
|
||||
ocsp_.resp.size()) == 0) {
|
||||
#ifndef OPENSSL_IS_BORINGSSL
|
||||
{
|
||||
#ifdef HAVE_ATOMIC_STD_SHARED_PTR
|
||||
std::atomic_store_explicit(
|
||||
&tls_ctx_data->ocsp_data,
|
||||
@@ -628,10 +637,10 @@ void ConnectionHandler::handle_ocsp_complete() {
|
||||
tls_ctx_data->ocsp_data =
|
||||
std::make_shared<std::vector<uint8_t>>(std::move(ocsp_.resp));
|
||||
#endif // !HAVE_ATOMIC_STD_SHARED_PTR
|
||||
}
|
||||
#else // OPENSSL_IS_BORINGSSL
|
||||
SSL_CTX_set_ocsp_response(ssl_ctx, ocsp_.resp.data(), ocsp_.resp.size());
|
||||
SSL_CTX_set_ocsp_response(ssl_ctx, ocsp_.resp.data(), ocsp_.resp.size());
|
||||
#endif // OPENSSL_IS_BORINGSSL
|
||||
}
|
||||
|
||||
++ocsp_.next;
|
||||
proceed_next_cert_ocsp();
|
||||
@@ -656,6 +665,12 @@ void ConnectionHandler::proceed_next_cert_ocsp() {
|
||||
// We have updated all ocsp response, and schedule next update.
|
||||
ev_timer_set(&ocsp_timer_, get_config()->tls.ocsp.update_interval, 0.);
|
||||
ev_timer_start(loop_, &ocsp_timer_);
|
||||
|
||||
if (enable_acceptor_on_ocsp_completion_) {
|
||||
enable_acceptor_on_ocsp_completion_ = false;
|
||||
enable_acceptor();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -855,4 +870,8 @@ ConnectionHandler::get_indexed_ssl_ctx(size_t idx) const {
|
||||
return indexed_ssl_ctx_[idx];
|
||||
}
|
||||
|
||||
void ConnectionHandler::set_enable_acceptor_on_ocsp_completion(bool f) {
|
||||
enable_acceptor_on_ocsp_completion_ = f;
|
||||
}
|
||||
|
||||
} // namespace shrpx
|
||||
|
||||
@@ -174,6 +174,8 @@ public:
|
||||
void
|
||||
worker_replace_downstream(std::shared_ptr<DownstreamConfig> downstreamconf);
|
||||
|
||||
void set_enable_acceptor_on_ocsp_completion(bool f);
|
||||
|
||||
private:
|
||||
// Stores all SSL_CTX objects.
|
||||
std::vector<SSL_CTX *> all_ssl_ctx_;
|
||||
@@ -220,6 +222,9 @@ private:
|
||||
size_t tls_ticket_key_memcached_fail_count_;
|
||||
unsigned int worker_round_robin_cnt_;
|
||||
bool graceful_shutdown_;
|
||||
// true if acceptors should be enabled after the initial ocsp update
|
||||
// has finished.
|
||||
bool enable_acceptor_on_ocsp_completion_;
|
||||
};
|
||||
|
||||
} // namespace shrpx
|
||||
|
||||
@@ -204,6 +204,7 @@ int DNSResolver::handle_event(int rfd, int wfd) {
|
||||
default:
|
||||
// Unreachable
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -250,6 +250,7 @@ int DNSTracker::resolve(Address *result, DNSQuery *dnsq) {
|
||||
return DNS_STATUS_OK;
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +158,8 @@ Downstream *DownstreamQueue::remove_and_get_blocked(Downstream *downstream,
|
||||
|
||||
auto next_downstream = link->downstream;
|
||||
auto link2 = next_downstream->detach_blocked_link();
|
||||
// This is required with --disable-assert.
|
||||
(void)link2;
|
||||
assert(link2 == link);
|
||||
ent.blocked.remove(link);
|
||||
delete link;
|
||||
|
||||
@@ -334,6 +334,7 @@ int Http2Session::resolve_name() {
|
||||
return 0;
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2115,7 +2116,10 @@ int Http2Session::write_tls() {
|
||||
for (;;) {
|
||||
if (wb_.rleft() > 0) {
|
||||
auto iovcnt = wb_.riovec(&iov, 1);
|
||||
assert(iovcnt == 1);
|
||||
if (iovcnt != 1) {
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
auto nwrite = conn_.write_tls(iov.iov_base, iov.iov_len);
|
||||
|
||||
if (nwrite == 0) {
|
||||
|
||||
@@ -1307,7 +1307,10 @@ int HttpDownstreamConnection::write_tls() {
|
||||
|
||||
while (input->rleft() > 0) {
|
||||
auto iovcnt = input->riovec(&iov, 1);
|
||||
assert(iovcnt == 1);
|
||||
if (iovcnt != 1) {
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
auto nwrite = conn_.write_tls(iov.iov_base, iov.iov_len);
|
||||
|
||||
if (nwrite == 0) {
|
||||
|
||||
@@ -478,7 +478,10 @@ int LiveCheck::write_tls() {
|
||||
for (;;) {
|
||||
if (wb_.rleft() > 0) {
|
||||
auto iovcnt = wb_.riovec(&iov, 1);
|
||||
assert(iovcnt == 1);
|
||||
if (iovcnt != 1) {
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
auto nwrite = conn_.write_tls(iov.iov_base, iov.iov_len);
|
||||
|
||||
if (nwrite == 0) {
|
||||
@@ -544,7 +547,10 @@ int LiveCheck::write_clear() {
|
||||
for (;;) {
|
||||
if (wb_.rleft() > 0) {
|
||||
auto iovcnt = wb_.riovec(&iov, 1);
|
||||
assert(iovcnt == 1);
|
||||
if (iovcnt != 1) {
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
auto nwrite = conn_.write_clear(iov.iov_base, iov.iov_len);
|
||||
|
||||
if (nwrite == 0) {
|
||||
|
||||
148
src/shrpx_tls.cc
148
src/shrpx_tls.cc
@@ -45,6 +45,7 @@
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/ocsp.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
@@ -186,19 +187,43 @@ int servername_callback(SSL *ssl, int *al, void *arg) {
|
||||
|
||||
#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
// boringssl removed SSL_get_sigalgs.
|
||||
auto num_sigalg =
|
||||
SSL_get_sigalgs(ssl, 0, nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
auto num_shared_curves = SSL_get_shared_curve(ssl, -1);
|
||||
|
||||
for (auto i = 0; i < num_shared_curves; ++i) {
|
||||
auto shared_curve = SSL_get_shared_curve(ssl, i);
|
||||
|
||||
for (auto i = 0; i < num_sigalg; ++i) {
|
||||
int sigalg;
|
||||
SSL_get_sigalgs(ssl, i, nullptr, nullptr, &sigalg, nullptr, nullptr);
|
||||
for (auto ssl_ctx : ssl_ctx_list) {
|
||||
auto cert = SSL_CTX_get0_certificate(ssl_ctx);
|
||||
// X509_get_signature_nid is available since OpenSSL 1.0.2.
|
||||
auto cert_sigalg = X509_get_signature_nid(cert);
|
||||
|
||||
if (sigalg == cert_sigalg) {
|
||||
#if OPENSSL_1_1_API
|
||||
auto pubkey = X509_get0_pubkey(cert);
|
||||
#else // !OPENSSL_1_1_API
|
||||
auto pubkey = X509_get_pubkey(cert);
|
||||
#endif // !OPENSSL_1_1_API
|
||||
|
||||
if (EVP_PKEY_base_id(pubkey) != EVP_PKEY_EC) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if OPENSSL_1_1_API
|
||||
auto eckey = EVP_PKEY_get0_EC_KEY(pubkey);
|
||||
#else // !OPENSSL_1_1_API
|
||||
auto eckey = EVP_PKEY_get1_EC_KEY(pubkey);
|
||||
#endif // !OPENSSL_1_1_API
|
||||
|
||||
if (eckey == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto ecgroup = EC_KEY_get0_group(eckey);
|
||||
auto cert_curve = EC_GROUP_get_curve_name(ecgroup);
|
||||
|
||||
#if !OPENSSL_1_1_API
|
||||
EC_KEY_free(eckey);
|
||||
EVP_PKEY_free(pubkey);
|
||||
#endif // !OPENSSL_1_1_API
|
||||
|
||||
if (shared_curve == cert_curve) {
|
||||
SSL_set_SSL_CTX(ssl, ssl_ctx);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
@@ -1511,8 +1536,6 @@ int cert_lookup_tree_add_ssl_ctx(
|
||||
#endif // defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER <
|
||||
// 0x10002000L
|
||||
|
||||
auto idx = indexed_ssl_ctx.size();
|
||||
|
||||
auto altnames = static_cast<GENERAL_NAMES *>(
|
||||
X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr));
|
||||
if (altnames) {
|
||||
@@ -1555,15 +1578,16 @@ int cert_lookup_tree_add_ssl_ctx(
|
||||
auto end_buf = std::copy_n(name, len, std::begin(buf));
|
||||
util::inp_strlower(std::begin(buf), end_buf);
|
||||
|
||||
auto nidx = lt->add_cert(StringRef{std::begin(buf), end_buf}, idx);
|
||||
if (nidx == -1) {
|
||||
auto idx = lt->add_cert(StringRef{std::begin(buf), end_buf},
|
||||
indexed_ssl_ctx.size());
|
||||
if (idx == -1) {
|
||||
continue;
|
||||
}
|
||||
idx = nidx;
|
||||
if (idx < indexed_ssl_ctx.size()) {
|
||||
|
||||
if (static_cast<size_t>(idx) < indexed_ssl_ctx.size()) {
|
||||
indexed_ssl_ctx[idx].push_back(ssl_ctx);
|
||||
} else {
|
||||
assert(idx == indexed_ssl_ctx.size());
|
||||
assert(static_cast<size_t>(idx) == indexed_ssl_ctx.size());
|
||||
indexed_ssl_ctx.emplace_back(std::vector<SSL_CTX *>{ssl_ctx});
|
||||
}
|
||||
}
|
||||
@@ -1595,15 +1619,16 @@ int cert_lookup_tree_add_ssl_ctx(
|
||||
|
||||
util::inp_strlower(std::begin(buf), end_buf);
|
||||
|
||||
auto nidx = lt->add_cert(StringRef{std::begin(buf), end_buf}, idx);
|
||||
if (nidx == -1) {
|
||||
auto idx =
|
||||
lt->add_cert(StringRef{std::begin(buf), end_buf}, indexed_ssl_ctx.size());
|
||||
if (idx == -1) {
|
||||
return 0;
|
||||
}
|
||||
idx = nidx;
|
||||
if (idx < indexed_ssl_ctx.size()) {
|
||||
|
||||
if (static_cast<size_t>(idx) < indexed_ssl_ctx.size()) {
|
||||
indexed_ssl_ctx[idx].push_back(ssl_ctx);
|
||||
} else {
|
||||
assert(idx == indexed_ssl_ctx.size());
|
||||
assert(static_cast<size_t>(idx) == indexed_ssl_ctx.size());
|
||||
indexed_ssl_ctx.emplace_back(std::vector<SSL_CTX *>{ssl_ctx});
|
||||
}
|
||||
|
||||
@@ -1794,6 +1819,87 @@ int proto_version_from_string(const StringRef &v) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
||||
size_t ocsp_resplen) {
|
||||
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
int rv;
|
||||
|
||||
STACK_OF(X509) * chain_certs;
|
||||
SSL_CTX_get0_chain_certs(ssl_ctx, &chain_certs);
|
||||
|
||||
auto resp = d2i_OCSP_RESPONSE(nullptr, &ocsp_resp, ocsp_resplen);
|
||||
if (resp == nullptr) {
|
||||
LOG(ERROR) << "d2i_OCSP_RESPONSE failed";
|
||||
return -1;
|
||||
}
|
||||
auto resp_deleter = defer(OCSP_RESPONSE_free, resp);
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
auto bs = OCSP_response_get1_basic(resp);
|
||||
if (bs == nullptr) {
|
||||
LOG(ERROR) << "OCSP_response_get1_basic failed: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
return -1;
|
||||
}
|
||||
auto bs_deleter = defer(OCSP_BASICRESP_free, bs);
|
||||
|
||||
auto store = X509_STORE_new();
|
||||
auto store_deleter = defer(X509_STORE_free, store);
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
rv = OCSP_basic_verify(bs, chain_certs, store, OCSP_TRUSTOTHER);
|
||||
|
||||
if (rv != 1) {
|
||||
LOG(ERROR) << "OCSP_basic_verify failed: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto sresp = OCSP_resp_get0(bs, 0);
|
||||
if (sresp == nullptr) {
|
||||
LOG(ERROR) << "OCSP response verification failed: no single response";
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if OPENSSL_1_1_API
|
||||
auto certid = OCSP_SINGLERESP_get0_id(sresp);
|
||||
#else // !OPENSSL_1_1_API
|
||||
auto certid = sresp->certId;
|
||||
#endif // !OPENSSL_1_1_API
|
||||
assert(certid != nullptr);
|
||||
|
||||
ASN1_INTEGER *serial;
|
||||
rv = OCSP_id_get0_info(nullptr, nullptr, nullptr, &serial,
|
||||
const_cast<OCSP_CERTID *>(certid));
|
||||
if (rv != 1) {
|
||||
LOG(ERROR) << "OCSP_id_get0_info failed";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (serial == nullptr) {
|
||||
LOG(ERROR) << "OCSP response does not contain serial number";
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto cert = SSL_CTX_get0_certificate(ssl_ctx);
|
||||
auto cert_serial = X509_get_serialNumber(cert);
|
||||
|
||||
if (ASN1_INTEGER_cmp(cert_serial, serial)) {
|
||||
LOG(ERROR) << "OCSP verification serial numbers do not match";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "OCSP verification succeeded";
|
||||
}
|
||||
#endif // !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >=
|
||||
// 0x10002000L
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace tls
|
||||
|
||||
} // namespace shrpx
|
||||
|
||||
@@ -264,6 +264,11 @@ X509 *load_certificate(const char *filename);
|
||||
// TLS version string.
|
||||
int proto_version_from_string(const StringRef &v);
|
||||
|
||||
// Verifies OCSP response |ocsp_resp| of length |ocsp_resplen|. This
|
||||
// function returns 0 if it succeeds, or -1.
|
||||
int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
||||
size_t ocsp_resplen);
|
||||
|
||||
} // namespace tls
|
||||
|
||||
} // namespace shrpx
|
||||
|
||||
@@ -154,9 +154,9 @@ void test_shrpx_tls_cert_lookup_tree_add_ssl_ctx(void) {
|
||||
|
||||
CU_ASSERT(-1 == tree.lookup(StringRef::from_lit("not-used.nghttp2.org")));
|
||||
CU_ASSERT(0 == tree.lookup(StringRef::from_lit("test.nghttp2.org")));
|
||||
CU_ASSERT(0 == tree.lookup(StringRef::from_lit("w.test.nghttp2.org")));
|
||||
CU_ASSERT(0 == tree.lookup(StringRef::from_lit("www.test.nghttp2.org")));
|
||||
CU_ASSERT(1 == tree.lookup(StringRef::from_lit("test.example.com")));
|
||||
CU_ASSERT(1 == tree.lookup(StringRef::from_lit("w.test.nghttp2.org")));
|
||||
CU_ASSERT(2 == tree.lookup(StringRef::from_lit("www.test.nghttp2.org")));
|
||||
CU_ASSERT(3 == tree.lookup(StringRef::from_lit("test.example.com")));
|
||||
}
|
||||
|
||||
template <size_t N, size_t M>
|
||||
|
||||
@@ -547,6 +547,11 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
||||
ev_io_start(loop, &ipcev);
|
||||
|
||||
if (tls::upstream_tls_enabled(config->conn) && !config->tls.ocsp.disabled) {
|
||||
if (config->tls.ocsp.startup) {
|
||||
conn_handler.set_enable_acceptor_on_ocsp_completion(true);
|
||||
conn_handler.disable_acceptor();
|
||||
}
|
||||
|
||||
conn_handler.proceed_next_cert_ocsp();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user