Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
nghttp2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
nghttp2
Commits
c2de0057
Commit
c2de0057
authored
Aug 15, 2021
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nghttpx: Create QUIC SSL_CTX
We choose an easier route to duplicate SSL_CTX for QUIC.
parent
81089e7e
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
528 additions
and
1 deletion
+528
-1
src/shrpx_connection_handler.cc
src/shrpx_connection_handler.cc
+65
-0
src/shrpx_connection_handler.h
src/shrpx_connection_handler.h
+4
-0
src/shrpx_http3_upstream.cc
src/shrpx_http3_upstream.cc
+19
-1
src/shrpx_http3_upstream.h
src/shrpx_http3_upstream.h
+14
-0
src/shrpx_tls.cc
src/shrpx_tls.cc
+406
-0
src/shrpx_tls.h
src/shrpx_tls.h
+20
-0
No files found.
src/shrpx_connection_handler.cc
View file @
c2de0057
...
...
@@ -156,6 +156,17 @@ ConnectionHandler::~ConnectionHandler() {
ev_timer_stop
(
loop_
,
&
ocsp_timer_
);
ev_timer_stop
(
loop_
,
&
disable_acceptor_timer_
);
for
(
auto
ssl_ctx
:
quic_all_ssl_ctx_
)
{
if
(
ssl_ctx
==
nullptr
)
{
continue
;
}
auto
tls_ctx_data
=
static_cast
<
tls
::
TLSContextData
*>
(
SSL_CTX_get_app_data
(
ssl_ctx
));
delete
tls_ctx_data
;
SSL_CTX_free
(
ssl_ctx
);
}
for
(
auto
ssl_ctx
:
all_ssl_ctx_
)
{
auto
tls_ctx_data
=
static_cast
<
tls
::
TLSContextData
*>
(
SSL_CTX_get_app_data
(
ssl_ctx
));
...
...
@@ -209,6 +220,16 @@ int ConnectionHandler::create_single_worker() {
nb_
#endif // HAVE_NEVERBLEED
);
quic_cert_tree_
=
tls
::
create_cert_lookup_tree
();
tls
::
setup_quic_server_ssl_context
(
quic_all_ssl_ctx_
,
quic_indexed_ssl_ctx_
,
quic_cert_tree_
.
get
()
#ifdef HAVE_NEVERBLEED
,
nb_
#endif // HAVE_NEVERBLEED
);
auto
cl_ssl_ctx
=
tls
::
setup_downstream_client_ssl_context
(
#ifdef HAVE_NEVERBLEED
nb_
...
...
@@ -217,6 +238,7 @@ int ConnectionHandler::create_single_worker() {
if
(
cl_ssl_ctx
)
{
all_ssl_ctx_
.
push_back
(
cl_ssl_ctx
);
quic_all_ssl_ctx_
.
push_back
(
nullptr
);
}
auto
config
=
get_config
();
...
...
@@ -233,6 +255,7 @@ int ConnectionHandler::create_single_worker() {
tlsconf
.
cacert
,
memcachedconf
.
cert_file
,
memcachedconf
.
private_key_file
,
nullptr
);
all_ssl_ctx_
.
push_back
(
session_cache_ssl_ctx
);
quic_all_ssl_ctx_
.
push_back
(
nullptr
);
}
}
...
...
@@ -263,6 +286,16 @@ int ConnectionHandler::create_worker_thread(size_t num) {
nb_
# endif // HAVE_NEVERBLEED
);
quic_cert_tree_
=
tls
::
create_cert_lookup_tree
();
tls
::
setup_quic_server_ssl_context
(
quic_all_ssl_ctx_
,
quic_indexed_ssl_ctx_
,
quic_cert_tree_
.
get
()
# ifdef HAVE_NEVERBLEED
,
nb_
# endif // HAVE_NEVERBLEED
);
auto
cl_ssl_ctx
=
tls
::
setup_downstream_client_ssl_context
(
# ifdef HAVE_NEVERBLEED
nb_
...
...
@@ -271,6 +304,7 @@ int ConnectionHandler::create_worker_thread(size_t num) {
if
(
cl_ssl_ctx
)
{
all_ssl_ctx_
.
push_back
(
cl_ssl_ctx
);
quic_all_ssl_ctx_
.
push_back
(
nullptr
);
}
auto
config
=
get_config
();
...
...
@@ -294,6 +328,7 @@ int ConnectionHandler::create_worker_thread(size_t num) {
tlsconf
.
cacert
,
memcachedconf
.
cert_file
,
memcachedconf
.
private_key_file
,
nullptr
);
all_ssl_ctx_
.
push_back
(
session_cache_ssl_ctx
);
quic_all_ssl_ctx_
.
push_back
(
nullptr
);
}
}
...
...
@@ -608,6 +643,7 @@ void ConnectionHandler::handle_ocsp_complete() {
ev_child_stop
(
loop_
,
&
ocsp_
.
chldev
);
assert
(
ocsp_
.
next
<
all_ssl_ctx_
.
size
());
assert
(
all_ssl_ctx_
.
size
()
==
quic_all_ssl_ctx_
.
size
());
auto
ssl_ctx
=
all_ssl_ctx_
[
ocsp_
.
next
];
auto
tls_ctx_data
=
...
...
@@ -635,6 +671,29 @@ void ConnectionHandler::handle_ocsp_complete() {
if
(
tlsconf
.
ocsp
.
no_verify
||
tls
::
verify_ocsp_response
(
ssl_ctx
,
ocsp_
.
resp
.
data
(),
ocsp_
.
resp
.
size
())
==
0
)
{
// We have list of SSL_CTX with the same certificate in
// quic_all_ssl_ctx_ as well. Some SSL_CTXs are missing there in
// that case we get nullptr.
auto
quic_ssl_ctx
=
quic_all_ssl_ctx_
[
ocsp_
.
next
];
if
(
quic_ssl_ctx
)
{
auto
quic_tls_ctx_data
=
static_cast
<
tls
::
TLSContextData
*>
(
SSL_CTX_get_app_data
(
quic_ssl_ctx
));
#ifndef OPENSSL_IS_BORINGSSL
# ifdef HAVE_ATOMIC_STD_SHARED_PTR
std
::
atomic_store_explicit
(
&
quic_tls_ctx_data
->
ocsp_data
,
std
::
make_shared
<
std
::
vector
<
uint8_t
>>
(
ocsp_
.
resp
),
std
::
memory_order_release
);
# else // !HAVE_ATOMIC_STD_SHARED_PTR
std
::
lock_guard
<
std
::
mutex
>
g
(
quic_tls_ctx_data
->
mu
);
quic_tls_ctx_data
->
ocsp_data
=
std
::
make_shared
<
std
::
vector
<
uint8_t
>>
(
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
());
#endif // OPENSSL_IS_BORINGSSL
}
#ifndef OPENSSL_IS_BORINGSSL
# ifdef HAVE_ATOMIC_STD_SHARED_PTR
std
::
atomic_store_explicit
(
...
...
@@ -815,6 +874,7 @@ SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
nullptr
);
all_ssl_ctx_
.
push_back
(
ssl_ctx
);
quic_all_ssl_ctx_
.
push_back
(
nullptr
);
return
ssl_ctx
;
}
...
...
@@ -877,6 +937,11 @@ ConnectionHandler::get_indexed_ssl_ctx(size_t idx) const {
return
indexed_ssl_ctx_
[
idx
];
}
const
std
::
vector
<
SSL_CTX
*>
&
ConnectionHandler
::
get_quic_indexed_ssl_ctx
(
size_t
idx
)
const
{
return
quic_indexed_ssl_ctx_
[
idx
];
}
void
ConnectionHandler
::
set_enable_acceptor_on_ocsp_completion
(
bool
f
)
{
enable_acceptor_on_ocsp_completion_
=
f
;
}
...
...
src/shrpx_connection_handler.h
View file @
c2de0057
...
...
@@ -159,6 +159,7 @@ public:
SSL_CTX
*
get_ssl_ctx
(
size_t
idx
)
const
;
const
std
::
vector
<
SSL_CTX
*>
&
get_indexed_ssl_ctx
(
size_t
idx
)
const
;
const
std
::
vector
<
SSL_CTX
*>
&
get_quic_indexed_ssl_ctx
(
size_t
idx
)
const
;
#ifdef HAVE_NEVERBLEED
void
set_neverbleed
(
neverbleed_t
*
nb
);
...
...
@@ -187,6 +188,8 @@ private:
// selection among them are performed by hostname presented by SNI,
// and signature algorithm presented by client.
std
::
vector
<
std
::
vector
<
SSL_CTX
*>>
indexed_ssl_ctx_
;
std
::
vector
<
SSL_CTX
*>
quic_all_ssl_ctx_
;
std
::
vector
<
std
::
vector
<
SSL_CTX
*>>
quic_indexed_ssl_ctx_
;
OCSPUpdateContext
ocsp_
;
std
::
mt19937
&
gen_
;
// ev_loop for each worker
...
...
@@ -203,6 +206,7 @@ private:
// Otherwise, nullptr and workers_ has instances of Worker instead.
std
::
unique_ptr
<
Worker
>
single_worker_
;
std
::
unique_ptr
<
tls
::
CertLookupTree
>
cert_tree_
;
std
::
unique_ptr
<
tls
::
CertLookupTree
>
quic_cert_tree_
;
std
::
unique_ptr
<
MemcachedDispatcher
>
tls_ticket_key_memcached_dispatcher_
;
// Current TLS session ticket keys. Note that TLS connection does
// not refer to this field directly. They use TicketKeys object in
...
...
src/shrpx_http3_upstream.cc
View file @
c2de0057
...
...
@@ -30,7 +30,8 @@
namespace
shrpx
{
Http3Upstream
::
Http3Upstream
(
ClientHandler
*
handler
)
:
handler_
{
handler
}
{}
Http3Upstream
::
Http3Upstream
(
ClientHandler
*
handler
)
:
handler_
{
handler
},
tls_alert_
{
0
}
{}
Http3Upstream
::~
Http3Upstream
()
{}
...
...
@@ -129,4 +130,21 @@ int Http3Upstream::on_read(const UpstreamAddr *faddr,
return
0
;
}
int
Http3Upstream
::
on_rx_secret
(
ngtcp2_crypto_level
level
,
const
uint8_t
*
secret
,
size_t
secretlen
)
{
return
0
;
}
int
Http3Upstream
::
on_tx_secret
(
ngtcp2_crypto_level
level
,
const
uint8_t
*
secret
,
size_t
secretlen
)
{
return
0
;
}
int
Http3Upstream
::
add_crypto_data
(
ngtcp2_crypto_level
level
,
const
uint8_t
*
data
,
size_t
datalen
)
{
return
0
;
}
void
Http3Upstream
::
set_tls_alert
(
uint8_t
alert
)
{
tls_alert_
=
alert
;
}
}
// namespace shrpx
src/shrpx_http3_upstream.h
View file @
c2de0057
...
...
@@ -26,6 +26,9 @@
#define SHRPX_HTTP3_UPSTREAM_H
#include "shrpx.h"
#include <ngtcp2/ngtcp2.h>
#include "shrpx_upstream.h"
#include "network.h"
...
...
@@ -84,8 +87,19 @@ public:
int
on_read
(
const
UpstreamAddr
*
faddr
,
const
Address
&
remote_addr
,
const
Address
&
local_addr
,
const
uint8_t
*
data
,
size_t
datalen
);
int
on_rx_secret
(
ngtcp2_crypto_level
level
,
const
uint8_t
*
secret
,
size_t
secretlen
);
int
on_tx_secret
(
ngtcp2_crypto_level
level
,
const
uint8_t
*
secret
,
size_t
secretlen
);
int
add_crypto_data
(
ngtcp2_crypto_level
level
,
const
uint8_t
*
data
,
size_t
datalen
);
void
set_tls_alert
(
uint8_t
alert
);
private:
ClientHandler
*
handler_
;
uint8_t
tls_alert_
;
};
}
// namespace shrpx
...
...
src/shrpx_tls.cc
View file @
c2de0057
...
...
@@ -51,6 +51,10 @@
#include <nghttp2/nghttp2.h>
#include <ngtcp2/ngtcp2.h>
#include <ngtcp2/ngtcp2_crypto.h>
#include <ngtcp2/ngtcp2_crypto_openssl.h>
#include "shrpx_log.h"
#include "shrpx_client_handler.h"
#include "shrpx_config.h"
...
...
@@ -60,6 +64,7 @@
#include "shrpx_memcached_request.h"
#include "shrpx_memcached_dispatcher.h"
#include "shrpx_connection_handler.h"
#include "shrpx_http3_upstream.h"
#include "util.h"
#include "tls.h"
#include "template.h"
...
...
@@ -600,6 +605,32 @@ int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
}
// namespace
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
namespace
{
int
quic_alpn_select_proto_cb
(
SSL
*
ssl
,
const
unsigned
char
**
out
,
unsigned
char
*
outlen
,
const
unsigned
char
*
in
,
unsigned
int
inlen
,
void
*
arg
)
{
for
(
auto
p
=
in
,
end
=
in
+
inlen
;
p
<
end
;)
{
auto
proto_id
=
p
+
1
;
auto
proto_len
=
*
p
;
if
(
proto_id
+
proto_len
<=
end
&&
util
::
streq_l
(
"h3"
,
StringRef
{
proto_id
,
proto_len
}))
{
*
out
=
reinterpret_cast
<
const
unsigned
char
*>
(
proto_id
);
*
outlen
=
proto_len
;
return
SSL_TLSEXT_ERR_OK
;
}
p
+=
1
+
proto_len
;
}
return
SSL_TLSEXT_ERR_NOACK
;
}
}
// namespace
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L
# ifndef TLSEXT_TYPE_signed_certificate_timestamp
...
...
@@ -1042,6 +1073,322 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
return
ssl_ctx
;
}
namespace
{
int
quic_set_encryption_secrets
(
SSL
*
ssl
,
OSSL_ENCRYPTION_LEVEL
ossl_level
,
const
uint8_t
*
rx_secret
,
const
uint8_t
*
tx_secret
,
size_t
secretlen
)
{
auto
conn
=
static_cast
<
Connection
*>
(
SSL_get_app_data
(
ssl
));
auto
handler
=
static_cast
<
ClientHandler
*>
(
conn
->
data
);
auto
upstream
=
static_cast
<
Http3Upstream
*>
(
handler
->
get_upstream
());
auto
level
=
ngtcp2_crypto_openssl_from_ossl_encryption_level
(
ossl_level
);
if
(
upstream
->
on_rx_secret
(
level
,
rx_secret
,
secretlen
)
!=
0
)
{
return
0
;
}
if
(
tx_secret
&&
upstream
->
on_tx_secret
(
level
,
tx_secret
,
secretlen
)
!=
0
)
{
return
0
;
}
return
1
;
}
}
// namespace
namespace
{
int
quic_add_handshake_data
(
SSL
*
ssl
,
OSSL_ENCRYPTION_LEVEL
ossl_level
,
const
uint8_t
*
data
,
size_t
len
)
{
auto
conn
=
static_cast
<
Connection
*>
(
SSL_get_app_data
(
ssl
));
auto
handler
=
static_cast
<
ClientHandler
*>
(
conn
->
data
);
auto
upstream
=
static_cast
<
Http3Upstream
*>
(
handler
->
get_upstream
());
auto
level
=
ngtcp2_crypto_openssl_from_ossl_encryption_level
(
ossl_level
);
upstream
->
add_crypto_data
(
level
,
data
,
len
);
return
1
;
}
}
// namespace
namespace
{
int
quic_flush_flight
(
SSL
*
ssl
)
{
return
1
;
}
}
// namespace
namespace
{
int
quic_send_alert
(
SSL
*
ssl
,
OSSL_ENCRYPTION_LEVEL
ossl_level
,
uint8_t
alert
)
{
auto
conn
=
static_cast
<
Connection
*>
(
SSL_get_app_data
(
ssl
));
auto
handler
=
static_cast
<
ClientHandler
*>
(
conn
->
data
);
auto
upstream
=
static_cast
<
Http3Upstream
*>
(
handler
->
get_upstream
());
upstream
->
set_tls_alert
(
alert
);
return
1
;
}
}
// namespace
namespace
{
auto
quic_method
=
SSL_QUIC_METHOD
{
quic_set_encryption_secrets
,
quic_add_handshake_data
,
quic_flush_flight
,
quic_send_alert
,
};
}
// namespace
SSL_CTX
*
create_quic_ssl_context
(
const
char
*
private_key_file
,
const
char
*
cert_file
,
const
std
::
vector
<
uint8_t
>
&
sct_data
#ifdef HAVE_NEVERBLEED
,
neverbleed_t
*
nb
#endif // HAVE_NEVERBLEED
)
{
auto
ssl_ctx
=
SSL_CTX_new
(
TLS_server_method
());
if
(
!
ssl_ctx
)
{
LOG
(
FATAL
)
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
constexpr
auto
ssl_opts
=
(
SSL_OP_ALL
&
~
SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
)
|
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
|
SSL_OP_SINGLE_ECDH_USE
|
SSL_OP_SINGLE_DH_USE
|
SSL_OP_CIPHER_SERVER_PREFERENCE
#if OPENSSL_1_1_1_API
// The reason for disabling built-in anti-replay in OpenSSL is
// that it only works if client gets back to the same server.
// The freshness check described in
// https://tools.ietf.org/html/rfc8446#section-8.3 is still
// performed.
|
SSL_OP_NO_ANTI_REPLAY
#endif // OPENSSL_1_1_1_API
;
auto
config
=
mod_config
();
auto
&
tlsconf
=
config
->
tls
;
SSL_CTX_set_options
(
ssl_ctx
,
ssl_opts
);
SSL_CTX_set_min_proto_version
(
ssl_ctx
,
TLS1_3_VERSION
);
SSL_CTX_set_max_proto_version
(
ssl_ctx
,
TLS1_3_VERSION
);
const
unsigned
char
sid_ctx
[]
=
"shrpx"
;
SSL_CTX_set_session_id_context
(
ssl_ctx
,
sid_ctx
,
sizeof
(
sid_ctx
)
-
1
);
SSL_CTX_set_session_cache_mode
(
ssl_ctx
,
SSL_SESS_CACHE_SERVER
);
if
(
!
tlsconf
.
session_cache
.
memcached
.
host
.
empty
())
{
SSL_CTX_sess_set_new_cb
(
ssl_ctx
,
tls_session_new_cb
);
SSL_CTX_sess_set_get_cb
(
ssl_ctx
,
tls_session_get_cb
);
}
SSL_CTX_set_timeout
(
ssl_ctx
,
tlsconf
.
session_timeout
.
count
());
if
(
SSL_CTX_set_cipher_list
(
ssl_ctx
,
tlsconf
.
ciphers
.
c_str
())
==
0
)
{
LOG
(
FATAL
)
<<
"SSL_CTX_set_cipher_list "
<<
tlsconf
.
ciphers
<<
" failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
#if OPENSSL_1_1_1_API
if
(
SSL_CTX_set_ciphersuites
(
ssl_ctx
,
tlsconf
.
tls13_ciphers
.
c_str
())
==
0
)
{
LOG
(
FATAL
)
<<
"SSL_CTX_set_ciphersuites "
<<
tlsconf
.
tls13_ciphers
<<
" failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
#endif // OPENSSL_1_1_1_API
#ifndef OPENSSL_NO_EC
# if !LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L
if
(
SSL_CTX_set1_curves_list
(
ssl_ctx
,
tlsconf
.
ecdh_curves
.
c_str
())
!=
1
)
{
LOG
(
FATAL
)
<<
"SSL_CTX_set1_curves_list "
<<
tlsconf
.
ecdh_curves
<<
" failed"
;
DIE
();
}
# if !defined(OPENSSL_IS_BORINGSSL) && !OPENSSL_1_1_API
// It looks like we need this function call for OpenSSL 1.0.2. This
// function was deprecated in OpenSSL 1.1.0 and BoringSSL.
SSL_CTX_set_ecdh_auto
(
ssl_ctx
,
1
);
# endif // !defined(OPENSSL_IS_BORINGSSL) && !OPENSSL_1_1_API
# else // LIBRESSL_LEGACY_API || OPENSSL_VERSION_NUBMER < 0x10002000L
// Use P-256, which is sufficiently secure at the time of this
// writing.
auto
ecdh
=
EC_KEY_new_by_curve_name
(
NID_X9_62_prime256v1
);
if
(
ecdh
==
nullptr
)
{
LOG
(
FATAL
)
<<
"EC_KEY_new_by_curv_name failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
SSL_CTX_set_tmp_ecdh
(
ssl_ctx
,
ecdh
);
EC_KEY_free
(
ecdh
);
# endif // LIBRESSL_LEGACY_API || OPENSSL_VERSION_NUBMER < 0x10002000L
#endif // OPENSSL_NO_EC
if
(
!
tlsconf
.
dh_param_file
.
empty
())
{
// Read DH parameters from file
auto
bio
=
BIO_new_file
(
tlsconf
.
dh_param_file
.
c_str
(),
"r"
);
if
(
bio
==
nullptr
)
{
LOG
(
FATAL
)
<<
"BIO_new_file() failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
auto
dh
=
PEM_read_bio_DHparams
(
bio
,
nullptr
,
nullptr
,
nullptr
);
if
(
dh
==
nullptr
)
{
LOG
(
FATAL
)
<<
"PEM_read_bio_DHparams() failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
SSL_CTX_set_tmp_dh
(
ssl_ctx
,
dh
);
DH_free
(
dh
);
BIO_free
(
bio
);
}
SSL_CTX_set_mode
(
ssl_ctx
,
SSL_MODE_RELEASE_BUFFERS
);
if
(
SSL_CTX_set_default_verify_paths
(
ssl_ctx
)
!=
1
)
{
LOG
(
WARN
)
<<
"Could not load system trusted ca certificates: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
}
if
(
!
tlsconf
.
cacert
.
empty
())
{
if
(
SSL_CTX_load_verify_locations
(
ssl_ctx
,
tlsconf
.
cacert
.
c_str
(),
nullptr
)
!=
1
)
{
LOG
(
FATAL
)
<<
"Could not load trusted ca certificates from "
<<
tlsconf
.
cacert
<<
": "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
}
if
(
!
tlsconf
.
private_key_passwd
.
empty
())
{
SSL_CTX_set_default_passwd_cb
(
ssl_ctx
,
ssl_pem_passwd_cb
);
SSL_CTX_set_default_passwd_cb_userdata
(
ssl_ctx
,
config
);
}
#ifndef HAVE_NEVERBLEED
if
(
SSL_CTX_use_PrivateKey_file
(
ssl_ctx
,
private_key_file
,
SSL_FILETYPE_PEM
)
!=
1
)
{
LOG
(
FATAL
)
<<
"SSL_CTX_use_PrivateKey_file failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
}
#else // HAVE_NEVERBLEED
std
::
array
<
char
,
NEVERBLEED_ERRBUF_SIZE
>
errbuf
;
if
(
neverbleed_load_private_key_file
(
nb
,
ssl_ctx
,
private_key_file
,
errbuf
.
data
())
!=
1
)
{
LOG
(
FATAL
)
<<
"neverbleed_load_private_key_file failed: "
<<
errbuf
.
data
();
DIE
();
}
#endif // HAVE_NEVERBLEED
if
(
SSL_CTX_use_certificate_chain_file
(
ssl_ctx
,
cert_file
)
!=
1
)
{
LOG
(
FATAL
)
<<
"SSL_CTX_use_certificate_file failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
if
(
SSL_CTX_check_private_key
(
ssl_ctx
)
!=
1
)
{
LOG
(
FATAL
)
<<
"SSL_CTX_check_private_key failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
if
(
tlsconf
.
client_verify
.
enabled
)
{
if
(
!
tlsconf
.
client_verify
.
cacert
.
empty
())
{
if
(
SSL_CTX_load_verify_locations
(
ssl_ctx
,
tlsconf
.
client_verify
.
cacert
.
c_str
(),
nullptr
)
!=
1
)
{
LOG
(
FATAL
)
<<
"Could not load trusted ca certificates from "
<<
tlsconf
.
client_verify
.
cacert
<<
": "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
// It is heard that SSL_CTX_load_verify_locations() may leave
// error even though it returns success. See
// http://forum.nginx.org/read.php?29,242540
ERR_clear_error
();
auto
list
=
SSL_load_client_CA_file
(
tlsconf
.
client_verify
.
cacert
.
c_str
());
if
(
!
list
)
{
LOG
(
FATAL
)
<<
"Could not load ca certificates from "
<<
tlsconf
.
client_verify
.
cacert
<<
": "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
SSL_CTX_set_client_CA_list
(
ssl_ctx
,
list
);
}
SSL_CTX_set_verify
(
ssl_ctx
,
SSL_VERIFY_PEER
|
SSL_VERIFY_CLIENT_ONCE
|
SSL_VERIFY_FAIL_IF_NO_PEER_CERT
,
verify_callback
);
}
SSL_CTX_set_tlsext_servername_callback
(
ssl_ctx
,
servername_callback
);
SSL_CTX_set_tlsext_ticket_key_cb
(
ssl_ctx
,
ticket_key_cb
);
#ifndef OPENSSL_IS_BORINGSSL
SSL_CTX_set_tlsext_status_cb
(
ssl_ctx
,
ocsp_resp_cb
);
#endif // OPENSSL_IS_BORINGSSL
#ifdef OPENSSL_IS_BORINGSSL
SSL_CTX_set_early_data_enabled
(
ssl_ctx
,
1
);
#endif // OPENSSL_IS_BORINGSSL
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
// ALPN selection callback
SSL_CTX_set_alpn_select_cb
(
ssl_ctx
,
quic_alpn_select_proto_cb
,
nullptr
);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L && \
!defined(OPENSSL_IS_BORINGSSL)
// SSL_extension_supported(TLSEXT_TYPE_signed_certificate_timestamp)
// returns 1, which means OpenSSL internally handles it. But
// OpenSSL handles signed_certificate_timestamp extension specially,
// and it lets custom handler to process the extension.
if
(
!
sct_data
.
empty
())
{
# if OPENSSL_1_1_1_API
// It is not entirely clear to me that SSL_EXT_CLIENT_HELLO is
// required here. sct_parse_cb is called without
// SSL_EXT_CLIENT_HELLO being set. But the passed context value
// is SSL_EXT_CLIENT_HELLO.
if
(
SSL_CTX_add_custom_ext
(
ssl_ctx
,
TLSEXT_TYPE_signed_certificate_timestamp
,
SSL_EXT_CLIENT_HELLO
|
SSL_EXT_TLS1_2_SERVER_HELLO
|
SSL_EXT_TLS1_3_CERTIFICATE
|
SSL_EXT_IGNORE_ON_RESUMPTION
,
sct_add_cb
,
sct_free_cb
,
nullptr
,
sct_parse_cb
,
nullptr
)
!=
1
)
{
LOG
(
FATAL
)
<<
"SSL_CTX_add_custom_ext failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
# else // !OPENSSL_1_1_1_API
if
(
SSL_CTX_add_server_custom_ext
(
ssl_ctx
,
TLSEXT_TYPE_signed_certificate_timestamp
,
legacy_sct_add_cb
,
legacy_sct_free_cb
,
nullptr
,
legacy_sct_parse_cb
,
nullptr
)
!=
1
)
{
LOG
(
FATAL
)
<<
"SSL_CTX_add_server_custom_ext failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
# endif // !OPENSSL_1_1_1_API
}
#endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L &&
// !defined(OPENSSL_IS_BORINGSSL)
#if OPENSSL_1_1_1_API
if
(
SSL_CTX_set_max_early_data
(
ssl_ctx
,
std
::
numeric_limits
<
uint32_t
>::
max
())
!=
1
)
{
LOG
(
FATAL
)
<<
"SSL_CTX_set_max_early_data failed: "
<<
ERR_error_string
(
ERR_get_error
(),
nullptr
);
DIE
();
}
#endif // OPENSSL_1_1_1_API
#ifndef OPENSSL_NO_PSK
SSL_CTX_set_psk_server_callback
(
ssl_ctx
,
psk_server_cb
);
#endif // !LIBRESSL_NO_PSK
SSL_CTX_set_quic_method
(
ssl_ctx
,
&
quic_method
);
auto
tls_ctx_data
=
new
TLSContextData
();
tls_ctx_data
->
cert_file
=
cert_file
;
tls_ctx_data
->
sct_data
=
sct_data
;
SSL_CTX_set_app_data
(
ssl_ctx
,
tls_ctx_data
);
return
ssl_ctx
;
}
namespace
{
int
select_h2_next_proto_cb
(
SSL
*
ssl
,
unsigned
char
**
out
,
unsigned
char
*
outlen
,
const
unsigned
char
*
in
,
...
...
@@ -1747,6 +2094,10 @@ bool in_proto_list(const std::vector<StringRef> &protos,
}
bool
upstream_tls_enabled
(
const
ConnectionConfig
&
connconf
)
{
if
(
connconf
.
quic_listener
.
addrs
.
size
())
{
return
true
;
}
const
auto
&
faddrs
=
connconf
.
listener
.
addrs
;
return
std
::
any_of
(
std
::
begin
(
faddrs
),
std
::
end
(
faddrs
),
[](
const
UpstreamAddr
&
faddr
)
{
return
faddr
.
tls
;
});
...
...
@@ -1826,6 +2177,61 @@ setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
return
ssl_ctx
;
}
SSL_CTX
*
setup_quic_server_ssl_context
(
std
::
vector
<
SSL_CTX
*>
&
all_ssl_ctx
,
std
::
vector
<
std
::
vector
<
SSL_CTX
*>>
&
indexed_ssl_ctx
,
CertLookupTree
*
cert_tree
#ifdef HAVE_NEVERBLEED
,
neverbleed_t
*
nb
#endif // HAVE_NEVERBLEED
)
{
auto
config
=
get_config
();
if
(
!
upstream_tls_enabled
(
config
->
conn
))
{
return
nullptr
;
}
auto
&
tlsconf
=
config
->
tls
;
auto
ssl_ctx
=
create_quic_ssl_context
(
tlsconf
.
private_key_file
.
c_str
(),
tlsconf
.
cert_file
.
c_str
(),
tlsconf
.
sct_data
#ifdef HAVE_NEVERBLEED
,
nb
#endif // HAVE_NEVERBLEED
);
all_ssl_ctx
.
push_back
(
ssl_ctx
);
assert
(
cert_tree
);
if
(
cert_lookup_tree_add_ssl_ctx
(
cert_tree
,
indexed_ssl_ctx
,
ssl_ctx
)
==
-
1
)
{
LOG
(
FATAL
)
<<
"Failed to add default certificate."
;
DIE
();
}
for
(
auto
&
c
:
tlsconf
.
subcerts
)
{
auto
ssl_ctx
=
create_quic_ssl_context
(
c
.
private_key_file
.
c_str
(),
c
.
cert_file
.
c_str
(),
c
.
sct_data
#ifdef HAVE_NEVERBLEED
,
nb
#endif // HAVE_NEVERBLEED
);
all_ssl_ctx
.
push_back
(
ssl_ctx
);
if
(
cert_lookup_tree_add_ssl_ctx
(
cert_tree
,
indexed_ssl_ctx
,
ssl_ctx
)
==
-
1
)
{
LOG
(
FATAL
)
<<
"Failed to add sub certificate."
;
DIE
();
}
}
return
ssl_ctx
;
}
SSL_CTX
*
setup_downstream_client_ssl_context
(
#ifdef HAVE_NEVERBLEED
neverbleed_t
*
nb
...
...
src/shrpx_tls.h
View file @
c2de0057
...
...
@@ -100,6 +100,16 @@ SSL_CTX *create_ssl_client_context(
unsigned
char
*
outlen
,
const
unsigned
char
*
in
,
unsigned
int
inlen
,
void
*
arg
));
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
));
ClientHandler
*
accept_connection
(
Worker
*
worker
,
int
fd
,
sockaddr
*
addr
,
int
addrlen
,
const
UpstreamAddr
*
faddr
);
...
...
@@ -217,6 +227,16 @@ setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
#endif // HAVE_NEVERBLEED
);
SSL_CTX
*
setup_quic_server_ssl_context
(
std
::
vector
<
SSL_CTX
*>
&
all_ssl_ctx
,
std
::
vector
<
std
::
vector
<
SSL_CTX
*>>
&
indexed_ssl_ctx
,
CertLookupTree
*
cert_tree
#ifdef HAVE_NEVERBLEED
,
neverbleed_t
*
nb
#endif // HAVE_NEVERBLEED
);
// Setups client side SSL_CTX.
SSL_CTX
*
setup_downstream_client_ssl_context
(
#ifdef HAVE_NEVERBLEED
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment