mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 00:20:08 +01:00
deps: add ngtcp2 test binaries
The goal here is to add the ngtcp2 client and server samples so that we can use them in CI to test our QUIC implementation. PR-URL: https://github.com/nodejs/node/pull/59946 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
parent
2e5c8dff9c
commit
65a32bac18
11
deps/nghttp2/nghttp2.gyp
vendored
11
deps/nghttp2/nghttp2.gyp
vendored
|
|
@ -67,6 +67,17 @@
|
|||
'sources': [
|
||||
'<@(nghttp2_sources)',
|
||||
]
|
||||
},
|
||||
{
|
||||
'target_name': 'sfparse',
|
||||
'type': 'static_library',
|
||||
'include_dirs': ['lib'],
|
||||
'sources': [
|
||||
'lib/sfparse.c',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [ 'lib/includes' ]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
177
deps/ngtcp2/ngtcp2.gyp
vendored
177
deps/ngtcp2/ngtcp2.gyp
vendored
|
|
@ -87,6 +87,36 @@
|
|||
'nghttp3/lib/nghttp3_unreachable.c',
|
||||
'nghttp3/lib/nghttp3_vec.c',
|
||||
'nghttp3/lib/nghttp3_version.c',
|
||||
],
|
||||
'ngtcp2_test_server_sources': [
|
||||
'ngtcp2/examples/tls_server_session_ossl.cc',
|
||||
'ngtcp2/examples/tls_server_context_ossl.cc',
|
||||
'ngtcp2/examples/tls_session_base_ossl.cc',
|
||||
'ngtcp2/examples/util_openssl.cc',
|
||||
'ngtcp2/examples/http.cc',
|
||||
'ngtcp2/examples/server_base.cc',
|
||||
'ngtcp2/examples/shared.cc',
|
||||
'ngtcp2/examples/server.cc',
|
||||
'ngtcp2/examples/util.cc',
|
||||
'ngtcp2/examples/debug.cc',
|
||||
'ngtcp2/examples/siphash.cc',
|
||||
'ngtcp2/third-party/urlparse/urlparse.c',
|
||||
'ngtcp2/third-party/libev/ev.c',
|
||||
],
|
||||
'ngtcp2_test_client_sources': [
|
||||
'ngtcp2/examples/tls_client_session_ossl.cc',
|
||||
'ngtcp2/examples/tls_client_context_ossl.cc',
|
||||
'ngtcp2/examples/tls_session_base_ossl.cc',
|
||||
'ngtcp2/examples/util_openssl.cc',
|
||||
'ngtcp2/examples/http.cc',
|
||||
'ngtcp2/examples/client_base.cc',
|
||||
'ngtcp2/examples/shared.cc',
|
||||
'ngtcp2/examples/client.cc',
|
||||
'ngtcp2/examples/util.cc',
|
||||
'ngtcp2/examples/debug.cc',
|
||||
'ngtcp2/examples/siphash.cc',
|
||||
'ngtcp2/third-party/urlparse/urlparse.c',
|
||||
'ngtcp2/third-party/libev/ev.c',
|
||||
]
|
||||
},
|
||||
'targets': [
|
||||
|
|
@ -131,19 +161,6 @@
|
|||
'HAVE_NETINET_IN_H',
|
||||
],
|
||||
}],
|
||||
# TODO: Support OpenSSL 3.5 shared library builds.
|
||||
# The complexity here is that we need to use the ngtcp2 ossl
|
||||
# adapter, which does not include any conditional checks to
|
||||
# see if the version of OpenSSL used has the necessary QUIC
|
||||
# APIs, so we need to ensure that we conditionally enable use
|
||||
# of the adapter only when we know that the OpenSSL version we
|
||||
# are compiling against has the necessary APIs. We can do that
|
||||
# by checkig the OpenSSL version number but, currently, the
|
||||
# code that does so checks only the VERSION.dat file that is
|
||||
# bundled with the openssl dependency. We'll need to update
|
||||
# that to support the shared library case, where the version
|
||||
# of the shared library needs to be determined.
|
||||
#
|
||||
# TODO: Support Boringssl here also. ngtcp2 provides an adapter
|
||||
# for Boringssl. If we can detect that boringssl is being used
|
||||
# here then we can use that adapter and also set the
|
||||
|
|
@ -225,6 +242,140 @@
|
|||
'sources': [
|
||||
'<@(nghttp3_sources)'
|
||||
]
|
||||
},
|
||||
{
|
||||
'target_name': 'ngtcp2_test_server',
|
||||
'type': 'executable',
|
||||
'cflags': [ '-Wno-everything' ],
|
||||
'include_dirs': [
|
||||
'',
|
||||
'ngtcp2/examples/',
|
||||
'ngtcp2/lib/includes/',
|
||||
'ngtcp2/crypto/includes/',
|
||||
'ngtcp2/third-party/urlparse/',
|
||||
'ngtcp2/third-party/libev/',
|
||||
'../../nghttp2/lib',
|
||||
],
|
||||
'dependencies': [
|
||||
'ngtcp2',
|
||||
'nghttp3',
|
||||
'../openssl/openssl.gyp:openssl',
|
||||
'../nghttp2/nghttp2.gyp:sfparse',
|
||||
],
|
||||
'defines': [
|
||||
'HAVE_CONFIG_H',
|
||||
'WITH_EXAMPLE_OSSL',
|
||||
'EV_STANDALONE=1',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="mac"', {
|
||||
'defines': [
|
||||
'__APPLE_USE_RFC_3542',
|
||||
]
|
||||
}],
|
||||
['OS=="solaris"', {
|
||||
'defines': [
|
||||
'IPTOS_ECN_MASK=0x03',
|
||||
],
|
||||
'link_settings': {
|
||||
'libraries': [ '-lsocket', '-lnsl' ],
|
||||
},
|
||||
}],
|
||||
['OS=="win"', {
|
||||
'defines': [
|
||||
'WIN32',
|
||||
'_WINDOWS',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'CompileAs': '1'
|
||||
},
|
||||
},
|
||||
}],
|
||||
['OS!="win"', {
|
||||
'defines': [
|
||||
'HAVE_UNISTD_H',
|
||||
'HAVE_ARPA_INET_H',
|
||||
'HAVE_NETINET_IN_H',
|
||||
'HAVE_NETINET_IP_H',
|
||||
],
|
||||
}],
|
||||
[ 'OS=="linux" or OS=="openharmony"', {
|
||||
'link_settings': {
|
||||
'libraries': [ '-ldl', '-lrt' ],
|
||||
},
|
||||
}],
|
||||
],
|
||||
'sources': [
|
||||
'<@(ngtcp2_test_server_sources)'
|
||||
]
|
||||
},
|
||||
{
|
||||
'target_name': 'ngtcp2_test_client',
|
||||
'type': 'executable',
|
||||
'cflags': [ '-Wno-everything' ],
|
||||
'include_dirs': [
|
||||
'',
|
||||
'ngtcp2/examples/',
|
||||
'ngtcp2/lib/includes/',
|
||||
'ngtcp2/crypto/includes/',
|
||||
'ngtcp2/third-party/urlparse/',
|
||||
'ngtcp2/third-party/libev/',
|
||||
'../../nghttp2/lib',
|
||||
],
|
||||
'dependencies': [
|
||||
'ngtcp2',
|
||||
'nghttp3',
|
||||
'../openssl/openssl.gyp:openssl',
|
||||
'../nghttp2/nghttp2.gyp:sfparse',
|
||||
],
|
||||
'defines': [
|
||||
'HAVE_CONFIG_H',
|
||||
'WITH_EXAMPLE_OSSL',
|
||||
'EV_STANDALONE=1',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="mac"', {
|
||||
'defines': [
|
||||
'__APPLE_USE_RFC_3542',
|
||||
]
|
||||
}],
|
||||
['OS=="solaris"', {
|
||||
'defines': [
|
||||
'IPTOS_ECN_MASK=0x03',
|
||||
],
|
||||
'link_settings': {
|
||||
'libraries': [ '-lsocket', '-lnsl' ],
|
||||
},
|
||||
}],
|
||||
['OS=="win"', {
|
||||
'defines': [
|
||||
'WIN32',
|
||||
'_WINDOWS',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'CompileAs': '1'
|
||||
},
|
||||
},
|
||||
}],
|
||||
['OS!="win"', {
|
||||
'defines': [
|
||||
'HAVE_UNISTD_H',
|
||||
'HAVE_ARPA_INET_H',
|
||||
'HAVE_NETINET_IN_H',
|
||||
'HAVE_NETINET_IP_H',
|
||||
],
|
||||
}],
|
||||
[ 'OS=="linux" or OS=="openharmony"', {
|
||||
'link_settings': {
|
||||
'libraries': [ '-ldl', '-lrt' ],
|
||||
},
|
||||
}],
|
||||
],
|
||||
'sources': [
|
||||
'<@(ngtcp2_test_client_sources)'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
3379
deps/ngtcp2/ngtcp2/examples/client.cc
vendored
Normal file
3379
deps/ngtcp2/ngtcp2/examples/client.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
198
deps/ngtcp2/ngtcp2/examples/client.h
vendored
Normal file
198
deps/ngtcp2/ngtcp2/examples/client.h
vendored
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 CLIENT_H
|
||||
#define CLIENT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include <ev.h>
|
||||
|
||||
#include "client_base.h"
|
||||
#include "tls_client_context.h"
|
||||
#include "tls_client_session.h"
|
||||
#include "network.h"
|
||||
#include "shared.h"
|
||||
#include "template.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
struct Stream {
|
||||
Stream(const Request &req, int64_t stream_id);
|
||||
~Stream();
|
||||
|
||||
int open_file(const std::string_view &path);
|
||||
|
||||
Request req;
|
||||
int64_t stream_id;
|
||||
int fd;
|
||||
};
|
||||
|
||||
class Client;
|
||||
|
||||
struct Endpoint {
|
||||
Address addr;
|
||||
ev_io rev;
|
||||
Client *client;
|
||||
int fd;
|
||||
};
|
||||
|
||||
class Client : public ClientBase {
|
||||
public:
|
||||
Client(struct ev_loop *loop, uint32_t client_chosen_version,
|
||||
uint32_t original_version);
|
||||
~Client();
|
||||
|
||||
int init(int fd, const Address &local_addr, const Address &remote_addr,
|
||||
const char *addr, const char *port, TLSClientContext &tls_ctx);
|
||||
void disconnect();
|
||||
|
||||
int on_read(const Endpoint &ep);
|
||||
int on_write();
|
||||
int write_streams();
|
||||
int feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi, std::span<const uint8_t> data);
|
||||
int handle_expiry();
|
||||
void update_timer();
|
||||
int handshake_completed();
|
||||
int handshake_confirmed();
|
||||
void recv_version_negotiation(const uint32_t *sv, size_t nsv);
|
||||
|
||||
int send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr,
|
||||
unsigned int ecn, std::span<const uint8_t> data);
|
||||
std::pair<std::span<const uint8_t>, int>
|
||||
send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr,
|
||||
unsigned int ecn, std::span<const uint8_t> data, size_t gso_size);
|
||||
int send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
int on_stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||
int on_extend_max_streams();
|
||||
int handle_error();
|
||||
int make_stream_early();
|
||||
int change_local_addr();
|
||||
void start_change_local_addr_timer();
|
||||
int update_key(uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
|
||||
ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
|
||||
const uint8_t *current_rx_secret,
|
||||
const uint8_t *current_tx_secret, size_t secretlen);
|
||||
int initiate_key_update();
|
||||
void start_key_update_timer();
|
||||
void start_delay_stream_timer();
|
||||
|
||||
int select_preferred_address(Address &selected_addr,
|
||||
const ngtcp2_preferred_addr *paddr);
|
||||
|
||||
std::optional<Endpoint *> endpoint_for(const Address &remote_addr);
|
||||
|
||||
void set_remote_addr(const ngtcp2_addr &remote_addr);
|
||||
|
||||
int setup_httpconn();
|
||||
int submit_http_request(const Stream *stream);
|
||||
int recv_stream_data(uint32_t flags, int64_t stream_id,
|
||||
std::span<const uint8_t> data);
|
||||
int acked_stream_data_offset(int64_t stream_id, uint64_t datalen);
|
||||
void http_consume(int64_t stream_id, size_t nconsumed);
|
||||
void http_write_data(int64_t stream_id, std::span<const uint8_t> data);
|
||||
int on_stream_reset(int64_t stream_id);
|
||||
int on_stream_stop_sending(int64_t stream_id);
|
||||
int extend_max_stream_data(int64_t stream_id, uint64_t max_data);
|
||||
int stop_sending(int64_t stream_id, uint64_t app_error_code);
|
||||
int reset_stream(int64_t stream_id, uint64_t app_error_code);
|
||||
int http_stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||
|
||||
void on_send_blocked(const ngtcp2_path &path, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
void start_wev_endpoint(const Endpoint &ep);
|
||||
int send_blocked_packet();
|
||||
ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest,
|
||||
size_t destlen, ngtcp2_tstamp ts);
|
||||
|
||||
const std::vector<uint32_t> &get_offered_versions() const;
|
||||
|
||||
bool get_early_data() const;
|
||||
void early_data_rejected();
|
||||
|
||||
bool should_exit() const;
|
||||
|
||||
private:
|
||||
std::vector<Endpoint> endpoints_;
|
||||
Address remote_addr_;
|
||||
ev_io wev_;
|
||||
ev_timer timer_;
|
||||
ev_timer change_local_addr_timer_;
|
||||
ev_timer key_update_timer_;
|
||||
ev_timer delay_stream_timer_;
|
||||
ev_signal sigintev_;
|
||||
struct ev_loop *loop_;
|
||||
std::unordered_map<int64_t, std::unique_ptr<Stream>> streams_;
|
||||
std::vector<uint32_t> offered_versions_;
|
||||
nghttp3_conn *httpconn_;
|
||||
// addr_ is the server host address.
|
||||
const char *addr_;
|
||||
// port_ is the server port.
|
||||
const char *port_;
|
||||
// nstreams_done_ is the number of streams opened.
|
||||
size_t nstreams_done_;
|
||||
// nstreams_closed_ is the number of streams get closed.
|
||||
size_t nstreams_closed_;
|
||||
// nkey_update_ is the number of key update occurred.
|
||||
size_t nkey_update_;
|
||||
uint32_t client_chosen_version_;
|
||||
uint32_t original_version_;
|
||||
// early_data_ is true if client attempts to do 0RTT data transfer.
|
||||
bool early_data_;
|
||||
// handshake_confirmed_ gets true after handshake has been
|
||||
// confirmed.
|
||||
bool handshake_confirmed_;
|
||||
bool no_gso_;
|
||||
|
||||
struct {
|
||||
bool send_blocked;
|
||||
// blocked field is effective only when send_blocked is true.
|
||||
struct {
|
||||
const Endpoint *endpoint;
|
||||
Address remote_addr;
|
||||
unsigned int ecn;
|
||||
std::span<const uint8_t> data;
|
||||
size_t gso_size;
|
||||
} blocked;
|
||||
std::array<uint8_t, 64_k> data;
|
||||
} tx_;
|
||||
};
|
||||
|
||||
#endif // !defined(CLIENT_H)
|
||||
207
deps/ngtcp2/ngtcp2/examples/client_base.cc
vendored
Normal file
207
deps/ngtcp2/ngtcp2/examples/client_base.cc
vendored
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "client_base.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "debug.h"
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
using namespace std::literals;
|
||||
|
||||
extern Config config;
|
||||
|
||||
static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) {
|
||||
auto c = static_cast<ClientBase *>(conn_ref->user_data);
|
||||
return c->conn();
|
||||
}
|
||||
|
||||
ClientBase::ClientBase()
|
||||
: conn_ref_{get_conn, this},
|
||||
qlog_(nullptr),
|
||||
conn_(nullptr),
|
||||
ticket_received_(false) {
|
||||
ngtcp2_ccerr_default(&last_error_);
|
||||
}
|
||||
|
||||
ClientBase::~ClientBase() {
|
||||
if (conn_) {
|
||||
ngtcp2_conn_del(conn_);
|
||||
}
|
||||
|
||||
if (qlog_) {
|
||||
fclose(qlog_);
|
||||
}
|
||||
}
|
||||
|
||||
int ClientBase::write_transport_params(const char *path,
|
||||
const ngtcp2_transport_params *params) {
|
||||
auto f = std::ofstream(path);
|
||||
if (!f) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
f << "initial_max_streams_bidi=" << params->initial_max_streams_bidi << '\n'
|
||||
<< "initial_max_streams_uni=" << params->initial_max_streams_uni << '\n'
|
||||
<< "initial_max_stream_data_bidi_local="
|
||||
<< params->initial_max_stream_data_bidi_local << '\n'
|
||||
<< "initial_max_stream_data_bidi_remote="
|
||||
<< params->initial_max_stream_data_bidi_remote << '\n'
|
||||
<< "initial_max_stream_data_uni=" << params->initial_max_stream_data_uni
|
||||
<< '\n'
|
||||
<< "initial_max_data=" << params->initial_max_data << '\n'
|
||||
<< "active_connection_id_limit=" << params->active_connection_id_limit
|
||||
<< '\n'
|
||||
<< "max_datagram_frame_size=" << params->max_datagram_frame_size << '\n';
|
||||
|
||||
f.close();
|
||||
if (!f) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ClientBase::read_transport_params(const char *path,
|
||||
ngtcp2_transport_params *params) {
|
||||
auto f = std::ifstream(path);
|
||||
if (!f) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (std::string line; std::getline(f, line);) {
|
||||
if (util::istarts_with(line, "initial_max_streams_bidi="sv)) {
|
||||
if (auto n = util::parse_uint(line.c_str() +
|
||||
"initial_max_streams_bidi="sv.size());
|
||||
!n) {
|
||||
return -1;
|
||||
} else {
|
||||
params->initial_max_streams_bidi = *n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (util::istarts_with(line, "initial_max_streams_uni="sv)) {
|
||||
if (auto n = util::parse_uint(line.c_str() +
|
||||
"initial_max_streams_uni="sv.size());
|
||||
!n) {
|
||||
return -1;
|
||||
} else {
|
||||
params->initial_max_streams_uni = *n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (util::istarts_with(line, "initial_max_stream_data_bidi_local="sv)) {
|
||||
if (auto n = util::parse_uint(
|
||||
line.c_str() + "initial_max_stream_data_bidi_local="sv.size());
|
||||
!n) {
|
||||
return -1;
|
||||
} else {
|
||||
params->initial_max_stream_data_bidi_local = *n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (util::istarts_with(line, "initial_max_stream_data_bidi_remote="sv)) {
|
||||
if (auto n = util::parse_uint(
|
||||
line.c_str() + "initial_max_stream_data_bidi_remote="sv.size());
|
||||
!n) {
|
||||
return -1;
|
||||
} else {
|
||||
params->initial_max_stream_data_bidi_remote = *n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (util::istarts_with(line, "initial_max_stream_data_uni="sv)) {
|
||||
if (auto n = util::parse_uint(line.c_str() +
|
||||
"initial_max_stream_data_uni="sv.size());
|
||||
!n) {
|
||||
return -1;
|
||||
} else {
|
||||
params->initial_max_stream_data_uni = *n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (util::istarts_with(line, "initial_max_data="sv)) {
|
||||
if (auto n =
|
||||
util::parse_uint(line.c_str() + "initial_max_data="sv.size());
|
||||
!n) {
|
||||
return -1;
|
||||
} else {
|
||||
params->initial_max_data = *n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (util::istarts_with(line, "active_connection_id_limit="sv)) {
|
||||
if (auto n = util::parse_uint(line.c_str() +
|
||||
"active_connection_id_limit="sv.size());
|
||||
!n) {
|
||||
return -1;
|
||||
} else {
|
||||
params->active_connection_id_limit = *n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (util::istarts_with(line, "max_datagram_frame_size="sv)) {
|
||||
if (auto n = util::parse_uint(line.c_str() +
|
||||
"max_datagram_frame_size="sv.size());
|
||||
!n) {
|
||||
return -1;
|
||||
} else {
|
||||
params->max_datagram_frame_size = *n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngtcp2_conn *ClientBase::conn() const { return conn_; }
|
||||
|
||||
void qlog_write_cb(void *user_data, uint32_t flags, const void *data,
|
||||
size_t datalen) {
|
||||
auto c = static_cast<ClientBase *>(user_data);
|
||||
c->write_qlog(data, datalen);
|
||||
}
|
||||
|
||||
void ClientBase::write_qlog(const void *data, size_t datalen) {
|
||||
assert(qlog_);
|
||||
fwrite(data, 1, datalen, qlog_);
|
||||
}
|
||||
|
||||
ngtcp2_crypto_conn_ref *ClientBase::conn_ref() { return &conn_ref_; }
|
||||
|
||||
void ClientBase::ticket_received() { ticket_received_ = true; }
|
||||
230
deps/ngtcp2/ngtcp2/examples/client_base.h
vendored
Normal file
230
deps/ngtcp2/ngtcp2/examples/client_base.h
vendored
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 CLIENT_BASE_H
|
||||
#define CLIENT_BASE_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <functional>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
|
||||
#include "tls_client_session.h"
|
||||
#include "network.h"
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
struct Request {
|
||||
std::string_view scheme;
|
||||
std::string authority;
|
||||
std::string path;
|
||||
};
|
||||
|
||||
struct Config {
|
||||
ngtcp2_cid dcid;
|
||||
ngtcp2_cid scid;
|
||||
bool scid_present;
|
||||
// tx_loss_prob is probability of losing outgoing packet.
|
||||
double tx_loss_prob;
|
||||
// rx_loss_prob is probability of losing incoming packet.
|
||||
double rx_loss_prob;
|
||||
// fd is a file descriptor to read input for streams.
|
||||
int fd;
|
||||
// ciphers is the list of enabled ciphers.
|
||||
const char *ciphers;
|
||||
// groups is the list of supported groups.
|
||||
const char *groups;
|
||||
// nstreams is the number of streams to open.
|
||||
size_t nstreams;
|
||||
// data is the pointer to memory region which maps file denoted by
|
||||
// fd.
|
||||
uint8_t *data;
|
||||
// datalen is the length of file denoted by fd.
|
||||
size_t datalen;
|
||||
// version is a QUIC version to use.
|
||||
uint32_t version;
|
||||
// quiet suppresses the output normally shown except for the error
|
||||
// messages.
|
||||
bool quiet;
|
||||
// timeout is an idle timeout for QUIC connection.
|
||||
ngtcp2_duration timeout;
|
||||
// session_file is a path to a file to write, and read TLS session.
|
||||
const char *session_file;
|
||||
// tp_file is a path to a file to write, and read QUIC transport
|
||||
// parameters.
|
||||
const char *tp_file;
|
||||
// show_secret is true if transport secrets should be printed out.
|
||||
bool show_secret;
|
||||
// change_local_addr is the duration after which client changes
|
||||
// local address.
|
||||
ngtcp2_duration change_local_addr;
|
||||
// key_update is the duration after which client initiates key
|
||||
// update.
|
||||
ngtcp2_duration key_update;
|
||||
// delay_stream is the duration after which client sends the first
|
||||
// 1-RTT stream.
|
||||
ngtcp2_duration delay_stream;
|
||||
// nat_rebinding is true if simulated NAT rebinding is enabled.
|
||||
bool nat_rebinding;
|
||||
// no_preferred_addr is true if client do not follow preferred
|
||||
// address offered by server.
|
||||
bool no_preferred_addr;
|
||||
std::string_view http_method;
|
||||
// download is a path to a directory where a downloaded file is
|
||||
// saved. If it is empty, no file is saved.
|
||||
std::string_view download;
|
||||
// requests contains URIs to request.
|
||||
std::vector<Request> requests;
|
||||
// no_quic_dump is true if hexdump of QUIC STREAM and CRYPTO data
|
||||
// should be disabled.
|
||||
bool no_quic_dump;
|
||||
// no_http_dump is true if hexdump of HTTP response body should be
|
||||
// disabled.
|
||||
bool no_http_dump;
|
||||
// qlog_file is the path to write qlog.
|
||||
std::string_view qlog_file;
|
||||
// qlog_dir is the path to directory where qlog is stored. qlog_dir
|
||||
// and qlog_file are mutually exclusive.
|
||||
std::string_view qlog_dir;
|
||||
// max_data is the initial connection-level flow control window.
|
||||
uint64_t max_data;
|
||||
// max_stream_data_bidi_local is the initial stream-level flow
|
||||
// control window for a bidirectional stream that the local endpoint
|
||||
// initiates.
|
||||
uint64_t max_stream_data_bidi_local;
|
||||
// max_stream_data_bidi_remote is the initial stream-level flow
|
||||
// control window for a bidirectional stream that the remote
|
||||
// endpoint initiates.
|
||||
uint64_t max_stream_data_bidi_remote;
|
||||
// max_stream_data_uni is the initial stream-level flow control
|
||||
// window for a unidirectional stream.
|
||||
uint64_t max_stream_data_uni;
|
||||
// max_streams_bidi is the number of the concurrent bidirectional
|
||||
// streams.
|
||||
uint64_t max_streams_bidi;
|
||||
// max_streams_uni is the number of the concurrent unidirectional
|
||||
// streams.
|
||||
uint64_t max_streams_uni;
|
||||
// max_window is the maximum connection-level flow control window
|
||||
// size if auto-tuning is enabled.
|
||||
uint64_t max_window;
|
||||
// max_stream_window is the maximum stream-level flow control window
|
||||
// size if auto-tuning is enabled.
|
||||
uint64_t max_stream_window;
|
||||
// exit_on_first_stream_close is the flag that if it is true, client
|
||||
// exits when a first HTTP stream gets closed. It is not
|
||||
// necessarily the same time when the underlying QUIC stream closes
|
||||
// due to the QPACK synchronization.
|
||||
bool exit_on_first_stream_close;
|
||||
// exit_on_all_streams_close is the flag that if it is true, client
|
||||
// exits when all HTTP streams get closed.
|
||||
bool exit_on_all_streams_close;
|
||||
// disable_early_data disables early data.
|
||||
bool disable_early_data;
|
||||
// static_secret is used to derive keying materials for Stateless
|
||||
// Retry token.
|
||||
std::array<uint8_t, 32> static_secret;
|
||||
// cc_algo is the congestion controller algorithm.
|
||||
ngtcp2_cc_algo cc_algo;
|
||||
// token_file is a path to file to read or write token from
|
||||
// NEW_TOKEN frame.
|
||||
std::string_view token_file;
|
||||
// sni is the value sent in TLS SNI, overriding DNS name of the
|
||||
// remote host.
|
||||
std::string_view sni;
|
||||
// initial_rtt is an initial RTT.
|
||||
ngtcp2_duration initial_rtt;
|
||||
// max_udp_payload_size is the maximum UDP payload size that client
|
||||
// transmits.
|
||||
size_t max_udp_payload_size;
|
||||
// handshake_timeout is the period of time before giving up QUIC
|
||||
// connection establishment.
|
||||
ngtcp2_duration handshake_timeout;
|
||||
// preferred_versions includes QUIC versions in the order of
|
||||
// preference. Client uses this field to select a version from the
|
||||
// version set offered in Version Negotiation packet.
|
||||
std::vector<uint32_t> preferred_versions;
|
||||
// available_versions includes QUIC versions that are sent in
|
||||
// available_versions field of version_information
|
||||
// transport_parameter.
|
||||
std::vector<uint32_t> available_versions;
|
||||
// no_pmtud disables Path MTU Discovery.
|
||||
bool no_pmtud;
|
||||
// ack_thresh is the minimum number of the received ACK eliciting
|
||||
// packets that triggers immediate acknowledgement.
|
||||
size_t ack_thresh;
|
||||
// wait_for_ticket, if true, waits for a ticket to be received
|
||||
// before exiting on exit_on_first_stream_close or
|
||||
// exit_on_all_streams_close.
|
||||
bool wait_for_ticket;
|
||||
// initial_pkt_num is the initial packet number for each packet
|
||||
// number space. If it is set to UINT32_MAX, it is chosen randomly.
|
||||
uint32_t initial_pkt_num;
|
||||
// pmtud_probes is the array of UDP datagram payload size to probes.
|
||||
std::vector<uint16_t> pmtud_probes;
|
||||
// ech_config_list contains ECHConfigList.
|
||||
std::vector<uint8_t> ech_config_list;
|
||||
// ech_config_list_file is a path to a file to read and write
|
||||
// ECHConfigList.
|
||||
const char *ech_config_list_file;
|
||||
};
|
||||
|
||||
class ClientBase {
|
||||
public:
|
||||
ClientBase();
|
||||
~ClientBase();
|
||||
|
||||
ngtcp2_conn *conn() const;
|
||||
|
||||
int write_transport_params(const char *path,
|
||||
const ngtcp2_transport_params *params);
|
||||
int read_transport_params(const char *path, ngtcp2_transport_params *params);
|
||||
|
||||
void write_qlog(const void *data, size_t datalen);
|
||||
|
||||
ngtcp2_crypto_conn_ref *conn_ref();
|
||||
|
||||
void ticket_received();
|
||||
|
||||
protected:
|
||||
ngtcp2_crypto_conn_ref conn_ref_;
|
||||
TLSClientSession tls_session_;
|
||||
FILE *qlog_;
|
||||
ngtcp2_conn *conn_;
|
||||
ngtcp2_ccerr last_error_;
|
||||
bool ticket_received_;
|
||||
};
|
||||
|
||||
void qlog_write_cb(void *user_data, uint32_t flags, const void *data,
|
||||
size_t datalen);
|
||||
|
||||
#endif // !defined(CLIENT_BASE_H)
|
||||
322
deps/ngtcp2/ngtcp2/examples/debug.cc
vendored
Normal file
322
deps/ngtcp2/ngtcp2/examples/debug.cc
vendored
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "debug.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <random>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
namespace debug {
|
||||
|
||||
namespace {
|
||||
auto randgen = util::make_mt19937();
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
auto *outfile = stderr;
|
||||
} // namespace
|
||||
|
||||
int handshake_completed(ngtcp2_conn *conn, void *user_data) {
|
||||
fprintf(outfile, "QUIC handshake has completed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handshake_confirmed(ngtcp2_conn *conn, void *user_data) {
|
||||
fprintf(outfile, "QUIC handshake has been confirmed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool packet_lost(double prob) {
|
||||
auto p = std::uniform_real_distribution<>(0, 1)(randgen);
|
||||
return p < prob;
|
||||
}
|
||||
|
||||
void print_crypto_data(ngtcp2_encryption_level encryption_level,
|
||||
std::span<const uint8_t> data) {
|
||||
const char *encryption_level_str;
|
||||
switch (encryption_level) {
|
||||
case NGTCP2_ENCRYPTION_LEVEL_INITIAL:
|
||||
encryption_level_str = "Initial";
|
||||
break;
|
||||
case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE:
|
||||
encryption_level_str = "Handshake";
|
||||
break;
|
||||
case NGTCP2_ENCRYPTION_LEVEL_1RTT:
|
||||
encryption_level_str = "1-RTT";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
fprintf(outfile, "Ordered CRYPTO data in %s crypto level\n",
|
||||
encryption_level_str);
|
||||
util::hexdump(outfile, data.data(), data.size());
|
||||
}
|
||||
|
||||
void print_stream_data(int64_t stream_id, std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "Ordered STREAM data stream_id=0x%" PRIx64 "\n", stream_id);
|
||||
util::hexdump(outfile, data.data(), data.size());
|
||||
}
|
||||
|
||||
void print_initial_secret(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "initial_secret=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_client_in_secret(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "client_in_secret=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_server_in_secret(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "server_in_secret=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_handshake_secret(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "handshake_secret=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_client_hs_secret(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "client_hs_secret=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_server_hs_secret(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "server_hs_secret=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_client_0rtt_secret(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "client_0rtt_secret=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_client_1rtt_secret(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "client_1rtt_secret=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_server_1rtt_secret(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "server_1rtt_secret=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_client_pp_key(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "+ client_pp_key=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_server_pp_key(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "+ server_pp_key=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_client_pp_iv(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "+ client_pp_iv=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_server_pp_iv(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "+ server_pp_iv=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_client_pp_hp(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "+ client_pp_hp=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_server_pp_hp(std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "+ server_pp_hp=%s\n", util::format_hex(data).c_str());
|
||||
}
|
||||
|
||||
void print_secrets(std::span<const uint8_t> secret,
|
||||
std::span<const uint8_t> key, std::span<const uint8_t> iv,
|
||||
std::span<const uint8_t> hp) {
|
||||
std::cerr << "+ secret=" << util::format_hex(secret) << "\n"
|
||||
<< "+ key=" << util::format_hex(key) << "\n"
|
||||
<< "+ iv=" << util::format_hex(iv) << "\n"
|
||||
<< "+ hp=" << util::format_hex(hp) << std::endl;
|
||||
}
|
||||
|
||||
void print_secrets(std::span<const uint8_t> secret,
|
||||
std::span<const uint8_t> key, std::span<const uint8_t> iv) {
|
||||
std::cerr << "+ secret=" << util::format_hex(secret) << "\n"
|
||||
<< "+ key=" << util::format_hex(key) << "\n"
|
||||
<< "+ iv=" << util::format_hex(iv) << std::endl;
|
||||
}
|
||||
|
||||
void print_hp_mask(std::span<const uint8_t> mask,
|
||||
std::span<const uint8_t> sample) {
|
||||
fprintf(outfile, "mask=%s sample=%s\n", util::format_hex(mask).c_str(),
|
||||
util::format_hex(sample).c_str());
|
||||
}
|
||||
|
||||
void log_printf(void *user_data, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
std::array<char, 4096> buf;
|
||||
|
||||
va_start(ap, fmt);
|
||||
auto n = vsnprintf(buf.data(), buf.size(), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (static_cast<size_t>(n) >= buf.size()) {
|
||||
n = buf.size() - 1;
|
||||
}
|
||||
|
||||
buf[static_cast<size_t>(n++)] = '\n';
|
||||
|
||||
while (write(fileno(stderr), buf.data(), static_cast<size_t>(n)) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
}
|
||||
|
||||
void path_validation(const ngtcp2_path *path,
|
||||
ngtcp2_path_validation_result res) {
|
||||
auto local_addr = util::straddr(
|
||||
reinterpret_cast<sockaddr *>(path->local.addr), path->local.addrlen);
|
||||
auto remote_addr = util::straddr(
|
||||
reinterpret_cast<sockaddr *>(path->remote.addr), path->remote.addrlen);
|
||||
|
||||
std::cerr << "Path validation against path {local:" << local_addr
|
||||
<< ", remote:" << remote_addr << "} "
|
||||
<< (res == NGTCP2_PATH_VALIDATION_RESULT_SUCCESS ? "succeeded"
|
||||
: "failed")
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void print_http_begin_request_headers(int64_t stream_id) {
|
||||
fprintf(outfile, "http: stream 0x%" PRIx64 " request headers started\n",
|
||||
stream_id);
|
||||
}
|
||||
|
||||
void print_http_begin_response_headers(int64_t stream_id) {
|
||||
fprintf(outfile, "http: stream 0x%" PRIx64 " response headers started\n",
|
||||
stream_id);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void print_header(std::span<const uint8_t> name, std::span<const uint8_t> value,
|
||||
uint8_t flags) {
|
||||
fprintf(outfile, "[%.*s: %.*s]%s\n", static_cast<int>(name.size()),
|
||||
name.data(), static_cast<int>(value.size()), value.data(),
|
||||
(flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? "(sensitive)" : "");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_header(const nghttp3_rcbuf *name, const nghttp3_rcbuf *value,
|
||||
uint8_t flags) {
|
||||
auto namebuf = nghttp3_rcbuf_get_buf(name);
|
||||
auto valuebuf = nghttp3_rcbuf_get_buf(value);
|
||||
print_header({namebuf.base, namebuf.len}, {valuebuf.base, valuebuf.len},
|
||||
flags);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_header(const nghttp3_nv &nv) {
|
||||
print_header({nv.name, nv.namelen}, {nv.value, nv.valuelen}, nv.flags);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void print_http_header(int64_t stream_id, const nghttp3_rcbuf *name,
|
||||
const nghttp3_rcbuf *value, uint8_t flags) {
|
||||
fprintf(outfile, "http: stream 0x%" PRIx64 " ", stream_id);
|
||||
print_header(name, value, flags);
|
||||
}
|
||||
|
||||
void print_http_end_headers(int64_t stream_id) {
|
||||
fprintf(outfile, "http: stream 0x%" PRIx64 " headers ended\n", stream_id);
|
||||
}
|
||||
|
||||
void print_http_data(int64_t stream_id, std::span<const uint8_t> data) {
|
||||
fprintf(outfile, "http: stream 0x%" PRIx64 " body %zu bytes\n", stream_id,
|
||||
data.size());
|
||||
util::hexdump(outfile, data.data(), data.size());
|
||||
}
|
||||
|
||||
void print_http_begin_trailers(int64_t stream_id) {
|
||||
fprintf(outfile, "http: stream 0x%" PRIx64 " trailers started\n", stream_id);
|
||||
}
|
||||
|
||||
void print_http_end_trailers(int64_t stream_id) {
|
||||
fprintf(outfile, "http: stream 0x%" PRIx64 " trailers ended\n", stream_id);
|
||||
}
|
||||
|
||||
void print_http_request_headers(int64_t stream_id, const nghttp3_nv *nva,
|
||||
size_t nvlen) {
|
||||
fprintf(outfile, "http: stream 0x%" PRIx64 " submit request headers\n",
|
||||
stream_id);
|
||||
for (size_t i = 0; i < nvlen; ++i) {
|
||||
auto &nv = nva[i];
|
||||
print_header(nv);
|
||||
}
|
||||
}
|
||||
|
||||
void print_http_response_headers(int64_t stream_id, const nghttp3_nv *nva,
|
||||
size_t nvlen) {
|
||||
fprintf(outfile, "http: stream 0x%" PRIx64 " submit response headers\n",
|
||||
stream_id);
|
||||
for (size_t i = 0; i < nvlen; ++i) {
|
||||
auto &nv = nva[i];
|
||||
print_header(nv);
|
||||
}
|
||||
}
|
||||
|
||||
void print_http_settings(const nghttp3_settings *settings) {
|
||||
fprintf(outfile,
|
||||
"http: remote settings\n"
|
||||
"http: SETTINGS_MAX_FIELD_SECTION_SIZE=%" PRIu64 "\n"
|
||||
"http: SETTINGS_QPACK_MAX_TABLE_CAPACITY=%zu\n"
|
||||
"http: SETTINGS_QPACK_BLOCKED_STREAMS=%zu\n"
|
||||
"http: SETTINGS_ENABLE_CONNECT_PROTOCOL=%d\n"
|
||||
"http: SETTINGS_H3_DATAGRAM=%d\n",
|
||||
settings->max_field_section_size, settings->qpack_max_dtable_capacity,
|
||||
settings->qpack_blocked_streams, settings->enable_connect_protocol,
|
||||
settings->h3_datagram);
|
||||
}
|
||||
|
||||
void print_http_origin(const uint8_t *origin, size_t originlen) {
|
||||
fprintf(outfile, "http: origin [%.*s]\n", static_cast<int>(originlen),
|
||||
origin);
|
||||
}
|
||||
|
||||
void print_http_end_origin() { fprintf(outfile, "http: origin ended\n"); }
|
||||
|
||||
std::string_view secret_title(ngtcp2_encryption_level level) {
|
||||
switch (level) {
|
||||
case NGTCP2_ENCRYPTION_LEVEL_0RTT:
|
||||
return "early_traffic"sv;
|
||||
case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE:
|
||||
return "handshake_traffic"sv;
|
||||
case NGTCP2_ENCRYPTION_LEVEL_1RTT:
|
||||
return "application_traffic"sv;
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace debug
|
||||
|
||||
} // namespace ngtcp2
|
||||
131
deps/ngtcp2/ngtcp2/examples/debug.h
vendored
Normal file
131
deps/ngtcp2/ngtcp2/examples/debug.h
vendored
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
// For travis and PRIu64
|
||||
# define __STDC_FORMAT_MACROS
|
||||
#endif // !defined(__STDC_FORMAT_MACROS)
|
||||
|
||||
#include <cinttypes>
|
||||
#include <string_view>
|
||||
#include <span>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
namespace debug {
|
||||
|
||||
int handshake_completed(ngtcp2_conn *conn, void *user_data);
|
||||
|
||||
int handshake_confirmed(ngtcp2_conn *conn, void *user_data);
|
||||
|
||||
bool packet_lost(double prob);
|
||||
|
||||
void print_crypto_data(ngtcp2_encryption_level encryption_level,
|
||||
std::span<const uint8_t> data);
|
||||
|
||||
void print_stream_data(int64_t stream_id, std::span<const uint8_t> data);
|
||||
|
||||
void print_initial_secret(std::span<const uint8_t> data);
|
||||
|
||||
void print_client_in_secret(std::span<const uint8_t> data);
|
||||
void print_server_in_secret(std::span<const uint8_t> data);
|
||||
|
||||
void print_handshake_secret(std::span<const uint8_t> data);
|
||||
|
||||
void print_client_hs_secret(std::span<const uint8_t> data);
|
||||
void print_server_hs_secret(std::span<const uint8_t> data);
|
||||
|
||||
void print_client_0rtt_secret(std::span<const uint8_t> data);
|
||||
|
||||
void print_client_1rtt_secret(std::span<const uint8_t> data);
|
||||
void print_server_1rtt_secret(std::span<const uint8_t> data);
|
||||
|
||||
void print_client_pp_key(std::span<const uint8_t> data);
|
||||
void print_server_pp_key(std::span<const uint8_t> data);
|
||||
|
||||
void print_client_pp_iv(std::span<const uint8_t> data);
|
||||
void print_server_pp_iv(std::span<const uint8_t> data);
|
||||
|
||||
void print_client_pp_hp(std::span<const uint8_t> data);
|
||||
void print_server_pp_hp(std::span<const uint8_t> data);
|
||||
|
||||
void print_secrets(std::span<const uint8_t> secret,
|
||||
std::span<const uint8_t> key, std::span<const uint8_t> iv,
|
||||
std::span<const uint8_t> hp);
|
||||
|
||||
void print_secrets(std::span<const uint8_t> secret,
|
||||
std::span<const uint8_t> key, std::span<const uint8_t> iv);
|
||||
|
||||
void print_hp_mask(std::span<const uint8_t> mask,
|
||||
std::span<const uint8_t> sample);
|
||||
|
||||
void log_printf(void *user_data, const char *fmt, ...);
|
||||
|
||||
void path_validation(const ngtcp2_path *path,
|
||||
ngtcp2_path_validation_result res);
|
||||
|
||||
void print_http_begin_request_headers(int64_t stream_id);
|
||||
|
||||
void print_http_begin_response_headers(int64_t stream_id);
|
||||
|
||||
void print_http_header(int64_t stream_id, const nghttp3_rcbuf *name,
|
||||
const nghttp3_rcbuf *value, uint8_t flags);
|
||||
|
||||
void print_http_end_headers(int64_t stream_id);
|
||||
|
||||
void print_http_data(int64_t stream_id, std::span<const uint8_t> data);
|
||||
|
||||
void print_http_begin_trailers(int64_t stream_id);
|
||||
|
||||
void print_http_end_trailers(int64_t stream_id);
|
||||
|
||||
void print_http_request_headers(int64_t stream_id, const nghttp3_nv *nva,
|
||||
size_t nvlen);
|
||||
|
||||
void print_http_response_headers(int64_t stream_id, const nghttp3_nv *nva,
|
||||
size_t nvlen);
|
||||
|
||||
void print_http_settings(const nghttp3_settings *settings);
|
||||
|
||||
void print_http_origin(const uint8_t *origin, size_t originlen);
|
||||
|
||||
void print_http_end_origin();
|
||||
|
||||
std::string_view secret_title(ngtcp2_encryption_level level);
|
||||
|
||||
} // namespace debug
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
#endif // !defined(DEBUG_H)
|
||||
49
deps/ngtcp2/ngtcp2/examples/examplestest.cc
vendored
Normal file
49
deps/ngtcp2/ngtcp2/examples/examplestest.cc
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2018 ngtcp2 contributors
|
||||
* Copyright (c) 2013 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "munit.h"
|
||||
|
||||
// include test cases' include files here
|
||||
#include "util_test.h"
|
||||
#include "siphash_test.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const MunitSuite suites[] = {
|
||||
ngtcp2::util_suite,
|
||||
ngtcp2::siphash_suite,
|
||||
{},
|
||||
};
|
||||
const MunitSuite suite = {
|
||||
.prefix = "",
|
||||
.suites = suites,
|
||||
.iterations = 1,
|
||||
};
|
||||
|
||||
return munit_suite_main(&suite, nullptr, argc, argv);
|
||||
}
|
||||
699
deps/ngtcp2/ngtcp2/examples/gtlssimpleclient.c
vendored
Normal file
699
deps/ngtcp2/ngtcp2/examples/gtlssimpleclient.c
vendored
Normal file
|
|
@ -0,0 +1,699 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2021-2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* defined(HAVE_CONFIG_H) */
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
#include <ngtcp2/ngtcp2_crypto_gnutls.h>
|
||||
|
||||
#include <gnutls/crypto.h>
|
||||
#include <gnutls/gnutls.h>
|
||||
|
||||
#include <ev.h>
|
||||
|
||||
#define REMOTE_HOST "127.0.0.1"
|
||||
#define REMOTE_PORT "4433"
|
||||
#define ALPN "hq-interop"
|
||||
#define MESSAGE "GET /\r\n"
|
||||
|
||||
/*
|
||||
* Example 1: Handshake with www.google.com
|
||||
*
|
||||
* #define REMOTE_HOST "www.google.com"
|
||||
* #define REMOTE_PORT "443"
|
||||
* #define ALPN "h3"
|
||||
*
|
||||
* and undefine MESSAGE macro.
|
||||
*/
|
||||
|
||||
static uint64_t timestamp(void) {
|
||||
struct timespec tp;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0) {
|
||||
fprintf(stderr, "clock_gettime: %s\n", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return (uint64_t)tp.tv_sec * NGTCP2_SECONDS + (uint64_t)tp.tv_nsec;
|
||||
}
|
||||
|
||||
static int create_sock(struct sockaddr *addr, socklen_t *paddrlen,
|
||||
const char *host, const char *port) {
|
||||
struct addrinfo hints = {0};
|
||||
struct addrinfo *res, *rp;
|
||||
int rv;
|
||||
int fd = -1;
|
||||
|
||||
hints.ai_flags = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
rv = getaddrinfo(host, port, &hints, &res);
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (rp = res; rp; rp = rp->ai_next) {
|
||||
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if (fd == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
*paddrlen = rp->ai_addrlen;
|
||||
memcpy(addr, rp->ai_addr, rp->ai_addrlen);
|
||||
|
||||
end:
|
||||
freeaddrinfo(res);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int connect_sock(struct sockaddr *local_addr, socklen_t *plocal_addrlen,
|
||||
int fd, const struct sockaddr *remote_addr,
|
||||
size_t remote_addrlen) {
|
||||
socklen_t len;
|
||||
|
||||
if (connect(fd, remote_addr, (socklen_t)remote_addrlen) != 0) {
|
||||
fprintf(stderr, "connect: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = *plocal_addrlen;
|
||||
|
||||
if (getsockname(fd, local_addr, &len) == -1) {
|
||||
fprintf(stderr, "getsockname: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
*plocal_addrlen = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct client {
|
||||
ngtcp2_crypto_conn_ref conn_ref;
|
||||
int fd;
|
||||
struct sockaddr_storage local_addr;
|
||||
socklen_t local_addrlen;
|
||||
gnutls_certificate_credentials_t cred;
|
||||
gnutls_session_t session;
|
||||
ngtcp2_conn *conn;
|
||||
|
||||
struct {
|
||||
int64_t stream_id;
|
||||
const uint8_t *data;
|
||||
size_t datalen;
|
||||
size_t nwrite;
|
||||
} stream;
|
||||
|
||||
ngtcp2_ccerr last_error;
|
||||
|
||||
ev_io rev;
|
||||
ev_timer timer;
|
||||
};
|
||||
|
||||
static int hook_func(gnutls_session_t session, unsigned int htype,
|
||||
unsigned when, unsigned int incoming,
|
||||
const gnutls_datum_t *msg) {
|
||||
(void)session;
|
||||
(void)htype;
|
||||
(void)when;
|
||||
(void)incoming;
|
||||
(void)msg;
|
||||
/* we could save session data here */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int numeric_host_family(const char *hostname, int family) {
|
||||
uint8_t dst[sizeof(struct in6_addr)];
|
||||
return inet_pton(family, hostname, dst) == 1;
|
||||
}
|
||||
|
||||
static int numeric_host(const char *hostname) {
|
||||
return numeric_host_family(hostname, AF_INET) ||
|
||||
numeric_host_family(hostname, AF_INET6);
|
||||
}
|
||||
|
||||
static const char priority[] =
|
||||
"NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:"
|
||||
"+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:+GROUP-X25519:"
|
||||
"+GROUP-SECP384R1:"
|
||||
"+GROUP-SECP521R1:%DISABLE_TLS13_COMPAT_MODE";
|
||||
|
||||
static const gnutls_datum_t alpn = {(uint8_t *)ALPN, sizeof(ALPN) - 1};
|
||||
|
||||
static int client_gnutls_init(struct client *c) {
|
||||
int rv = gnutls_certificate_allocate_credentials(&c->cred);
|
||||
|
||||
if (rv == 0)
|
||||
rv = gnutls_certificate_set_x509_system_trust(c->cred);
|
||||
if (rv < 0) {
|
||||
fprintf(stderr, "cred init failed: %d: %s\n", rv, gnutls_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = gnutls_init(&c->session, GNUTLS_CLIENT | GNUTLS_ENABLE_EARLY_DATA |
|
||||
GNUTLS_NO_END_OF_EARLY_DATA);
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "gnutls_init: %s\n", gnutls_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_gnutls_configure_client_session(c->session) != 0) {
|
||||
fprintf(stderr, "ngtcp2_crypto_gnutls_configure_client_session failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = gnutls_priority_set_direct(c->session, priority, NULL);
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "gnutls_priority_set_direct: %s\n", gnutls_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
gnutls_handshake_set_hook_function(c->session, GNUTLS_HANDSHAKE_ANY,
|
||||
GNUTLS_HOOK_POST, hook_func);
|
||||
|
||||
gnutls_session_set_ptr(c->session, &c->conn_ref);
|
||||
|
||||
rv = gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, c->cred);
|
||||
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "gnutls_credentials_set: %s\n", gnutls_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
gnutls_alpn_set_protocols(c->session, &alpn, 1, GNUTLS_ALPN_MANDATORY);
|
||||
|
||||
if (!numeric_host(REMOTE_HOST)) {
|
||||
gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, REMOTE_HOST,
|
||||
strlen(REMOTE_HOST));
|
||||
} else {
|
||||
gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, "localhost",
|
||||
strlen("localhost"));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rand_cb(uint8_t *dest, size_t destlen,
|
||||
const ngtcp2_rand_ctx *rand_ctx) {
|
||||
(void)rand_ctx;
|
||||
|
||||
(void)gnutls_rnd(GNUTLS_RND_RANDOM, dest, destlen);
|
||||
}
|
||||
|
||||
static int get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid,
|
||||
uint8_t *token, size_t cidlen,
|
||||
void *user_data) {
|
||||
(void)conn;
|
||||
(void)user_data;
|
||||
|
||||
if (gnutls_rnd(GNUTLS_RND_RANDOM, cid->data, cidlen) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
cid->datalen = cidlen;
|
||||
|
||||
if (gnutls_rnd(GNUTLS_RND_RANDOM, token, NGTCP2_STATELESS_RESET_TOKENLEN) !=
|
||||
0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int extend_max_local_streams_bidi(ngtcp2_conn *conn,
|
||||
uint64_t max_streams,
|
||||
void *user_data) {
|
||||
#ifdef MESSAGE
|
||||
struct client *c = user_data;
|
||||
int rv;
|
||||
int64_t stream_id;
|
||||
(void)max_streams;
|
||||
|
||||
if (c->stream.stream_id != -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = ngtcp2_conn_open_bidi_stream(conn, &stream_id, NULL);
|
||||
if (rv != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->stream.stream_id = stream_id;
|
||||
c->stream.data = (const uint8_t *)MESSAGE;
|
||||
c->stream.datalen = sizeof(MESSAGE) - 1;
|
||||
|
||||
return 0;
|
||||
#else /* !defined(MESSAGE) */
|
||||
(void)conn;
|
||||
(void)max_streams;
|
||||
(void)user_data;
|
||||
|
||||
return 0;
|
||||
#endif /* !defined(MESSAGE) */
|
||||
}
|
||||
|
||||
static void log_printf(void *user_data, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
(void)user_data;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static int client_quic_init(struct client *c,
|
||||
const struct sockaddr *remote_addr,
|
||||
socklen_t remote_addrlen,
|
||||
const struct sockaddr *local_addr,
|
||||
socklen_t local_addrlen) {
|
||||
ngtcp2_path path = {
|
||||
.local =
|
||||
{
|
||||
.addr = (struct sockaddr *)local_addr,
|
||||
.addrlen = local_addrlen,
|
||||
},
|
||||
.remote =
|
||||
{
|
||||
.addr = (struct sockaddr *)remote_addr,
|
||||
.addrlen = remote_addrlen,
|
||||
},
|
||||
};
|
||||
ngtcp2_callbacks callbacks = {
|
||||
.client_initial = ngtcp2_crypto_client_initial_cb,
|
||||
.recv_crypto_data = ngtcp2_crypto_recv_crypto_data_cb,
|
||||
.encrypt = ngtcp2_crypto_encrypt_cb,
|
||||
.decrypt = ngtcp2_crypto_decrypt_cb,
|
||||
.hp_mask = ngtcp2_crypto_hp_mask_cb,
|
||||
.recv_retry = ngtcp2_crypto_recv_retry_cb,
|
||||
.extend_max_local_streams_bidi = extend_max_local_streams_bidi,
|
||||
.rand = rand_cb,
|
||||
.get_new_connection_id = get_new_connection_id_cb,
|
||||
.update_key = ngtcp2_crypto_update_key_cb,
|
||||
.delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb,
|
||||
.delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
|
||||
.get_path_challenge_data = ngtcp2_crypto_get_path_challenge_data_cb,
|
||||
.version_negotiation = ngtcp2_crypto_version_negotiation_cb,
|
||||
};
|
||||
ngtcp2_cid dcid, scid;
|
||||
ngtcp2_settings settings;
|
||||
ngtcp2_transport_params params;
|
||||
int rv;
|
||||
|
||||
dcid.datalen = NGTCP2_MIN_INITIAL_DCIDLEN;
|
||||
if (gnutls_rnd(GNUTLS_RND_RANDOM, dcid.data, dcid.datalen) != 0) {
|
||||
fprintf(stderr, "gnutls_rnd failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
scid.datalen = 8;
|
||||
if (gnutls_rnd(GNUTLS_RND_RANDOM, scid.data, scid.datalen) != 0) {
|
||||
fprintf(stderr, "gnutls_rnd failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngtcp2_settings_default(&settings);
|
||||
|
||||
settings.initial_ts = timestamp();
|
||||
settings.log_printf = log_printf;
|
||||
|
||||
ngtcp2_transport_params_default(¶ms);
|
||||
|
||||
params.initial_max_streams_uni = 3;
|
||||
params.initial_max_stream_data_bidi_local = 128 * 1024;
|
||||
params.initial_max_data = 1024 * 1024;
|
||||
|
||||
rv =
|
||||
ngtcp2_conn_client_new(&c->conn, &dcid, &scid, &path, NGTCP2_PROTO_VER_V1,
|
||||
&callbacks, &settings, ¶ms, NULL, c);
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "ngtcp2_conn_client_new: %s\n", ngtcp2_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngtcp2_conn_set_tls_native_handle(c->conn, c->session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_read(struct client *c) {
|
||||
uint8_t buf[65536];
|
||||
struct sockaddr_storage addr;
|
||||
struct iovec iov = {
|
||||
.iov_base = buf,
|
||||
.iov_len = sizeof(buf),
|
||||
};
|
||||
struct msghdr msg = {0};
|
||||
ssize_t nread;
|
||||
ngtcp2_path path;
|
||||
ngtcp2_pkt_info pi = {0};
|
||||
int rv;
|
||||
|
||||
msg.msg_name = &addr;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
for (;;) {
|
||||
msg.msg_namelen = sizeof(addr);
|
||||
|
||||
nread = recvmsg(c->fd, &msg, MSG_DONTWAIT);
|
||||
|
||||
if (nread == -1) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
fprintf(stderr, "recvmsg: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
path.local.addrlen = c->local_addrlen;
|
||||
path.local.addr = (struct sockaddr *)&c->local_addr;
|
||||
path.remote.addrlen = msg.msg_namelen;
|
||||
path.remote.addr = msg.msg_name;
|
||||
|
||||
rv = ngtcp2_conn_read_pkt(c->conn, &path, &pi, buf, (size_t)nread,
|
||||
timestamp());
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "ngtcp2_conn_read_pkt: %s\n", ngtcp2_strerror(rv));
|
||||
if (!c->last_error.error_code) {
|
||||
if (rv == NGTCP2_ERR_CRYPTO) {
|
||||
ngtcp2_ccerr_set_tls_alert(
|
||||
&c->last_error, ngtcp2_conn_get_tls_alert(c->conn), NULL, 0);
|
||||
} else {
|
||||
ngtcp2_ccerr_set_liberr(&c->last_error, rv, NULL, 0);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_send_packet(struct client *c, const uint8_t *data,
|
||||
size_t datalen) {
|
||||
struct iovec iov = {
|
||||
.iov_base = (uint8_t *)data,
|
||||
.iov_len = datalen,
|
||||
};
|
||||
struct msghdr msg = {0};
|
||||
ssize_t nwrite;
|
||||
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
do {
|
||||
nwrite = sendmsg(c->fd, &msg, 0);
|
||||
} while (nwrite == -1 && errno == EINTR);
|
||||
|
||||
if (nwrite == -1) {
|
||||
fprintf(stderr, "sendmsg: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t client_get_message(struct client *c, int64_t *pstream_id,
|
||||
int *pfin, ngtcp2_vec *datav,
|
||||
size_t datavcnt) {
|
||||
if (datavcnt == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c->stream.stream_id != -1 && c->stream.nwrite < c->stream.datalen) {
|
||||
*pstream_id = c->stream.stream_id;
|
||||
*pfin = 1;
|
||||
datav->base = (uint8_t *)c->stream.data + c->stream.nwrite;
|
||||
datav->len = c->stream.datalen - c->stream.nwrite;
|
||||
return 1;
|
||||
}
|
||||
|
||||
*pstream_id = -1;
|
||||
*pfin = 0;
|
||||
datav->base = NULL;
|
||||
datav->len = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_write_streams(struct client *c) {
|
||||
ngtcp2_tstamp ts = timestamp();
|
||||
ngtcp2_pkt_info pi;
|
||||
ngtcp2_ssize nwrite;
|
||||
uint8_t buf[1452];
|
||||
ngtcp2_path_storage ps;
|
||||
ngtcp2_vec datav;
|
||||
size_t datavcnt;
|
||||
int64_t stream_id;
|
||||
ngtcp2_ssize wdatalen;
|
||||
uint32_t flags;
|
||||
int fin;
|
||||
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
for (;;) {
|
||||
datavcnt = client_get_message(c, &stream_id, &fin, &datav, 1);
|
||||
|
||||
flags = NGTCP2_WRITE_STREAM_FLAG_MORE;
|
||||
if (fin) {
|
||||
flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
|
||||
}
|
||||
|
||||
nwrite = ngtcp2_conn_writev_stream(c->conn, &ps.path, &pi, buf, sizeof(buf),
|
||||
&wdatalen, flags, stream_id, &datav,
|
||||
datavcnt, ts);
|
||||
if (nwrite < 0) {
|
||||
switch (nwrite) {
|
||||
case NGTCP2_ERR_WRITE_MORE:
|
||||
c->stream.nwrite += (size_t)wdatalen;
|
||||
continue;
|
||||
default:
|
||||
fprintf(stderr, "ngtcp2_conn_writev_stream: %s\n",
|
||||
ngtcp2_strerror((int)nwrite));
|
||||
ngtcp2_ccerr_set_liberr(&c->last_error, (int)nwrite, NULL, 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (nwrite == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wdatalen > 0) {
|
||||
c->stream.nwrite += (size_t)wdatalen;
|
||||
}
|
||||
|
||||
if (client_send_packet(c, buf, (size_t)nwrite) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_write(struct client *c) {
|
||||
ngtcp2_tstamp expiry, now;
|
||||
ev_tstamp t;
|
||||
|
||||
if (client_write_streams(c) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
expiry = ngtcp2_conn_get_expiry(c->conn);
|
||||
now = timestamp();
|
||||
|
||||
t = expiry < now ? 1e-9 : (ev_tstamp)(expiry - now) / NGTCP2_SECONDS;
|
||||
|
||||
c->timer.repeat = t;
|
||||
ev_timer_again(EV_DEFAULT, &c->timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_handle_expiry(struct client *c) {
|
||||
int rv = ngtcp2_conn_handle_expiry(c->conn, timestamp());
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "ngtcp2_conn_handle_expiry: %s\n", ngtcp2_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void client_close(struct client *c) {
|
||||
ngtcp2_ssize nwrite;
|
||||
ngtcp2_pkt_info pi;
|
||||
ngtcp2_path_storage ps;
|
||||
uint8_t buf[1280];
|
||||
|
||||
if (ngtcp2_conn_in_closing_period(c->conn) ||
|
||||
ngtcp2_conn_in_draining_period(c->conn)) {
|
||||
goto fin;
|
||||
}
|
||||
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
nwrite = ngtcp2_conn_write_connection_close(
|
||||
c->conn, &ps.path, &pi, buf, sizeof(buf), &c->last_error, timestamp());
|
||||
if (nwrite < 0) {
|
||||
fprintf(stderr, "ngtcp2_conn_write_connection_close: %s\n",
|
||||
ngtcp2_strerror((int)nwrite));
|
||||
goto fin;
|
||||
}
|
||||
|
||||
client_send_packet(c, buf, (size_t)nwrite);
|
||||
|
||||
fin:
|
||||
ev_break(EV_DEFAULT, EVBREAK_ALL);
|
||||
}
|
||||
|
||||
static void read_cb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||
struct client *c = w->data;
|
||||
(void)loop;
|
||||
(void)revents;
|
||||
|
||||
if (client_read(c) != 0) {
|
||||
client_close(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (client_write(c) != 0) {
|
||||
client_close(c);
|
||||
}
|
||||
}
|
||||
|
||||
static void timer_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||
struct client *c = w->data;
|
||||
(void)loop;
|
||||
(void)revents;
|
||||
|
||||
if (client_handle_expiry(c) != 0) {
|
||||
client_close(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (client_write(c) != 0) {
|
||||
client_close(c);
|
||||
}
|
||||
}
|
||||
|
||||
static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) {
|
||||
struct client *c = conn_ref->user_data;
|
||||
return c->conn;
|
||||
}
|
||||
|
||||
static int client_init(struct client *c) {
|
||||
struct sockaddr_storage remote_addr, local_addr;
|
||||
socklen_t remote_addrlen, local_addrlen = sizeof(local_addr);
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
|
||||
ngtcp2_ccerr_default(&c->last_error);
|
||||
|
||||
c->fd = create_sock((struct sockaddr *)&remote_addr, &remote_addrlen,
|
||||
REMOTE_HOST, REMOTE_PORT);
|
||||
if (c->fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect_sock((struct sockaddr *)&local_addr, &local_addrlen, c->fd,
|
||||
(struct sockaddr *)&remote_addr, remote_addrlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&c->local_addr, &local_addr, sizeof(c->local_addr));
|
||||
c->local_addrlen = local_addrlen;
|
||||
|
||||
if (client_gnutls_init(c) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (client_quic_init(c, (struct sockaddr *)&remote_addr, remote_addrlen,
|
||||
(struct sockaddr *)&local_addr, local_addrlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
c->stream.stream_id = -1;
|
||||
|
||||
c->conn_ref.get_conn = get_conn;
|
||||
c->conn_ref.user_data = c;
|
||||
|
||||
ev_io_init(&c->rev, read_cb, c->fd, EV_READ);
|
||||
c->rev.data = c;
|
||||
ev_io_start(EV_DEFAULT, &c->rev);
|
||||
|
||||
ev_timer_init(&c->timer, timer_cb, 0., 0.);
|
||||
c->timer.data = c;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void client_free(struct client *c) {
|
||||
ngtcp2_conn_del(c->conn);
|
||||
gnutls_deinit(c->session);
|
||||
gnutls_certificate_free_credentials(c->cred);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct client c;
|
||||
|
||||
if (client_init(&c) != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (client_write(&c) != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ev_run(EV_DEFAULT, 0);
|
||||
|
||||
client_free(&c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
2867
deps/ngtcp2/ngtcp2/examples/h09client.cc
vendored
Normal file
2867
deps/ngtcp2/ngtcp2/examples/h09client.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
202
deps/ngtcp2/ngtcp2/examples/h09client.h
vendored
Normal file
202
deps/ngtcp2/ngtcp2/examples/h09client.h
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 H09CLIENT_H
|
||||
#define H09CLIENT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <span>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include <ev.h>
|
||||
|
||||
#include "client_base.h"
|
||||
#include "tls_client_context.h"
|
||||
#include "tls_client_session.h"
|
||||
#include "network.h"
|
||||
#include "shared.h"
|
||||
#include "template.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
struct Stream {
|
||||
Stream(const Request &req, int64_t stream_id);
|
||||
~Stream();
|
||||
|
||||
int open_file(const std::string_view &path);
|
||||
|
||||
Request req;
|
||||
int64_t stream_id;
|
||||
int fd;
|
||||
std::string rawreqbuf;
|
||||
nghttp3_buf reqbuf;
|
||||
};
|
||||
|
||||
struct StreamIDLess {
|
||||
constexpr bool operator()(const Stream *lhs, const Stream *rhs) const {
|
||||
return lhs->stream_id < rhs->stream_id;
|
||||
}
|
||||
};
|
||||
|
||||
class Client;
|
||||
|
||||
struct Endpoint {
|
||||
Address addr;
|
||||
ev_io rev;
|
||||
Client *client;
|
||||
int fd;
|
||||
};
|
||||
|
||||
class Client : public ClientBase {
|
||||
public:
|
||||
Client(struct ev_loop *loop, uint32_t client_chosen_version,
|
||||
uint32_t original_version);
|
||||
~Client();
|
||||
|
||||
int init(int fd, const Address &local_addr, const Address &remote_addr,
|
||||
const char *addr, const char *port, TLSClientContext &tls_ctx);
|
||||
void disconnect();
|
||||
|
||||
int on_read(const Endpoint &ep);
|
||||
int on_write();
|
||||
int write_streams();
|
||||
int feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi, std::span<const uint8_t> data);
|
||||
int handle_expiry();
|
||||
void update_timer();
|
||||
int handshake_completed();
|
||||
int handshake_confirmed();
|
||||
void recv_version_negotiation(const uint32_t *sv, size_t nsv);
|
||||
|
||||
int send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr,
|
||||
unsigned int ecn, std::span<const uint8_t> data);
|
||||
std::pair<std::span<const uint8_t>, int>
|
||||
send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr,
|
||||
unsigned int ecn, std::span<const uint8_t> data, size_t gso_size);
|
||||
int send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
int on_stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||
int on_extend_max_streams();
|
||||
int handle_error();
|
||||
int make_stream_early();
|
||||
int change_local_addr();
|
||||
void start_change_local_addr_timer();
|
||||
int update_key(uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
|
||||
ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
|
||||
const uint8_t *current_rx_secret,
|
||||
const uint8_t *current_tx_secret, size_t secretlen);
|
||||
int initiate_key_update();
|
||||
void start_key_update_timer();
|
||||
void start_delay_stream_timer();
|
||||
|
||||
int select_preferred_address(Address &selected_addr,
|
||||
const ngtcp2_preferred_addr *paddr);
|
||||
|
||||
std::optional<Endpoint *> endpoint_for(const Address &remote_addr);
|
||||
|
||||
void set_remote_addr(const ngtcp2_addr &remote_addr);
|
||||
|
||||
int submit_http_request(Stream *stream);
|
||||
int recv_stream_data(uint32_t flags, int64_t stream_id,
|
||||
std::span<const uint8_t> data);
|
||||
int acked_stream_data_offset(int64_t stream_id, uint64_t offset,
|
||||
uint64_t datalen);
|
||||
int extend_max_stream_data(int64_t stream_id, uint64_t max_data);
|
||||
|
||||
void write_qlog(const void *data, size_t datalen);
|
||||
|
||||
void on_send_blocked(const ngtcp2_path &path, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
void start_wev_endpoint(const Endpoint &ep);
|
||||
int send_blocked_packet();
|
||||
ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest,
|
||||
size_t destlen, ngtcp2_tstamp ts);
|
||||
|
||||
const std::vector<uint32_t> &get_offered_versions() const;
|
||||
|
||||
void early_data_rejected();
|
||||
|
||||
bool should_exit() const;
|
||||
|
||||
private:
|
||||
std::vector<Endpoint> endpoints_;
|
||||
Address remote_addr_;
|
||||
ev_io wev_;
|
||||
ev_timer timer_;
|
||||
ev_timer change_local_addr_timer_;
|
||||
ev_timer key_update_timer_;
|
||||
ev_timer delay_stream_timer_;
|
||||
ev_signal sigintev_;
|
||||
struct ev_loop *loop_;
|
||||
std::unordered_map<int64_t, std::unique_ptr<Stream>> streams_;
|
||||
std::set<Stream *, StreamIDLess> sendq_;
|
||||
std::vector<uint32_t> offered_versions_;
|
||||
// addr_ is the server host address.
|
||||
const char *addr_;
|
||||
// port_ is the server port.
|
||||
const char *port_;
|
||||
// nstreams_done_ is the number of streams opened.
|
||||
size_t nstreams_done_;
|
||||
// nstreams_closed_ is the number of streams get closed.
|
||||
size_t nstreams_closed_;
|
||||
// nkey_update_ is the number of key update occurred.
|
||||
size_t nkey_update_;
|
||||
uint32_t client_chosen_version_;
|
||||
uint32_t original_version_;
|
||||
// early_data_ is true if client attempts to do 0RTT data transfer.
|
||||
bool early_data_;
|
||||
// handshake_confirmed_ gets true after handshake has been
|
||||
// confirmed.
|
||||
bool handshake_confirmed_;
|
||||
bool no_gso_;
|
||||
|
||||
struct {
|
||||
bool send_blocked;
|
||||
// blocked field is effective only when send_blocked is true.
|
||||
struct {
|
||||
const Endpoint *endpoint;
|
||||
Address remote_addr;
|
||||
unsigned int ecn;
|
||||
std::span<const uint8_t> data;
|
||||
size_t gso_size;
|
||||
} blocked;
|
||||
std::array<uint8_t, 64_k> data;
|
||||
} tx_;
|
||||
};
|
||||
|
||||
#endif // !defined(H09CLIENT_H)
|
||||
3294
deps/ngtcp2/ngtcp2/examples/h09server.cc
vendored
Normal file
3294
deps/ngtcp2/ngtcp2/examples/h09server.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
257
deps/ngtcp2/ngtcp2/examples/h09server.h
vendored
Normal file
257
deps/ngtcp2/ngtcp2/examples/h09server.h
vendored
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 H09SERVER_H
|
||||
#define H09SERVER_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <string_view>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <span>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include <ev.h>
|
||||
|
||||
#include "server_base.h"
|
||||
#include "tls_server_context.h"
|
||||
#include "network.h"
|
||||
#include "shared.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
struct HTTPHeader {
|
||||
HTTPHeader(const std::string_view &name, const std::string_view &value)
|
||||
: name(name), value(value) {}
|
||||
|
||||
std::string_view name;
|
||||
std::string_view value;
|
||||
};
|
||||
|
||||
class Handler;
|
||||
struct FileEntry;
|
||||
|
||||
struct Stream {
|
||||
Stream(int64_t stream_id, Handler *handler);
|
||||
|
||||
int start_response();
|
||||
std::pair<FileEntry, int> open_file(const std::string &path);
|
||||
void map_file(const FileEntry &fe);
|
||||
int send_status_response(unsigned int status_code);
|
||||
|
||||
int64_t stream_id;
|
||||
Handler *handler;
|
||||
// uri is request uri/path.
|
||||
std::string uri;
|
||||
std::string status_resp_body;
|
||||
nghttp3_buf respbuf;
|
||||
http_parser htp;
|
||||
// eos gets true when one HTTP request message is seen.
|
||||
bool eos;
|
||||
};
|
||||
|
||||
struct StreamIDLess {
|
||||
constexpr bool operator()(const Stream *lhs, const Stream *rhs) const {
|
||||
return lhs->stream_id < rhs->stream_id;
|
||||
}
|
||||
};
|
||||
|
||||
class Server;
|
||||
|
||||
// Endpoint is a local endpoint.
|
||||
struct Endpoint {
|
||||
Address addr;
|
||||
ev_io rev;
|
||||
Server *server;
|
||||
int fd;
|
||||
};
|
||||
|
||||
class Handler : public HandlerBase {
|
||||
public:
|
||||
Handler(struct ev_loop *loop, Server *server);
|
||||
~Handler();
|
||||
|
||||
int init(const Endpoint &ep, const Address &local_addr, const sockaddr *sa,
|
||||
socklen_t salen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid,
|
||||
const ngtcp2_cid *ocid, std::span<const uint8_t> token,
|
||||
ngtcp2_token_type token_type, uint32_t version,
|
||||
TLSServerContext &tls_ctx);
|
||||
|
||||
int on_read(const Endpoint &ep, const Address &local_addr, const sockaddr *sa,
|
||||
socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
int on_write();
|
||||
int write_streams();
|
||||
int feed_data(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
void update_timer();
|
||||
int handle_expiry();
|
||||
void signal_write();
|
||||
int handshake_completed();
|
||||
|
||||
Server *server() const;
|
||||
int recv_stream_data(uint32_t flags, int64_t stream_id,
|
||||
std::span<const uint8_t> data);
|
||||
int acked_stream_data_offset(int64_t stream_id, uint64_t offset,
|
||||
uint64_t datalen);
|
||||
uint32_t version() const;
|
||||
void on_stream_open(int64_t stream_id);
|
||||
int on_stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||
void start_draining_period();
|
||||
int start_closing_period();
|
||||
int handle_error();
|
||||
int send_conn_close();
|
||||
int send_conn_close(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi, std::span<const uint8_t> data);
|
||||
|
||||
int update_key(uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
|
||||
ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
|
||||
const uint8_t *current_rx_secret,
|
||||
const uint8_t *current_tx_secret, size_t secretlen);
|
||||
|
||||
Stream *find_stream(int64_t stream_id);
|
||||
int extend_max_stream_data(int64_t stream_id, uint64_t max_data);
|
||||
void shutdown_read(int64_t stream_id, uint64_t app_error_code);
|
||||
|
||||
void write_qlog(const void *data, size_t datalen);
|
||||
void add_sendq(Stream *stream);
|
||||
|
||||
void on_send_blocked(const ngtcp2_path &path, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
void start_wev_endpoint(const Endpoint &ep);
|
||||
int send_packet(const ngtcp2_path &path, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
int send_blocked_packet();
|
||||
|
||||
ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest,
|
||||
size_t destlen, ngtcp2_tstamp ts);
|
||||
|
||||
private:
|
||||
struct ev_loop *loop_;
|
||||
Server *server_;
|
||||
ev_io wev_;
|
||||
ev_timer timer_;
|
||||
FILE *qlog_;
|
||||
ngtcp2_cid scid_;
|
||||
std::unordered_map<int64_t, std::unique_ptr<Stream>> streams_;
|
||||
std::set<Stream *, StreamIDLess> sendq_;
|
||||
// conn_closebuf_ contains a packet which contains CONNECTION_CLOSE.
|
||||
// This packet is repeatedly sent as a response to the incoming
|
||||
// packet in draining period.
|
||||
std::unique_ptr<Buffer> conn_closebuf_;
|
||||
// nkey_update_ is the number of key update occurred.
|
||||
size_t nkey_update_;
|
||||
bool no_gso_;
|
||||
struct {
|
||||
size_t bytes_recv;
|
||||
size_t bytes_sent;
|
||||
size_t num_pkts_recv;
|
||||
size_t next_pkts_recv;
|
||||
} close_wait_;
|
||||
|
||||
struct {
|
||||
bool send_blocked;
|
||||
// blocked field is effective only when send_blocked is true.
|
||||
struct {
|
||||
const Endpoint *endpoint;
|
||||
Address local_addr;
|
||||
Address remote_addr;
|
||||
unsigned int ecn;
|
||||
std::span<const uint8_t> data;
|
||||
size_t gso_size;
|
||||
} blocked;
|
||||
std::unique_ptr<uint8_t[]> data;
|
||||
} tx_;
|
||||
};
|
||||
|
||||
class Server {
|
||||
public:
|
||||
Server(struct ev_loop *loop, TLSServerContext &tls_ctx);
|
||||
~Server();
|
||||
|
||||
int init(const char *addr, const char *port);
|
||||
void disconnect();
|
||||
void close();
|
||||
|
||||
int on_read(const Endpoint &ep);
|
||||
void read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
int send_version_negotiation(uint32_t version, std::span<const uint8_t> dcid,
|
||||
std::span<const uint8_t> scid,
|
||||
const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
int send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep,
|
||||
const Address &local_addr, const sockaddr *sa, socklen_t salen,
|
||||
size_t max_pktlen);
|
||||
int send_stateless_connection_close(const ngtcp2_pkt_hd *chd,
|
||||
const Endpoint &ep,
|
||||
const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
int send_stateless_reset(size_t pktlen, std::span<const uint8_t> dcid,
|
||||
const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
int verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
int verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa,
|
||||
socklen_t salen);
|
||||
int send_packet(const Endpoint &ep, const ngtcp2_addr &local_addr,
|
||||
const ngtcp2_addr &remote_addr, unsigned int ecn,
|
||||
std::span<const uint8_t> data);
|
||||
std::pair<std::span<const uint8_t>, int>
|
||||
send_packet(const Endpoint &ep, bool &no_gso, const ngtcp2_addr &local_addr,
|
||||
const ngtcp2_addr &remote_addr, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
void remove(const Handler *h);
|
||||
|
||||
void associate_cid(const ngtcp2_cid *cid, Handler *h);
|
||||
void dissociate_cid(const ngtcp2_cid *cid);
|
||||
|
||||
void on_stateless_reset_regen();
|
||||
|
||||
private:
|
||||
std::unordered_map<ngtcp2_cid, Handler *> handlers_;
|
||||
struct ev_loop *loop_;
|
||||
std::vector<Endpoint> endpoints_;
|
||||
TLSServerContext &tls_ctx_;
|
||||
ev_signal sigintev_;
|
||||
ev_timer stateless_reset_regen_timer_;
|
||||
size_t stateless_reset_bucket_;
|
||||
};
|
||||
|
||||
#endif // !defined(H09SERVER_H)
|
||||
140
deps/ngtcp2/ngtcp2/examples/http.cc
vendored
Normal file
140
deps/ngtcp2/ngtcp2/examples/http.cc
vendored
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
* Copyright (c) 2012 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "http.h"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
namespace http {
|
||||
|
||||
std::string_view get_reason_phrase(unsigned int status_code) {
|
||||
switch (status_code) {
|
||||
case 100:
|
||||
return "Continue"sv;
|
||||
case 101:
|
||||
return "Switching Protocols"sv;
|
||||
case 200:
|
||||
return "OK"sv;
|
||||
case 201:
|
||||
return "Created"sv;
|
||||
case 202:
|
||||
return "Accepted"sv;
|
||||
case 203:
|
||||
return "Non-Authoritative Information"sv;
|
||||
case 204:
|
||||
return "No Content"sv;
|
||||
case 205:
|
||||
return "Reset Content"sv;
|
||||
case 206:
|
||||
return "Partial Content"sv;
|
||||
case 300:
|
||||
return "Multiple Choices"sv;
|
||||
case 301:
|
||||
return "Moved Permanently"sv;
|
||||
case 302:
|
||||
return "Found"sv;
|
||||
case 303:
|
||||
return "See Other"sv;
|
||||
case 304:
|
||||
return "Not Modified"sv;
|
||||
case 305:
|
||||
return "Use Proxy"sv;
|
||||
// case 306: return "(Unused)"sv;
|
||||
case 307:
|
||||
return "Temporary Redirect"sv;
|
||||
case 308:
|
||||
return "Permanent Redirect"sv;
|
||||
case 400:
|
||||
return "Bad Request"sv;
|
||||
case 401:
|
||||
return "Unauthorized"sv;
|
||||
case 402:
|
||||
return "Payment Required"sv;
|
||||
case 403:
|
||||
return "Forbidden"sv;
|
||||
case 404:
|
||||
return "Not Found"sv;
|
||||
case 405:
|
||||
return "Method Not Allowed"sv;
|
||||
case 406:
|
||||
return "Not Acceptable"sv;
|
||||
case 407:
|
||||
return "Proxy Authentication Required"sv;
|
||||
case 408:
|
||||
return "Request Timeout"sv;
|
||||
case 409:
|
||||
return "Conflict"sv;
|
||||
case 410:
|
||||
return "Gone"sv;
|
||||
case 411:
|
||||
return "Length Required"sv;
|
||||
case 412:
|
||||
return "Precondition Failed"sv;
|
||||
case 413:
|
||||
return "Payload Too Large"sv;
|
||||
case 414:
|
||||
return "URI Too Long"sv;
|
||||
case 415:
|
||||
return "Unsupported Media Type"sv;
|
||||
case 416:
|
||||
return "Requested Range Not Satisfiable"sv;
|
||||
case 417:
|
||||
return "Expectation Failed"sv;
|
||||
case 421:
|
||||
return "Misdirected Request"sv;
|
||||
case 426:
|
||||
return "Upgrade Required"sv;
|
||||
case 428:
|
||||
return "Precondition Required"sv;
|
||||
case 429:
|
||||
return "Too Many Requests"sv;
|
||||
case 431:
|
||||
return "Request Header Fields Too Large"sv;
|
||||
case 451:
|
||||
return "Unavailable For Legal Reasons"sv;
|
||||
case 500:
|
||||
return "Internal Server Error"sv;
|
||||
case 501:
|
||||
return "Not Implemented"sv;
|
||||
case 502:
|
||||
return "Bad Gateway"sv;
|
||||
case 503:
|
||||
return "Service Unavailable"sv;
|
||||
case 504:
|
||||
return "Gateway Timeout"sv;
|
||||
case 505:
|
||||
return "HTTP Version Not Supported"sv;
|
||||
case 511:
|
||||
return "Network Authentication Required"sv;
|
||||
default:
|
||||
return ""sv;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace http
|
||||
|
||||
} // namespace ngtcp2
|
||||
44
deps/ngtcp2/ngtcp2/examples/http.h
vendored
Normal file
44
deps/ngtcp2/ngtcp2/examples/http.h
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 HTTP_H
|
||||
#define HTTP_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
namespace http {
|
||||
|
||||
std::string_view get_reason_phrase(unsigned int status_code);
|
||||
|
||||
} // namespace http
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
#endif // !defined(HTTP_H)
|
||||
80
deps/ngtcp2/ngtcp2/examples/network.h
vendored
Normal file
80
deps/ngtcp2/ngtcp2/examples/network.h
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
* Copyright (c) 2016 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 NETWORK_H
|
||||
#define NETWORK_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif // defined(HAVE_SYS_SOCKET_H)
|
||||
#include <sys/un.h>
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif // defined(HAVE_NETINET_IN_H)
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif // defined(HAVE_ARPA_INET_H)
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
enum network_error {
|
||||
NETWORK_ERR_OK = 0,
|
||||
NETWORK_ERR_FATAL = -10,
|
||||
NETWORK_ERR_SEND_BLOCKED = -11,
|
||||
NETWORK_ERR_CLOSE_WAIT = -12,
|
||||
NETWORK_ERR_RETRY = -13,
|
||||
NETWORK_ERR_DROP_CONN = -14,
|
||||
};
|
||||
|
||||
union in_addr_union {
|
||||
in_addr in;
|
||||
in6_addr in6;
|
||||
};
|
||||
|
||||
union sockaddr_union {
|
||||
sockaddr_storage storage;
|
||||
sockaddr sa;
|
||||
sockaddr_in6 in6;
|
||||
sockaddr_in in;
|
||||
};
|
||||
|
||||
struct Address {
|
||||
socklen_t len;
|
||||
union sockaddr_union su;
|
||||
uint32_t ifindex;
|
||||
};
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
#endif // !defined(NETWORK_H)
|
||||
4054
deps/ngtcp2/ngtcp2/examples/server.cc
vendored
Normal file
4054
deps/ngtcp2/ngtcp2/examples/server.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
276
deps/ngtcp2/ngtcp2/examples/server.h
vendored
Normal file
276
deps/ngtcp2/ngtcp2/examples/server.h
vendored
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <string_view>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include <ev.h>
|
||||
|
||||
#include "server_base.h"
|
||||
#include "tls_server_context.h"
|
||||
#include "network.h"
|
||||
#include "shared.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
struct HTTPHeader {
|
||||
HTTPHeader(const std::string_view &name, const std::string_view &value)
|
||||
: name(name), value(value) {}
|
||||
|
||||
std::string_view name;
|
||||
std::string_view value;
|
||||
};
|
||||
|
||||
class Handler;
|
||||
struct FileEntry;
|
||||
|
||||
struct Stream {
|
||||
Stream(int64_t stream_id, Handler *handler);
|
||||
|
||||
int start_response(nghttp3_conn *conn);
|
||||
std::pair<FileEntry, int> open_file(const std::string &path);
|
||||
void map_file(const FileEntry &fe);
|
||||
int send_status_response(nghttp3_conn *conn, unsigned int status_code,
|
||||
const std::vector<HTTPHeader> &extra_headers = {});
|
||||
int send_redirect_response(nghttp3_conn *conn, unsigned int status_code,
|
||||
const std::string_view &path);
|
||||
int64_t find_dyn_length(const std::string_view &path);
|
||||
void http_acked_stream_data(uint64_t datalen);
|
||||
|
||||
int64_t stream_id;
|
||||
Handler *handler;
|
||||
// uri is request uri/path.
|
||||
std::string uri;
|
||||
std::string method;
|
||||
std::string authority;
|
||||
std::string status_resp_body;
|
||||
// data is a pointer to the memory which maps file denoted by fd.
|
||||
uint8_t *data;
|
||||
// datalen is the length of mapped file by data.
|
||||
uint64_t datalen;
|
||||
// dynresp is true if dynamic data response is enabled.
|
||||
bool dynresp;
|
||||
// dyndataleft is the number of dynamic data left to send.
|
||||
uint64_t dyndataleft;
|
||||
// dynbuflen is the number of bytes in-flight.
|
||||
uint64_t dynbuflen;
|
||||
};
|
||||
|
||||
class Server;
|
||||
|
||||
// Endpoint is a local endpoint.
|
||||
struct Endpoint {
|
||||
Address addr;
|
||||
ev_io rev;
|
||||
Server *server;
|
||||
int fd;
|
||||
};
|
||||
|
||||
class Handler : public HandlerBase {
|
||||
public:
|
||||
Handler(struct ev_loop *loop, Server *server);
|
||||
~Handler();
|
||||
|
||||
int init(const Endpoint &ep, const Address &local_addr, const sockaddr *sa,
|
||||
socklen_t salen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid,
|
||||
const ngtcp2_cid *ocid, std::span<const uint8_t> token,
|
||||
ngtcp2_token_type token_type, uint32_t version,
|
||||
TLSServerContext &tls_ctx);
|
||||
|
||||
int on_read(const Endpoint &ep, const Address &local_addr, const sockaddr *sa,
|
||||
socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
int on_write();
|
||||
int write_streams();
|
||||
int feed_data(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
void update_timer();
|
||||
int handle_expiry();
|
||||
void signal_write();
|
||||
int handshake_completed();
|
||||
|
||||
Server *server() const;
|
||||
int recv_stream_data(uint32_t flags, int64_t stream_id,
|
||||
std::span<const uint8_t> data);
|
||||
int acked_stream_data_offset(int64_t stream_id, uint64_t datalen);
|
||||
uint32_t version() const;
|
||||
void on_stream_open(int64_t stream_id);
|
||||
int on_stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||
void start_draining_period();
|
||||
int start_closing_period();
|
||||
int handle_error();
|
||||
int send_conn_close();
|
||||
int send_conn_close(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi, std::span<const uint8_t> data);
|
||||
|
||||
int update_key(uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
|
||||
ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
|
||||
const uint8_t *current_rx_secret,
|
||||
const uint8_t *current_tx_secret, size_t secretlen);
|
||||
|
||||
int setup_httpconn();
|
||||
void http_consume(int64_t stream_id, size_t nconsumed);
|
||||
void extend_max_remote_streams_bidi(uint64_t max_streams);
|
||||
Stream *find_stream(int64_t stream_id);
|
||||
void http_begin_request_headers(int64_t stream_id);
|
||||
void http_recv_request_header(Stream *stream, int32_t token,
|
||||
nghttp3_rcbuf *name, nghttp3_rcbuf *value);
|
||||
int http_end_request_headers(Stream *stream);
|
||||
int http_end_stream(Stream *stream);
|
||||
int start_response(Stream *stream);
|
||||
int on_stream_reset(int64_t stream_id);
|
||||
int on_stream_stop_sending(int64_t stream_id);
|
||||
int extend_max_stream_data(int64_t stream_id, uint64_t max_data);
|
||||
void shutdown_read(int64_t stream_id, uint64_t app_error_code);
|
||||
void http_acked_stream_data(Stream *stream, uint64_t datalen);
|
||||
void http_stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||
int http_stop_sending(int64_t stream_id, uint64_t app_error_code);
|
||||
int http_reset_stream(int64_t stream_id, uint64_t app_error_code);
|
||||
|
||||
void write_qlog(const void *data, size_t datalen);
|
||||
|
||||
void on_send_blocked(const ngtcp2_path &path, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
void start_wev_endpoint(const Endpoint &ep);
|
||||
int send_packet(const ngtcp2_path &path, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
int send_blocked_packet();
|
||||
|
||||
ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest,
|
||||
size_t destlen, ngtcp2_tstamp ts);
|
||||
|
||||
private:
|
||||
struct ev_loop *loop_;
|
||||
Server *server_;
|
||||
ev_io wev_;
|
||||
ev_timer timer_;
|
||||
FILE *qlog_;
|
||||
ngtcp2_cid scid_;
|
||||
nghttp3_conn *httpconn_;
|
||||
std::unordered_map<int64_t, std::unique_ptr<Stream>> streams_;
|
||||
// conn_closebuf_ contains a packet which contains CONNECTION_CLOSE.
|
||||
// This packet is repeatedly sent as a response to the incoming
|
||||
// packet in draining period.
|
||||
std::unique_ptr<Buffer> conn_closebuf_;
|
||||
// nkey_update_ is the number of key update occurred.
|
||||
size_t nkey_update_;
|
||||
bool no_gso_;
|
||||
struct {
|
||||
size_t bytes_recv;
|
||||
size_t bytes_sent;
|
||||
size_t num_pkts_recv;
|
||||
size_t next_pkts_recv;
|
||||
} close_wait_;
|
||||
|
||||
struct {
|
||||
bool send_blocked;
|
||||
// blocked field is effective only when send_blocked is true.
|
||||
struct {
|
||||
const Endpoint *endpoint;
|
||||
Address local_addr;
|
||||
Address remote_addr;
|
||||
unsigned int ecn;
|
||||
std::span<const uint8_t> data;
|
||||
size_t gso_size;
|
||||
} blocked;
|
||||
std::unique_ptr<uint8_t[]> data;
|
||||
} tx_;
|
||||
};
|
||||
|
||||
class Server {
|
||||
public:
|
||||
Server(struct ev_loop *loop, TLSServerContext &tls_ctx);
|
||||
~Server();
|
||||
|
||||
int init(const char *addr, const char *port);
|
||||
void disconnect();
|
||||
void close();
|
||||
|
||||
int on_read(const Endpoint &ep);
|
||||
void read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
int send_version_negotiation(uint32_t version, std::span<const uint8_t> dcid,
|
||||
std::span<const uint8_t> scid,
|
||||
const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
int send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep,
|
||||
const Address &local_addr, const sockaddr *sa, socklen_t salen,
|
||||
size_t max_pktlen);
|
||||
int send_stateless_connection_close(const ngtcp2_pkt_hd *chd,
|
||||
const Endpoint &ep,
|
||||
const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
int send_stateless_reset(size_t pktlen, std::span<const uint8_t> dcid,
|
||||
const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
int verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
int verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa,
|
||||
socklen_t salen);
|
||||
int send_packet(const Endpoint &ep, const ngtcp2_addr &local_addr,
|
||||
const ngtcp2_addr &remote_addr, unsigned int ecn,
|
||||
std::span<const uint8_t> data);
|
||||
std::pair<std::span<const uint8_t>, int>
|
||||
send_packet(const Endpoint &ep, bool &no_gso, const ngtcp2_addr &local_addr,
|
||||
const ngtcp2_addr &remote_addr, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
void remove(const Handler *h);
|
||||
|
||||
void associate_cid(const ngtcp2_cid *cid, Handler *h);
|
||||
void dissociate_cid(const ngtcp2_cid *cid);
|
||||
|
||||
void on_stateless_reset_regen();
|
||||
|
||||
private:
|
||||
std::unordered_map<ngtcp2_cid, Handler *> handlers_;
|
||||
struct ev_loop *loop_;
|
||||
std::vector<Endpoint> endpoints_;
|
||||
TLSServerContext &tls_ctx_;
|
||||
ev_signal sigintev_;
|
||||
ev_timer stateless_reset_regen_timer_;
|
||||
size_t stateless_reset_bucket_;
|
||||
};
|
||||
|
||||
#endif // !defined(SERVER_H)
|
||||
58
deps/ngtcp2/ngtcp2/examples/server_base.cc
vendored
Normal file
58
deps/ngtcp2/ngtcp2/examples/server_base.cc
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "server_base.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
extern Config config;
|
||||
|
||||
Buffer::Buffer(const uint8_t *data, size_t datalen)
|
||||
: buf{data, data + datalen}, begin(buf.data()), tail(begin + datalen) {}
|
||||
Buffer::Buffer(size_t datalen) : buf(datalen), begin(buf.data()), tail(begin) {}
|
||||
|
||||
static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) {
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
return h->conn();
|
||||
}
|
||||
|
||||
HandlerBase::HandlerBase() : conn_ref_{get_conn, this}, conn_(nullptr) {
|
||||
ngtcp2_ccerr_default(&last_error_);
|
||||
}
|
||||
|
||||
HandlerBase::~HandlerBase() {
|
||||
if (conn_) {
|
||||
ngtcp2_conn_del(conn_);
|
||||
}
|
||||
}
|
||||
|
||||
ngtcp2_conn *HandlerBase::conn() const { return conn_; }
|
||||
|
||||
ngtcp2_crypto_conn_ref *HandlerBase::conn_ref() { return &conn_ref_; }
|
||||
204
deps/ngtcp2/ngtcp2/examples/server_base.h
vendored
Normal file
204
deps/ngtcp2/ngtcp2/examples/server_base.h
vendored
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 SERVER_BASE_H
|
||||
#define SERVER_BASE_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <functional>
|
||||
#include <span>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
|
||||
#include "tls_server_session.h"
|
||||
#include "network.h"
|
||||
#include "shared.h"
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
struct Config {
|
||||
Address preferred_ipv4_addr;
|
||||
Address preferred_ipv6_addr;
|
||||
// tx_loss_prob is probability of losing outgoing packet.
|
||||
double tx_loss_prob;
|
||||
// rx_loss_prob is probability of losing incoming packet.
|
||||
double rx_loss_prob;
|
||||
// ciphers is the list of enabled ciphers.
|
||||
const char *ciphers;
|
||||
// groups is the list of supported groups.
|
||||
const char *groups;
|
||||
// htdocs is a root directory to serve documents.
|
||||
std::string htdocs;
|
||||
// mime_types_file is a path to "MIME media types and the
|
||||
// extensions" file. Ubuntu mime-support package includes it in
|
||||
// /etc/mime/types.
|
||||
std::string_view mime_types_file;
|
||||
// mime_types maps file extension to MIME media type.
|
||||
std::unordered_map<std::string, std::string> mime_types;
|
||||
// port is the port number which server listens on for incoming
|
||||
// connections.
|
||||
uint16_t port;
|
||||
// quiet suppresses the output normally shown except for the error
|
||||
// messages.
|
||||
bool quiet;
|
||||
// timeout is an idle timeout for QUIC connection.
|
||||
ngtcp2_duration timeout;
|
||||
// show_secret is true if transport secrets should be printed out.
|
||||
bool show_secret;
|
||||
// validate_addr is true if server requires address validation.
|
||||
bool validate_addr;
|
||||
// early_response is true if server starts sending response when it
|
||||
// receives HTTP header fields without waiting for request body. If
|
||||
// HTTP response data is written before receiving request body,
|
||||
// STOP_SENDING is sent.
|
||||
bool early_response;
|
||||
// verify_client is true if server verifies client with X.509
|
||||
// certificate based authentication.
|
||||
bool verify_client;
|
||||
// qlog_dir is the path to directory where qlog is stored.
|
||||
std::string_view qlog_dir;
|
||||
// no_quic_dump is true if hexdump of QUIC STREAM and CRYPTO data
|
||||
// should be disabled.
|
||||
bool no_quic_dump;
|
||||
// no_http_dump is true if hexdump of HTTP response body should be
|
||||
// disabled.
|
||||
bool no_http_dump;
|
||||
// max_data is the initial connection-level flow control window.
|
||||
uint64_t max_data;
|
||||
// max_stream_data_bidi_local is the initial stream-level flow
|
||||
// control window for a bidirectional stream that the local endpoint
|
||||
// initiates.
|
||||
uint64_t max_stream_data_bidi_local;
|
||||
// max_stream_data_bidi_remote is the initial stream-level flow
|
||||
// control window for a bidirectional stream that the remote
|
||||
// endpoint initiates.
|
||||
uint64_t max_stream_data_bidi_remote;
|
||||
// max_stream_data_uni is the initial stream-level flow control
|
||||
// window for a unidirectional stream.
|
||||
uint64_t max_stream_data_uni;
|
||||
// max_streams_bidi is the number of the concurrent bidirectional
|
||||
// streams.
|
||||
uint64_t max_streams_bidi;
|
||||
// max_streams_uni is the number of the concurrent unidirectional
|
||||
// streams.
|
||||
uint64_t max_streams_uni;
|
||||
// max_window is the maximum connection-level flow control window
|
||||
// size if auto-tuning is enabled.
|
||||
uint64_t max_window;
|
||||
// max_stream_window is the maximum stream-level flow control window
|
||||
// size if auto-tuning is enabled.
|
||||
uint64_t max_stream_window;
|
||||
// max_dyn_length is the maximum length of dynamically generated
|
||||
// response.
|
||||
uint64_t max_dyn_length;
|
||||
// static_secret is used to derive keying materials for Retry and
|
||||
// Stateless Retry token.
|
||||
std::array<uint8_t, 32> static_secret;
|
||||
// cc_algo is the congestion controller algorithm.
|
||||
ngtcp2_cc_algo cc_algo;
|
||||
// initial_rtt is an initial RTT.
|
||||
ngtcp2_duration initial_rtt;
|
||||
// max_udp_payload_size is the maximum UDP payload size that server
|
||||
// transmits.
|
||||
size_t max_udp_payload_size;
|
||||
// send_trailers controls whether server sends trailer fields or
|
||||
// not.
|
||||
bool send_trailers;
|
||||
// handshake_timeout is the period of time before giving up QUIC
|
||||
// connection establishment.
|
||||
ngtcp2_duration handshake_timeout;
|
||||
// preferred_versions includes QUIC versions in the order of
|
||||
// preference. Server negotiates one of those versions if a client
|
||||
// initially selects a less preferred version.
|
||||
std::vector<uint32_t> preferred_versions;
|
||||
// available_versions includes QUIC versions that are sent in
|
||||
// available_versions field of version_information
|
||||
// transport_parameter.
|
||||
std::vector<uint32_t> available_versions;
|
||||
// no_pmtud disables Path MTU Discovery.
|
||||
bool no_pmtud;
|
||||
// ack_thresh is the minimum number of the received ACK eliciting
|
||||
// packets that triggers immediate acknowledgement.
|
||||
size_t ack_thresh;
|
||||
// initial_pkt_num is the initial packet number for each packet
|
||||
// number space. If it is set to UINT32_MAX, it is chosen randomly.
|
||||
uint32_t initial_pkt_num;
|
||||
// pmtud_probes is the array of UDP datagram payload size to probes.
|
||||
std::vector<uint16_t> pmtud_probes;
|
||||
// ech_config contains server-side ECH configuration.
|
||||
util::ECHServerConfig ech_config;
|
||||
// origin_list contains a payload of ORIGIN frame.
|
||||
std::optional<std::vector<uint8_t>> origin_list;
|
||||
};
|
||||
|
||||
struct Buffer {
|
||||
Buffer(const uint8_t *data, size_t datalen);
|
||||
explicit Buffer(size_t datalen);
|
||||
|
||||
size_t size() const { return as_unsigned(tail - begin); }
|
||||
size_t left() const { return as_unsigned(buf.data() + buf.size() - tail); }
|
||||
uint8_t *const wpos() { return tail; }
|
||||
std::span<const uint8_t> data() const { return {begin, size()}; }
|
||||
void push(size_t len) { tail += len; }
|
||||
void reset() { tail = begin; }
|
||||
|
||||
std::vector<uint8_t> buf;
|
||||
// begin points to the beginning of the buffer. This might point to
|
||||
// buf.data() if a buffer space is allocated by this object. It is
|
||||
// also allowed to point to the external shared buffer.
|
||||
uint8_t *begin;
|
||||
// tail points to the position of the buffer where write should
|
||||
// occur.
|
||||
uint8_t *tail;
|
||||
};
|
||||
|
||||
class HandlerBase {
|
||||
public:
|
||||
HandlerBase();
|
||||
~HandlerBase();
|
||||
|
||||
ngtcp2_conn *conn() const;
|
||||
|
||||
TLSServerSession *get_session() { return &tls_session_; }
|
||||
|
||||
ngtcp2_crypto_conn_ref *conn_ref();
|
||||
|
||||
protected:
|
||||
ngtcp2_crypto_conn_ref conn_ref_;
|
||||
TLSServerSession tls_session_;
|
||||
ngtcp2_conn *conn_;
|
||||
ngtcp2_ccerr last_error_;
|
||||
};
|
||||
|
||||
#endif // !defined(SERVER_BASE_H)
|
||||
507
deps/ngtcp2/ngtcp2/examples/shared.cc
vendored
Normal file
507
deps/ngtcp2/ngtcp2/examples/shared.cc
vendored
Normal file
|
|
@ -0,0 +1,507 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2019 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "shared.h"
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif // defined(HAVE_NETINET_IN_H)
|
||||
#ifdef HAVE_NETINET_UDP_H
|
||||
# include <netinet/udp.h>
|
||||
#endif // defined(HAVE_NETINET_UDP_H)
|
||||
#ifdef HAVE_NETINET_IP_H
|
||||
# include <netinet/ip.h>
|
||||
#endif // defined(HAVE_NETINET_IP_H)
|
||||
#ifdef HAVE_ASM_TYPES_H
|
||||
# include <asm/types.h>
|
||||
#endif // defined(HAVE_ASM_TYPES_H)
|
||||
#ifdef HAVE_LINUX_NETLINK_H
|
||||
# include <linux/netlink.h>
|
||||
#endif // defined(HAVE_LINUX_NETLINK_H)
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
# include <linux/rtnetlink.h>
|
||||
#endif // defined(HAVE_LINUX_RTNETLINK_H)
|
||||
|
||||
#include "template.h"
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
uint8_t msghdr_get_ecn(msghdr *msg, int family) {
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == IPPROTO_IP &&
|
||||
#ifdef __APPLE__
|
||||
cmsg->cmsg_type == IP_RECVTOS
|
||||
#else // !defined(__APPLE__)
|
||||
cmsg->cmsg_type == IP_TOS
|
||||
#endif // !defined(__APPLE__)
|
||||
&& cmsg->cmsg_len) {
|
||||
return *reinterpret_cast<uint8_t *>(CMSG_DATA(cmsg)) & IPTOS_ECN_MASK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_TCLASS &&
|
||||
cmsg->cmsg_len) {
|
||||
unsigned int tos;
|
||||
|
||||
memcpy(&tos, CMSG_DATA(cmsg), sizeof(int));
|
||||
|
||||
return tos & IPTOS_ECN_MASK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fd_set_recv_ecn(int fd, int family) {
|
||||
unsigned int tos = 1;
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_RECVTOS, &tos,
|
||||
static_cast<socklen_t>(sizeof(tos))) == -1) {
|
||||
std::cerr << "setsockopt: " << strerror(errno) << std::endl;
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVTCLASS, &tos,
|
||||
static_cast<socklen_t>(sizeof(tos))) == -1) {
|
||||
std::cerr << "setsockopt: " << strerror(errno) << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void fd_set_ip_mtu_discover(int fd, int family) {
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IPV6_MTU_DISCOVER)
|
||||
int val;
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
val = IP_PMTUDISC_PROBE;
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &val,
|
||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||
std::cerr << "setsockopt: IP_MTU_DISCOVER: " << strerror(errno)
|
||||
<< std::endl;
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
val = IPV6_PMTUDISC_PROBE;
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
|
||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||
std::cerr << "setsockopt: IPV6_MTU_DISCOVER: " << strerror(errno)
|
||||
<< std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif // defined(IP_MTU_DISCOVER) && defined(IPV6_MTU_DISCOVER)
|
||||
}
|
||||
|
||||
void fd_set_ip_dontfrag(int fd, int family) {
|
||||
#if defined(IP_DONTFRAG) && defined(IPV6_DONTFRAG)
|
||||
int val = 1;
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &val,
|
||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||
std::cerr << "setsockopt: IP_DONTFRAG: " << strerror(errno) << std::endl;
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_DONTFRAG, &val,
|
||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||
std::cerr << "setsockopt: IPV6_DONTFRAG: " << strerror(errno)
|
||||
<< std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif // defined(IP_DONTFRAG) && defined(IPV6_DONTFRAG)
|
||||
}
|
||||
|
||||
void fd_set_udp_gro(int fd) {
|
||||
#ifdef UDP_GRO
|
||||
int val = 1;
|
||||
|
||||
if (setsockopt(fd, IPPROTO_UDP, UDP_GRO, &val,
|
||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||
std::cerr << "setsockopt: UDP_GRO: " << strerror(errno) << std::endl;
|
||||
}
|
||||
#endif // defined(UDP_GRO)
|
||||
}
|
||||
|
||||
std::optional<Address> msghdr_get_local_addr(msghdr *msg, int family) {
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
|
||||
in_pktinfo pktinfo;
|
||||
memcpy(&pktinfo, CMSG_DATA(cmsg), sizeof(pktinfo));
|
||||
Address res{
|
||||
.len = sizeof(res.su.in),
|
||||
.ifindex = static_cast<uint32_t>(pktinfo.ipi_ifindex),
|
||||
};
|
||||
auto &sa = res.su.in;
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_addr = pktinfo.ipi_addr;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
case AF_INET6:
|
||||
for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
|
||||
in6_pktinfo pktinfo;
|
||||
memcpy(&pktinfo, CMSG_DATA(cmsg), sizeof(pktinfo));
|
||||
Address res{
|
||||
.len = sizeof(res.su.in6),
|
||||
.ifindex = static_cast<uint32_t>(pktinfo.ipi6_ifindex),
|
||||
};
|
||||
auto &sa = res.su.in6;
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_addr = pktinfo.ipi6_addr;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t msghdr_get_udp_gro(msghdr *msg) {
|
||||
int gso_size = 0;
|
||||
|
||||
#ifdef UDP_GRO
|
||||
for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == SOL_UDP && cmsg->cmsg_type == UDP_GRO) {
|
||||
memcpy(&gso_size, CMSG_DATA(cmsg), sizeof(gso_size));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // defined(UDP_GRO)
|
||||
|
||||
return static_cast<size_t>(gso_size);
|
||||
}
|
||||
|
||||
void set_port(Address &dst, const Address &src) {
|
||||
switch (dst.su.storage.ss_family) {
|
||||
case AF_INET:
|
||||
assert(AF_INET == src.su.storage.ss_family);
|
||||
dst.su.in.sin_port = src.su.in.sin_port;
|
||||
return;
|
||||
case AF_INET6:
|
||||
assert(AF_INET6 == src.su.storage.ss_family);
|
||||
dst.su.in6.sin6_port = src.su.in6.sin6_port;
|
||||
return;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
|
||||
struct nlmsg {
|
||||
nlmsghdr hdr;
|
||||
rtmsg msg;
|
||||
rtattr dst;
|
||||
in_addr_union dst_addr;
|
||||
};
|
||||
|
||||
namespace {
|
||||
int send_netlink_msg(int fd, const Address &remote_addr, uint32_t seq) {
|
||||
nlmsg nlmsg{
|
||||
.hdr =
|
||||
{
|
||||
.nlmsg_type = RTM_GETROUTE,
|
||||
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
|
||||
.nlmsg_seq = seq,
|
||||
},
|
||||
.msg =
|
||||
{
|
||||
.rtm_family = static_cast<unsigned char>(remote_addr.su.sa.sa_family),
|
||||
.rtm_protocol = RTPROT_KERNEL,
|
||||
},
|
||||
.dst =
|
||||
{
|
||||
.rta_type = RTA_DST,
|
||||
},
|
||||
};
|
||||
|
||||
switch (remote_addr.su.sa.sa_family) {
|
||||
case AF_INET:
|
||||
nlmsg.dst.rta_len = RTA_LENGTH(sizeof(remote_addr.su.in.sin_addr));
|
||||
memcpy(RTA_DATA(&nlmsg.dst), &remote_addr.su.in.sin_addr,
|
||||
sizeof(remote_addr.su.in.sin_addr));
|
||||
break;
|
||||
case AF_INET6:
|
||||
nlmsg.dst.rta_len = RTA_LENGTH(sizeof(remote_addr.su.in6.sin6_addr));
|
||||
memcpy(RTA_DATA(&nlmsg.dst), &remote_addr.su.in6.sin6_addr,
|
||||
sizeof(remote_addr.su.in6.sin6_addr));
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
nlmsg.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(nlmsg.msg) + nlmsg.dst.rta_len);
|
||||
|
||||
sockaddr_nl sa{
|
||||
.nl_family = AF_NETLINK,
|
||||
};
|
||||
|
||||
iovec iov{
|
||||
.iov_base = &nlmsg,
|
||||
.iov_len = nlmsg.hdr.nlmsg_len,
|
||||
};
|
||||
msghdr msg{
|
||||
.msg_name = &sa,
|
||||
.msg_namelen = sizeof(sa),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
ssize_t nwrite;
|
||||
|
||||
do {
|
||||
nwrite = sendmsg(fd, &msg, 0);
|
||||
} while (nwrite == -1 && errno == EINTR);
|
||||
|
||||
if (nwrite == -1) {
|
||||
std::cerr << "sendmsg: Could not write netlink message: " << strerror(errno)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int recv_netlink_msg(in_addr_union &iau, int fd, uint32_t seq) {
|
||||
std::array<uint8_t, 8192> buf;
|
||||
iovec iov = {
|
||||
.iov_base = buf.data(),
|
||||
.iov_len = buf.size(),
|
||||
};
|
||||
sockaddr_nl sa{};
|
||||
msghdr msg{
|
||||
.msg_name = &sa,
|
||||
.msg_namelen = sizeof(sa),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
ssize_t nread;
|
||||
|
||||
do {
|
||||
nread = recvmsg(fd, &msg, 0);
|
||||
} while (nread == -1 && errno == EINTR);
|
||||
|
||||
if (nread == -1) {
|
||||
std::cerr << "recvmsg: Could not receive netlink message: "
|
||||
<< strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t in_addrlen = 0;
|
||||
|
||||
for (auto hdr = reinterpret_cast<nlmsghdr *>(buf.data());
|
||||
NLMSG_OK(hdr, nread); hdr = NLMSG_NEXT(hdr, nread)) {
|
||||
if (seq != hdr->nlmsg_seq) {
|
||||
std::cerr << "netlink: unexpected sequence number " << hdr->nlmsg_seq
|
||||
<< " while expecting " << seq << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->nlmsg_flags & NLM_F_MULTI) {
|
||||
std::cerr << "netlink: unexpected NLM_F_MULTI flag set" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (hdr->nlmsg_type) {
|
||||
case NLMSG_DONE:
|
||||
std::cerr << "netlink: unexpected NLMSG_DONE" << std::endl;
|
||||
return -1;
|
||||
case NLMSG_NOOP:
|
||||
continue;
|
||||
case NLMSG_ERROR:
|
||||
std::cerr << "netlink: "
|
||||
<< strerror(-static_cast<nlmsgerr *>(NLMSG_DATA(hdr))->error)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto attrlen = hdr->nlmsg_len - NLMSG_SPACE(sizeof(rtmsg));
|
||||
|
||||
for (auto rta = reinterpret_cast<rtattr *>(
|
||||
static_cast<uint8_t *>(NLMSG_DATA(hdr)) + sizeof(rtmsg));
|
||||
RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) {
|
||||
if (rta->rta_type != RTA_PREFSRC) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (static_cast<rtmsg *>(NLMSG_DATA(hdr))->rtm_family) {
|
||||
case AF_INET:
|
||||
in_addrlen = sizeof(in_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
in_addrlen = sizeof(in6_addr);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
if (RTA_LENGTH(in_addrlen) != rta->rta_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&iau, RTA_DATA(rta), in_addrlen);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_addrlen == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read ACK
|
||||
sa = {};
|
||||
msg = {};
|
||||
|
||||
msg.msg_name = &sa;
|
||||
msg.msg_namelen = sizeof(sa);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
int error = -1;
|
||||
|
||||
do {
|
||||
nread = recvmsg(fd, &msg, 0);
|
||||
} while (nread == -1 && errno == EINTR);
|
||||
|
||||
if (nread == -1) {
|
||||
std::cerr << "recvmsg: Could not receive netlink message: "
|
||||
<< strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = -1;
|
||||
|
||||
for (auto hdr = reinterpret_cast<nlmsghdr *>(buf.data());
|
||||
NLMSG_OK(hdr, nread); hdr = NLMSG_NEXT(hdr, nread)) {
|
||||
if (seq != hdr->nlmsg_seq) {
|
||||
std::cerr << "netlink: unexpected sequence number " << hdr->nlmsg_seq
|
||||
<< " while expecting " << seq << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->nlmsg_flags & NLM_F_MULTI) {
|
||||
std::cerr << "netlink: unexpected NLM_F_MULTI flag set" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (hdr->nlmsg_type) {
|
||||
case NLMSG_DONE:
|
||||
std::cerr << "netlink: unexpected NLMSG_DONE" << std::endl;
|
||||
return -1;
|
||||
case NLMSG_NOOP:
|
||||
continue;
|
||||
case NLMSG_ERROR:
|
||||
error = -static_cast<nlmsgerr *>(NLMSG_DATA(hdr))->error;
|
||||
if (error == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::cerr << "netlink: " << strerror(error) << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (error != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int get_local_addr(in_addr_union &iau, const Address &remote_addr) {
|
||||
sockaddr_nl sa{
|
||||
.nl_family = AF_NETLINK,
|
||||
};
|
||||
|
||||
auto fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (fd == -1) {
|
||||
std::cerr << "socket: Could not create netlink socket: " << strerror(errno)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto fd_d = defer(close, fd);
|
||||
|
||||
if (bind(fd, reinterpret_cast<sockaddr *>(&sa), sizeof(sa)) == -1) {
|
||||
std::cerr << "bind: Could not bind netlink socket: " << strerror(errno)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t seq = 1;
|
||||
|
||||
if (send_netlink_msg(fd, remote_addr, seq) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return recv_netlink_msg(iau, fd, seq);
|
||||
}
|
||||
|
||||
#endif // defined(HAVE_LINUX_NETLINK_H)
|
||||
|
||||
bool addreq(const sockaddr *sa, const in_addr_union &iau) {
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
return memcmp(&reinterpret_cast<const sockaddr_in *>(sa)->sin_addr, &iau.in,
|
||||
sizeof(iau.in)) == 0;
|
||||
case AF_INET6:
|
||||
return memcmp(&reinterpret_cast<const sockaddr_in6 *>(sa)->sin6_addr,
|
||||
&iau.in6, sizeof(iau.in6)) == 0;
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ngtcp2
|
||||
99
deps/ngtcp2/ngtcp2/examples/shared.h
vendored
Normal file
99
deps/ngtcp2/ngtcp2/examples/shared.h
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 SHARED_H
|
||||
#define SHARED_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <span>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
#include "network.h"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
enum class AppProtocol {
|
||||
H3,
|
||||
HQ,
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
consteval std::span<const uint8_t> as_uint8_span(const uint8_t (&s)[N]) {
|
||||
return {s, N - 1};
|
||||
}
|
||||
|
||||
constexpr uint8_t RAW_HQ_ALPN[] = "\xahq-interop";
|
||||
constexpr auto HQ_ALPN = as_uint8_span(RAW_HQ_ALPN);
|
||||
constexpr auto HQ_ALPN_V1 = as_uint8_span(RAW_HQ_ALPN);
|
||||
|
||||
constexpr uint8_t RAW_H3_ALPN[] = "\x2h3";
|
||||
constexpr auto H3_ALPN = as_uint8_span(RAW_H3_ALPN);
|
||||
constexpr auto H3_ALPN_V1 = as_uint8_span(RAW_H3_ALPN);
|
||||
|
||||
constexpr uint32_t TLS_ALERT_ECH_REQUIRED = 121;
|
||||
|
||||
// msghdr_get_ecn gets ECN bits from |msg|. |family| is the address
|
||||
// family from which packet is received.
|
||||
uint8_t msghdr_get_ecn(msghdr *msg, int family);
|
||||
|
||||
// fd_set_recv_ecn sets socket option to |fd| so that it can receive
|
||||
// ECN bits.
|
||||
void fd_set_recv_ecn(int fd, int family);
|
||||
|
||||
// fd_set_ip_mtu_discover sets IP(V6)_MTU_DISCOVER socket option to
|
||||
// |fd|.
|
||||
void fd_set_ip_mtu_discover(int fd, int family);
|
||||
|
||||
// fd_set_ip_dontfrag sets IP(V6)_DONTFRAG socket option to |fd|.
|
||||
void fd_set_ip_dontfrag(int fd, int family);
|
||||
|
||||
// fd_set_udp_gro sets UDP_GRO socket option to |fd|.
|
||||
void fd_set_udp_gro(int fd);
|
||||
|
||||
std::optional<Address> msghdr_get_local_addr(msghdr *msg, int family);
|
||||
|
||||
// msghdr_get_udp_gro returns UDP_GRO value from |msg|. If UDP_GRO is
|
||||
// not found, or UDP_GRO is not supported, this function returns 0.
|
||||
size_t msghdr_get_udp_gro(msghdr *msg);
|
||||
|
||||
void set_port(Address &dst, const Address &src);
|
||||
|
||||
// get_local_addr stores preferred local address (interface address)
|
||||
// in |iau| for a given destination address |remote_addr|.
|
||||
int get_local_addr(in_addr_union &iau, const Address &remote_addr);
|
||||
|
||||
// addreq returns true if |sa| and |iau| contain the same address.
|
||||
bool addreq(const sockaddr *sa, const in_addr_union &iau);
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
#endif // !defined(SHARED_H)
|
||||
662
deps/ngtcp2/ngtcp2/examples/simpleclient.c
vendored
Normal file
662
deps/ngtcp2/ngtcp2/examples/simpleclient.c
vendored
Normal file
|
|
@ -0,0 +1,662 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2021 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* defined(HAVE_CONFIG_H) */
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
#include <ngtcp2/ngtcp2_crypto_quictls.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <ev.h>
|
||||
|
||||
#define REMOTE_HOST "127.0.0.1"
|
||||
#define REMOTE_PORT "4433"
|
||||
#define ALPN "\xahq-interop"
|
||||
#define MESSAGE "GET /\r\n"
|
||||
|
||||
/*
|
||||
* Example 1: Handshake with www.google.com
|
||||
*
|
||||
* #define REMOTE_HOST "www.google.com"
|
||||
* #define REMOTE_PORT "443"
|
||||
* #define ALPN "\x2h3"
|
||||
*
|
||||
* and undefine MESSAGE macro.
|
||||
*/
|
||||
|
||||
static uint64_t timestamp(void) {
|
||||
struct timespec tp;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0) {
|
||||
fprintf(stderr, "clock_gettime: %s\n", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return (uint64_t)tp.tv_sec * NGTCP2_SECONDS + (uint64_t)tp.tv_nsec;
|
||||
}
|
||||
|
||||
static int create_sock(struct sockaddr *addr, socklen_t *paddrlen,
|
||||
const char *host, const char *port) {
|
||||
struct addrinfo hints = {0};
|
||||
struct addrinfo *res, *rp;
|
||||
int rv;
|
||||
int fd = -1;
|
||||
|
||||
hints.ai_flags = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
rv = getaddrinfo(host, port, &hints, &res);
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (rp = res; rp; rp = rp->ai_next) {
|
||||
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if (fd == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
*paddrlen = rp->ai_addrlen;
|
||||
memcpy(addr, rp->ai_addr, rp->ai_addrlen);
|
||||
|
||||
end:
|
||||
freeaddrinfo(res);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int connect_sock(struct sockaddr *local_addr, socklen_t *plocal_addrlen,
|
||||
int fd, const struct sockaddr *remote_addr,
|
||||
size_t remote_addrlen) {
|
||||
socklen_t len;
|
||||
|
||||
if (connect(fd, remote_addr, (socklen_t)remote_addrlen) != 0) {
|
||||
fprintf(stderr, "connect: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = *plocal_addrlen;
|
||||
|
||||
if (getsockname(fd, local_addr, &len) == -1) {
|
||||
fprintf(stderr, "getsockname: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
*plocal_addrlen = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct client {
|
||||
ngtcp2_crypto_conn_ref conn_ref;
|
||||
int fd;
|
||||
struct sockaddr_storage local_addr;
|
||||
socklen_t local_addrlen;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL *ssl;
|
||||
ngtcp2_conn *conn;
|
||||
|
||||
struct {
|
||||
int64_t stream_id;
|
||||
const uint8_t *data;
|
||||
size_t datalen;
|
||||
size_t nwrite;
|
||||
} stream;
|
||||
|
||||
ngtcp2_ccerr last_error;
|
||||
|
||||
ev_io rev;
|
||||
ev_timer timer;
|
||||
};
|
||||
|
||||
static int numeric_host_family(const char *hostname, int family) {
|
||||
uint8_t dst[sizeof(struct in6_addr)];
|
||||
return inet_pton(family, hostname, dst) == 1;
|
||||
}
|
||||
|
||||
static int numeric_host(const char *hostname) {
|
||||
return numeric_host_family(hostname, AF_INET) ||
|
||||
numeric_host_family(hostname, AF_INET6);
|
||||
}
|
||||
|
||||
static int client_ssl_init(struct client *c) {
|
||||
c->ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||
if (!c->ssl_ctx) {
|
||||
fprintf(stderr, "SSL_CTX_new: %s\n",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_quictls_configure_client_context(c->ssl_ctx) != 0) {
|
||||
fprintf(stderr, "ngtcp2_crypto_quictls_configure_client_context failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
c->ssl = SSL_new(c->ssl_ctx);
|
||||
if (!c->ssl) {
|
||||
fprintf(stderr, "SSL_new: %s\n", ERR_error_string(ERR_get_error(), NULL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_set_app_data(c->ssl, &c->conn_ref);
|
||||
SSL_set_connect_state(c->ssl);
|
||||
SSL_set_alpn_protos(c->ssl, (const unsigned char *)ALPN, sizeof(ALPN) - 1);
|
||||
if (!numeric_host(REMOTE_HOST)) {
|
||||
SSL_set_tlsext_host_name(c->ssl, REMOTE_HOST);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rand_cb(uint8_t *dest, size_t destlen,
|
||||
const ngtcp2_rand_ctx *rand_ctx) {
|
||||
int rv;
|
||||
(void)rand_ctx;
|
||||
|
||||
rv = RAND_bytes(dest, (int)destlen);
|
||||
if (rv != 1) {
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static int get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid,
|
||||
uint8_t *token, size_t cidlen,
|
||||
void *user_data) {
|
||||
(void)conn;
|
||||
(void)user_data;
|
||||
|
||||
if (RAND_bytes(cid->data, (int)cidlen) != 1) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
cid->datalen = cidlen;
|
||||
|
||||
if (RAND_bytes(token, NGTCP2_STATELESS_RESET_TOKENLEN) != 1) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int extend_max_local_streams_bidi(ngtcp2_conn *conn,
|
||||
uint64_t max_streams,
|
||||
void *user_data) {
|
||||
#ifdef MESSAGE
|
||||
struct client *c = user_data;
|
||||
int rv;
|
||||
int64_t stream_id;
|
||||
(void)max_streams;
|
||||
|
||||
if (c->stream.stream_id != -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = ngtcp2_conn_open_bidi_stream(conn, &stream_id, NULL);
|
||||
if (rv != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->stream.stream_id = stream_id;
|
||||
c->stream.data = (const uint8_t *)MESSAGE;
|
||||
c->stream.datalen = sizeof(MESSAGE) - 1;
|
||||
|
||||
return 0;
|
||||
#else /* !defined(MESSAGE) */
|
||||
(void)conn;
|
||||
(void)max_streams;
|
||||
(void)user_data;
|
||||
|
||||
return 0;
|
||||
#endif /* !defined(MESSAGE) */
|
||||
}
|
||||
|
||||
static void log_printf(void *user_data, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
(void)user_data;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static int client_quic_init(struct client *c,
|
||||
const struct sockaddr *remote_addr,
|
||||
socklen_t remote_addrlen,
|
||||
const struct sockaddr *local_addr,
|
||||
socklen_t local_addrlen) {
|
||||
ngtcp2_path path = {
|
||||
.local =
|
||||
{
|
||||
.addr = (struct sockaddr *)local_addr,
|
||||
.addrlen = local_addrlen,
|
||||
},
|
||||
.remote =
|
||||
{
|
||||
.addr = (struct sockaddr *)remote_addr,
|
||||
.addrlen = remote_addrlen,
|
||||
},
|
||||
};
|
||||
ngtcp2_callbacks callbacks = {
|
||||
.client_initial = ngtcp2_crypto_client_initial_cb,
|
||||
.recv_crypto_data = ngtcp2_crypto_recv_crypto_data_cb,
|
||||
.encrypt = ngtcp2_crypto_encrypt_cb,
|
||||
.decrypt = ngtcp2_crypto_decrypt_cb,
|
||||
.hp_mask = ngtcp2_crypto_hp_mask_cb,
|
||||
.recv_retry = ngtcp2_crypto_recv_retry_cb,
|
||||
.extend_max_local_streams_bidi = extend_max_local_streams_bidi,
|
||||
.rand = rand_cb,
|
||||
.get_new_connection_id = get_new_connection_id_cb,
|
||||
.update_key = ngtcp2_crypto_update_key_cb,
|
||||
.delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb,
|
||||
.delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
|
||||
.get_path_challenge_data = ngtcp2_crypto_get_path_challenge_data_cb,
|
||||
.version_negotiation = ngtcp2_crypto_version_negotiation_cb,
|
||||
};
|
||||
ngtcp2_cid dcid, scid;
|
||||
ngtcp2_settings settings;
|
||||
ngtcp2_transport_params params;
|
||||
int rv;
|
||||
|
||||
dcid.datalen = NGTCP2_MIN_INITIAL_DCIDLEN;
|
||||
if (RAND_bytes(dcid.data, (int)dcid.datalen) != 1) {
|
||||
fprintf(stderr, "RAND_bytes failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
scid.datalen = 8;
|
||||
if (RAND_bytes(scid.data, (int)scid.datalen) != 1) {
|
||||
fprintf(stderr, "RAND_bytes failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngtcp2_settings_default(&settings);
|
||||
|
||||
settings.initial_ts = timestamp();
|
||||
settings.log_printf = log_printf;
|
||||
|
||||
ngtcp2_transport_params_default(¶ms);
|
||||
|
||||
params.initial_max_streams_uni = 3;
|
||||
params.initial_max_stream_data_bidi_local = 128 * 1024;
|
||||
params.initial_max_data = 1024 * 1024;
|
||||
|
||||
rv =
|
||||
ngtcp2_conn_client_new(&c->conn, &dcid, &scid, &path, NGTCP2_PROTO_VER_V1,
|
||||
&callbacks, &settings, ¶ms, NULL, c);
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "ngtcp2_conn_client_new: %s\n", ngtcp2_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngtcp2_conn_set_tls_native_handle(c->conn, c->ssl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_read(struct client *c) {
|
||||
uint8_t buf[65536];
|
||||
struct sockaddr_storage addr;
|
||||
struct iovec iov = {
|
||||
.iov_base = buf,
|
||||
.iov_len = sizeof(buf),
|
||||
};
|
||||
struct msghdr msg = {0};
|
||||
ssize_t nread;
|
||||
ngtcp2_path path;
|
||||
ngtcp2_pkt_info pi = {0};
|
||||
int rv;
|
||||
|
||||
msg.msg_name = &addr;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
for (;;) {
|
||||
msg.msg_namelen = sizeof(addr);
|
||||
|
||||
nread = recvmsg(c->fd, &msg, MSG_DONTWAIT);
|
||||
|
||||
if (nread == -1) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
fprintf(stderr, "recvmsg: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
path.local.addrlen = c->local_addrlen;
|
||||
path.local.addr = (struct sockaddr *)&c->local_addr;
|
||||
path.remote.addrlen = msg.msg_namelen;
|
||||
path.remote.addr = msg.msg_name;
|
||||
|
||||
rv = ngtcp2_conn_read_pkt(c->conn, &path, &pi, buf, (size_t)nread,
|
||||
timestamp());
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "ngtcp2_conn_read_pkt: %s\n", ngtcp2_strerror(rv));
|
||||
if (!c->last_error.error_code) {
|
||||
if (rv == NGTCP2_ERR_CRYPTO) {
|
||||
ngtcp2_ccerr_set_tls_alert(
|
||||
&c->last_error, ngtcp2_conn_get_tls_alert(c->conn), NULL, 0);
|
||||
} else {
|
||||
ngtcp2_ccerr_set_liberr(&c->last_error, rv, NULL, 0);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_send_packet(struct client *c, const uint8_t *data,
|
||||
size_t datalen) {
|
||||
struct iovec iov = {
|
||||
.iov_base = (uint8_t *)data,
|
||||
.iov_len = datalen,
|
||||
};
|
||||
struct msghdr msg = {0};
|
||||
ssize_t nwrite;
|
||||
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
do {
|
||||
nwrite = sendmsg(c->fd, &msg, 0);
|
||||
} while (nwrite == -1 && errno == EINTR);
|
||||
|
||||
if (nwrite == -1) {
|
||||
fprintf(stderr, "sendmsg: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t client_get_message(struct client *c, int64_t *pstream_id,
|
||||
int *pfin, ngtcp2_vec *datav,
|
||||
size_t datavcnt) {
|
||||
if (datavcnt == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c->stream.stream_id != -1 && c->stream.nwrite < c->stream.datalen) {
|
||||
*pstream_id = c->stream.stream_id;
|
||||
*pfin = 1;
|
||||
datav->base = (uint8_t *)c->stream.data + c->stream.nwrite;
|
||||
datav->len = c->stream.datalen - c->stream.nwrite;
|
||||
return 1;
|
||||
}
|
||||
|
||||
*pstream_id = -1;
|
||||
*pfin = 0;
|
||||
datav->base = NULL;
|
||||
datav->len = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_write_streams(struct client *c) {
|
||||
ngtcp2_tstamp ts = timestamp();
|
||||
ngtcp2_pkt_info pi;
|
||||
ngtcp2_ssize nwrite;
|
||||
uint8_t buf[1452];
|
||||
ngtcp2_path_storage ps;
|
||||
ngtcp2_vec datav;
|
||||
size_t datavcnt;
|
||||
int64_t stream_id;
|
||||
ngtcp2_ssize wdatalen;
|
||||
uint32_t flags;
|
||||
int fin;
|
||||
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
for (;;) {
|
||||
datavcnt = client_get_message(c, &stream_id, &fin, &datav, 1);
|
||||
|
||||
flags = NGTCP2_WRITE_STREAM_FLAG_MORE;
|
||||
if (fin) {
|
||||
flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
|
||||
}
|
||||
|
||||
nwrite = ngtcp2_conn_writev_stream(c->conn, &ps.path, &pi, buf, sizeof(buf),
|
||||
&wdatalen, flags, stream_id, &datav,
|
||||
datavcnt, ts);
|
||||
if (nwrite < 0) {
|
||||
switch (nwrite) {
|
||||
case NGTCP2_ERR_WRITE_MORE:
|
||||
c->stream.nwrite += (size_t)wdatalen;
|
||||
continue;
|
||||
default:
|
||||
fprintf(stderr, "ngtcp2_conn_writev_stream: %s\n",
|
||||
ngtcp2_strerror((int)nwrite));
|
||||
ngtcp2_ccerr_set_liberr(&c->last_error, (int)nwrite, NULL, 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (nwrite == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wdatalen > 0) {
|
||||
c->stream.nwrite += (size_t)wdatalen;
|
||||
}
|
||||
|
||||
if (client_send_packet(c, buf, (size_t)nwrite) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_write(struct client *c) {
|
||||
ngtcp2_tstamp expiry, now;
|
||||
ev_tstamp t;
|
||||
|
||||
if (client_write_streams(c) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
expiry = ngtcp2_conn_get_expiry(c->conn);
|
||||
now = timestamp();
|
||||
|
||||
t = expiry < now ? 1e-9 : (ev_tstamp)(expiry - now) / NGTCP2_SECONDS;
|
||||
|
||||
c->timer.repeat = t;
|
||||
ev_timer_again(EV_DEFAULT, &c->timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_handle_expiry(struct client *c) {
|
||||
int rv = ngtcp2_conn_handle_expiry(c->conn, timestamp());
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "ngtcp2_conn_handle_expiry: %s\n", ngtcp2_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void client_close(struct client *c) {
|
||||
ngtcp2_ssize nwrite;
|
||||
ngtcp2_pkt_info pi;
|
||||
ngtcp2_path_storage ps;
|
||||
uint8_t buf[1280];
|
||||
|
||||
if (ngtcp2_conn_in_closing_period(c->conn) ||
|
||||
ngtcp2_conn_in_draining_period(c->conn)) {
|
||||
goto fin;
|
||||
}
|
||||
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
nwrite = ngtcp2_conn_write_connection_close(
|
||||
c->conn, &ps.path, &pi, buf, sizeof(buf), &c->last_error, timestamp());
|
||||
if (nwrite < 0) {
|
||||
fprintf(stderr, "ngtcp2_conn_write_connection_close: %s\n",
|
||||
ngtcp2_strerror((int)nwrite));
|
||||
goto fin;
|
||||
}
|
||||
|
||||
client_send_packet(c, buf, (size_t)nwrite);
|
||||
|
||||
fin:
|
||||
ev_break(EV_DEFAULT, EVBREAK_ALL);
|
||||
}
|
||||
|
||||
static void read_cb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||
struct client *c = w->data;
|
||||
(void)loop;
|
||||
(void)revents;
|
||||
|
||||
if (client_read(c) != 0) {
|
||||
client_close(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (client_write(c) != 0) {
|
||||
client_close(c);
|
||||
}
|
||||
}
|
||||
|
||||
static void timer_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||
struct client *c = w->data;
|
||||
(void)loop;
|
||||
(void)revents;
|
||||
|
||||
if (client_handle_expiry(c) != 0) {
|
||||
client_close(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (client_write(c) != 0) {
|
||||
client_close(c);
|
||||
}
|
||||
}
|
||||
|
||||
static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) {
|
||||
struct client *c = conn_ref->user_data;
|
||||
return c->conn;
|
||||
}
|
||||
|
||||
static int client_init(struct client *c) {
|
||||
struct sockaddr_storage remote_addr, local_addr;
|
||||
socklen_t remote_addrlen, local_addrlen = sizeof(local_addr);
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
|
||||
ngtcp2_ccerr_default(&c->last_error);
|
||||
|
||||
c->fd = create_sock((struct sockaddr *)&remote_addr, &remote_addrlen,
|
||||
REMOTE_HOST, REMOTE_PORT);
|
||||
if (c->fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect_sock((struct sockaddr *)&local_addr, &local_addrlen, c->fd,
|
||||
(struct sockaddr *)&remote_addr, remote_addrlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&c->local_addr, &local_addr, sizeof(c->local_addr));
|
||||
c->local_addrlen = local_addrlen;
|
||||
|
||||
if (client_ssl_init(c) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (client_quic_init(c, (struct sockaddr *)&remote_addr, remote_addrlen,
|
||||
(struct sockaddr *)&local_addr, local_addrlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
c->stream.stream_id = -1;
|
||||
|
||||
c->conn_ref.get_conn = get_conn;
|
||||
c->conn_ref.user_data = c;
|
||||
|
||||
ev_io_init(&c->rev, read_cb, c->fd, EV_READ);
|
||||
c->rev.data = c;
|
||||
ev_io_start(EV_DEFAULT, &c->rev);
|
||||
|
||||
ev_timer_init(&c->timer, timer_cb, 0., 0.);
|
||||
c->timer.data = c;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void client_free(struct client *c) {
|
||||
ngtcp2_conn_del(c->conn);
|
||||
SSL_free(c->ssl);
|
||||
SSL_CTX_free(c->ssl_ctx);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct client c;
|
||||
|
||||
srandom((unsigned int)timestamp());
|
||||
|
||||
if (client_init(&c) != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (client_write(&c) != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ev_run(EV_DEFAULT, 0);
|
||||
|
||||
client_free(&c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
115
deps/ngtcp2/ngtcp2/examples/siphash.cc
vendored
Normal file
115
deps/ngtcp2/ngtcp2/examples/siphash.cc
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/* Copyright 2019 The BoringSSL Authors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 nghttp2 contributors
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "siphash.h"
|
||||
|
||||
namespace {
|
||||
auto CRYPTO_load_u64_le(std::span<const uint8_t, sizeof(uint64_t)> in) {
|
||||
uint64_t v;
|
||||
|
||||
memcpy(&v, in.data(), sizeof(v));
|
||||
|
||||
if constexpr (std::endian::native == std::endian::big) {
|
||||
return byteswap(v);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
constexpr void siphash_round(uint64_t v[4]) {
|
||||
v[0] += v[1];
|
||||
v[2] += v[3];
|
||||
v[1] = std::rotl(v[1], 13);
|
||||
v[3] = std::rotl(v[3], 16);
|
||||
v[1] ^= v[0];
|
||||
v[3] ^= v[2];
|
||||
v[0] = std::rotl(v[0], 32);
|
||||
v[2] += v[1];
|
||||
v[0] += v[3];
|
||||
v[1] = std::rotl(v[1], 17);
|
||||
v[3] = std::rotl(v[3], 21);
|
||||
v[1] ^= v[2];
|
||||
v[3] ^= v[0];
|
||||
v[2] = std::rotl(v[2], 32);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
uint64_t siphash24(std::span<const uint64_t, 2> key,
|
||||
std::span<const uint8_t> input) {
|
||||
const auto orig_input_len = input.size();
|
||||
uint64_t v[]{
|
||||
key[0] ^ UINT64_C(0x736f6d6570736575),
|
||||
key[1] ^ UINT64_C(0x646f72616e646f6d),
|
||||
key[0] ^ UINT64_C(0x6c7967656e657261),
|
||||
key[1] ^ UINT64_C(0x7465646279746573),
|
||||
};
|
||||
|
||||
while (input.size() >= sizeof(uint64_t)) {
|
||||
auto m = CRYPTO_load_u64_le(input.first<sizeof(uint64_t)>());
|
||||
v[3] ^= m;
|
||||
siphash_round(v);
|
||||
siphash_round(v);
|
||||
v[0] ^= m;
|
||||
|
||||
input = input.subspan(sizeof(uint64_t));
|
||||
}
|
||||
|
||||
std::array<uint8_t, sizeof(uint64_t)> last_block{};
|
||||
std::ranges::copy(input, std::ranges::begin(last_block));
|
||||
last_block.back() = orig_input_len & 0xff;
|
||||
|
||||
auto last_block_word = CRYPTO_load_u64_le(last_block);
|
||||
v[3] ^= last_block_word;
|
||||
siphash_round(v);
|
||||
siphash_round(v);
|
||||
v[0] ^= last_block_word;
|
||||
|
||||
v[2] ^= 0xff;
|
||||
siphash_round(v);
|
||||
siphash_round(v);
|
||||
siphash_round(v);
|
||||
siphash_round(v);
|
||||
|
||||
return v[0] ^ v[1] ^ v[2] ^ v[3];
|
||||
}
|
||||
62
deps/ngtcp2/ngtcp2/examples/siphash.h
vendored
Normal file
62
deps/ngtcp2/ngtcp2/examples/siphash.h
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/* Copyright 2019 The BoringSSL Authors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 nghttp2 contributors
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 SIPHASH_H
|
||||
#define SIPHASH_H
|
||||
|
||||
#include <bit>
|
||||
#include <concepts>
|
||||
#include <algorithm>
|
||||
#include <span>
|
||||
|
||||
// SipHash is a fast, secure PRF that is often used for hash tables.
|
||||
|
||||
// siphash24 implements SipHash-2-4. See
|
||||
// https://131002.net/siphash/siphash.pdf
|
||||
uint64_t siphash24(std::span<const uint64_t, 2> key,
|
||||
std::span<const uint8_t> input);
|
||||
|
||||
// Define here to be usable in tests.
|
||||
template <std::integral T> T byteswap(T v) {
|
||||
auto c = std::bit_cast<std::array<uint8_t, sizeof(T)>>(v);
|
||||
std::ranges::reverse(c);
|
||||
return std::bit_cast<T>(c);
|
||||
}
|
||||
|
||||
#endif // !defined(SIPHASH_H)
|
||||
98
deps/ngtcp2/ngtcp2/examples/siphash_test.cc
vendored
Normal file
98
deps/ngtcp2/ngtcp2/examples/siphash_test.cc
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 nghttp2 contributors
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "siphash_test.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
|
||||
#include "siphash.h"
|
||||
#include "siphash_vector.h"
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
namespace {
|
||||
const MunitTest tests[]{
|
||||
munit_void_test(test_siphash),
|
||||
munit_void_test(test_siphash_vector),
|
||||
munit_test_end(),
|
||||
};
|
||||
} // namespace
|
||||
|
||||
const MunitSuite siphash_suite{
|
||||
.prefix = "/siphash",
|
||||
.tests = tests,
|
||||
};
|
||||
|
||||
void test_siphash(void) {
|
||||
std::array<uint8_t, 16> key_bytes;
|
||||
std::iota(std::ranges::begin(key_bytes), std::ranges::end(key_bytes), 0);
|
||||
|
||||
std::array<uint64_t, 2> key;
|
||||
memcpy(key.data(), key_bytes.data(), key_bytes.size());
|
||||
|
||||
if constexpr (std::endian::native == std::endian::big) {
|
||||
key[0] = byteswap(key[0]);
|
||||
key[1] = byteswap(key[1]);
|
||||
}
|
||||
|
||||
std::array<uint8_t, 15> input;
|
||||
std::iota(std::ranges::begin(input), std::ranges::end(input), 0);
|
||||
|
||||
assert_uint64(0xa129ca6149be45e5ull, ==, siphash24(key, input));
|
||||
}
|
||||
|
||||
void test_siphash_vector(void) {
|
||||
std::array<uint8_t, 16> key_bytes;
|
||||
std::iota(std::ranges::begin(key_bytes), std::ranges::end(key_bytes), 0);
|
||||
|
||||
std::array<uint64_t, 2> key;
|
||||
memcpy(key.data(), key_bytes.data(), key_bytes.size());
|
||||
|
||||
if constexpr (std::endian::native == std::endian::big) {
|
||||
key[0] = byteswap(key[0]);
|
||||
key[1] = byteswap(key[1]);
|
||||
}
|
||||
|
||||
std::array<uint8_t, 64> in;
|
||||
|
||||
for (size_t i = 0; i < 64; ++i) {
|
||||
in[i] = static_cast<uint8_t>(i);
|
||||
auto h = siphash24(key, std::span{in}.first(i));
|
||||
|
||||
uint64_t expect;
|
||||
|
||||
memcpy(&expect, &vectors_sip64[i], sizeof(expect));
|
||||
|
||||
if constexpr (std::endian::native == std::endian::big) {
|
||||
expect = byteswap(expect);
|
||||
}
|
||||
|
||||
assert_uint64(expect, ==, h);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ngtcp2
|
||||
46
deps/ngtcp2/ngtcp2/examples/siphash_test.h
vendored
Normal file
46
deps/ngtcp2/ngtcp2/examples/siphash_test.h
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 nghttp2 contributors
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 SIPHASH_TEST_H
|
||||
#define SIPHASH_TEST_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#define MUNIT_ENABLE_ASSERT_ALIASES
|
||||
|
||||
#include "munit.h"
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
extern const MunitSuite siphash_suite;
|
||||
|
||||
munit_void_test_decl(test_siphash)
|
||||
munit_void_test_decl(test_siphash_vector)
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
#endif // !defined(SIPHASH_TEST_H)
|
||||
645
deps/ngtcp2/ngtcp2/examples/siphash_vector.h
vendored
Normal file
645
deps/ngtcp2/ngtcp2/examples/siphash_vector.h
vendored
Normal file
|
|
@ -0,0 +1,645 @@
|
|||
// https://github.com/veorq/SipHash/blob/f26d35e964c6290ffe23d9043475ad3129f409e0/vectors.h
|
||||
#include <stdint.h>
|
||||
|
||||
const uint8_t vectors_sip64[64][8] = {
|
||||
{
|
||||
0x31,
|
||||
0x0e,
|
||||
0x0e,
|
||||
0xdd,
|
||||
0x47,
|
||||
0xdb,
|
||||
0x6f,
|
||||
0x72,
|
||||
},
|
||||
{
|
||||
0xfd,
|
||||
0x67,
|
||||
0xdc,
|
||||
0x93,
|
||||
0xc5,
|
||||
0x39,
|
||||
0xf8,
|
||||
0x74,
|
||||
},
|
||||
{
|
||||
0x5a,
|
||||
0x4f,
|
||||
0xa9,
|
||||
0xd9,
|
||||
0x09,
|
||||
0x80,
|
||||
0x6c,
|
||||
0x0d,
|
||||
},
|
||||
{
|
||||
0x2d,
|
||||
0x7e,
|
||||
0xfb,
|
||||
0xd7,
|
||||
0x96,
|
||||
0x66,
|
||||
0x67,
|
||||
0x85,
|
||||
},
|
||||
{
|
||||
0xb7,
|
||||
0x87,
|
||||
0x71,
|
||||
0x27,
|
||||
0xe0,
|
||||
0x94,
|
||||
0x27,
|
||||
0xcf,
|
||||
},
|
||||
{
|
||||
0x8d,
|
||||
0xa6,
|
||||
0x99,
|
||||
0xcd,
|
||||
0x64,
|
||||
0x55,
|
||||
0x76,
|
||||
0x18,
|
||||
},
|
||||
{
|
||||
0xce,
|
||||
0xe3,
|
||||
0xfe,
|
||||
0x58,
|
||||
0x6e,
|
||||
0x46,
|
||||
0xc9,
|
||||
0xcb,
|
||||
},
|
||||
{
|
||||
0x37,
|
||||
0xd1,
|
||||
0x01,
|
||||
0x8b,
|
||||
0xf5,
|
||||
0x00,
|
||||
0x02,
|
||||
0xab,
|
||||
},
|
||||
{
|
||||
0x62,
|
||||
0x24,
|
||||
0x93,
|
||||
0x9a,
|
||||
0x79,
|
||||
0xf5,
|
||||
0xf5,
|
||||
0x93,
|
||||
},
|
||||
{
|
||||
0xb0,
|
||||
0xe4,
|
||||
0xa9,
|
||||
0x0b,
|
||||
0xdf,
|
||||
0x82,
|
||||
0x00,
|
||||
0x9e,
|
||||
},
|
||||
{
|
||||
0xf3,
|
||||
0xb9,
|
||||
0xdd,
|
||||
0x94,
|
||||
0xc5,
|
||||
0xbb,
|
||||
0x5d,
|
||||
0x7a,
|
||||
},
|
||||
{
|
||||
0xa7,
|
||||
0xad,
|
||||
0x6b,
|
||||
0x22,
|
||||
0x46,
|
||||
0x2f,
|
||||
0xb3,
|
||||
0xf4,
|
||||
},
|
||||
{
|
||||
0xfb,
|
||||
0xe5,
|
||||
0x0e,
|
||||
0x86,
|
||||
0xbc,
|
||||
0x8f,
|
||||
0x1e,
|
||||
0x75,
|
||||
},
|
||||
{
|
||||
0x90,
|
||||
0x3d,
|
||||
0x84,
|
||||
0xc0,
|
||||
0x27,
|
||||
0x56,
|
||||
0xea,
|
||||
0x14,
|
||||
},
|
||||
{
|
||||
0xee,
|
||||
0xf2,
|
||||
0x7a,
|
||||
0x8e,
|
||||
0x90,
|
||||
0xca,
|
||||
0x23,
|
||||
0xf7,
|
||||
},
|
||||
{
|
||||
0xe5,
|
||||
0x45,
|
||||
0xbe,
|
||||
0x49,
|
||||
0x61,
|
||||
0xca,
|
||||
0x29,
|
||||
0xa1,
|
||||
},
|
||||
{
|
||||
0xdb,
|
||||
0x9b,
|
||||
0xc2,
|
||||
0x57,
|
||||
0x7f,
|
||||
0xcc,
|
||||
0x2a,
|
||||
0x3f,
|
||||
},
|
||||
{
|
||||
0x94,
|
||||
0x47,
|
||||
0xbe,
|
||||
0x2c,
|
||||
0xf5,
|
||||
0xe9,
|
||||
0x9a,
|
||||
0x69,
|
||||
},
|
||||
{
|
||||
0x9c,
|
||||
0xd3,
|
||||
0x8d,
|
||||
0x96,
|
||||
0xf0,
|
||||
0xb3,
|
||||
0xc1,
|
||||
0x4b,
|
||||
},
|
||||
{
|
||||
0xbd,
|
||||
0x61,
|
||||
0x79,
|
||||
0xa7,
|
||||
0x1d,
|
||||
0xc9,
|
||||
0x6d,
|
||||
0xbb,
|
||||
},
|
||||
{
|
||||
0x98,
|
||||
0xee,
|
||||
0xa2,
|
||||
0x1a,
|
||||
0xf2,
|
||||
0x5c,
|
||||
0xd6,
|
||||
0xbe,
|
||||
},
|
||||
{
|
||||
0xc7,
|
||||
0x67,
|
||||
0x3b,
|
||||
0x2e,
|
||||
0xb0,
|
||||
0xcb,
|
||||
0xf2,
|
||||
0xd0,
|
||||
},
|
||||
{
|
||||
0x88,
|
||||
0x3e,
|
||||
0xa3,
|
||||
0xe3,
|
||||
0x95,
|
||||
0x67,
|
||||
0x53,
|
||||
0x93,
|
||||
},
|
||||
{
|
||||
0xc8,
|
||||
0xce,
|
||||
0x5c,
|
||||
0xcd,
|
||||
0x8c,
|
||||
0x03,
|
||||
0x0c,
|
||||
0xa8,
|
||||
},
|
||||
{
|
||||
0x94,
|
||||
0xaf,
|
||||
0x49,
|
||||
0xf6,
|
||||
0xc6,
|
||||
0x50,
|
||||
0xad,
|
||||
0xb8,
|
||||
},
|
||||
{
|
||||
0xea,
|
||||
0xb8,
|
||||
0x85,
|
||||
0x8a,
|
||||
0xde,
|
||||
0x92,
|
||||
0xe1,
|
||||
0xbc,
|
||||
},
|
||||
{
|
||||
0xf3,
|
||||
0x15,
|
||||
0xbb,
|
||||
0x5b,
|
||||
0xb8,
|
||||
0x35,
|
||||
0xd8,
|
||||
0x17,
|
||||
},
|
||||
{
|
||||
0xad,
|
||||
0xcf,
|
||||
0x6b,
|
||||
0x07,
|
||||
0x63,
|
||||
0x61,
|
||||
0x2e,
|
||||
0x2f,
|
||||
},
|
||||
{
|
||||
0xa5,
|
||||
0xc9,
|
||||
0x1d,
|
||||
0xa7,
|
||||
0xac,
|
||||
0xaa,
|
||||
0x4d,
|
||||
0xde,
|
||||
},
|
||||
{
|
||||
0x71,
|
||||
0x65,
|
||||
0x95,
|
||||
0x87,
|
||||
0x66,
|
||||
0x50,
|
||||
0xa2,
|
||||
0xa6,
|
||||
},
|
||||
{
|
||||
0x28,
|
||||
0xef,
|
||||
0x49,
|
||||
0x5c,
|
||||
0x53,
|
||||
0xa3,
|
||||
0x87,
|
||||
0xad,
|
||||
},
|
||||
{
|
||||
0x42,
|
||||
0xc3,
|
||||
0x41,
|
||||
0xd8,
|
||||
0xfa,
|
||||
0x92,
|
||||
0xd8,
|
||||
0x32,
|
||||
},
|
||||
{
|
||||
0xce,
|
||||
0x7c,
|
||||
0xf2,
|
||||
0x72,
|
||||
0x2f,
|
||||
0x51,
|
||||
0x27,
|
||||
0x71,
|
||||
},
|
||||
{
|
||||
0xe3,
|
||||
0x78,
|
||||
0x59,
|
||||
0xf9,
|
||||
0x46,
|
||||
0x23,
|
||||
0xf3,
|
||||
0xa7,
|
||||
},
|
||||
{
|
||||
0x38,
|
||||
0x12,
|
||||
0x05,
|
||||
0xbb,
|
||||
0x1a,
|
||||
0xb0,
|
||||
0xe0,
|
||||
0x12,
|
||||
},
|
||||
{
|
||||
0xae,
|
||||
0x97,
|
||||
0xa1,
|
||||
0x0f,
|
||||
0xd4,
|
||||
0x34,
|
||||
0xe0,
|
||||
0x15,
|
||||
},
|
||||
{
|
||||
0xb4,
|
||||
0xa3,
|
||||
0x15,
|
||||
0x08,
|
||||
0xbe,
|
||||
0xff,
|
||||
0x4d,
|
||||
0x31,
|
||||
},
|
||||
{
|
||||
0x81,
|
||||
0x39,
|
||||
0x62,
|
||||
0x29,
|
||||
0xf0,
|
||||
0x90,
|
||||
0x79,
|
||||
0x02,
|
||||
},
|
||||
{
|
||||
0x4d,
|
||||
0x0c,
|
||||
0xf4,
|
||||
0x9e,
|
||||
0xe5,
|
||||
0xd4,
|
||||
0xdc,
|
||||
0xca,
|
||||
},
|
||||
{
|
||||
0x5c,
|
||||
0x73,
|
||||
0x33,
|
||||
0x6a,
|
||||
0x76,
|
||||
0xd8,
|
||||
0xbf,
|
||||
0x9a,
|
||||
},
|
||||
{
|
||||
0xd0,
|
||||
0xa7,
|
||||
0x04,
|
||||
0x53,
|
||||
0x6b,
|
||||
0xa9,
|
||||
0x3e,
|
||||
0x0e,
|
||||
},
|
||||
{
|
||||
0x92,
|
||||
0x59,
|
||||
0x58,
|
||||
0xfc,
|
||||
0xd6,
|
||||
0x42,
|
||||
0x0c,
|
||||
0xad,
|
||||
},
|
||||
{
|
||||
0xa9,
|
||||
0x15,
|
||||
0xc2,
|
||||
0x9b,
|
||||
0xc8,
|
||||
0x06,
|
||||
0x73,
|
||||
0x18,
|
||||
},
|
||||
{
|
||||
0x95,
|
||||
0x2b,
|
||||
0x79,
|
||||
0xf3,
|
||||
0xbc,
|
||||
0x0a,
|
||||
0xa6,
|
||||
0xd4,
|
||||
},
|
||||
{
|
||||
0xf2,
|
||||
0x1d,
|
||||
0xf2,
|
||||
0xe4,
|
||||
0x1d,
|
||||
0x45,
|
||||
0x35,
|
||||
0xf9,
|
||||
},
|
||||
{
|
||||
0x87,
|
||||
0x57,
|
||||
0x75,
|
||||
0x19,
|
||||
0x04,
|
||||
0x8f,
|
||||
0x53,
|
||||
0xa9,
|
||||
},
|
||||
{
|
||||
0x10,
|
||||
0xa5,
|
||||
0x6c,
|
||||
0xf5,
|
||||
0xdf,
|
||||
0xcd,
|
||||
0x9a,
|
||||
0xdb,
|
||||
},
|
||||
{
|
||||
0xeb,
|
||||
0x75,
|
||||
0x09,
|
||||
0x5c,
|
||||
0xcd,
|
||||
0x98,
|
||||
0x6c,
|
||||
0xd0,
|
||||
},
|
||||
{
|
||||
0x51,
|
||||
0xa9,
|
||||
0xcb,
|
||||
0x9e,
|
||||
0xcb,
|
||||
0xa3,
|
||||
0x12,
|
||||
0xe6,
|
||||
},
|
||||
{
|
||||
0x96,
|
||||
0xaf,
|
||||
0xad,
|
||||
0xfc,
|
||||
0x2c,
|
||||
0xe6,
|
||||
0x66,
|
||||
0xc7,
|
||||
},
|
||||
{
|
||||
0x72,
|
||||
0xfe,
|
||||
0x52,
|
||||
0x97,
|
||||
0x5a,
|
||||
0x43,
|
||||
0x64,
|
||||
0xee,
|
||||
},
|
||||
{
|
||||
0x5a,
|
||||
0x16,
|
||||
0x45,
|
||||
0xb2,
|
||||
0x76,
|
||||
0xd5,
|
||||
0x92,
|
||||
0xa1,
|
||||
},
|
||||
{
|
||||
0xb2,
|
||||
0x74,
|
||||
0xcb,
|
||||
0x8e,
|
||||
0xbf,
|
||||
0x87,
|
||||
0x87,
|
||||
0x0a,
|
||||
},
|
||||
{
|
||||
0x6f,
|
||||
0x9b,
|
||||
0xb4,
|
||||
0x20,
|
||||
0x3d,
|
||||
0xe7,
|
||||
0xb3,
|
||||
0x81,
|
||||
},
|
||||
{
|
||||
0xea,
|
||||
0xec,
|
||||
0xb2,
|
||||
0xa3,
|
||||
0x0b,
|
||||
0x22,
|
||||
0xa8,
|
||||
0x7f,
|
||||
},
|
||||
{
|
||||
0x99,
|
||||
0x24,
|
||||
0xa4,
|
||||
0x3c,
|
||||
0xc1,
|
||||
0x31,
|
||||
0x57,
|
||||
0x24,
|
||||
},
|
||||
{
|
||||
0xbd,
|
||||
0x83,
|
||||
0x8d,
|
||||
0x3a,
|
||||
0xaf,
|
||||
0xbf,
|
||||
0x8d,
|
||||
0xb7,
|
||||
},
|
||||
{
|
||||
0x0b,
|
||||
0x1a,
|
||||
0x2a,
|
||||
0x32,
|
||||
0x65,
|
||||
0xd5,
|
||||
0x1a,
|
||||
0xea,
|
||||
},
|
||||
{
|
||||
0x13,
|
||||
0x50,
|
||||
0x79,
|
||||
0xa3,
|
||||
0x23,
|
||||
0x1c,
|
||||
0xe6,
|
||||
0x60,
|
||||
},
|
||||
{
|
||||
0x93,
|
||||
0x2b,
|
||||
0x28,
|
||||
0x46,
|
||||
0xe4,
|
||||
0xd7,
|
||||
0x06,
|
||||
0x66,
|
||||
},
|
||||
{
|
||||
0xe1,
|
||||
0x91,
|
||||
0x5f,
|
||||
0x5c,
|
||||
0xb1,
|
||||
0xec,
|
||||
0xa4,
|
||||
0x6c,
|
||||
},
|
||||
{
|
||||
0xf3,
|
||||
0x25,
|
||||
0x96,
|
||||
0x5c,
|
||||
0xa1,
|
||||
0x6d,
|
||||
0x62,
|
||||
0x9f,
|
||||
},
|
||||
{
|
||||
0x57,
|
||||
0x5f,
|
||||
0xf2,
|
||||
0x8e,
|
||||
0x60,
|
||||
0x38,
|
||||
0x1b,
|
||||
0xe5,
|
||||
},
|
||||
{
|
||||
0x72,
|
||||
0x45,
|
||||
0x06,
|
||||
0xeb,
|
||||
0x4c,
|
||||
0x32,
|
||||
0x8a,
|
||||
0x95,
|
||||
},
|
||||
};
|
||||
91
deps/ngtcp2/ngtcp2/examples/template.h
vendored
Normal file
91
deps/ngtcp2/ngtcp2/examples/template.h
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
* Copyright (c) 2015 ngttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TEMPLATE_H
|
||||
#define TEMPLATE_H
|
||||
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <span>
|
||||
|
||||
template <std::integral T>
|
||||
[[nodiscard]] constexpr auto as_unsigned(T n) noexcept {
|
||||
return static_cast<std::make_unsigned_t<T>>(n);
|
||||
}
|
||||
|
||||
template <std::unsigned_integral T>
|
||||
[[nodiscard]] constexpr auto as_signed(T n) noexcept {
|
||||
return static_cast<std::make_signed_t<T>>(n);
|
||||
}
|
||||
|
||||
// inspired by <http://blog.korfuri.fr/post/go-defer-in-cpp/>, but our
|
||||
// template can take functions returning other than void.
|
||||
template <typename F, typename... T> struct Defer {
|
||||
Defer(F &&f, T &&...t)
|
||||
: f(std::bind(std::forward<F>(f), std::forward<T>(t)...)) {}
|
||||
Defer(Defer &&o) noexcept : f(std::move(o.f)) {}
|
||||
~Defer() { f(); }
|
||||
|
||||
using ResultType = std::invoke_result_t<F, T...>;
|
||||
std::function<ResultType()> f;
|
||||
};
|
||||
|
||||
template <typename F, typename... T> Defer<F, T...> defer(F &&f, T &&...t) {
|
||||
return Defer<F, T...>(std::forward<F>(f), std::forward<T>(t)...);
|
||||
}
|
||||
|
||||
template <typename T, size_t N> constexpr size_t array_size(T (&)[N]) {
|
||||
return N;
|
||||
}
|
||||
|
||||
template <typename T, size_t N> constexpr size_t str_size(T (&)[N]) {
|
||||
return N - 1;
|
||||
}
|
||||
|
||||
// User-defined literals for K, M, and G (powers of 1024)
|
||||
|
||||
constexpr unsigned long long operator""_k(unsigned long long k) {
|
||||
return k * 1024;
|
||||
}
|
||||
|
||||
constexpr unsigned long long operator""_m(unsigned long long m) {
|
||||
return m * 1024 * 1024;
|
||||
}
|
||||
|
||||
constexpr unsigned long long operator""_g(unsigned long long g) {
|
||||
return g * 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
[[nodiscard]] std::span<uint8_t, N == std::dynamic_extent ? std::dynamic_extent
|
||||
: N * sizeof(T)>
|
||||
as_writable_uint8_span(std::span<T, N> s) noexcept {
|
||||
return std::span<uint8_t, N == std::dynamic_extent ? std::dynamic_extent
|
||||
: N * sizeof(T)>{
|
||||
reinterpret_cast<uint8_t *>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
#endif // !defined(TEMPLATE_H)
|
||||
60
deps/ngtcp2/ngtcp2/examples/tests/README.rst
vendored
Normal file
60
deps/ngtcp2/ngtcp2/examples/tests/README.rst
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
Examples Tests
|
||||
==============
|
||||
|
||||
This is a ``pytest`` suite intended to verify interoperability between
|
||||
the different example clients and servers built.
|
||||
|
||||
You run it by executing ``pytest`` on top level project dir or in
|
||||
the examples/tests directory.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
examples/test> pytest
|
||||
ngtcp2-examples: [0.9.0-DEV, crypto_libs=['quictls', 'wolfssl']]
|
||||
...
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
You need a Python3 (3.8 is probably sufficient), ``pytest`` and the
|
||||
Python ``cryptography`` module installed.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
If you run ``pytest`` without arguments, it will print the test suite
|
||||
and a ``.`` for every test case passed. Add ``-v`` and all test cases
|
||||
will be listed in the full name. Adding several ``v`` will increase the
|
||||
logging level on failure output.
|
||||
|
||||
The name of test cases include the crypto libs of the server and client
|
||||
used. For example:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
test_01_handshake.py::TestHandshake::test_01_01_get[quictls-quictls] PASSED [ 16%]
|
||||
test_01_handshake.py::TestHandshake::test_01_01_get[quictls-wolfssl] PASSED
|
||||
|
||||
Here, ``test_01_01`` is run first with the quictls server and client and then
|
||||
with the quictls server and wolfSSL client. By default, the test suite runs
|
||||
all combinations of servers and clients that have been configured in the project.
|
||||
|
||||
To track down problems, you can restrict the test cases that are run by
|
||||
matching patterns:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
# only tests with wolfSSL example server
|
||||
> pytest -v -k 'wolfssl-'
|
||||
# only tests with wolfSSL example client
|
||||
> pytest -v -k 'test and -wolfssl'
|
||||
# tests with a specific combination
|
||||
> pytest -v -k 'quictls-wolfssl'
|
||||
|
||||
|
||||
Analysing
|
||||
---------
|
||||
|
||||
To make analysis of a broken test case easier, you best run only that
|
||||
test case. Use ``pytest -vv`` (or more) to get more verbose logging.
|
||||
Inspect server and client log files in ``examples/tests/gen``.
|
||||
0
deps/ngtcp2/ngtcp2/examples/tests/__init__.py
vendored
Normal file
0
deps/ngtcp2/ngtcp2/examples/tests/__init__.py
vendored
Normal file
28
deps/ngtcp2/ngtcp2/examples/tests/conftest.py
vendored
Normal file
28
deps/ngtcp2/ngtcp2/examples/tests/conftest.py
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import logging
|
||||
import pytest
|
||||
|
||||
from .ngtcp2test import Env
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("env")
|
||||
def pytest_report_header(config):
|
||||
env = Env()
|
||||
return [
|
||||
f"ngtcp2-examples: [{env.version}, crypto_libs={env.crypto_libs}]",
|
||||
f"example clients: {env.clients}",
|
||||
f"example servers: {env.servers}",
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="package")
|
||||
def env(pytestconfig) -> Env:
|
||||
console = logging.StreamHandler()
|
||||
console.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
|
||||
logging.getLogger('').addHandler(console)
|
||||
env = Env(pytestconfig=pytestconfig)
|
||||
level = logging.DEBUG if env.verbose > 0 else logging.INFO
|
||||
console.setLevel(level)
|
||||
logging.getLogger('').setLevel(level=level)
|
||||
env.setup()
|
||||
|
||||
return env
|
||||
6
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/__init__.py
vendored
Normal file
6
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/__init__.py
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from .env import Env, CryptoLib
|
||||
from .log import LogFile
|
||||
from .client import ExampleClient, ClientRun
|
||||
from .server import ExampleServer, ServerRun
|
||||
from .certs import Ngtcp2TestCA, Credentials
|
||||
from .tls import HandShake, HSRecord
|
||||
476
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/certs.py
vendored
Normal file
476
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/certs.py
vendored
Normal file
|
|
@ -0,0 +1,476 @@
|
|||
import os
|
||||
import re
|
||||
from datetime import timedelta, datetime
|
||||
from typing import List, Any, Optional
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import ec, rsa
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey
|
||||
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
|
||||
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption, load_pem_private_key
|
||||
from cryptography.x509 import ExtendedKeyUsageOID, NameOID
|
||||
|
||||
|
||||
EC_SUPPORTED = {}
|
||||
EC_SUPPORTED.update([(curve.name.upper(), curve) for curve in [
|
||||
ec.SECP192R1,
|
||||
ec.SECP224R1,
|
||||
ec.SECP256R1,
|
||||
ec.SECP384R1,
|
||||
]])
|
||||
|
||||
|
||||
def _private_key(key_type):
|
||||
if isinstance(key_type, str):
|
||||
key_type = key_type.upper()
|
||||
m = re.match(r'^(RSA)?(\d+)$', key_type)
|
||||
if m:
|
||||
key_type = int(m.group(2))
|
||||
|
||||
if isinstance(key_type, int):
|
||||
return rsa.generate_private_key(
|
||||
public_exponent=65537,
|
||||
key_size=key_type,
|
||||
backend=default_backend()
|
||||
)
|
||||
if not isinstance(key_type, ec.EllipticCurve) and key_type in EC_SUPPORTED:
|
||||
key_type = EC_SUPPORTED[key_type]
|
||||
return ec.generate_private_key(
|
||||
curve=key_type,
|
||||
backend=default_backend()
|
||||
)
|
||||
|
||||
|
||||
class CertificateSpec:
|
||||
|
||||
def __init__(self, name: str = None, domains: List[str] = None,
|
||||
email: str = None,
|
||||
key_type: str = None, single_file: bool = False,
|
||||
valid_from: timedelta = timedelta(days=-1),
|
||||
valid_to: timedelta = timedelta(days=89),
|
||||
client: bool = False,
|
||||
sub_specs: List['CertificateSpec'] = None):
|
||||
self._name = name
|
||||
self.domains = domains
|
||||
self.client = client
|
||||
self.email = email
|
||||
self.key_type = key_type
|
||||
self.single_file = single_file
|
||||
self.valid_from = valid_from
|
||||
self.valid_to = valid_to
|
||||
self.sub_specs = sub_specs
|
||||
|
||||
@property
|
||||
def name(self) -> Optional[str]:
|
||||
if self._name:
|
||||
return self._name
|
||||
elif self.domains:
|
||||
return self.domains[0]
|
||||
return None
|
||||
|
||||
@property
|
||||
def type(self) -> Optional[str]:
|
||||
if self.domains and len(self.domains):
|
||||
return "server"
|
||||
elif self.client:
|
||||
return "client"
|
||||
elif self.name:
|
||||
return "ca"
|
||||
return None
|
||||
|
||||
|
||||
class Credentials:
|
||||
|
||||
def __init__(self, name: str, cert: Any, pkey: Any, issuer: 'Credentials' = None):
|
||||
self._name = name
|
||||
self._cert = cert
|
||||
self._pkey = pkey
|
||||
self._issuer = issuer
|
||||
self._cert_file = None
|
||||
self._pkey_file = None
|
||||
self._store = None
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def subject(self) -> x509.Name:
|
||||
return self._cert.subject
|
||||
|
||||
@property
|
||||
def key_type(self):
|
||||
if isinstance(self._pkey, RSAPrivateKey):
|
||||
return f"rsa{self._pkey.key_size}"
|
||||
elif isinstance(self._pkey, EllipticCurvePrivateKey):
|
||||
return f"{self._pkey.curve.name}"
|
||||
else:
|
||||
raise Exception(f"unknown key type: {self._pkey}")
|
||||
|
||||
@property
|
||||
def private_key(self) -> Any:
|
||||
return self._pkey
|
||||
|
||||
@property
|
||||
def certificate(self) -> Any:
|
||||
return self._cert
|
||||
|
||||
@property
|
||||
def cert_pem(self) -> bytes:
|
||||
return self._cert.public_bytes(Encoding.PEM)
|
||||
|
||||
@property
|
||||
def pkey_pem(self) -> bytes:
|
||||
return self._pkey.private_bytes(
|
||||
Encoding.PEM,
|
||||
PrivateFormat.TraditionalOpenSSL if self.key_type.startswith('rsa') else PrivateFormat.PKCS8,
|
||||
NoEncryption())
|
||||
|
||||
@property
|
||||
def issuer(self) -> Optional['Credentials']:
|
||||
return self._issuer
|
||||
|
||||
def set_store(self, store: 'CertStore'):
|
||||
self._store = store
|
||||
|
||||
def set_files(self, cert_file: str, pkey_file: str = None):
|
||||
self._cert_file = cert_file
|
||||
self._pkey_file = pkey_file
|
||||
|
||||
@property
|
||||
def cert_file(self) -> str:
|
||||
return self._cert_file
|
||||
|
||||
@property
|
||||
def pkey_file(self) -> Optional[str]:
|
||||
return self._pkey_file
|
||||
|
||||
def get_first(self, name) -> Optional['Credentials']:
|
||||
creds = self._store.get_credentials_for_name(name) if self._store else []
|
||||
return creds[0] if len(creds) else None
|
||||
|
||||
def get_credentials_for_name(self, name) -> List['Credentials']:
|
||||
return self._store.get_credentials_for_name(name) if self._store else []
|
||||
|
||||
def issue_certs(self, specs: List[CertificateSpec],
|
||||
chain: List['Credentials'] = None) -> List['Credentials']:
|
||||
return [self.issue_cert(spec=spec, chain=chain) for spec in specs]
|
||||
|
||||
def issue_cert(self, spec: CertificateSpec, chain: List['Credentials'] = None) -> 'Credentials':
|
||||
key_type = spec.key_type if spec.key_type else self.key_type
|
||||
creds = None
|
||||
if self._store:
|
||||
creds = self._store.load_credentials(
|
||||
name=spec.name, key_type=key_type, single_file=spec.single_file, issuer=self)
|
||||
if creds is None:
|
||||
creds = Ngtcp2TestCA.create_credentials(spec=spec, issuer=self, key_type=key_type,
|
||||
valid_from=spec.valid_from, valid_to=spec.valid_to)
|
||||
if self._store:
|
||||
self._store.save(creds, single_file=spec.single_file)
|
||||
if spec.type == "ca":
|
||||
self._store.save_chain(creds, "ca", with_root=True)
|
||||
|
||||
if spec.sub_specs:
|
||||
if self._store:
|
||||
sub_store = CertStore(fpath=os.path.join(self._store.path, creds.name))
|
||||
creds.set_store(sub_store)
|
||||
subchain = chain.copy() if chain else []
|
||||
subchain.append(self)
|
||||
creds.issue_certs(spec.sub_specs, chain=subchain)
|
||||
return creds
|
||||
|
||||
|
||||
class CertStore:
|
||||
|
||||
def __init__(self, fpath: str):
|
||||
self._store_dir = fpath
|
||||
if not os.path.exists(self._store_dir):
|
||||
os.makedirs(self._store_dir)
|
||||
self._creds_by_name = {}
|
||||
|
||||
@property
|
||||
def path(self) -> str:
|
||||
return self._store_dir
|
||||
|
||||
def save(self, creds: Credentials, name: str = None,
|
||||
chain: List[Credentials] = None,
|
||||
single_file: bool = False) -> None:
|
||||
name = name if name is not None else creds.name
|
||||
cert_file = self.get_cert_file(name=name, key_type=creds.key_type)
|
||||
pkey_file = self.get_pkey_file(name=name, key_type=creds.key_type)
|
||||
if single_file:
|
||||
pkey_file = None
|
||||
with open(cert_file, "wb") as fd:
|
||||
fd.write(creds.cert_pem)
|
||||
if chain:
|
||||
for c in chain:
|
||||
fd.write(c.cert_pem)
|
||||
if pkey_file is None:
|
||||
fd.write(creds.pkey_pem)
|
||||
if pkey_file is not None:
|
||||
with open(pkey_file, "wb") as fd:
|
||||
fd.write(creds.pkey_pem)
|
||||
creds.set_files(cert_file, pkey_file)
|
||||
self._add_credentials(name, creds)
|
||||
|
||||
def save_chain(self, creds: Credentials, infix: str, with_root=False):
|
||||
name = creds.name
|
||||
chain = [creds]
|
||||
while creds.issuer is not None:
|
||||
creds = creds.issuer
|
||||
chain.append(creds)
|
||||
if not with_root and len(chain) > 1:
|
||||
chain = chain[:-1]
|
||||
chain_file = os.path.join(self._store_dir, f'{name}-{infix}.pem')
|
||||
with open(chain_file, "wb") as fd:
|
||||
for c in chain:
|
||||
fd.write(c.cert_pem)
|
||||
|
||||
def _add_credentials(self, name: str, creds: Credentials):
|
||||
if name not in self._creds_by_name:
|
||||
self._creds_by_name[name] = []
|
||||
self._creds_by_name[name].append(creds)
|
||||
|
||||
def get_credentials_for_name(self, name) -> List[Credentials]:
|
||||
return self._creds_by_name[name] if name in self._creds_by_name else []
|
||||
|
||||
def get_cert_file(self, name: str, key_type=None) -> str:
|
||||
key_infix = ".{0}".format(key_type) if key_type is not None else ""
|
||||
return os.path.join(self._store_dir, f'{name}{key_infix}.cert.pem')
|
||||
|
||||
def get_pkey_file(self, name: str, key_type=None) -> str:
|
||||
key_infix = ".{0}".format(key_type) if key_type is not None else ""
|
||||
return os.path.join(self._store_dir, f'{name}{key_infix}.pkey.pem')
|
||||
|
||||
def load_pem_cert(self, fpath: str) -> x509.Certificate:
|
||||
with open(fpath) as fd:
|
||||
return x509.load_pem_x509_certificate("".join(fd.readlines()).encode())
|
||||
|
||||
def load_pem_pkey(self, fpath: str):
|
||||
with open(fpath) as fd:
|
||||
return load_pem_private_key("".join(fd.readlines()).encode(), password=None)
|
||||
|
||||
def load_credentials(self, name: str, key_type=None, single_file: bool = False, issuer: Credentials = None):
|
||||
cert_file = self.get_cert_file(name=name, key_type=key_type)
|
||||
pkey_file = cert_file if single_file else self.get_pkey_file(name=name, key_type=key_type)
|
||||
if os.path.isfile(cert_file) and os.path.isfile(pkey_file):
|
||||
cert = self.load_pem_cert(cert_file)
|
||||
pkey = self.load_pem_pkey(pkey_file)
|
||||
creds = Credentials(name=name, cert=cert, pkey=pkey, issuer=issuer)
|
||||
creds.set_store(self)
|
||||
creds.set_files(cert_file, pkey_file)
|
||||
self._add_credentials(name, creds)
|
||||
return creds
|
||||
return None
|
||||
|
||||
|
||||
class Ngtcp2TestCA:
|
||||
|
||||
@classmethod
|
||||
def create_root(cls, name: str, store_dir: str, key_type: str = "rsa2048") -> Credentials:
|
||||
store = CertStore(fpath=store_dir)
|
||||
creds = store.load_credentials(name="ca", key_type=key_type, issuer=None)
|
||||
if creds is None:
|
||||
creds = Ngtcp2TestCA._make_ca_credentials(name=name, key_type=key_type)
|
||||
store.save(creds, name="ca")
|
||||
creds.set_store(store)
|
||||
return creds
|
||||
|
||||
@staticmethod
|
||||
def create_credentials(spec: CertificateSpec, issuer: Credentials, key_type: Any,
|
||||
valid_from: timedelta = timedelta(days=-1),
|
||||
valid_to: timedelta = timedelta(days=89),
|
||||
) -> Credentials:
|
||||
"""Create a certificate signed by this CA for the given domains.
|
||||
:returns: the certificate and private key PEM file paths
|
||||
"""
|
||||
if spec.domains and len(spec.domains):
|
||||
creds = Ngtcp2TestCA._make_server_credentials(name=spec.name, domains=spec.domains,
|
||||
issuer=issuer, valid_from=valid_from,
|
||||
valid_to=valid_to, key_type=key_type)
|
||||
elif spec.client:
|
||||
creds = Ngtcp2TestCA._make_client_credentials(name=spec.name, issuer=issuer,
|
||||
email=spec.email, valid_from=valid_from,
|
||||
valid_to=valid_to, key_type=key_type)
|
||||
elif spec.name:
|
||||
creds = Ngtcp2TestCA._make_ca_credentials(name=spec.name, issuer=issuer,
|
||||
valid_from=valid_from, valid_to=valid_to,
|
||||
key_type=key_type)
|
||||
else:
|
||||
raise Exception(f"unrecognized certificate specification: {spec}")
|
||||
return creds
|
||||
|
||||
@staticmethod
|
||||
def _make_x509_name(org_name: str = None, common_name: str = None, parent: x509.Name = None) -> x509.Name:
|
||||
name_pieces = []
|
||||
if org_name:
|
||||
oid = NameOID.ORGANIZATIONAL_UNIT_NAME if parent else NameOID.ORGANIZATION_NAME
|
||||
name_pieces.append(x509.NameAttribute(oid, org_name))
|
||||
elif common_name:
|
||||
name_pieces.append(x509.NameAttribute(NameOID.COMMON_NAME, common_name))
|
||||
if parent:
|
||||
name_pieces.extend([rdn for rdn in parent])
|
||||
return x509.Name(name_pieces)
|
||||
|
||||
@staticmethod
|
||||
def _make_csr(
|
||||
subject: x509.Name,
|
||||
pkey: Any,
|
||||
issuer_subject: Optional[Credentials],
|
||||
valid_from_delta: timedelta = None,
|
||||
valid_until_delta: timedelta = None
|
||||
):
|
||||
pubkey = pkey.public_key()
|
||||
issuer_subject = issuer_subject if issuer_subject is not None else subject
|
||||
|
||||
valid_from = datetime.now()
|
||||
if valid_until_delta is not None:
|
||||
valid_from += valid_from_delta
|
||||
valid_until = datetime.now()
|
||||
if valid_until_delta is not None:
|
||||
valid_until += valid_until_delta
|
||||
|
||||
return (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(subject)
|
||||
.issuer_name(issuer_subject)
|
||||
.public_key(pubkey)
|
||||
.not_valid_before(valid_from)
|
||||
.not_valid_after(valid_until)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.add_extension(
|
||||
x509.SubjectKeyIdentifier.from_public_key(pubkey),
|
||||
critical=False,
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _add_ca_usages(csr: Any) -> Any:
|
||||
return csr.add_extension(
|
||||
x509.BasicConstraints(ca=True, path_length=9),
|
||||
critical=True,
|
||||
).add_extension(
|
||||
x509.KeyUsage(
|
||||
digital_signature=True,
|
||||
content_commitment=False,
|
||||
key_encipherment=False,
|
||||
data_encipherment=False,
|
||||
key_agreement=False,
|
||||
key_cert_sign=True,
|
||||
crl_sign=True,
|
||||
encipher_only=False,
|
||||
decipher_only=False),
|
||||
critical=True
|
||||
).add_extension(
|
||||
x509.ExtendedKeyUsage([
|
||||
ExtendedKeyUsageOID.CLIENT_AUTH,
|
||||
ExtendedKeyUsageOID.SERVER_AUTH,
|
||||
ExtendedKeyUsageOID.CODE_SIGNING,
|
||||
]),
|
||||
critical=True
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _add_leaf_usages(csr: Any, domains: List[str], issuer: Credentials) -> Any:
|
||||
return csr.add_extension(
|
||||
x509.BasicConstraints(ca=False, path_length=None),
|
||||
critical=True,
|
||||
).add_extension(
|
||||
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
issuer.certificate.extensions.get_extension_for_class(
|
||||
x509.SubjectKeyIdentifier).value),
|
||||
critical=False
|
||||
).add_extension(
|
||||
x509.SubjectAlternativeName([x509.DNSName(domain) for domain in domains]),
|
||||
critical=True,
|
||||
).add_extension(
|
||||
x509.ExtendedKeyUsage([
|
||||
ExtendedKeyUsageOID.SERVER_AUTH,
|
||||
]),
|
||||
critical=True
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _add_client_usages(csr: Any, issuer: Credentials, rfc82name: str = None) -> Any:
|
||||
cert = csr.add_extension(
|
||||
x509.BasicConstraints(ca=False, path_length=None),
|
||||
critical=True,
|
||||
).add_extension(
|
||||
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
issuer.certificate.extensions.get_extension_for_class(
|
||||
x509.SubjectKeyIdentifier).value),
|
||||
critical=False
|
||||
)
|
||||
if rfc82name:
|
||||
cert.add_extension(
|
||||
x509.SubjectAlternativeName([x509.RFC822Name(rfc82name)]),
|
||||
critical=True,
|
||||
)
|
||||
cert.add_extension(
|
||||
x509.ExtendedKeyUsage([
|
||||
ExtendedKeyUsageOID.CLIENT_AUTH,
|
||||
]),
|
||||
critical=True
|
||||
)
|
||||
return cert
|
||||
|
||||
@staticmethod
|
||||
def _make_ca_credentials(name, key_type: Any,
|
||||
issuer: Credentials = None,
|
||||
valid_from: timedelta = timedelta(days=-1),
|
||||
valid_to: timedelta = timedelta(days=89),
|
||||
) -> Credentials:
|
||||
pkey = _private_key(key_type=key_type)
|
||||
if issuer is not None:
|
||||
issuer_subject = issuer.certificate.subject
|
||||
issuer_key = issuer.private_key
|
||||
else:
|
||||
issuer_subject = None
|
||||
issuer_key = pkey
|
||||
subject = Ngtcp2TestCA._make_x509_name(org_name=name, parent=issuer.subject if issuer else None)
|
||||
csr = Ngtcp2TestCA._make_csr(subject=subject,
|
||||
issuer_subject=issuer_subject, pkey=pkey,
|
||||
valid_from_delta=valid_from, valid_until_delta=valid_to)
|
||||
csr = Ngtcp2TestCA._add_ca_usages(csr)
|
||||
cert = csr.sign(private_key=issuer_key,
|
||||
algorithm=hashes.SHA256(),
|
||||
backend=default_backend())
|
||||
return Credentials(name=name, cert=cert, pkey=pkey, issuer=issuer)
|
||||
|
||||
@staticmethod
|
||||
def _make_server_credentials(name: str, domains: List[str], issuer: Credentials,
|
||||
key_type: Any,
|
||||
valid_from: timedelta = timedelta(days=-1),
|
||||
valid_to: timedelta = timedelta(days=89),
|
||||
) -> Credentials:
|
||||
name = name
|
||||
pkey = _private_key(key_type=key_type)
|
||||
subject = Ngtcp2TestCA._make_x509_name(common_name=name, parent=issuer.subject)
|
||||
csr = Ngtcp2TestCA._make_csr(subject=subject,
|
||||
issuer_subject=issuer.certificate.subject, pkey=pkey,
|
||||
valid_from_delta=valid_from, valid_until_delta=valid_to)
|
||||
csr = Ngtcp2TestCA._add_leaf_usages(csr, domains=domains, issuer=issuer)
|
||||
cert = csr.sign(private_key=issuer.private_key,
|
||||
algorithm=hashes.SHA256(),
|
||||
backend=default_backend())
|
||||
return Credentials(name=name, cert=cert, pkey=pkey, issuer=issuer)
|
||||
|
||||
@staticmethod
|
||||
def _make_client_credentials(name: str,
|
||||
issuer: Credentials, email: Optional[str],
|
||||
key_type: Any,
|
||||
valid_from: timedelta = timedelta(days=-1),
|
||||
valid_to: timedelta = timedelta(days=89),
|
||||
) -> Credentials:
|
||||
pkey = _private_key(key_type=key_type)
|
||||
subject = Ngtcp2TestCA._make_x509_name(common_name=name, parent=issuer.subject)
|
||||
csr = Ngtcp2TestCA._make_csr(subject=subject,
|
||||
issuer_subject=issuer.certificate.subject, pkey=pkey,
|
||||
valid_from_delta=valid_from, valid_until_delta=valid_to)
|
||||
csr = Ngtcp2TestCA._add_client_usages(csr, issuer=issuer, rfc82name=email)
|
||||
cert = csr.sign(private_key=issuer.private_key,
|
||||
algorithm=hashes.SHA256(),
|
||||
backend=default_backend())
|
||||
return Credentials(name=name, cert=cert, pkey=pkey, issuer=issuer)
|
||||
187
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/client.py
vendored
Normal file
187
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/client.py
vendored
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
import logging
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from typing import List
|
||||
|
||||
import pytest
|
||||
|
||||
from .server import ExampleServer, ServerRun
|
||||
from .certs import Credentials
|
||||
from .tls import HandShake, HSRecord
|
||||
from .env import Env, CryptoLib
|
||||
from .log import LogFile, HexDumpScanner
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ClientRun:
|
||||
|
||||
def __init__(self, env: Env, returncode, logfile: LogFile, srun: ServerRun):
|
||||
self.env = env
|
||||
self.returncode = returncode
|
||||
self.logfile = logfile
|
||||
self.log_lines = logfile.get_recent()
|
||||
self._data_recs = None
|
||||
self._hs_recs = None
|
||||
self._srun = srun
|
||||
if self.env.verbose > 1:
|
||||
log.debug(f'read {len(self.log_lines)} lines from {logfile.path}')
|
||||
|
||||
@property
|
||||
def handshake(self) -> List[HSRecord]:
|
||||
if self._data_recs is None:
|
||||
crypto_line = re.compile(r'Ordered CRYPTO data in \S+ crypto level')
|
||||
scanner = HexDumpScanner(source=self.log_lines,
|
||||
leading_regex=crypto_line)
|
||||
self._data_recs = [data for data in scanner]
|
||||
if self.env.verbose > 1:
|
||||
log.debug(f'detected {len(self._data_recs)} crypto hexdumps '
|
||||
f'in {self.logfile.path}')
|
||||
if self._hs_recs is None:
|
||||
self._hs_recs = [hrec for hrec in HandShake(source=self._data_recs,
|
||||
verbose=self.env.verbose)]
|
||||
if self.env.verbose > 1:
|
||||
log.debug(f'detected {len(self._hs_recs)} crypto '
|
||||
f'records in {self.logfile.path}')
|
||||
return self._hs_recs
|
||||
|
||||
@property
|
||||
def hs_stripe(self) -> str:
|
||||
return ":".join([hrec.name for hrec in self.handshake])
|
||||
|
||||
@property
|
||||
def early_data_rejected(self) -> bool:
|
||||
for l in self.log_lines:
|
||||
if re.match(r'^Early data was rejected by server.*', l):
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def server(self) -> ServerRun:
|
||||
return self._srun
|
||||
|
||||
def norm_exp(self, c_hs, s_hs, allow_hello_retry=True):
|
||||
if allow_hello_retry and self.hs_stripe.startswith('HelloRetryRequest:'):
|
||||
c_hs = "HelloRetryRequest:" + c_hs
|
||||
s_hs = "ClientHello:" + s_hs
|
||||
return c_hs, s_hs
|
||||
|
||||
def _assert_hs(self, c_hs, s_hs):
|
||||
if re.match('^'+c_hs, self.hs_stripe) is None:
|
||||
# what happened?
|
||||
if self.hs_stripe == '':
|
||||
# server send nothing
|
||||
if self.server.hs_stripe == '':
|
||||
# client send nothing
|
||||
pytest.fail(f'client did not send a ClientHello"')
|
||||
else:
|
||||
# client send sth, but server did not respond
|
||||
pytest.fail(f'server did not respond to ClientHello: '
|
||||
f'{self.server.handshake[0].to_text()}"')
|
||||
else:
|
||||
pytest.fail(f'Expected "{c_hs}", got "{self.hs_stripe}"')
|
||||
assert re.match('^'+s_hs+'$', self.server.hs_stripe) is not None, \
|
||||
f'Expected "{s_hs}", got "{self.server.hs_stripe}"\n'
|
||||
|
||||
def assert_non_resume_handshake(self, allow_hello_retry=True):
|
||||
# for client/server where KEY_SHARE do not match, the hello is retried
|
||||
c_hs, s_hs = self.norm_exp(
|
||||
"ServerHello:EncryptedExtensions:(Compressed)?Certificate:CertificateVerify:Finished",
|
||||
"ClientHello:Finished", allow_hello_retry=allow_hello_retry)
|
||||
self._assert_hs(c_hs, s_hs)
|
||||
|
||||
def assert_resume_handshake(self):
|
||||
# for client/server where KEY_SHARE do not match, the hello is retried
|
||||
c_hs, s_hs = self.norm_exp("ServerHello:EncryptedExtensions:Finished",
|
||||
"ClientHello:Finished")
|
||||
self._assert_hs(c_hs, s_hs)
|
||||
|
||||
def assert_verify_null_handshake(self):
|
||||
c_hs, s_hs = self.norm_exp(
|
||||
"ServerHello:EncryptedExtensions:CertificateRequest:(Compressed)?Certificate:CertificateVerify:Finished",
|
||||
"ClientHello:Certificate:Finished")
|
||||
self._assert_hs(c_hs, s_hs)
|
||||
|
||||
def assert_verify_cert_handshake(self):
|
||||
c_hs, s_hs = self.norm_exp(
|
||||
"ServerHello:EncryptedExtensions:CertificateRequest:(Compressed)?Certificate:CertificateVerify:Finished",
|
||||
"ClientHello:Certificate:CertificateVerify:Finished")
|
||||
self._assert_hs(c_hs, s_hs)
|
||||
|
||||
|
||||
class ExampleClient:
|
||||
|
||||
def __init__(self, env: Env, crypto_lib: str):
|
||||
self.env = env
|
||||
self._crypto_lib = crypto_lib
|
||||
self._path = env.client_path(self._crypto_lib)
|
||||
self._log_path = f'{self.env.gen_dir}/{self._crypto_lib}-client.log'
|
||||
self._qlog_path = f'{self.env.gen_dir}/{self._crypto_lib}-client.qlog'
|
||||
self._session_path = f'{self.env.gen_dir}/{self._crypto_lib}-client.session'
|
||||
self._tp_path = f'{self.env.gen_dir}/{self._crypto_lib}-client.tp'
|
||||
self._data_path = f'{self.env.gen_dir}/{self._crypto_lib}-client.data'
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return self._path
|
||||
|
||||
@property
|
||||
def crypto_lib(self):
|
||||
return self._crypto_lib
|
||||
|
||||
@property
|
||||
def uses_cipher_config(self):
|
||||
return CryptoLib.uses_cipher_config(self.crypto_lib)
|
||||
|
||||
def supports_cipher(self, cipher):
|
||||
return CryptoLib.supports_cipher(self.crypto_lib, cipher)
|
||||
|
||||
def exists(self):
|
||||
return os.path.isfile(self.path)
|
||||
|
||||
def clear_session(self):
|
||||
if os.path.isfile(self._session_path):
|
||||
os.remove(self._session_path)
|
||||
if os.path.isfile(self._tp_path):
|
||||
os.remove(self._tp_path)
|
||||
|
||||
def http_get(self, server: ExampleServer, url: str, extra_args: List[str] = None,
|
||||
use_session=False, data=None,
|
||||
credentials: Credentials = None,
|
||||
ciphers: str = None):
|
||||
args = [
|
||||
self.path, '--exit-on-all-streams-close',
|
||||
f'--qlog-file={self._qlog_path}'
|
||||
]
|
||||
if use_session:
|
||||
args.append(f'--session-file={self._session_path}')
|
||||
args.append(f'--tp-file={self._tp_path}')
|
||||
if data is not None:
|
||||
with open(self._data_path, 'w') as fd:
|
||||
fd.write(data)
|
||||
args.append(f'--data={self._data_path}')
|
||||
if ciphers is not None:
|
||||
ciphers = CryptoLib.adjust_ciphers(self.crypto_lib, ciphers)
|
||||
args.append(f'--ciphers={ciphers}')
|
||||
if credentials is not None:
|
||||
args.append(f'--key={credentials.pkey_file}')
|
||||
args.append(f'--cert={credentials.cert_file}')
|
||||
if extra_args is not None:
|
||||
args.extend(extra_args)
|
||||
args.extend([
|
||||
'localhost', str(self.env.examples_port),
|
||||
url
|
||||
])
|
||||
if os.path.isfile(self._qlog_path):
|
||||
os.remove(self._qlog_path)
|
||||
with open(self._log_path, 'w') as log_file:
|
||||
logfile = LogFile(path=self._log_path)
|
||||
server.log.advance()
|
||||
process = subprocess.Popen(args=args, text=True,
|
||||
stdout=log_file, stderr=log_file)
|
||||
process.wait()
|
||||
return ClientRun(env=self.env, returncode=process.returncode,
|
||||
logfile=logfile, srun=server.get_run())
|
||||
|
||||
191
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/env.py
vendored
Normal file
191
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/env.py
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
import logging
|
||||
import os
|
||||
from configparser import ConfigParser, ExtendedInterpolation
|
||||
from typing import Dict, Optional
|
||||
|
||||
from .certs import CertificateSpec, Ngtcp2TestCA, Credentials
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CryptoLib:
|
||||
|
||||
IGNORES_CIPHER_CONFIG = [
|
||||
'picotls', 'boringssl'
|
||||
]
|
||||
UNSUPPORTED_CIPHERS = {
|
||||
'wolfssl': [
|
||||
'TLS_AES_128_CCM_SHA256', # no plans to
|
||||
],
|
||||
'picotls': [
|
||||
'TLS_AES_128_CCM_SHA256', # no plans to
|
||||
],
|
||||
'boringssl': [
|
||||
'TLS_AES_128_CCM_SHA256', # no plans to
|
||||
]
|
||||
}
|
||||
GNUTLS_CIPHERS = {
|
||||
'TLS_AES_128_GCM_SHA256': 'AES-128-GCM',
|
||||
'TLS_AES_256_GCM_SHA384': 'AES-256-GCM',
|
||||
'TLS_CHACHA20_POLY1305_SHA256': 'CHACHA20-POLY1305',
|
||||
'TLS_AES_128_CCM_SHA256': 'AES-128-CCM',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def uses_cipher_config(cls, crypto_lib):
|
||||
return crypto_lib not in cls.IGNORES_CIPHER_CONFIG
|
||||
|
||||
@classmethod
|
||||
def supports_cipher(cls, crypto_lib, cipher):
|
||||
return crypto_lib not in cls.UNSUPPORTED_CIPHERS or \
|
||||
cipher not in cls.UNSUPPORTED_CIPHERS[crypto_lib]
|
||||
|
||||
@classmethod
|
||||
def adjust_ciphers(cls, crypto_lib, ciphers: str) -> str:
|
||||
if crypto_lib == 'gnutls':
|
||||
gciphers = "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL"
|
||||
for cipher in ciphers.split(':'):
|
||||
gciphers += f':+{cls.GNUTLS_CIPHERS[cipher]}'
|
||||
return gciphers
|
||||
return ciphers
|
||||
|
||||
|
||||
def init_config_from(conf_path):
|
||||
if os.path.isfile(conf_path):
|
||||
config = ConfigParser(interpolation=ExtendedInterpolation())
|
||||
config.read(conf_path)
|
||||
return config
|
||||
return None
|
||||
|
||||
|
||||
TESTS_PATH = os.path.dirname(os.path.dirname(__file__))
|
||||
EXAMPLES_PATH = os.path.dirname(TESTS_PATH)
|
||||
DEF_CONFIG = init_config_from(os.path.join(TESTS_PATH, 'config.ini'))
|
||||
|
||||
|
||||
class Env:
|
||||
|
||||
@classmethod
|
||||
def get_crypto_libs(cls, configurable_ciphers=None):
|
||||
names = [name for name in DEF_CONFIG['examples']
|
||||
if DEF_CONFIG['examples'][name] == 'yes']
|
||||
if configurable_ciphers is not None:
|
||||
names = [n for n in names if CryptoLib.uses_cipher_config(n)]
|
||||
return names
|
||||
|
||||
def __init__(self, examples_dir=None, tests_dir=None, config=None,
|
||||
pytestconfig=None):
|
||||
self._verbose = pytestconfig.option.verbose if pytestconfig is not None else 0
|
||||
self._examples_dir = examples_dir if examples_dir is not None else EXAMPLES_PATH
|
||||
self._tests_dir = examples_dir if tests_dir is not None else TESTS_PATH
|
||||
self._gen_dir = os.path.join(self._tests_dir, 'gen')
|
||||
self.config = config if config is not None else DEF_CONFIG
|
||||
self._version = self.config['ngtcp2']['version']
|
||||
self._crypto_libs = [name for name in self.config['examples']
|
||||
if self.config['examples'][name] == 'yes']
|
||||
self._clients = [self.config['clients'][lib] for lib in self._crypto_libs
|
||||
if lib in self.config['clients']]
|
||||
self._servers = [self.config['servers'][lib] for lib in self._crypto_libs
|
||||
if lib in self.config['servers']]
|
||||
self._examples_pem = {
|
||||
'key': 'xxx',
|
||||
'cert': 'xxx',
|
||||
}
|
||||
self._htdocs_dir = os.path.join(self._gen_dir, 'htdocs')
|
||||
self._tld = 'tests.ngtcp2.nghttp2.org'
|
||||
self._example_domain = f"one.{self._tld}"
|
||||
self._ca = None
|
||||
self._cert_specs = [
|
||||
CertificateSpec(domains=[self._example_domain], key_type='rsa2048'),
|
||||
CertificateSpec(name="clientsX", sub_specs=[
|
||||
CertificateSpec(name="user1", client=True),
|
||||
]),
|
||||
]
|
||||
|
||||
def issue_certs(self):
|
||||
if self._ca is None:
|
||||
self._ca = Ngtcp2TestCA.create_root(name=self._tld,
|
||||
store_dir=os.path.join(self.gen_dir, 'ca'),
|
||||
key_type="rsa2048")
|
||||
self._ca.issue_certs(self._cert_specs)
|
||||
|
||||
def setup(self):
|
||||
os.makedirs(self._gen_dir, exist_ok=True)
|
||||
os.makedirs(self._htdocs_dir, exist_ok=True)
|
||||
self.issue_certs()
|
||||
|
||||
def get_server_credentials(self) -> Optional[Credentials]:
|
||||
creds = self.ca.get_credentials_for_name(self._example_domain)
|
||||
if len(creds) > 0:
|
||||
return creds[0]
|
||||
return None
|
||||
|
||||
@property
|
||||
def verbose(self) -> int:
|
||||
return self._verbose
|
||||
|
||||
@property
|
||||
def version(self) -> str:
|
||||
return self._version
|
||||
|
||||
@property
|
||||
def gen_dir(self) -> str:
|
||||
return self._gen_dir
|
||||
|
||||
@property
|
||||
def ca(self):
|
||||
return self._ca
|
||||
|
||||
@property
|
||||
def htdocs_dir(self) -> str:
|
||||
return self._htdocs_dir
|
||||
|
||||
@property
|
||||
def example_domain(self) -> str:
|
||||
return self._example_domain
|
||||
|
||||
@property
|
||||
def examples_dir(self) -> str:
|
||||
return self._examples_dir
|
||||
|
||||
@property
|
||||
def examples_port(self) -> int:
|
||||
return int(self.config['examples']['port'])
|
||||
|
||||
@property
|
||||
def examples_pem(self) -> Dict[str, str]:
|
||||
return self._examples_pem
|
||||
|
||||
@property
|
||||
def crypto_libs(self):
|
||||
return self._crypto_libs
|
||||
|
||||
@property
|
||||
def clients(self):
|
||||
return self._clients
|
||||
|
||||
@property
|
||||
def servers(self):
|
||||
return self._servers
|
||||
|
||||
def client_name(self, crypto_lib):
|
||||
if crypto_lib in self.config['clients']:
|
||||
return self.config['clients'][crypto_lib]
|
||||
return None
|
||||
|
||||
def client_path(self, crypto_lib):
|
||||
cname = self.client_name(crypto_lib)
|
||||
if cname is not None:
|
||||
return os.path.join(self.examples_dir, cname)
|
||||
return None
|
||||
|
||||
def server_name(self, crypto_lib):
|
||||
if crypto_lib in self.config['servers']:
|
||||
return self.config['servers'][crypto_lib]
|
||||
return None
|
||||
|
||||
def server_path(self, crypto_lib):
|
||||
sname = self.server_name(crypto_lib)
|
||||
if sname is not None:
|
||||
return os.path.join(self.examples_dir, sname)
|
||||
return None
|
||||
101
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/log.py
vendored
Normal file
101
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/log.py
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import binascii
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from datetime import timedelta, datetime
|
||||
from io import SEEK_END
|
||||
from typing import List
|
||||
|
||||
|
||||
class LogFile:
|
||||
|
||||
def __init__(self, path: str):
|
||||
self._path = path
|
||||
self._start_pos = 0
|
||||
self._last_pos = self._start_pos
|
||||
|
||||
@property
|
||||
def path(self) -> str:
|
||||
return self._path
|
||||
|
||||
def reset(self):
|
||||
self._start_pos = 0
|
||||
self._last_pos = self._start_pos
|
||||
|
||||
def advance(self) -> None:
|
||||
if os.path.isfile(self._path):
|
||||
with open(self._path) as fd:
|
||||
self._start_pos = fd.seek(0, SEEK_END)
|
||||
|
||||
def get_recent(self, advance=True) -> List[str]:
|
||||
lines = []
|
||||
if os.path.isfile(self._path):
|
||||
with open(self._path) as fd:
|
||||
fd.seek(self._last_pos, os.SEEK_SET)
|
||||
for line in fd:
|
||||
lines.append(line)
|
||||
if advance:
|
||||
self._last_pos = fd.tell()
|
||||
return lines
|
||||
|
||||
def scan_recent(self, pattern: re, timeout=10) -> bool:
|
||||
if not os.path.isfile(self.path):
|
||||
return False
|
||||
with open(self.path) as fd:
|
||||
end = datetime.now() + timedelta(seconds=timeout)
|
||||
while True:
|
||||
fd.seek(self._last_pos, os.SEEK_SET)
|
||||
for line in fd:
|
||||
if pattern.match(line):
|
||||
return True
|
||||
if datetime.now() > end:
|
||||
raise TimeoutError(f"pattern not found in error log after {timeout} seconds")
|
||||
time.sleep(.1)
|
||||
return False
|
||||
|
||||
|
||||
class HexDumpScanner:
|
||||
|
||||
def __init__(self, source, leading_regex=None):
|
||||
self._source = source
|
||||
self._leading_regex = leading_regex
|
||||
|
||||
def __iter__(self):
|
||||
data = b''
|
||||
offset = 0 if self._leading_regex is None else -1
|
||||
idx = 0
|
||||
for l in self._source:
|
||||
if offset == -1:
|
||||
pass
|
||||
elif offset == 0:
|
||||
# possible start of a hex dump
|
||||
m = re.match(r'^\s*0+(\s+-)?((\s+[0-9a-f]{2}){1,16})(\s+.*)$',
|
||||
l, re.IGNORECASE)
|
||||
if m:
|
||||
data = binascii.unhexlify(re.sub(r'\s+', '', m.group(2)))
|
||||
offset = 16
|
||||
idx = 1
|
||||
continue
|
||||
else:
|
||||
# possible continuation of a hexdump
|
||||
m = re.match(r'^\s*([0-9a-f]+)(\s+-)?((\s+[0-9a-f]{2}){1,16})'
|
||||
r'(\s+.*)$', l, re.IGNORECASE)
|
||||
if m:
|
||||
loffset = int(m.group(1), 16)
|
||||
if loffset == offset or loffset == idx:
|
||||
data += binascii.unhexlify(re.sub(r'\s+', '',
|
||||
m.group(3)))
|
||||
offset += 16
|
||||
idx += 1
|
||||
continue
|
||||
else:
|
||||
sys.stderr.write(f'wrong offset {loffset}, expected {offset} or {idx}\n')
|
||||
# not a hexdump line, produce any collected data
|
||||
if len(data) > 0:
|
||||
yield data
|
||||
data = b''
|
||||
offset = 0 if self._leading_regex is None \
|
||||
or self._leading_regex.match(l) else -1
|
||||
if len(data) > 0:
|
||||
yield data
|
||||
137
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/server.py
vendored
Normal file
137
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/server.py
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
import logging
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from threading import Thread
|
||||
|
||||
from .tls import HandShake
|
||||
from .env import Env, CryptoLib
|
||||
from .log import LogFile, HexDumpScanner
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ServerRun:
|
||||
|
||||
def __init__(self, env: Env, logfile: LogFile):
|
||||
self.env = env
|
||||
self._logfile = logfile
|
||||
self.log_lines = self._logfile.get_recent()
|
||||
self._data_recs = None
|
||||
self._hs_recs = None
|
||||
if self.env.verbose > 1:
|
||||
log.debug(f'read {len(self.log_lines)} lines from {logfile.path}')
|
||||
|
||||
@property
|
||||
def handshake(self):
|
||||
if self._data_recs is None:
|
||||
self._data_recs = [data for data in HexDumpScanner(source=self.log_lines)]
|
||||
if self.env.verbose > 1:
|
||||
log.debug(f'detected {len(self._data_recs)} hexdumps '
|
||||
f'in {self._logfile.path}')
|
||||
if self._hs_recs is None:
|
||||
self._hs_recs = [hrec for hrec in HandShake(source=self._data_recs,
|
||||
verbose=self.env.verbose)]
|
||||
if self.env.verbose > 1:
|
||||
log.debug(f'detected {len(self._hs_recs)} crypto records '
|
||||
f'in {self._logfile.path}')
|
||||
return self._hs_recs
|
||||
|
||||
@property
|
||||
def hs_stripe(self):
|
||||
return ":".join([hrec.name for hrec in self.handshake])
|
||||
|
||||
|
||||
def monitor_proc(env: Env, proc):
|
||||
_env = env
|
||||
proc.wait()
|
||||
|
||||
|
||||
class ExampleServer:
|
||||
|
||||
def __init__(self, env: Env, crypto_lib: str, verify_client=False):
|
||||
self.env = env
|
||||
self._crypto_lib = crypto_lib
|
||||
self._path = env.server_path(self._crypto_lib)
|
||||
self._logpath = f'{self.env.gen_dir}/{self._crypto_lib}-server.log'
|
||||
self._log = LogFile(path=self._logpath)
|
||||
self._logfile = None
|
||||
self._process = None
|
||||
self._verify_client = verify_client
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return self._path
|
||||
|
||||
@property
|
||||
def crypto_lib(self):
|
||||
return self._crypto_lib
|
||||
|
||||
@property
|
||||
def uses_cipher_config(self):
|
||||
return CryptoLib.uses_cipher_config(self.crypto_lib)
|
||||
|
||||
def supports_cipher(self, cipher):
|
||||
return CryptoLib.supports_cipher(self.crypto_lib, cipher)
|
||||
|
||||
@property
|
||||
def log(self):
|
||||
return self._log
|
||||
|
||||
def exists(self):
|
||||
return os.path.isfile(self.path)
|
||||
|
||||
def start(self):
|
||||
if self._process is not None:
|
||||
return False
|
||||
creds = self.env.get_server_credentials()
|
||||
assert creds
|
||||
args = [
|
||||
self.path,
|
||||
f'--htdocs={self.env.htdocs_dir}',
|
||||
]
|
||||
if self._verify_client:
|
||||
args.append('--verify-client')
|
||||
args.extend([
|
||||
'*', str(self.env.examples_port),
|
||||
creds.pkey_file, creds.cert_file
|
||||
])
|
||||
self._logfile = open(self._logpath, 'w')
|
||||
self._process = subprocess.Popen(args=args, text=True,
|
||||
stdout=self._logfile, stderr=self._logfile)
|
||||
t = Thread(target=monitor_proc, daemon=True, args=(self.env, self._process))
|
||||
t.start()
|
||||
timeout = 5
|
||||
end = datetime.now() + timedelta(seconds=timeout)
|
||||
while True:
|
||||
if self._process.poll():
|
||||
return False
|
||||
try:
|
||||
if self.log.scan_recent(pattern=re.compile(r'^Using document root'), timeout=0.5):
|
||||
break
|
||||
except TimeoutError:
|
||||
pass
|
||||
if datetime.now() > end:
|
||||
raise TimeoutError(f"pattern not found in error log after {timeout} seconds")
|
||||
self.log.advance()
|
||||
return True
|
||||
|
||||
def stop(self):
|
||||
if self._process:
|
||||
self._process.terminate()
|
||||
self._process = None
|
||||
if self._logfile:
|
||||
self._logfile.close()
|
||||
self._logfile = None
|
||||
return True
|
||||
|
||||
def restart(self):
|
||||
self.stop()
|
||||
self._log.reset()
|
||||
return self.start()
|
||||
|
||||
def get_run(self) -> ServerRun:
|
||||
return ServerRun(env=self.env, logfile=self.log)
|
||||
983
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/tls.py
vendored
Normal file
983
deps/ngtcp2/ngtcp2/examples/tests/ngtcp2test/tls.py
vendored
Normal file
|
|
@ -0,0 +1,983 @@
|
|||
import binascii
|
||||
import logging
|
||||
import sys
|
||||
from collections.abc import Iterator
|
||||
from typing import Dict, Any, Iterable
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ParseError(Exception):
|
||||
pass
|
||||
|
||||
def _get_int(d, n):
|
||||
if len(d) < n:
|
||||
raise ParseError(f'get_int: {n} bytes needed, but data is {d}')
|
||||
if n == 1:
|
||||
dlen = d[0]
|
||||
else:
|
||||
dlen = int.from_bytes(d[0:n], byteorder='big')
|
||||
return d[n:], dlen
|
||||
|
||||
|
||||
def _get_field(d, dlen):
|
||||
if dlen > 0:
|
||||
if len(d) < dlen:
|
||||
raise ParseError(f'field len={dlen}, but data len={len(d)}')
|
||||
field = d[0:dlen]
|
||||
return d[dlen:], field
|
||||
return d, b''
|
||||
|
||||
|
||||
def _get_len_field(d, n):
|
||||
d, dlen = _get_int(d, n)
|
||||
return _get_field(d, dlen)
|
||||
|
||||
|
||||
# d are bytes that start with a quic variable length integer
|
||||
def _get_qint(d):
|
||||
i = d[0] & 0xc0
|
||||
if i == 0:
|
||||
return d[1:], int(d[0])
|
||||
elif i == 0x40:
|
||||
ndata = bytearray(d[0:2])
|
||||
d = d[2:]
|
||||
ndata[0] = ndata[0] & ~0xc0
|
||||
return d, int.from_bytes(ndata, byteorder='big')
|
||||
elif i == 0x80:
|
||||
ndata = bytearray(d[0:4])
|
||||
d = d[4:]
|
||||
ndata[0] = ndata[0] & ~0xc0
|
||||
return d, int.from_bytes(ndata, byteorder='big')
|
||||
else:
|
||||
ndata = bytearray(d[0:8])
|
||||
d = d[8:]
|
||||
ndata[0] = ndata[0] & ~0xc0
|
||||
return d, int.from_bytes(ndata, byteorder='big')
|
||||
|
||||
|
||||
class TlsSupportedGroups:
|
||||
NAME_BY_ID = {
|
||||
0: 'Reserved',
|
||||
1: 'sect163k1',
|
||||
2: 'sect163r1',
|
||||
3: 'sect163r2',
|
||||
4: 'sect193r1',
|
||||
5: 'sect193r2',
|
||||
6: 'sect233k1',
|
||||
7: 'sect233r1',
|
||||
8: 'sect239k1',
|
||||
9: 'sect283k1',
|
||||
10: 'sect283r1',
|
||||
11: 'sect409k1',
|
||||
12: 'sect409r1',
|
||||
13: 'sect571k1',
|
||||
14: 'sect571r1',
|
||||
15: 'secp160k1',
|
||||
16: 'secp160r1',
|
||||
17: 'secp160r2',
|
||||
18: 'secp192k1',
|
||||
19: 'secp192r1',
|
||||
20: 'secp224k1',
|
||||
21: 'secp224r1',
|
||||
22: 'secp256k1',
|
||||
23: 'secp256r1',
|
||||
24: 'secp384r1',
|
||||
25: 'secp521r1',
|
||||
26: 'brainpoolP256r1',
|
||||
27: 'brainpoolP384r1',
|
||||
28: 'brainpoolP512r1',
|
||||
29: 'x25519',
|
||||
30: 'x448',
|
||||
31: 'brainpoolP256r1tls13',
|
||||
32: 'brainpoolP384r1tls13',
|
||||
33: 'brainpoolP512r1tls13',
|
||||
34: 'GC256A',
|
||||
35: 'GC256B',
|
||||
36: 'GC256C',
|
||||
37: 'GC256D',
|
||||
38: 'GC512A',
|
||||
39: 'GC512B',
|
||||
40: 'GC512C',
|
||||
41: 'curveSM2',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def name(cls, gid):
|
||||
if gid in cls.NAME_BY_ID:
|
||||
return f'{cls.NAME_BY_ID[gid]}(0x{gid:0x})'
|
||||
return f'0x{gid:0x}'
|
||||
|
||||
|
||||
class TlsSignatureScheme:
|
||||
NAME_BY_ID = {
|
||||
0x0201: 'rsa_pkcs1_sha1',
|
||||
0x0202: 'Reserved',
|
||||
0x0203: 'ecdsa_sha1',
|
||||
0x0401: 'rsa_pkcs1_sha256',
|
||||
0x0403: 'ecdsa_secp256r1_sha256',
|
||||
0x0420: 'rsa_pkcs1_sha256_legacy',
|
||||
0x0501: 'rsa_pkcs1_sha384',
|
||||
0x0503: 'ecdsa_secp384r1_sha384',
|
||||
0x0520: 'rsa_pkcs1_sha384_legacy',
|
||||
0x0601: 'rsa_pkcs1_sha512',
|
||||
0x0603: 'ecdsa_secp521r1_sha512',
|
||||
0x0620: 'rsa_pkcs1_sha512_legacy',
|
||||
0x0704: 'eccsi_sha256',
|
||||
0x0705: 'iso_ibs1',
|
||||
0x0706: 'iso_ibs2',
|
||||
0x0707: 'iso_chinese_ibs',
|
||||
0x0708: 'sm2sig_sm3',
|
||||
0x0709: 'gostr34102012_256a',
|
||||
0x070A: 'gostr34102012_256b',
|
||||
0x070B: 'gostr34102012_256c',
|
||||
0x070C: 'gostr34102012_256d',
|
||||
0x070D: 'gostr34102012_512a',
|
||||
0x070E: 'gostr34102012_512b',
|
||||
0x070F: 'gostr34102012_512c',
|
||||
0x0804: 'rsa_pss_rsae_sha256',
|
||||
0x0805: 'rsa_pss_rsae_sha384',
|
||||
0x0806: 'rsa_pss_rsae_sha512',
|
||||
0x0807: 'ed25519',
|
||||
0x0808: 'ed448',
|
||||
0x0809: 'rsa_pss_pss_sha256',
|
||||
0x080A: 'rsa_pss_pss_sha384',
|
||||
0x080B: 'rsa_pss_pss_sha512',
|
||||
0x081A: 'ecdsa_brainpoolP256r1tls13_sha256',
|
||||
0x081B: 'ecdsa_brainpoolP384r1tls13_sha384',
|
||||
0x081C: 'ecdsa_brainpoolP512r1tls13_sha512',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def name(cls, gid):
|
||||
if gid in cls.NAME_BY_ID:
|
||||
return f'{cls.NAME_BY_ID[gid]}(0x{gid:0x})'
|
||||
return f'0x{gid:0x}'
|
||||
|
||||
|
||||
class TlsCipherSuites:
|
||||
NAME_BY_ID = {
|
||||
0x1301: 'TLS_AES_128_GCM_SHA256',
|
||||
0x1302: 'TLS_AES_256_GCM_SHA384',
|
||||
0x1303: 'TLS_CHACHA20_POLY1305_SHA256',
|
||||
0x1304: 'TLS_AES_128_CCM_SHA256',
|
||||
0x1305: 'TLS_AES_128_CCM_8_SHA256',
|
||||
0x00ff: 'TLS_EMPTY_RENEGOTIATION_INFO_SCSV',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def name(cls, cid):
|
||||
if cid in cls.NAME_BY_ID:
|
||||
return f'{cls.NAME_BY_ID[cid]}(0x{cid:0x})'
|
||||
return f'Cipher(0x{cid:0x})'
|
||||
|
||||
|
||||
class PskKeyExchangeMode:
|
||||
NAME_BY_ID = {
|
||||
0x00: 'psk_ke',
|
||||
0x01: 'psk_dhe_ke',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def name(cls, gid):
|
||||
if gid in cls.NAME_BY_ID:
|
||||
return f'{cls.NAME_BY_ID[gid]}(0x{gid:0x})'
|
||||
return f'0x{gid:0x}'
|
||||
|
||||
|
||||
class QuicTransportParam:
|
||||
NAME_BY_ID = {
|
||||
0x00: 'original_destination_connection_id',
|
||||
0x01: 'max_idle_timeout',
|
||||
0x02: 'stateless_reset_token',
|
||||
0x03: 'max_udp_payload_size',
|
||||
0x04: 'initial_max_data',
|
||||
0x05: 'initial_max_stream_data_bidi_local',
|
||||
0x06: 'initial_max_stream_data_bidi_remote',
|
||||
0x07: 'initial_max_stream_data_uni',
|
||||
0x08: 'initial_max_streams_bidi',
|
||||
0x09: 'initial_max_streams_uni',
|
||||
0x0a: 'ack_delay_exponent',
|
||||
0x0b: 'max_ack_delay',
|
||||
0x0c: 'disable_active_migration',
|
||||
0x0d: 'preferred_address',
|
||||
0x0e: 'active_connection_id_limit',
|
||||
0x0f: 'initial_source_connection_id',
|
||||
0x10: 'retry_source_connection_id',
|
||||
}
|
||||
TYPE_BY_ID = {
|
||||
0x00: bytes,
|
||||
0x01: int,
|
||||
0x02: bytes,
|
||||
0x03: int,
|
||||
0x04: int,
|
||||
0x05: int,
|
||||
0x06: int,
|
||||
0x07: int,
|
||||
0x08: int,
|
||||
0x09: int,
|
||||
0x0a: int,
|
||||
0x0b: int,
|
||||
0x0c: int,
|
||||
0x0d: bytes,
|
||||
0x0e: int,
|
||||
0x0f: bytes,
|
||||
0x10: bytes,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def name(cls, cid):
|
||||
if cid in cls.NAME_BY_ID:
|
||||
return f'{cls.NAME_BY_ID[cid]}(0x{cid:0x})'
|
||||
return f'QuicTP(0x{cid:0x})'
|
||||
|
||||
@classmethod
|
||||
def is_qint(cls, cid):
|
||||
if cid in cls.TYPE_BY_ID:
|
||||
return cls.TYPE_BY_ID[cid] == int
|
||||
return False
|
||||
|
||||
|
||||
class Extension:
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
self._eid = eid
|
||||
self._name = name
|
||||
self._edata = edata
|
||||
self._hsid = hsid
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self._edata
|
||||
|
||||
@property
|
||||
def hsid(self):
|
||||
return self._hsid
|
||||
|
||||
def to_json(self):
|
||||
jdata = {
|
||||
'id': self._eid,
|
||||
'name': self._name,
|
||||
}
|
||||
if len(self.data) > 0:
|
||||
jdata['data'] = binascii.hexlify(self.data).decode()
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
s = f'{ind}{self._name}(0x{self._eid:0x})'
|
||||
if len(self._edata):
|
||||
s += f'\n{ind} data({len(self._edata)}): ' \
|
||||
f'{binascii.hexlify(self._edata).decode()}'
|
||||
return s
|
||||
|
||||
|
||||
class ExtSupportedGroups(Extension):
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
super().__init__(eid=eid, name=name, edata=edata, hsid=hsid)
|
||||
d = edata
|
||||
self._groups = []
|
||||
while len(d) > 0:
|
||||
d, gid = _get_int(d, 2)
|
||||
self._groups.append(gid)
|
||||
|
||||
def to_json(self):
|
||||
jdata = {
|
||||
'id': self._eid,
|
||||
'name': self._name,
|
||||
}
|
||||
if len(self._groups):
|
||||
jdata['groups'] = [TlsSupportedGroups.name(gid)
|
||||
for gid in self._groups]
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
gnames = [TlsSupportedGroups.name(gid) for gid in self._groups]
|
||||
s = f'{ind}{self._name}(0x{self._eid:0x}): {", ".join(gnames)}'
|
||||
return s
|
||||
|
||||
|
||||
class ExtKeyShare(Extension):
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
super().__init__(eid=eid, name=name, edata=edata, hsid=hsid)
|
||||
d = self.data
|
||||
self._keys = []
|
||||
self._group = None
|
||||
self._pubkey = None
|
||||
if self.hsid == 2: # ServerHello
|
||||
# single key share (group, pubkey)
|
||||
d, self._group = _get_int(d, 2)
|
||||
d, self._pubkey = _get_len_field(d, 2)
|
||||
elif self.hsid == 6: # HelloRetryRequest
|
||||
assert len(d) == 2
|
||||
d, self._group = _get_int(d, 2)
|
||||
else:
|
||||
# list if key shares (group, pubkey)
|
||||
d, shares = _get_len_field(d, 2)
|
||||
while len(shares) > 0:
|
||||
shares, group = _get_int(shares, 2)
|
||||
shares, pubkey = _get_len_field(shares, 2)
|
||||
self._keys.append({
|
||||
'group': TlsSupportedGroups.name(group),
|
||||
'pubkey': binascii.hexlify(pubkey).decode()
|
||||
})
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
if self._group is not None:
|
||||
jdata['group'] = TlsSupportedGroups.name(self._group)
|
||||
if self._pubkey is not None:
|
||||
jdata['pubkey'] = binascii.hexlify(self._pubkey).decode()
|
||||
if len(self._keys) > 0:
|
||||
jdata['keys'] = self._keys
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
s = f'{ind}{self._name}(0x{self._eid:0x})'
|
||||
if self._group is not None:
|
||||
s += f'\n{ind} group: {TlsSupportedGroups.name(self._group)}'
|
||||
if self._pubkey is not None:
|
||||
s += f'\n{ind} pubkey: {binascii.hexlify(self._pubkey).decode()}'
|
||||
if len(self._keys) > 0:
|
||||
for idx, key in enumerate(self._keys):
|
||||
s += f'\n{ind} {idx}: {key["group"]}, {key["pubkey"]}'
|
||||
return s
|
||||
|
||||
|
||||
class ExtSNI(Extension):
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
super().__init__(eid=eid, name=name, edata=edata, hsid=hsid)
|
||||
d = self.data
|
||||
self._indicators = []
|
||||
while len(d) > 0:
|
||||
d, entry = _get_len_field(d, 2)
|
||||
entry, stype = _get_int(entry, 1)
|
||||
entry, sname = _get_len_field(entry, 2)
|
||||
self._indicators.append({
|
||||
'type': stype,
|
||||
'name': sname.decode()
|
||||
})
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
for i in self._indicators:
|
||||
if i['type'] == 0:
|
||||
jdata['host_name'] = i['name']
|
||||
else:
|
||||
jdata[f'0x{i["type"]}'] = i['name']
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
s = f'{ind}{self._name}(0x{self._eid:0x})'
|
||||
if len(self._indicators) == 1 and self._indicators[0]['type'] == 0:
|
||||
s += f': {self._indicators[0]["name"]}'
|
||||
else:
|
||||
for i in self._indicators:
|
||||
ikey = 'host_name' if i["type"] == 0 else f'type(0x{i["type"]:0x}'
|
||||
s += f'\n{ind} {ikey}: {i["name"]}'
|
||||
return s
|
||||
|
||||
|
||||
class ExtALPN(Extension):
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
super().__init__(eid=eid, name=name, edata=edata, hsid=hsid)
|
||||
d = self.data
|
||||
d, list_len = _get_int(d, 2)
|
||||
self._protocols = []
|
||||
while len(d) > 0:
|
||||
d, proto = _get_len_field(d, 1)
|
||||
self._protocols.append(proto.decode())
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
if len(self._protocols) == 1:
|
||||
jdata['alpn'] = self._protocols[0]
|
||||
else:
|
||||
jdata['alpn'] = self._protocols
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return f'{ind}{self._name}(0x{self._eid:0x}): {", ".join(self._protocols)}'
|
||||
|
||||
|
||||
class ExtEarlyData(Extension):
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
super().__init__(eid=eid, name=name, edata=edata, hsid=hsid)
|
||||
self._max_size = None
|
||||
d = self.data
|
||||
if hsid == 4: # SessionTicket
|
||||
assert len(d) == 4, f'expected 4, len is {len(d)} data={d}'
|
||||
d, self._max_size = _get_int(d, 4)
|
||||
else:
|
||||
assert len(d) == 0
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
if self._max_size is not None:
|
||||
jdata['max_size'] = self._max_size
|
||||
return jdata
|
||||
|
||||
|
||||
class ExtSignatureAlgorithms(Extension):
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
super().__init__(eid=eid, name=name, edata=edata, hsid=hsid)
|
||||
d = self.data
|
||||
d, list_len = _get_int(d, 2)
|
||||
self._algos = []
|
||||
while len(d) > 0:
|
||||
d, algo = _get_int(d, 2)
|
||||
self._algos.append(TlsSignatureScheme.name(algo))
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
if len(self._algos) > 0:
|
||||
jdata['algorithms'] = self._algos
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return f'{ind}{self._name}(0x{self._eid:0x}): {", ".join(self._algos)}'
|
||||
|
||||
|
||||
class ExtPSKExchangeModes(Extension):
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
super().__init__(eid=eid, name=name, edata=edata, hsid=hsid)
|
||||
d = self.data
|
||||
d, list_len = _get_int(d, 1)
|
||||
self._modes = []
|
||||
while len(d) > 0:
|
||||
d, mode = _get_int(d, 1)
|
||||
self._modes.append(PskKeyExchangeMode.name(mode))
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
jdata['modes'] = self._modes
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return f'{ind}{self._name}(0x{self._eid:0x}): {", ".join(self._modes)}'
|
||||
|
||||
|
||||
class ExtPreSharedKey(Extension):
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
super().__init__(eid=eid, name=name, edata=edata, hsid=hsid)
|
||||
self._kid = None
|
||||
self._identities = None
|
||||
self._binders = None
|
||||
d = self.data
|
||||
if hsid == 1: # client hello
|
||||
d, idata = _get_len_field(d, 2)
|
||||
self._identities = []
|
||||
while len(idata):
|
||||
idata, identity = _get_len_field(idata, 2)
|
||||
idata, obfs_age = _get_int(idata, 4)
|
||||
self._identities.append({
|
||||
'id': binascii.hexlify(identity).decode(),
|
||||
'age': obfs_age,
|
||||
})
|
||||
d, binders = _get_len_field(d, 2)
|
||||
self._binders = []
|
||||
while len(binders) > 0:
|
||||
binders, hmac = _get_len_field(binders, 1)
|
||||
self._binders.append(binascii.hexlify(hmac).decode())
|
||||
assert len(d) == 0
|
||||
else:
|
||||
d, self._kid = _get_int(d, 2)
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
if self.hsid == 1:
|
||||
jdata['identities'] = self._identities
|
||||
jdata['binders'] = self._binders
|
||||
else:
|
||||
jdata['identity'] = self._kid
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
s = f'{ind}{self._name}(0x{self._hsid:0x})'
|
||||
if self.hsid == 1:
|
||||
for idx, i in enumerate(self._identities):
|
||||
s += f'\n{ind} {idx}: {i["id"]} ({i["age"]})'
|
||||
s += f'\n{ind} binders: {self._binders}'
|
||||
else:
|
||||
s += f'\n{ind} identity: {self._kid}'
|
||||
return s
|
||||
|
||||
|
||||
class ExtSupportedVersions(Extension):
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
super().__init__(eid=eid, name=name, edata=edata, hsid=hsid)
|
||||
d = self.data
|
||||
self._versions = []
|
||||
if hsid == 1: # client hello
|
||||
d, list_len = _get_int(d, 1)
|
||||
while len(d) > 0:
|
||||
d, version = _get_int(d, 2)
|
||||
self._versions.append(f'0x{version:0x}')
|
||||
else:
|
||||
d, version = _get_int(d, 2)
|
||||
self._versions.append(f'0x{version:0x}')
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
if len(self._versions) == 1:
|
||||
jdata['version'] = self._versions[0]
|
||||
else:
|
||||
jdata['versions'] = self._versions
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return f'{ind}{self._name}(0x{self._eid:0x}): {", ".join(self._versions)}'
|
||||
|
||||
|
||||
class ExtQuicTP(Extension):
|
||||
|
||||
def __init__(self, eid, name, edata, hsid):
|
||||
super().__init__(eid=eid, name=name, edata=edata, hsid=hsid)
|
||||
d = self.data
|
||||
self._params = []
|
||||
while len(d) > 0:
|
||||
d, ptype = _get_qint(d)
|
||||
d, plen = _get_qint(d)
|
||||
d, pvalue = _get_field(d, plen)
|
||||
if QuicTransportParam.is_qint(ptype):
|
||||
_, pvalue = _get_qint(pvalue)
|
||||
else:
|
||||
pvalue = binascii.hexlify(pvalue).decode()
|
||||
self._params.append({
|
||||
'key': QuicTransportParam.name(ptype),
|
||||
'value': pvalue,
|
||||
})
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
jdata['params'] = self._params
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
s = f'{ind}{self._name}(0x{self._eid:0x})'
|
||||
for p in self._params:
|
||||
s += f'\n{ind} {p["key"]}: {p["value"]}'
|
||||
return s
|
||||
|
||||
|
||||
class TlsExtensions:
|
||||
|
||||
EXT_TYPES = [
|
||||
(0x00, 'SNI', ExtSNI),
|
||||
(0x01, 'MAX_FRAGMENT_LENGTH', Extension),
|
||||
(0x03, 'TRUSTED_CA_KEYS', Extension),
|
||||
(0x04, 'TRUNCATED_HMAC', Extension),
|
||||
(0x05, 'OSCP_STATUS_REQUEST', Extension),
|
||||
(0x0a, 'SUPPORTED_GROUPS', ExtSupportedGroups),
|
||||
(0x0b, 'EC_POINT_FORMATS', Extension),
|
||||
(0x0d, 'SIGNATURE_ALGORITHMS', ExtSignatureAlgorithms),
|
||||
(0x0e, 'USE_SRTP', Extension),
|
||||
(0x10, 'ALPN', ExtALPN),
|
||||
(0x11, 'STATUS_REQUEST_V2', Extension),
|
||||
(0x16, 'ENCRYPT_THEN_MAC', Extension),
|
||||
(0x17, 'EXTENDED_MASTER_SECRET', Extension),
|
||||
(0x23, 'SESSION_TICKET', Extension),
|
||||
(0x29, 'PRE_SHARED_KEY', ExtPreSharedKey),
|
||||
(0x2a, 'EARLY_DATA', ExtEarlyData),
|
||||
(0x2b, 'SUPPORTED_VERSIONS', ExtSupportedVersions),
|
||||
(0x2c, 'COOKIE', Extension),
|
||||
(0x2d, 'PSK_KEY_EXCHANGE_MODES', ExtPSKExchangeModes),
|
||||
(0x31, 'POST_HANDSHAKE_AUTH', Extension),
|
||||
(0x32, 'SIGNATURE_ALGORITHMS_CERT', Extension),
|
||||
(0x33, 'KEY_SHARE', ExtKeyShare),
|
||||
(0x39, 'QUIC_TP_PARAMS', ExtQuicTP),
|
||||
(0xff01, 'RENEGOTIATION_INFO', Extension),
|
||||
]
|
||||
NAME_BY_ID = {}
|
||||
CLASS_BY_ID = {}
|
||||
|
||||
@classmethod
|
||||
def init(cls):
|
||||
for (eid, name, ecls) in cls.EXT_TYPES:
|
||||
cls.NAME_BY_ID[eid] = name
|
||||
cls.CLASS_BY_ID[eid] = ecls
|
||||
|
||||
@classmethod
|
||||
def from_data(cls, hsid, data):
|
||||
exts = []
|
||||
d = data
|
||||
while len(d):
|
||||
d, eid = _get_int(d, 2)
|
||||
d, elen = _get_int(d, 2)
|
||||
d, edata = _get_field(d, elen)
|
||||
if eid in cls.NAME_BY_ID:
|
||||
ename = cls.NAME_BY_ID[eid]
|
||||
ecls = cls.CLASS_BY_ID[eid]
|
||||
exts.append(ecls(eid=eid, name=ename, edata=edata, hsid=hsid))
|
||||
else:
|
||||
exts.append(Extension(eid=eid, name=f'(0x{eid:0x})',
|
||||
edata=edata, hsid=hsid))
|
||||
return exts
|
||||
|
||||
|
||||
TlsExtensions.init()
|
||||
|
||||
|
||||
class HSRecord:
|
||||
|
||||
def __init__(self, hsid: int, name: str, data):
|
||||
self._hsid = hsid
|
||||
self._name = name
|
||||
self._data = data
|
||||
|
||||
@property
|
||||
def hsid(self):
|
||||
return self._hsid
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, value):
|
||||
self._name = value
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self._data
|
||||
|
||||
def __repr__(self):
|
||||
return f'{self.name}[{binascii.hexlify(self._data).decode()}]'
|
||||
|
||||
def to_json(self) -> Dict[str, Any]:
|
||||
return {
|
||||
'name': self.name,
|
||||
'data': binascii.hexlify(self._data).decode(),
|
||||
}
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return f'{ind}{self._name}\n'\
|
||||
f'{ind} id: 0x{self._hsid:0x}\n'\
|
||||
f'{ind} data({len(self._data)}): '\
|
||||
f'{binascii.hexlify(self._data).decode()}'
|
||||
|
||||
|
||||
class ClientHello(HSRecord):
|
||||
|
||||
def __init__(self, hsid: int, name: str, data):
|
||||
super().__init__(hsid=hsid, name=name, data=data)
|
||||
d = data
|
||||
d, self._version = _get_int(d, 2)
|
||||
d, self._random = _get_field(d, 32)
|
||||
d, self._session_id = _get_len_field(d, 1)
|
||||
self._ciphers = []
|
||||
d, ciphers = _get_len_field(d, 2)
|
||||
while len(ciphers):
|
||||
ciphers, cipher = _get_int(ciphers, 2)
|
||||
self._ciphers.append(TlsCipherSuites.name(cipher))
|
||||
d, comps = _get_len_field(d, 1)
|
||||
self._compressions = [int(c) for c in comps]
|
||||
d, edata = _get_len_field(d, 2)
|
||||
self._extensions = TlsExtensions.from_data(hsid, edata)
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
jdata['version'] = f'0x{self._version:0x}'
|
||||
jdata['random'] = f'{binascii.hexlify(self._random).decode()}'
|
||||
jdata['session_id'] = binascii.hexlify(self._session_id).decode()
|
||||
jdata['ciphers'] = self._ciphers
|
||||
jdata['compressions'] = self._compressions
|
||||
jdata['extensions'] = [ext.to_json() for ext in self._extensions]
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return super().to_text(indent=indent) + '\n'\
|
||||
f'{ind} version: 0x{self._version:0x}\n'\
|
||||
f'{ind} random: {binascii.hexlify(self._random).decode()}\n' \
|
||||
f'{ind} session_id: {binascii.hexlify(self._session_id).decode()}\n' \
|
||||
f'{ind} ciphers: {", ".join(self._ciphers)}\n'\
|
||||
f'{ind} compressions: {self._compressions}\n'\
|
||||
f'{ind} extensions: \n' + '\n'.join(
|
||||
[ext.to_text(indent=indent+4) for ext in self._extensions])
|
||||
|
||||
|
||||
class ServerHello(HSRecord):
|
||||
|
||||
HELLO_RETRY_RANDOM = binascii.unhexlify(
|
||||
'CF21AD74E59A6111BE1D8C021E65B891C2A211167ABB8C5E079E09E2C8A8339C'
|
||||
)
|
||||
|
||||
def __init__(self, hsid: int, name: str, data):
|
||||
super().__init__(hsid=hsid, name=name, data=data)
|
||||
d = data
|
||||
d, self._version = _get_int(d, 2)
|
||||
d, self._random = _get_field(d, 32)
|
||||
if self._random == self.HELLO_RETRY_RANDOM:
|
||||
self.name = 'HelloRetryRequest'
|
||||
hsid = 6
|
||||
d, self._session_id = _get_len_field(d, 1)
|
||||
d, cipher = _get_int(d, 2)
|
||||
self._cipher = TlsCipherSuites.name(cipher)
|
||||
d, self._compression = _get_int(d, 1)
|
||||
d, edata = _get_len_field(d, 2)
|
||||
self._extensions = TlsExtensions.from_data(hsid, edata)
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
jdata['version'] = f'0x{self._version:0x}'
|
||||
jdata['random'] = f'{binascii.hexlify(self._random).decode()}'
|
||||
jdata['session_id'] = binascii.hexlify(self._session_id).decode()
|
||||
jdata['cipher'] = self._cipher
|
||||
jdata['compression'] = int(self._compression)
|
||||
jdata['extensions'] = [ext.to_json() for ext in self._extensions]
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return super().to_text(indent=indent) + '\n'\
|
||||
f'{ind} version: 0x{self._version:0x}\n'\
|
||||
f'{ind} random: {binascii.hexlify(self._random).decode()}\n' \
|
||||
f'{ind} session_id: {binascii.hexlify(self._session_id).decode()}\n' \
|
||||
f'{ind} cipher: {self._cipher}\n'\
|
||||
f'{ind} compression: {int(self._compression)}\n'\
|
||||
f'{ind} extensions: \n' + '\n'.join(
|
||||
[ext.to_text(indent=indent+4) for ext in self._extensions])
|
||||
|
||||
|
||||
class EncryptedExtensions(HSRecord):
|
||||
|
||||
def __init__(self, hsid: int, name: str, data):
|
||||
super().__init__(hsid=hsid, name=name, data=data)
|
||||
d = data
|
||||
d, edata = _get_len_field(d, 2)
|
||||
self._extensions = TlsExtensions.from_data(hsid, edata)
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
jdata['extensions'] = [ext.to_json() for ext in self._extensions]
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return super().to_text(indent=indent) + '\n'\
|
||||
f'{ind} extensions: \n' + '\n'.join(
|
||||
[ext.to_text(indent=indent+4) for ext in self._extensions])
|
||||
|
||||
|
||||
class CertificateRequest(HSRecord):
|
||||
|
||||
def __init__(self, hsid: int, name: str, data):
|
||||
super().__init__(hsid=hsid, name=name, data=data)
|
||||
d = data
|
||||
d, self._context = _get_int(d, 1)
|
||||
d, edata = _get_len_field(d, 2)
|
||||
self._extensions = TlsExtensions.from_data(hsid, edata)
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
jdata['context'] = self._context
|
||||
jdata['extensions'] = [ext.to_json() for ext in self._extensions]
|
||||
return jdata
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return super().to_text(indent=indent) + '\n'\
|
||||
f'{ind} context: {self._context}\n'\
|
||||
f'{ind} extensions: \n' + '\n'.join(
|
||||
[ext.to_text(indent=indent+4) for ext in self._extensions])
|
||||
|
||||
|
||||
class Certificate(HSRecord):
|
||||
|
||||
def __init__(self, hsid: int, name: str, data):
|
||||
super().__init__(hsid=hsid, name=name, data=data)
|
||||
d = data
|
||||
d, self._context = _get_int(d, 1)
|
||||
d, clist = _get_len_field(d, 3)
|
||||
self._cert_entries = []
|
||||
while len(clist) > 0:
|
||||
clist, cert_data = _get_len_field(clist, 3)
|
||||
clist, cert_exts = _get_len_field(clist, 2)
|
||||
exts = TlsExtensions.from_data(hsid, cert_exts)
|
||||
self._cert_entries.append({
|
||||
'cert': binascii.hexlify(cert_data).decode(),
|
||||
'extensions': exts,
|
||||
})
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
jdata['context'] = self._context
|
||||
jdata['certificate_list'] = [{
|
||||
'cert': e['cert'],
|
||||
'extensions': [x.to_json() for x in e['extensions']],
|
||||
} for e in self._cert_entries]
|
||||
return jdata
|
||||
|
||||
def _enxtry_text(self, e, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return f'{ind} cert: {e["cert"]}\n'\
|
||||
f'{ind} extensions: \n' + '\n'.join(
|
||||
[x.to_text(indent=indent + 4) for x in e['extensions']])
|
||||
|
||||
def to_text(self, indent: int = 0):
|
||||
ind = ' ' * (indent + 2)
|
||||
return super().to_text(indent=indent) + '\n'\
|
||||
f'{ind} context: {self._context}\n'\
|
||||
f'{ind} certificate_list: \n' + '\n'.join(
|
||||
[self._enxtry_text(e, indent+4) for e in self._cert_entries])
|
||||
|
||||
|
||||
class SessionTicket(HSRecord):
|
||||
|
||||
def __init__(self, hsid: int, name: str, data):
|
||||
super().__init__(hsid=hsid, name=name, data=data)
|
||||
d = data
|
||||
d, self._lifetime = _get_int(d, 4)
|
||||
d, self._age = _get_int(d, 4)
|
||||
d, self._nonce = _get_len_field(d, 1)
|
||||
d, self._ticket = _get_len_field(d, 2)
|
||||
d, edata = _get_len_field(d, 2)
|
||||
self._extensions = TlsExtensions.from_data(hsid, edata)
|
||||
|
||||
def to_json(self):
|
||||
jdata = super().to_json()
|
||||
jdata['lifetime'] = self._lifetime
|
||||
jdata['age'] = self._age
|
||||
jdata['nonce'] = binascii.hexlify(self._nonce).decode()
|
||||
jdata['ticket'] = binascii.hexlify(self._ticket).decode()
|
||||
jdata['extensions'] = [ext.to_json() for ext in self._extensions]
|
||||
return jdata
|
||||
|
||||
|
||||
class HSIterator(Iterator):
|
||||
|
||||
def __init__(self, recs):
|
||||
self._recs = recs
|
||||
self._index = 0
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
try:
|
||||
result = self._recs[self._index]
|
||||
except IndexError:
|
||||
raise StopIteration
|
||||
self._index += 1
|
||||
return result
|
||||
|
||||
|
||||
class HandShake:
|
||||
REC_TYPES = [
|
||||
(1, 'ClientHello', ClientHello),
|
||||
(2, 'ServerHello', ServerHello),
|
||||
(3, 'HelloVerifyRequest', HSRecord),
|
||||
(4, 'SessionTicket', SessionTicket),
|
||||
(5, 'EndOfEarlyData', HSRecord),
|
||||
(6, 'HelloRetryRequest', ServerHello),
|
||||
(8, 'EncryptedExtensions', EncryptedExtensions),
|
||||
(11, 'Certificate', Certificate),
|
||||
(12, 'ServerKeyExchange ', HSRecord),
|
||||
(13, 'CertificateRequest', CertificateRequest),
|
||||
(14, 'ServerHelloDone', HSRecord),
|
||||
(15, 'CertificateVerify', HSRecord),
|
||||
(16, 'ClientKeyExchange', HSRecord),
|
||||
(20, 'Finished', HSRecord),
|
||||
(22, 'CertificateStatus', HSRecord),
|
||||
(24, 'KeyUpdate', HSRecord),
|
||||
(25, 'CompressedCertificate', HSRecord),
|
||||
]
|
||||
RT_NAME_BY_ID = {}
|
||||
RT_CLS_BY_ID = {}
|
||||
|
||||
@classmethod
|
||||
def _parse_rec(cls, data):
|
||||
d, hsid = _get_int(data, 1)
|
||||
if hsid not in cls.RT_CLS_BY_ID:
|
||||
raise ParseError(f'unknown type {hsid}')
|
||||
d, rec_len = _get_int(d, 3)
|
||||
if rec_len > len(d):
|
||||
# incomplete, need more data
|
||||
return data, None
|
||||
d, rec_data = _get_field(d, rec_len)
|
||||
if hsid in cls.RT_CLS_BY_ID:
|
||||
name = cls.RT_NAME_BY_ID[hsid]
|
||||
rcls = cls.RT_CLS_BY_ID[hsid]
|
||||
else:
|
||||
name = f'CryptoRecord(0x{hsid:0x})'
|
||||
rcls = HSRecord
|
||||
return d, rcls(hsid=hsid, name=name, data=rec_data)
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, source, strict=False, verbose: int = 0):
|
||||
d = b''
|
||||
hsid = 0
|
||||
hsrecs = []
|
||||
if verbose > 0:
|
||||
log.debug(f'scanning for handshake records')
|
||||
blocks = [d for d in source]
|
||||
while len(blocks) > 0:
|
||||
try:
|
||||
total_data = b''.join(blocks)
|
||||
remain, r = cls._parse_rec(total_data)
|
||||
if r is None:
|
||||
# if we could not recognize a record, skip the first
|
||||
# data block and try again
|
||||
blocks = blocks[1:]
|
||||
continue
|
||||
hsrecs.append(r)
|
||||
cons_len = len(total_data) - len(remain)
|
||||
while cons_len > 0 and len(blocks) > 0:
|
||||
if cons_len >= len(blocks[0]):
|
||||
cons_len -= len(blocks[0])
|
||||
blocks = blocks[1:]
|
||||
else:
|
||||
blocks[0] = blocks[0][cons_len:]
|
||||
cons_len = 0
|
||||
if verbose > 2:
|
||||
log.debug(f'added record: {r.to_text()}')
|
||||
except ParseError as err:
|
||||
# if we could not recognize a record, skip the first
|
||||
# data block and try again
|
||||
blocks = blocks[1:]
|
||||
if len(blocks) > 0 and strict:
|
||||
raise Exception(f'possibly incomplete handshake record '
|
||||
f'id={hsid}, from raw={blocks}\n')
|
||||
return hsrecs
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def init(cls):
|
||||
for (hsid, name, rcls) in cls.REC_TYPES:
|
||||
cls.RT_NAME_BY_ID[hsid] = name
|
||||
cls.RT_CLS_BY_ID[hsid] = rcls
|
||||
|
||||
def __init__(self, source: Iterable[bytes], strict: bool = False,
|
||||
verbose: int = 0):
|
||||
self._source = source
|
||||
self._strict = strict
|
||||
self._verbose = verbose
|
||||
|
||||
def __iter__(self):
|
||||
return HSIterator(recs=self._parse(self._source, strict=self._strict,
|
||||
verbose=self._verbose))
|
||||
|
||||
|
||||
HandShake.init()
|
||||
30
deps/ngtcp2/ngtcp2/examples/tests/test_01_handshake.py
vendored
Normal file
30
deps/ngtcp2/ngtcp2/examples/tests/test_01_handshake.py
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import pytest
|
||||
|
||||
from .ngtcp2test import ExampleClient
|
||||
from .ngtcp2test import ExampleServer
|
||||
from .ngtcp2test import Env
|
||||
|
||||
|
||||
@pytest.mark.skipif(condition=len(Env.get_crypto_libs()) == 0,
|
||||
reason="no crypto lib examples configured")
|
||||
class TestHandshake:
|
||||
|
||||
@pytest.fixture(scope='class', params=Env.get_crypto_libs())
|
||||
def server(self, env, request) -> ExampleServer:
|
||||
s = ExampleServer(env=env, crypto_lib=request.param)
|
||||
assert s.exists(), f'server not found: {s.path}'
|
||||
assert s.start()
|
||||
yield s
|
||||
s.stop()
|
||||
|
||||
@pytest.fixture(scope='function', params=Env.get_crypto_libs())
|
||||
def client(self, env, request) -> ExampleClient:
|
||||
client = ExampleClient(env=env, crypto_lib=request.param)
|
||||
assert client.exists()
|
||||
yield client
|
||||
|
||||
def test_01_01_get(self, env: Env, server, client):
|
||||
# run simple GET, no sessions, needs to give full handshake
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/')
|
||||
assert cr.returncode == 0
|
||||
cr.assert_non_resume_handshake()
|
||||
46
deps/ngtcp2/ngtcp2/examples/tests/test_02_resume.py
vendored
Normal file
46
deps/ngtcp2/ngtcp2/examples/tests/test_02_resume.py
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import pytest
|
||||
|
||||
from .ngtcp2test import ExampleClient
|
||||
from .ngtcp2test import ExampleServer
|
||||
from .ngtcp2test import Env
|
||||
|
||||
|
||||
@pytest.mark.skipif(condition=len(Env.get_crypto_libs()) == 0,
|
||||
reason="no crypto lib examples configured")
|
||||
class TestResume:
|
||||
|
||||
@pytest.fixture(scope='class', params=Env.get_crypto_libs())
|
||||
def server(self, env, request) -> ExampleServer:
|
||||
s = ExampleServer(env=env, crypto_lib=request.param)
|
||||
assert s.exists(), f'server not found: {s.path}'
|
||||
assert s.start()
|
||||
yield s
|
||||
s.stop()
|
||||
|
||||
@pytest.fixture(scope='function', params=Env.get_crypto_libs())
|
||||
def client(self, env, request) -> ExampleClient:
|
||||
client = ExampleClient(env=env, crypto_lib=request.param)
|
||||
assert client.exists()
|
||||
yield client
|
||||
|
||||
def test_02_01(self, env: Env, server, client):
|
||||
# run GET with sessions but no early data, cleared first, then reused
|
||||
client.clear_session()
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/',
|
||||
use_session=True,
|
||||
extra_args=['--disable-early-data'])
|
||||
assert cr.returncode == 0
|
||||
cr.assert_non_resume_handshake()
|
||||
# Now do this again and we expect a resumption, meaning no certificate
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/',
|
||||
use_session=True,
|
||||
extra_args=['--disable-early-data'])
|
||||
assert cr.returncode == 0
|
||||
cr.assert_resume_handshake()
|
||||
# restart the server, do it again
|
||||
server.restart()
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/',
|
||||
use_session=True,
|
||||
extra_args=['--disable-early-data'])
|
||||
assert cr.returncode == 0
|
||||
cr.assert_non_resume_handshake()
|
||||
56
deps/ngtcp2/ngtcp2/examples/tests/test_03_earlydata.py
vendored
Normal file
56
deps/ngtcp2/ngtcp2/examples/tests/test_03_earlydata.py
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import pytest
|
||||
|
||||
from .ngtcp2test import ExampleClient
|
||||
from .ngtcp2test import ExampleServer
|
||||
from .ngtcp2test import Env
|
||||
|
||||
|
||||
@pytest.mark.skipif(condition=len(Env.get_crypto_libs()) == 0,
|
||||
reason="no crypto lib examples configured")
|
||||
class TestEarlyData:
|
||||
|
||||
@pytest.fixture(scope='class', params=Env.get_crypto_libs())
|
||||
def server(self, env, request) -> ExampleServer:
|
||||
s = ExampleServer(env=env, crypto_lib=request.param)
|
||||
assert s.exists(), f'server not found: {s.path}'
|
||||
assert s.start()
|
||||
yield s
|
||||
s.stop()
|
||||
|
||||
@pytest.fixture(scope='function', params=Env.get_crypto_libs())
|
||||
def client(self, env, request) -> ExampleClient:
|
||||
client = ExampleClient(env=env, crypto_lib=request.param)
|
||||
assert client.exists()
|
||||
yield client
|
||||
|
||||
def test_03_01(self, env: Env, server, client):
|
||||
# run GET with sessions, cleared first, without a session, early
|
||||
# data will not even be attempted
|
||||
client.clear_session()
|
||||
edata = 'This is the early data. It is not much.'
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/',
|
||||
use_session=True, data=edata)
|
||||
assert cr.returncode == 0
|
||||
cr.assert_non_resume_handshake()
|
||||
# resume session, early data is sent and accepted
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/',
|
||||
use_session=True, data=edata)
|
||||
assert cr.returncode == 0
|
||||
cr.assert_resume_handshake()
|
||||
assert not cr.early_data_rejected
|
||||
# restart the server, resume, early data is attempted but will not work
|
||||
server.restart()
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/',
|
||||
use_session=True, data=edata)
|
||||
assert cr.returncode == 0
|
||||
assert cr.early_data_rejected
|
||||
cr.assert_non_resume_handshake()
|
||||
# restart again, sent data, but not as early data
|
||||
server.restart()
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/',
|
||||
use_session=True, data=edata,
|
||||
extra_args=['--disable-early-data'])
|
||||
assert cr.returncode == 0
|
||||
# we see no rejection, since it was not used
|
||||
assert not cr.early_data_rejected
|
||||
cr.assert_non_resume_handshake()
|
||||
57
deps/ngtcp2/ngtcp2/examples/tests/test_04_clientcert.py
vendored
Normal file
57
deps/ngtcp2/ngtcp2/examples/tests/test_04_clientcert.py
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import pytest
|
||||
|
||||
from .ngtcp2test import ExampleClient
|
||||
from .ngtcp2test import ExampleServer
|
||||
from .ngtcp2test import Env
|
||||
|
||||
|
||||
@pytest.mark.skipif(condition=len(Env.get_crypto_libs()) == 0,
|
||||
reason="no crypto lib examples configured")
|
||||
class TestClientCert:
|
||||
|
||||
@pytest.fixture(scope='class', params=Env.get_crypto_libs())
|
||||
def server(self, env, request) -> ExampleServer:
|
||||
s = ExampleServer(env=env, crypto_lib=request.param,
|
||||
verify_client=True)
|
||||
assert s.exists(), f'server not found: {s.path}'
|
||||
assert s.start()
|
||||
yield s
|
||||
s.stop()
|
||||
|
||||
@pytest.fixture(scope='function', params=Env.get_crypto_libs())
|
||||
def client(self, env, request) -> ExampleClient:
|
||||
client = ExampleClient(env=env, crypto_lib=request.param)
|
||||
assert client.exists()
|
||||
yield client
|
||||
|
||||
def test_04_01(self, env: Env, server, client):
|
||||
# run GET with a server requesting a cert, client has none to offer
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/')
|
||||
assert cr.returncode == 0
|
||||
cr.assert_verify_null_handshake()
|
||||
creqs = [r for r in cr.handshake if r.hsid == 13] # CertificateRequest
|
||||
assert len(creqs) == 1
|
||||
creq = creqs[0].to_json()
|
||||
certs = [r for r in cr.server.handshake if r.hsid == 11] # Certificate
|
||||
assert len(certs) == 1
|
||||
crec = certs[0].to_json()
|
||||
assert len(crec['certificate_list']) == 0
|
||||
assert creq['context'] == crec['context']
|
||||
# TODO: check that GET had no answer
|
||||
|
||||
def test_04_02(self, env: Env, server, client):
|
||||
# run GET with a server requesting a cert, client has cert to offer
|
||||
credentials = env.ca.get_first("clientsX")
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/',
|
||||
credentials=credentials)
|
||||
assert cr.returncode == 0
|
||||
cr.assert_verify_cert_handshake()
|
||||
creqs = [r for r in cr.handshake if r.hsid == 13] # CertificateRequest
|
||||
assert len(creqs) == 1
|
||||
creq = creqs[0].to_json()
|
||||
certs = [r for r in cr.server.handshake if r.hsid == 11] # Certificate
|
||||
assert len(certs) == 1
|
||||
crec = certs[0].to_json()
|
||||
assert len(crec['certificate_list']) == 1
|
||||
assert creq['context'] == crec['context']
|
||||
# TODO: check that GET indeed gave a response
|
||||
46
deps/ngtcp2/ngtcp2/examples/tests/test_05_ciphers.py
vendored
Normal file
46
deps/ngtcp2/ngtcp2/examples/tests/test_05_ciphers.py
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from .ngtcp2test import ExampleClient
|
||||
from .ngtcp2test import ExampleServer
|
||||
from .ngtcp2test import Env
|
||||
|
||||
|
||||
@pytest.mark.skipif(condition=len(Env.get_crypto_libs()) == 0,
|
||||
reason="no crypto lib examples configured")
|
||||
class TestCiphers:
|
||||
|
||||
@pytest.fixture(scope='class', params=Env.get_crypto_libs())
|
||||
def server(self, env, request) -> ExampleServer:
|
||||
s = ExampleServer(env=env, crypto_lib=request.param)
|
||||
assert s.exists(), f'server not found: {s.path}'
|
||||
assert s.start()
|
||||
yield s
|
||||
s.stop()
|
||||
|
||||
@pytest.fixture(scope='function',
|
||||
params=Env.get_crypto_libs(configurable_ciphers=True))
|
||||
def client(self, env, request) -> ExampleClient:
|
||||
client = ExampleClient(env=env, crypto_lib=request.param)
|
||||
assert client.exists()
|
||||
yield client
|
||||
|
||||
@pytest.mark.parametrize('cipher', [
|
||||
'TLS_AES_128_GCM_SHA256',
|
||||
'TLS_AES_256_GCM_SHA384',
|
||||
'TLS_CHACHA20_POLY1305_SHA256',
|
||||
'TLS_AES_128_CCM_SHA256',
|
||||
])
|
||||
def test_05_01_get(self, env: Env, server, client, cipher):
|
||||
if not client.uses_cipher_config:
|
||||
pytest.skip(f'client {client.crypto_lib} ignores cipher config\n')
|
||||
# run simple GET, no sessions, needs to give full handshake
|
||||
if not client.supports_cipher(cipher):
|
||||
pytest.skip(f'client {client.crypto_lib} does not support {cipher}\n')
|
||||
if not server.supports_cipher(cipher):
|
||||
pytest.skip(f'server {server.crypto_lib} does not support {cipher}\n')
|
||||
cr = client.http_get(server, url=f'https://{env.example_domain}/',
|
||||
ciphers=cipher)
|
||||
assert cr.returncode == 0
|
||||
cr.assert_non_resume_handshake()
|
||||
56
deps/ngtcp2/ngtcp2/examples/tls_client_context.h
vendored
Normal file
56
deps/ngtcp2/ngtcp2/examples/tls_client_context.h
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_CONTEXT_H
|
||||
#define TLS_CLIENT_CONTEXT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#ifdef WITH_EXAMPLE_QUICTLS
|
||||
# include "tls_client_context_quictls.h"
|
||||
#endif // defined(WITH_EXAMPLE_QUICTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_GNUTLS
|
||||
# include "tls_client_context_gnutls.h"
|
||||
#endif // defined(WITH_EXAMPLE_GNUTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_BORINGSSL
|
||||
# include "tls_client_context_boringssl.h"
|
||||
#endif // defined(WITH_EXAMPLE_BORINGSSL)
|
||||
|
||||
#ifdef WITH_EXAMPLE_PICOTLS
|
||||
# include "tls_client_context_picotls.h"
|
||||
#endif // defined(WITH_EXAMPLE_PICOTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_WOLFSSL
|
||||
# include "tls_client_context_wolfssl.h"
|
||||
#endif // defined(WITH_EXAMPLE_WOLFSSL)
|
||||
|
||||
#ifdef WITH_EXAMPLE_OSSL
|
||||
# include "tls_client_context_ossl.h"
|
||||
#endif // defined(WITH_EXAMPLE_OSSL)
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_H)
|
||||
142
deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.cc
vendored
Normal file
142
deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.cc
vendored
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2021 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_client_context_boringssl.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_boringssl.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "client_base.h"
|
||||
#include "template.h"
|
||||
#include "tls_shared_boringssl.h"
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSClientContext::TLSClientContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSClientContext::~TLSClientContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX *TLSClientContext::get_native_handle() const { return ssl_ctx_; }
|
||||
|
||||
namespace {
|
||||
int new_session_cb(SSL *ssl, SSL_SESSION *session) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto c = static_cast<ClientBase *>(conn_ref->user_data);
|
||||
|
||||
c->ticket_received();
|
||||
|
||||
auto f = BIO_new_file(config.session_file, "w");
|
||||
if (f == nullptr) {
|
||||
std::cerr << "Could not write TLS session in " << config.session_file
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!PEM_write_bio_SSL_SESSION(f, session)) {
|
||||
std::cerr << "Unable to write TLS session to file" << std::endl;
|
||||
}
|
||||
|
||||
BIO_free(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int TLSClientContext::init(const char *private_key_file,
|
||||
const char *cert_file) {
|
||||
ssl_ctx_ = SSL_CTX_new(TLS_client_method());
|
||||
if (!ssl_ctx_) {
|
||||
std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx_) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_boringssl_configure_client_context failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_default_verify_paths(ssl_ctx_);
|
||||
|
||||
if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) {
|
||||
std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (private_key_file && cert_file) {
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
std::cerr << "SSL_CTX_use_PrivateKey_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) {
|
||||
std::cerr << "SSL_CTX_use_certificate_chain_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.session_file) {
|
||||
SSL_CTX_set_session_cache_mode(ssl_ctx_, SSL_SESS_CACHE_CLIENT |
|
||||
SSL_SESS_CACHE_NO_INTERNAL);
|
||||
SSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBBROTLI
|
||||
if (!SSL_CTX_add_cert_compression_alg(
|
||||
ssl_ctx_, ngtcp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI,
|
||||
ngtcp2::tls::cert_compress, ngtcp2::tls::cert_decompress)) {
|
||||
std::cerr << "SSL_CTX_add_cert_compression_alg failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
#endif // defined(HAVE_LIBBROTLI)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern std::ofstream keylog_file;
|
||||
|
||||
namespace {
|
||||
void keylog_callback(const SSL *ssl, const char *line) {
|
||||
keylog_file.write(line, static_cast<std::streamsize>(strlen(line)));
|
||||
keylog_file.put('\n');
|
||||
keylog_file.flush();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TLSClientContext::enable_keylog() {
|
||||
SSL_CTX_set_keylog_callback(ssl_ctx_, keylog_callback);
|
||||
}
|
||||
49
deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.h
vendored
Normal file
49
deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.h
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2021 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_CONTEXT_BORINGSSL_H
|
||||
#define TLS_CLIENT_CONTEXT_BORINGSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
class TLSClientContext {
|
||||
public:
|
||||
TLSClientContext();
|
||||
~TLSClientContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file);
|
||||
|
||||
SSL_CTX *get_native_handle() const;
|
||||
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_BORINGSSL_H)
|
||||
149
deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.cc
vendored
Normal file
149
deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.cc
vendored
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_client_context_ossl.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_ossl.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "client_base.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace {
|
||||
auto _ = []() {
|
||||
if (ngtcp2_crypto_ossl_init() != 0) {
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}();
|
||||
} // namespace
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSClientContext::TLSClientContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSClientContext::~TLSClientContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX *TLSClientContext::get_native_handle() const { return ssl_ctx_; }
|
||||
|
||||
namespace {
|
||||
int new_session_cb(SSL *ssl, SSL_SESSION *session) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto c = static_cast<ClientBase *>(conn_ref->user_data);
|
||||
|
||||
c->ticket_received();
|
||||
|
||||
if (SSL_SESSION_get_max_early_data(session) !=
|
||||
std::numeric_limits<uint32_t>::max()) {
|
||||
std::cerr << "max_early_data_size is not 0xffffffff" << std::endl;
|
||||
}
|
||||
auto f = BIO_new_file(config.session_file, "w");
|
||||
if (f == nullptr) {
|
||||
std::cerr << "Could not write TLS session in " << config.session_file
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!PEM_write_bio_SSL_SESSION(f, session)) {
|
||||
std::cerr << "Unable to write TLS session to file" << std::endl;
|
||||
}
|
||||
|
||||
BIO_free(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int TLSClientContext::init(const char *private_key_file,
|
||||
const char *cert_file) {
|
||||
ssl_ctx_ = SSL_CTX_new(TLS_client_method());
|
||||
if (!ssl_ctx_) {
|
||||
std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_default_verify_paths(ssl_ctx_);
|
||||
|
||||
if (SSL_CTX_set_ciphersuites(ssl_ctx_, config.ciphers) != 1) {
|
||||
std::cerr << "SSL_CTX_set_ciphersuites: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) {
|
||||
std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (private_key_file && cert_file) {
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
std::cerr << "SSL_CTX_use_PrivateKey_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) {
|
||||
std::cerr << "SSL_CTX_use_certificate_chain_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.session_file) {
|
||||
SSL_CTX_set_session_cache_mode(ssl_ctx_, SSL_SESS_CACHE_CLIENT |
|
||||
SSL_SESS_CACHE_NO_INTERNAL);
|
||||
SSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern std::ofstream keylog_file;
|
||||
|
||||
namespace {
|
||||
void keylog_callback(const SSL *ssl, const char *line) {
|
||||
keylog_file.write(line, static_cast<std::streamsize>(strlen(line)));
|
||||
keylog_file.put('\n');
|
||||
keylog_file.flush();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TLSClientContext::enable_keylog() {
|
||||
SSL_CTX_set_keylog_callback(ssl_ctx_, keylog_callback);
|
||||
}
|
||||
49
deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.h
vendored
Normal file
49
deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.h
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_CONTEXT_OSSL_H
|
||||
#define TLS_CLIENT_CONTEXT_OSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
class TLSClientContext {
|
||||
public:
|
||||
TLSClientContext();
|
||||
~TLSClientContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file);
|
||||
|
||||
SSL_CTX *get_native_handle() const;
|
||||
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_OSSL_H)
|
||||
171
deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.cc
vendored
Normal file
171
deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.cc
vendored
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_client_context_picotls.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_picotls.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include "client_base.h"
|
||||
#include "tls_shared_picotls.h"
|
||||
#include "template.h"
|
||||
|
||||
extern Config config;
|
||||
|
||||
namespace {
|
||||
int save_ticket_cb(ptls_save_ticket_t *self, ptls_t *ptls, ptls_iovec_t input) {
|
||||
auto conn_ref =
|
||||
static_cast<ngtcp2_crypto_conn_ref *>(*ptls_get_data_ptr(ptls));
|
||||
auto c = static_cast<ClientBase *>(conn_ref->user_data);
|
||||
|
||||
c->ticket_received();
|
||||
|
||||
auto f = BIO_new_file(config.session_file, "w");
|
||||
if (f == nullptr) {
|
||||
std::cerr << "Could not write TLS session in " << config.session_file
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!PEM_write_bio(f, "PICOTLS SESSION PARAMETERS", "", input.base,
|
||||
static_cast<long>(input.len))) {
|
||||
std::cerr << "Unable to write TLS session to file" << std::endl;
|
||||
}
|
||||
|
||||
BIO_free(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptls_save_ticket_t save_ticket = {save_ticket_cb};
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
ptls_key_exchange_algorithm_t *key_exchanges[] = {
|
||||
#if PTLS_OPENSSL_HAVE_X25519
|
||||
&ptls_openssl_x25519,
|
||||
#endif // PTLS_OPENSSL_X25519
|
||||
&ptls_openssl_secp256r1,
|
||||
&ptls_openssl_secp384r1,
|
||||
&ptls_openssl_secp521r1,
|
||||
#if PTLS_OPENSSL_HAVE_X25519MLKEM768
|
||||
&ptls_openssl_x25519mlkem768,
|
||||
#endif // PTLS_OPENSSL_HAVE_X25519MLKEM768
|
||||
nullptr,
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
ptls_cipher_suite_t *cipher_suites[] = {
|
||||
&ptls_openssl_aes128gcmsha256,
|
||||
&ptls_openssl_aes256gcmsha384,
|
||||
#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
|
||||
&ptls_openssl_chacha20poly1305sha256,
|
||||
#endif // PTLS_OPENSSL_CHACHA20POLY1305SHA256
|
||||
nullptr,
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TLSClientContext::TLSClientContext()
|
||||
: ctx_{
|
||||
.random_bytes = ptls_openssl_random_bytes,
|
||||
.get_time = &ptls_get_time,
|
||||
.key_exchanges = key_exchanges,
|
||||
.cipher_suites = cipher_suites,
|
||||
.require_dhe_on_psk = 1,
|
||||
}, sign_cert_{} {}
|
||||
|
||||
TLSClientContext::~TLSClientContext() {
|
||||
if (sign_cert_.key) {
|
||||
ptls_openssl_dispose_sign_certificate(&sign_cert_);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ctx_.certificates.count; ++i) {
|
||||
free(ctx_.certificates.list[i].base);
|
||||
}
|
||||
free(ctx_.certificates.list);
|
||||
}
|
||||
|
||||
ptls_context_t *TLSClientContext::get_native_handle() { return &ctx_; }
|
||||
|
||||
int TLSClientContext::init(const char *private_key_file,
|
||||
const char *cert_file) {
|
||||
if (ngtcp2_crypto_picotls_configure_client_context(&ctx_) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_picotls_configure_client_context failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.session_file) {
|
||||
ctx_.save_ticket = &save_ticket;
|
||||
}
|
||||
|
||||
if (private_key_file && cert_file) {
|
||||
if (ptls_load_certificates(&ctx_, cert_file) != 0) {
|
||||
std::cerr << "ptls_load_certificates failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (load_private_key(private_key_file) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TLSClientContext::load_private_key(const char *private_key_file) {
|
||||
auto fp = fopen(private_key_file, "rb");
|
||||
if (fp == nullptr) {
|
||||
std::cerr << "Could not open private key file " << private_key_file << ": "
|
||||
<< strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto fp_d = defer(fclose, fp);
|
||||
|
||||
auto pkey = PEM_read_PrivateKey(fp, nullptr, nullptr, nullptr);
|
||||
if (pkey == nullptr) {
|
||||
std::cerr << "Could not read private key file " << private_key_file
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto pkey_d = defer(EVP_PKEY_free, pkey);
|
||||
|
||||
if (ptls_openssl_init_sign_certificate(&sign_cert_, pkey) != 0) {
|
||||
std::cerr << "ptls_openssl_init_sign_certificate failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx_.sign_certificate = &sign_cert_.super;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TLSClientContext::enable_keylog() { ctx_.log_event = &log_event; }
|
||||
53
deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.h
vendored
Normal file
53
deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.h
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_CONTEXT_PICOTLS_H
|
||||
#define TLS_CLIENT_CONTEXT_PICOTLS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <picotls.h>
|
||||
#include <picotls/openssl.h>
|
||||
|
||||
class TLSClientContext {
|
||||
public:
|
||||
TLSClientContext();
|
||||
~TLSClientContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file);
|
||||
|
||||
ptls_context_t *get_native_handle();
|
||||
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
int load_private_key(const char *private_key_file);
|
||||
|
||||
ptls_context_t ctx_;
|
||||
ptls_openssl_sign_certificate_t sign_cert_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_PICOTLS_H)
|
||||
155
deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.cc
vendored
Normal file
155
deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.cc
vendored
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_client_context_quictls.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_quictls.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "client_base.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace {
|
||||
auto _ = []() {
|
||||
if (ngtcp2_crypto_quictls_init() != 0) {
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}();
|
||||
} // namespace
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSClientContext::TLSClientContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSClientContext::~TLSClientContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX *TLSClientContext::get_native_handle() const { return ssl_ctx_; }
|
||||
|
||||
namespace {
|
||||
int new_session_cb(SSL *ssl, SSL_SESSION *session) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto c = static_cast<ClientBase *>(conn_ref->user_data);
|
||||
|
||||
c->ticket_received();
|
||||
|
||||
if (SSL_SESSION_get_max_early_data(session) !=
|
||||
std::numeric_limits<uint32_t>::max()) {
|
||||
std::cerr << "max_early_data_size is not 0xffffffff" << std::endl;
|
||||
}
|
||||
auto f = BIO_new_file(config.session_file, "w");
|
||||
if (f == nullptr) {
|
||||
std::cerr << "Could not write TLS session in " << config.session_file
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!PEM_write_bio_SSL_SESSION(f, session)) {
|
||||
std::cerr << "Unable to write TLS session to file" << std::endl;
|
||||
}
|
||||
|
||||
BIO_free(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int TLSClientContext::init(const char *private_key_file,
|
||||
const char *cert_file) {
|
||||
ssl_ctx_ = SSL_CTX_new(TLS_client_method());
|
||||
if (!ssl_ctx_) {
|
||||
std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_quictls_configure_client_context(ssl_ctx_) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_quictls_configure_client_context failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_default_verify_paths(ssl_ctx_);
|
||||
|
||||
if (SSL_CTX_set_ciphersuites(ssl_ctx_, config.ciphers) != 1) {
|
||||
std::cerr << "SSL_CTX_set_ciphersuites: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) {
|
||||
std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (private_key_file && cert_file) {
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
std::cerr << "SSL_CTX_use_PrivateKey_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) {
|
||||
std::cerr << "SSL_CTX_use_certificate_chain_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.session_file) {
|
||||
SSL_CTX_set_session_cache_mode(ssl_ctx_, SSL_SESS_CACHE_CLIENT |
|
||||
SSL_SESS_CACHE_NO_INTERNAL);
|
||||
SSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern std::ofstream keylog_file;
|
||||
|
||||
namespace {
|
||||
void keylog_callback(const SSL *ssl, const char *line) {
|
||||
keylog_file.write(line, static_cast<std::streamsize>(strlen(line)));
|
||||
keylog_file.put('\n');
|
||||
keylog_file.flush();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TLSClientContext::enable_keylog() {
|
||||
SSL_CTX_set_keylog_callback(ssl_ctx_, keylog_callback);
|
||||
}
|
||||
49
deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.h
vendored
Normal file
49
deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.h
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_CONTEXT_QUICTLS_H
|
||||
#define TLS_CLIENT_CONTEXT_QUICTLS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
class TLSClientContext {
|
||||
public:
|
||||
TLSClientContext();
|
||||
~TLSClientContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file);
|
||||
|
||||
SSL_CTX *get_native_handle() const;
|
||||
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_QUICTLS_H)
|
||||
184
deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.cc
vendored
Normal file
184
deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.cc
vendored
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_client_context_wolfssl.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
|
||||
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
|
||||
#include "client_base.h"
|
||||
#include "template.h"
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSClientContext::TLSClientContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSClientContext::~TLSClientContext() {
|
||||
if (ssl_ctx_) {
|
||||
wolfSSL_CTX_free(ssl_ctx_);
|
||||
}
|
||||
}
|
||||
|
||||
WOLFSSL_CTX *TLSClientContext::get_native_handle() const { return ssl_ctx_; }
|
||||
|
||||
namespace {
|
||||
int new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) {
|
||||
std::cerr << "new_session_cb called" << std::endl;
|
||||
|
||||
auto conn_ref =
|
||||
static_cast<ngtcp2_crypto_conn_ref *>(wolfSSL_get_app_data(ssl));
|
||||
auto c = static_cast<ClientBase *>(conn_ref->user_data);
|
||||
|
||||
c->ticket_received();
|
||||
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
if (wolfSSL_SESSION_get_max_early_data(session) !=
|
||||
std::numeric_limits<uint32_t>::max()) {
|
||||
std::cerr << "max_early_data_size is not 0xffffffff" << std::endl;
|
||||
}
|
||||
|
||||
unsigned char sbuffer[16 * 1024], *data;
|
||||
auto sz = wolfSSL_i2d_SSL_SESSION(session, nullptr);
|
||||
if (sz <= 0) {
|
||||
std::cerr << "Could not export TLS session in " << config.session_file
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
if (static_cast<size_t>(sz) > sizeof(sbuffer)) {
|
||||
std::cerr << "Exported TLS session too large" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
data = sbuffer;
|
||||
sz = wolfSSL_i2d_SSL_SESSION(session, &data);
|
||||
|
||||
auto f = wolfSSL_BIO_new_file(config.session_file, "w");
|
||||
if (f == nullptr) {
|
||||
std::cerr << "Could not write TLS session in " << config.session_file
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto f_d = defer(wolfSSL_BIO_free, f);
|
||||
|
||||
if (!wolfSSL_PEM_write_bio(f, "WOLFSSL SESSION PARAMETERS", "", sbuffer,
|
||||
sz)) {
|
||||
std::cerr << "Unable to write TLS session to file" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
std::cerr << "new_session_cb: wrote " << sz << " of session data"
|
||||
<< std::endl;
|
||||
#else // !defined(HAVE_SESSION_TICKET)
|
||||
std::cerr << "TLS session tickets not enabled in wolfSSL " << std::endl;
|
||||
#endif // !defined(HAVE_SESSION_TICKET)
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int TLSClientContext::init(const char *private_key_file,
|
||||
const char *cert_file) {
|
||||
ssl_ctx_ = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
|
||||
if (!ssl_ctx_) {
|
||||
std::cerr << "wolfSSL_CTX_new: "
|
||||
<< wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx_) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_wolfssl_configure_client_context failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wolfSSL_CTX_set_default_verify_paths(ssl_ctx_) ==
|
||||
WOLFSSL_NOT_IMPLEMENTED) {
|
||||
/* hmm, not verifying the server cert for now */
|
||||
wolfSSL_CTX_set_verify(ssl_ctx_, WOLFSSL_VERIFY_NONE, 0);
|
||||
}
|
||||
|
||||
if (wolfSSL_CTX_set_cipher_list(ssl_ctx_, config.ciphers) !=
|
||||
WOLFSSL_SUCCESS) {
|
||||
std::cerr << "wolfSSL_CTX_set_cipher_list: "
|
||||
<< wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wolfSSL_CTX_set1_groups_list(
|
||||
ssl_ctx_, const_cast<char *>(config.groups)) != WOLFSSL_SUCCESS) {
|
||||
std::cerr << "wolfSSL_CTX_set1_groups_list(" << config.groups << ") failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (private_key_file && cert_file) {
|
||||
if (wolfSSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file,
|
||||
SSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) {
|
||||
std::cerr << "wolfSSL_CTX_use_PrivateKey_file: "
|
||||
<< wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wolfSSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) !=
|
||||
WOLFSSL_SUCCESS) {
|
||||
std::cerr << "wolfSSL_CTX_use_certificate_chain_file: "
|
||||
<< wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.session_file) {
|
||||
wolfSSL_CTX_UseSessionTicket(ssl_ctx_);
|
||||
wolfSSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern std::ofstream keylog_file;
|
||||
|
||||
#ifdef HAVE_SECRET_CALLBACK
|
||||
namespace {
|
||||
void keylog_callback(const WOLFSSL *ssl, const char *line) {
|
||||
keylog_file.write(line, static_cast<std::streamsize>(strlen(line)));
|
||||
keylog_file.put('\n');
|
||||
keylog_file.flush();
|
||||
}
|
||||
} // namespace
|
||||
#endif // defined(HAVE_SECRET_CALLBACK)
|
||||
|
||||
void TLSClientContext::enable_keylog() {
|
||||
#ifdef HAVE_SECRET_CALLBACK
|
||||
wolfSSL_CTX_set_keylog_callback(ssl_ctx_, keylog_callback);
|
||||
#endif // defined(HAVE_SECRET_CALLBACK)
|
||||
}
|
||||
51
deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.h
vendored
Normal file
51
deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.h
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_CONTEXT_WOLFSSL_H
|
||||
#define TLS_CLIENT_CONTEXT_WOLFSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/quic.h>
|
||||
|
||||
class TLSClientContext {
|
||||
public:
|
||||
TLSClientContext();
|
||||
~TLSClientContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file);
|
||||
|
||||
WOLFSSL_CTX *get_native_handle() const;
|
||||
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
WOLFSSL_CTX *ssl_ctx_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_WOLFSSL_H)
|
||||
56
deps/ngtcp2/ngtcp2/examples/tls_client_session.h
vendored
Normal file
56
deps/ngtcp2/ngtcp2/examples/tls_client_session.h
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_SESSION_H
|
||||
#define TLS_CLIENT_SESSION_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#ifdef WITH_EXAMPLE_QUICTLS
|
||||
# include "tls_client_session_quictls.h"
|
||||
#endif // defined(WITH_EXAMPLE_QUICTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_GNUTLS
|
||||
# include "tls_client_session_gnutls.h"
|
||||
#endif // defined(WITH_EXAMPLE_GNUTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_BORINGSSL
|
||||
# include "tls_client_session_boringssl.h"
|
||||
#endif // defined(WITH_EXAMPLE_BORINGSSL)
|
||||
|
||||
#ifdef WITH_EXAMPLE_PICOTLS
|
||||
# include "tls_client_session_picotls.h"
|
||||
#endif // defined(WITH_EXAMPLE_PICOTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_WOLFSSL
|
||||
# include "tls_client_session_wolfssl.h"
|
||||
#endif // defined(WITH_EXAMPLE_WOLFSSL)
|
||||
|
||||
#ifdef WITH_EXAMPLE_OSSL
|
||||
# include "tls_client_session_ossl.h"
|
||||
#endif // defined(WITH_EXAMPLE_OSSL)
|
||||
|
||||
#endif // !defined(TLS_CLIENT_SESSION_H)
|
||||
147
deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.cc
vendored
Normal file
147
deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.cc
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2021 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_client_session_boringssl.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "tls_client_context_boringssl.h"
|
||||
#include "client_base.h"
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
|
||||
TLSClientSession::TLSClientSession() {}
|
||||
|
||||
TLSClientSession::~TLSClientSession() {}
|
||||
|
||||
extern Config config;
|
||||
|
||||
int TLSClientSession::init(bool &early_data_enabled,
|
||||
const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client,
|
||||
uint32_t quic_version, AppProtocol app_proto) {
|
||||
early_data_enabled = false;
|
||||
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
ssl_ = SSL_new(ssl_ctx);
|
||||
if (!ssl_) {
|
||||
std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_set_app_data(ssl_, client->conn_ref());
|
||||
SSL_set_connect_state(ssl_);
|
||||
|
||||
switch (app_proto) {
|
||||
case AppProtocol::H3:
|
||||
SSL_set_alpn_protos(ssl_, H3_ALPN.data(), H3_ALPN.size());
|
||||
break;
|
||||
case AppProtocol::HQ:
|
||||
SSL_set_alpn_protos(ssl_, HQ_ALPN.data(), HQ_ALPN.size());
|
||||
break;
|
||||
}
|
||||
|
||||
if (!config.sni.empty()) {
|
||||
SSL_set_tlsext_host_name(ssl_, config.sni.data());
|
||||
} else if (util::numeric_host(remote_addr)) {
|
||||
// If remote host is numeric address, just send "localhost" as SNI
|
||||
// for now.
|
||||
SSL_set_tlsext_host_name(ssl_, "localhost");
|
||||
} else {
|
||||
SSL_set_tlsext_host_name(ssl_, remote_addr);
|
||||
}
|
||||
|
||||
if (config.session_file) {
|
||||
auto f = BIO_new_file(config.session_file, "r");
|
||||
if (f == nullptr) {
|
||||
std::cerr << "Could not read TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
auto session = PEM_read_bio_SSL_SESSION(f, nullptr, 0, nullptr);
|
||||
BIO_free(f);
|
||||
if (session == nullptr) {
|
||||
std::cerr << "Could not read TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
if (!SSL_set_session(ssl_, session)) {
|
||||
std::cerr << "Could not set session" << std::endl;
|
||||
} else if (!config.disable_early_data &&
|
||||
SSL_SESSION_early_data_capable(session)) {
|
||||
early_data_enabled = true;
|
||||
SSL_set_early_data_enabled(ssl_, 1);
|
||||
}
|
||||
SSL_SESSION_free(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.ech_config_list.empty() &&
|
||||
SSL_set1_ech_config_list(ssl_, config.ech_config_list.data(),
|
||||
config.ech_config_list.size()) != 1) {
|
||||
std::cerr << "Could not set ECHConfigList: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TLSClientSession::get_early_data_accepted() const {
|
||||
return SSL_early_data_accepted(ssl_);
|
||||
}
|
||||
|
||||
bool TLSClientSession::get_ech_accepted() const {
|
||||
return SSL_ech_accepted(ssl_);
|
||||
}
|
||||
|
||||
int TLSClientSession::write_ech_config_list(const char *path) const {
|
||||
const uint8_t *retry_configs;
|
||||
size_t retry_configslen;
|
||||
|
||||
SSL_get0_ech_retry_configs(ssl_, &retry_configs, &retry_configslen);
|
||||
if (retry_configslen == 0) {
|
||||
std::cerr << "No ECH retry configs found" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto f = std::ofstream(path);
|
||||
|
||||
if (!f) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
f.write(reinterpret_cast<const char *>(retry_configs),
|
||||
static_cast<std::streamsize>(retry_configslen));
|
||||
f.close();
|
||||
|
||||
if (!f) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
54
deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.h
vendored
Normal file
54
deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.h
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2021 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_SESSION_BORINGSSL_H
|
||||
#define TLS_CLIENT_SESSION_BORINGSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "tls_session_base_quictls.h"
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
class TLSClientContext;
|
||||
class ClientBase;
|
||||
|
||||
class TLSClientSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSClientSession();
|
||||
~TLSClientSession();
|
||||
|
||||
int init(bool &early_data_enabled, const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client, uint32_t quic_version,
|
||||
AppProtocol app_proto);
|
||||
|
||||
bool get_early_data_accepted() const;
|
||||
bool get_ech_accepted() const;
|
||||
int write_ech_config_list(const char *path) const;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_SESSION_BORINGSSL_H)
|
||||
121
deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.cc
vendored
Normal file
121
deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.cc
vendored
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_client_session_ossl.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "tls_client_context_ossl.h"
|
||||
#include "client_base.h"
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
|
||||
TLSClientSession::TLSClientSession() {}
|
||||
|
||||
TLSClientSession::~TLSClientSession() {}
|
||||
|
||||
extern Config config;
|
||||
|
||||
int TLSClientSession::init(bool &early_data_enabled,
|
||||
const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client,
|
||||
uint32_t quic_version, AppProtocol app_proto) {
|
||||
early_data_enabled = false;
|
||||
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
auto ssl = SSL_new(ssl_ctx);
|
||||
if (!ssl) {
|
||||
std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_ossl_ctx_set_ssl(ossl_ctx_, ssl);
|
||||
|
||||
if (ngtcp2_crypto_ossl_configure_client_session(ssl) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_ossl_configure_client_session failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_set_app_data(ssl, client->conn_ref());
|
||||
SSL_set_connect_state(ssl);
|
||||
|
||||
switch (app_proto) {
|
||||
case AppProtocol::H3:
|
||||
SSL_set_alpn_protos(ssl, H3_ALPN.data(), H3_ALPN.size());
|
||||
break;
|
||||
case AppProtocol::HQ:
|
||||
SSL_set_alpn_protos(ssl, HQ_ALPN.data(), HQ_ALPN.size());
|
||||
break;
|
||||
}
|
||||
|
||||
if (!config.sni.empty()) {
|
||||
SSL_set_tlsext_host_name(ssl, config.sni.data());
|
||||
} else if (util::numeric_host(remote_addr)) {
|
||||
// If remote host is numeric address, just send "localhost" as SNI
|
||||
// for now.
|
||||
SSL_set_tlsext_host_name(ssl, "localhost");
|
||||
} else {
|
||||
SSL_set_tlsext_host_name(ssl, remote_addr);
|
||||
}
|
||||
|
||||
if (config.session_file) {
|
||||
auto f = BIO_new_file(config.session_file, "r");
|
||||
if (f == nullptr) {
|
||||
std::cerr << "Could not read TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
auto session = PEM_read_bio_SSL_SESSION(f, nullptr, 0, nullptr);
|
||||
BIO_free(f);
|
||||
if (session == nullptr) {
|
||||
std::cerr << "Could not read TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
if (!SSL_set_session(ssl, session)) {
|
||||
std::cerr << "Could not set session" << std::endl;
|
||||
} else if (!config.disable_early_data &&
|
||||
SSL_SESSION_get_max_early_data(session)) {
|
||||
early_data_enabled = true;
|
||||
SSL_set_quic_tls_early_data_enabled(ssl, 1);
|
||||
}
|
||||
|
||||
SSL_SESSION_free(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TLSClientSession::get_early_data_accepted() const {
|
||||
auto ssl = ngtcp2_crypto_ossl_ctx_get_ssl(ossl_ctx_);
|
||||
|
||||
// SSL_get_early_data_status works after handshake completes.
|
||||
return SSL_get_early_data_status(ssl) == SSL_EARLY_DATA_ACCEPTED;
|
||||
}
|
||||
54
deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.h
vendored
Normal file
54
deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.h
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_SESSION_OSSL_H
|
||||
#define TLS_CLIENT_SESSION_OSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "tls_session_base_ossl.h"
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
class TLSClientContext;
|
||||
class ClientBase;
|
||||
|
||||
class TLSClientSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSClientSession();
|
||||
~TLSClientSession();
|
||||
|
||||
int init(bool &early_data_enabled, const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client, uint32_t quic_version,
|
||||
AppProtocol app_proto);
|
||||
|
||||
bool get_early_data_accepted() const;
|
||||
bool get_ech_accepted() const { return false; }
|
||||
int write_ech_config_list(const char *path) const { return 0; }
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_SESSION_OSSL_H)
|
||||
169
deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.cc
vendored
Normal file
169
deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.cc
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_client_session_picotls.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_picotls.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <picotls.h>
|
||||
|
||||
#include "tls_client_context_picotls.h"
|
||||
#include "client_base.h"
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSClientSession::TLSClientSession() {}
|
||||
|
||||
TLSClientSession::~TLSClientSession() {
|
||||
auto &hsprops = cptls_.handshake_properties;
|
||||
|
||||
delete[] hsprops.client.session_ticket.base;
|
||||
}
|
||||
|
||||
namespace {
|
||||
auto negotiated_protocols_h3 = std::to_array<ptls_iovec_t>({
|
||||
{
|
||||
.base = const_cast<uint8_t *>(&H3_ALPN_V1[1]),
|
||||
.len = H3_ALPN_V1[0],
|
||||
},
|
||||
});
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
auto negotiated_protocols_hq = std::to_array<ptls_iovec_t>({
|
||||
{
|
||||
.base = const_cast<uint8_t *>(&HQ_ALPN_V1[1]),
|
||||
.len = HQ_ALPN_V1[0],
|
||||
},
|
||||
});
|
||||
} // namespace
|
||||
|
||||
int TLSClientSession::init(bool &early_data_enabled, TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client,
|
||||
uint32_t quic_version, AppProtocol app_proto) {
|
||||
cptls_.ptls = ptls_client_new(tls_ctx.get_native_handle());
|
||||
if (!cptls_.ptls) {
|
||||
std::cerr << "ptls_client_new failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ptls_get_data_ptr(cptls_.ptls) = client->conn_ref();
|
||||
|
||||
auto conn = client->conn();
|
||||
auto &hsprops = cptls_.handshake_properties;
|
||||
|
||||
hsprops.additional_extensions = new ptls_raw_extension_t[2]{
|
||||
{
|
||||
.type = UINT16_MAX,
|
||||
},
|
||||
{
|
||||
.type = UINT16_MAX,
|
||||
},
|
||||
};
|
||||
|
||||
if (ngtcp2_crypto_picotls_configure_client_session(&cptls_, conn) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_picotls_configure_client_session failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (app_proto) {
|
||||
case AppProtocol::H3:
|
||||
hsprops.client.negotiated_protocols.list = negotiated_protocols_h3.data();
|
||||
hsprops.client.negotiated_protocols.count = negotiated_protocols_h3.size();
|
||||
|
||||
break;
|
||||
case AppProtocol::HQ:
|
||||
hsprops.client.negotiated_protocols.list = negotiated_protocols_hq.data();
|
||||
hsprops.client.negotiated_protocols.count = negotiated_protocols_hq.size();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (util::numeric_host(remote_addr)) {
|
||||
// If remote host is numeric address, just send "localhost" as SNI
|
||||
// for now.
|
||||
ptls_set_server_name(cptls_.ptls, "localhost", strlen("localhost"));
|
||||
} else {
|
||||
ptls_set_server_name(cptls_.ptls, remote_addr, strlen(remote_addr));
|
||||
}
|
||||
|
||||
if (config.session_file) {
|
||||
auto f = BIO_new_file(config.session_file, "r");
|
||||
if (f == nullptr) {
|
||||
std::cerr << "Could not read TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
auto f_d = defer(BIO_free, f);
|
||||
|
||||
char *name, *header;
|
||||
unsigned char *data;
|
||||
long datalen;
|
||||
|
||||
if (PEM_read_bio(f, &name, &header, &data, &datalen) != 1) {
|
||||
std::cerr << "Could not read TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
if ("PICOTLS SESSION PARAMETERS"sv != name) {
|
||||
std::cerr << "TLS session file contains unexpected name: " << name
|
||||
<< std::endl;
|
||||
} else {
|
||||
hsprops.client.session_ticket.base =
|
||||
new uint8_t[static_cast<size_t>(datalen)];
|
||||
hsprops.client.session_ticket.len = static_cast<size_t>(datalen);
|
||||
std::ranges::copy_n(data, datalen,
|
||||
hsprops.client.session_ticket.base);
|
||||
|
||||
if (!config.disable_early_data) {
|
||||
// No easy way to check max_early_data from ticket. We
|
||||
// need to run ptls_handle_message.
|
||||
early_data_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
OPENSSL_free(name);
|
||||
OPENSSL_free(header);
|
||||
OPENSSL_free(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TLSClientSession::get_early_data_accepted() const {
|
||||
return cptls_.handshake_properties.client.early_data_acceptance ==
|
||||
PTLS_EARLY_DATA_ACCEPTED;
|
||||
}
|
||||
54
deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.h
vendored
Normal file
54
deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.h
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_SESSION_PICOTLS_H
|
||||
#define TLS_CLIENT_SESSION_PICOTLS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "tls_session_base_picotls.h"
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
class TLSClientContext;
|
||||
class ClientBase;
|
||||
|
||||
class TLSClientSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSClientSession();
|
||||
~TLSClientSession();
|
||||
|
||||
int init(bool &early_data_enabled, TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client, uint32_t quic_version,
|
||||
AppProtocol app_proto);
|
||||
|
||||
bool get_early_data_accepted() const;
|
||||
bool get_ech_accepted() const { return false; }
|
||||
int write_ech_config_list(const char *path) const { return 0; }
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_SESSION_PICOTLS_H)
|
||||
113
deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.cc
vendored
Normal file
113
deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.cc
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_client_session_quictls.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "tls_client_context_quictls.h"
|
||||
#include "client_base.h"
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
|
||||
TLSClientSession::TLSClientSession() {}
|
||||
|
||||
TLSClientSession::~TLSClientSession() {}
|
||||
|
||||
extern Config config;
|
||||
|
||||
int TLSClientSession::init(bool &early_data_enabled,
|
||||
const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client,
|
||||
uint32_t quic_version, AppProtocol app_proto) {
|
||||
early_data_enabled = false;
|
||||
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
ssl_ = SSL_new(ssl_ctx);
|
||||
if (!ssl_) {
|
||||
std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_set_app_data(ssl_, client->conn_ref());
|
||||
SSL_set_connect_state(ssl_);
|
||||
|
||||
switch (app_proto) {
|
||||
case AppProtocol::H3:
|
||||
SSL_set_alpn_protos(ssl_, H3_ALPN.data(), H3_ALPN.size());
|
||||
break;
|
||||
case AppProtocol::HQ:
|
||||
SSL_set_alpn_protos(ssl_, HQ_ALPN.data(), HQ_ALPN.size());
|
||||
break;
|
||||
}
|
||||
|
||||
if (!config.sni.empty()) {
|
||||
SSL_set_tlsext_host_name(ssl_, config.sni.data());
|
||||
} else if (util::numeric_host(remote_addr)) {
|
||||
// If remote host is numeric address, just send "localhost" as SNI
|
||||
// for now.
|
||||
SSL_set_tlsext_host_name(ssl_, "localhost");
|
||||
} else {
|
||||
SSL_set_tlsext_host_name(ssl_, remote_addr);
|
||||
}
|
||||
|
||||
if (config.session_file) {
|
||||
auto f = BIO_new_file(config.session_file, "r");
|
||||
if (f == nullptr) {
|
||||
std::cerr << "Could not read TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
auto session = PEM_read_bio_SSL_SESSION(f, nullptr, 0, nullptr);
|
||||
BIO_free(f);
|
||||
if (session == nullptr) {
|
||||
std::cerr << "Could not read TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
if (!SSL_set_session(ssl_, session)) {
|
||||
std::cerr << "Could not set session" << std::endl;
|
||||
}
|
||||
#ifndef LIBRESSL_VERSION_NUMBER
|
||||
else if (!config.disable_early_data &&
|
||||
SSL_SESSION_get_max_early_data(session)) {
|
||||
early_data_enabled = true;
|
||||
SSL_set_quic_early_data_enabled(ssl_, 1);
|
||||
}
|
||||
#endif // !defined(LIBRESSL_VERSION_NUMBER)
|
||||
SSL_SESSION_free(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TLSClientSession::get_early_data_accepted() const {
|
||||
// SSL_get_early_data_status works after handshake completes.
|
||||
return SSL_get_early_data_status(ssl_) == SSL_EARLY_DATA_ACCEPTED;
|
||||
}
|
||||
54
deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.h
vendored
Normal file
54
deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.h
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_SESSION_QUICTLS_H
|
||||
#define TLS_CLIENT_SESSION_QUICTLS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "tls_session_base_quictls.h"
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
class TLSClientContext;
|
||||
class ClientBase;
|
||||
|
||||
class TLSClientSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSClientSession();
|
||||
~TLSClientSession();
|
||||
|
||||
int init(bool &early_data_enabled, const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client, uint32_t quic_version,
|
||||
AppProtocol app_proto);
|
||||
|
||||
bool get_early_data_accepted() const;
|
||||
bool get_ech_accepted() const { return false; }
|
||||
int write_ech_config_list(const char *path) const { return 0; }
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_SESSION_QUICTLS_H)
|
||||
160
deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.cc
vendored
Normal file
160
deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.cc
vendored
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_client_session_wolfssl.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "tls_client_context_wolfssl.h"
|
||||
#include "client_base.h"
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
TLSClientSession::TLSClientSession() {}
|
||||
|
||||
TLSClientSession::~TLSClientSession() {}
|
||||
|
||||
extern Config config;
|
||||
|
||||
namespace {
|
||||
int wolfssl_session_ticket_cb(WOLFSSL *ssl, const unsigned char *ticket,
|
||||
int ticketSz, void *cb_ctx) {
|
||||
std::cerr << "session ticket callback invoked" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int TLSClientSession::init(bool &early_data_enabled,
|
||||
const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client,
|
||||
uint32_t quic_version, AppProtocol app_proto) {
|
||||
early_data_enabled = false;
|
||||
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
ssl_ = wolfSSL_new(ssl_ctx);
|
||||
if (!ssl_) {
|
||||
std::cerr << "wolfSSL_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
wolfSSL_set_app_data(ssl_, client->conn_ref());
|
||||
wolfSSL_set_connect_state(ssl_);
|
||||
|
||||
switch (app_proto) {
|
||||
case AppProtocol::H3:
|
||||
wolfSSL_set_alpn_protos(ssl_, H3_ALPN.data(), H3_ALPN.size());
|
||||
break;
|
||||
case AppProtocol::HQ:
|
||||
wolfSSL_set_alpn_protos(ssl_, HQ_ALPN.data(), HQ_ALPN.size());
|
||||
break;
|
||||
}
|
||||
|
||||
if (!config.sni.empty()) {
|
||||
wolfSSL_UseSNI(ssl_, WOLFSSL_SNI_HOST_NAME, config.sni.data(),
|
||||
static_cast<uint16_t>(config.sni.length()));
|
||||
} else if (util::numeric_host(remote_addr)) {
|
||||
// If remote host is numeric address, just send "localhost" as SNI
|
||||
// for now.
|
||||
wolfSSL_UseSNI(ssl_, WOLFSSL_SNI_HOST_NAME, "localhost",
|
||||
sizeof("localhost") - 1);
|
||||
} else {
|
||||
wolfSSL_UseSNI(ssl_, WOLFSSL_SNI_HOST_NAME, remote_addr,
|
||||
static_cast<uint16_t>(strlen(remote_addr)));
|
||||
}
|
||||
|
||||
// Just use QUIC v1
|
||||
wolfSSL_set_quic_transport_version(ssl_, 0x39);
|
||||
|
||||
if (config.session_file) {
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
auto f = wolfSSL_BIO_new_file(config.session_file, "r");
|
||||
if (f == nullptr) {
|
||||
std::cerr << "Could not open TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
char *name, *header;
|
||||
unsigned char *data;
|
||||
const unsigned char *pdata;
|
||||
long datalen;
|
||||
WOLFSSL_SESSION *session;
|
||||
|
||||
if (wolfSSL_PEM_read_bio(f, &name, &header, &data, &datalen) != 1) {
|
||||
std::cerr << "Could not read TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
if ("WOLFSSL SESSION PARAMETERS"sv != name) {
|
||||
std::cerr << "TLS session file contains unexpected name: " << name
|
||||
<< std::endl;
|
||||
} else {
|
||||
pdata = data;
|
||||
session = wolfSSL_d2i_SSL_SESSION(nullptr, &pdata, datalen);
|
||||
if (session == nullptr) {
|
||||
std::cerr << "Could not parse TLS session from file "
|
||||
<< config.session_file << std::endl;
|
||||
} else {
|
||||
auto ret = wolfSSL_set_session(ssl_, session);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
std::cerr << "Could not install TLS session from file "
|
||||
<< config.session_file << std::endl;
|
||||
} else {
|
||||
if (!config.disable_early_data &&
|
||||
wolfSSL_SESSION_get_max_early_data(session)) {
|
||||
early_data_enabled = true;
|
||||
wolfSSL_set_quic_early_data_enabled(ssl_, 1);
|
||||
}
|
||||
}
|
||||
wolfSSL_SESSION_free(session);
|
||||
}
|
||||
}
|
||||
|
||||
wolfSSL_OPENSSL_free(name);
|
||||
wolfSSL_OPENSSL_free(header);
|
||||
wolfSSL_OPENSSL_free(data);
|
||||
}
|
||||
wolfSSL_BIO_free(f);
|
||||
}
|
||||
wolfSSL_UseSessionTicket(ssl_);
|
||||
wolfSSL_set_SessionTicket_cb(ssl_, wolfssl_session_ticket_cb, nullptr);
|
||||
#else // !defined(HAVE_SESSION_TICKET)
|
||||
std::cerr << "TLS session im-/export not enabled in wolfSSL" << std::endl;
|
||||
#endif // !defined(HAVE_SESSION_TICKET)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TLSClientSession::get_early_data_accepted() const {
|
||||
// wolfSSL_get_early_data_status works after handshake completes.
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
return wolfSSL_get_early_data_status(ssl_) == SSL_EARLY_DATA_ACCEPTED;
|
||||
#else // !defined(WOLFSSL_EARLY_DATA)
|
||||
return 0;
|
||||
#endif // !defined(WOLFSSL_EARLY_DATA)
|
||||
}
|
||||
54
deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.h
vendored
Normal file
54
deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.h
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_CLIENT_SESSION_WOLFSSL_H
|
||||
#define TLS_CLIENT_SESSION_WOLFSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "tls_session_base_wolfssl.h"
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
class TLSClientContext;
|
||||
class ClientBase;
|
||||
|
||||
class TLSClientSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSClientSession();
|
||||
~TLSClientSession();
|
||||
|
||||
int init(bool &early_data_enabled, const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client, uint32_t quic_version,
|
||||
AppProtocol app_proto);
|
||||
|
||||
bool get_early_data_accepted() const;
|
||||
bool get_ech_accepted() const { return false; }
|
||||
int write_ech_config_list(const char *path) const { return 0; }
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_SESSION_WOLFSSL_H)
|
||||
56
deps/ngtcp2/ngtcp2/examples/tls_server_context.h
vendored
Normal file
56
deps/ngtcp2/ngtcp2/examples/tls_server_context.h
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_CONTEXT_H
|
||||
#define TLS_SERVER_CONTEXT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#ifdef WITH_EXAMPLE_QUICTLS
|
||||
# include "tls_server_context_quictls.h"
|
||||
#endif // defined(WITH_EXAMPLE_QUICTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_GNUTLS
|
||||
# include "tls_server_context_gnutls.h"
|
||||
#endif // defined(WITH_EXAMPLE_GNUTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_BORINGSSL
|
||||
# include "tls_server_context_boringssl.h"
|
||||
#endif // defined(WITH_EXAMPLE_BORINGSSL)
|
||||
|
||||
#ifdef WITH_EXAMPLE_PICOTLS
|
||||
# include "tls_server_context_picotls.h"
|
||||
#endif // defined(WITH_EXAMPLE_PICOTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_WOLFSSL
|
||||
# include "tls_server_context_wolfssl.h"
|
||||
#endif // defined(WITH_EXAMPLE_WOLFSSL)
|
||||
|
||||
#ifdef WITH_EXAMPLE_OSSL
|
||||
# include "tls_server_context_ossl.h"
|
||||
#endif // defined(WITH_EXAMPLE_OSSL)
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_H)
|
||||
265
deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.cc
vendored
Normal file
265
deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.cc
vendored
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2021 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_server_context_boringssl.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_boringssl.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/hpke.h>
|
||||
|
||||
#include "server_base.h"
|
||||
#include "template.h"
|
||||
#include "tls_shared_boringssl.h"
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerContext::TLSServerContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSServerContext::~TLSServerContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX *TLSServerContext::get_native_handle() const { return ssl_ctx_; }
|
||||
|
||||
namespace {
|
||||
int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
// This should be the negotiated version, but we have not set the
|
||||
// negotiated version when this callback is called.
|
||||
auto version = ngtcp2_conn_get_client_chosen_version(h->conn());
|
||||
|
||||
switch (version) {
|
||||
case NGTCP2_PROTO_VER_V1:
|
||||
case NGTCP2_PROTO_VER_V2:
|
||||
break;
|
||||
default:
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Unexpected quic protocol version: " << std::hex << "0x"
|
||||
<< version << std::dec << std::endl;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
|
||||
for (auto s = std::span{in, inlen}; s.size() >= H3_ALPN_V1.size();
|
||||
s = s.subspan(s[0] + 1)) {
|
||||
if (std::ranges::equal(H3_ALPN_V1, s.first(H3_ALPN_V1.size()))) {
|
||||
*out = &s[1];
|
||||
*outlen = s[0];
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Client did not present ALPN " << &H3_ALPN_V1[1] << std::endl;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
// This should be the negotiated version, but we have not set the
|
||||
// negotiated version when this callback is called.
|
||||
auto version = ngtcp2_conn_get_client_chosen_version(h->conn());
|
||||
|
||||
switch (version) {
|
||||
case NGTCP2_PROTO_VER_V1:
|
||||
case NGTCP2_PROTO_VER_V2:
|
||||
break;
|
||||
default:
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Unexpected quic protocol version: " << std::hex << "0x"
|
||||
<< version << std::dec << std::endl;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
|
||||
for (auto s = std::span{in, inlen}; s.size() >= HQ_ALPN_V1.size();
|
||||
s = s.subspan(s[0] + 1)) {
|
||||
if (std::ranges::equal(HQ_ALPN_V1, s.first(HQ_ALPN_V1.size()))) {
|
||||
*out = &s[1];
|
||||
*outlen = s[0];
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Client did not present ALPN " << &HQ_ALPN_V1[1] << std::endl;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
// We don't verify the client certificate. Just request it for the
|
||||
// testing purpose.
|
||||
return 1;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int TLSServerContext::init(const char *private_key_file, const char *cert_file,
|
||||
AppProtocol app_proto) {
|
||||
constexpr static unsigned char sid_ctx[] = "ngtcp2 server";
|
||||
|
||||
ssl_ctx_ = SSL_CTX_new(TLS_server_method());
|
||||
if (!ssl_ctx_) {
|
||||
std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
constexpr auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
|
||||
SSL_OP_SINGLE_ECDH_USE |
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE;
|
||||
|
||||
SSL_CTX_set_options(ssl_ctx_, ssl_opts);
|
||||
|
||||
if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) {
|
||||
std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_mode(ssl_ctx_, SSL_MODE_RELEASE_BUFFERS);
|
||||
|
||||
if (ngtcp2_crypto_boringssl_configure_server_context(ssl_ctx_) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_boringssl_configure_server_context failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (app_proto) {
|
||||
case AppProtocol::H3:
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx_, alpn_select_proto_h3_cb, nullptr);
|
||||
break;
|
||||
case AppProtocol::HQ:
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx_, alpn_select_proto_hq_cb, nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
SSL_CTX_set_default_verify_paths(ssl_ctx_);
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
std::cerr << "SSL_CTX_use_PrivateKey_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) {
|
||||
std::cerr << "SSL_CTX_use_certificate_chain_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_check_private_key(ssl_ctx_) != 1) {
|
||||
std::cerr << "SSL_CTX_check_private_key: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_session_id_context(ssl_ctx_, sid_ctx, sizeof(sid_ctx) - 1);
|
||||
|
||||
if (config.verify_client) {
|
||||
SSL_CTX_set_verify(ssl_ctx_,
|
||||
SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE |
|
||||
SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
verify_cb);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBBROTLI
|
||||
if (!SSL_CTX_add_cert_compression_alg(
|
||||
ssl_ctx_, ngtcp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI,
|
||||
ngtcp2::tls::cert_compress, ngtcp2::tls::cert_decompress)) {
|
||||
std::cerr << "SSL_CTX_add_cert_compression_alg failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
#endif // defined(HAVE_LIBBROTLI)
|
||||
|
||||
if (!config.ech_config.ech_config.empty()) {
|
||||
const auto &echconf = config.ech_config;
|
||||
|
||||
auto pkey = EVP_HPKE_KEY_new();
|
||||
|
||||
if (EVP_HPKE_KEY_init(pkey, EVP_hpke_x25519_hkdf_sha256(),
|
||||
echconf.private_key.bytes.data(),
|
||||
echconf.private_key.bytes.size()) != 1) {
|
||||
std::cerr << "EVP_HPKE_KEY_init failed: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto pkey_d = defer(EVP_HPKE_KEY_free, pkey);
|
||||
|
||||
auto keys = SSL_ECH_KEYS_new();
|
||||
auto keys_d = defer(SSL_ECH_KEYS_free, keys);
|
||||
|
||||
if (SSL_ECH_KEYS_add(keys, 1, echconf.ech_config.data(),
|
||||
echconf.ech_config.size(), pkey) != 1) {
|
||||
std::cerr << "SSL_ECH_KEYS_add failed: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_set1_ech_keys(ssl_ctx_, keys) != 1) {
|
||||
std::cerr << "SSL_CTX_set1_ech_keys failed: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern std::ofstream keylog_file;
|
||||
|
||||
namespace {
|
||||
void keylog_callback(const SSL *ssl, const char *line) {
|
||||
keylog_file.write(line, static_cast<std::streamsize>(strlen(line)));
|
||||
keylog_file.put('\n');
|
||||
keylog_file.flush();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TLSServerContext::enable_keylog() {
|
||||
SSL_CTX_set_keylog_callback(ssl_ctx_, keylog_callback);
|
||||
}
|
||||
54
deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.h
vendored
Normal file
54
deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.h
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2021 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_CONTEXT_BORINGSSL_H
|
||||
#define TLS_SERVER_CONTEXT_BORINGSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
class TLSServerContext {
|
||||
public:
|
||||
TLSServerContext();
|
||||
~TLSServerContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file,
|
||||
AppProtocol app_proto);
|
||||
|
||||
SSL_CTX *get_native_handle() const;
|
||||
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_BORINGSSL_H)
|
||||
307
deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.cc
vendored
Normal file
307
deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.cc
vendored
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_server_context_ossl.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_ossl.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "server_base.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace {
|
||||
auto _ = []() {
|
||||
if (ngtcp2_crypto_ossl_init() != 0) {
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}();
|
||||
} // namespace
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerContext::TLSServerContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSServerContext::~TLSServerContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX *TLSServerContext::get_native_handle() const { return ssl_ctx_; }
|
||||
|
||||
namespace {
|
||||
int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
// This should be the negotiated version, but we have not set the
|
||||
// negotiated version when this callback is called.
|
||||
auto version = ngtcp2_conn_get_client_chosen_version(h->conn());
|
||||
|
||||
switch (version) {
|
||||
case NGTCP2_PROTO_VER_V1:
|
||||
case NGTCP2_PROTO_VER_V2:
|
||||
break;
|
||||
default:
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Unexpected quic protocol version: " << std::hex << "0x"
|
||||
<< version << std::dec << std::endl;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
|
||||
for (auto s = std::span{in, inlen}; s.size() >= H3_ALPN_V1.size();
|
||||
s = s.subspan(s[0] + 1)) {
|
||||
if (std::ranges::equal(H3_ALPN_V1, s.first(H3_ALPN_V1.size()))) {
|
||||
*out = &s[1];
|
||||
*outlen = s[0];
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Client did not present ALPN " << &H3_ALPN_V1[1] << std::endl;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
// This should be the negotiated version, but we have not set the
|
||||
// negotiated version when this callback is called.
|
||||
auto version = ngtcp2_conn_get_client_chosen_version(h->conn());
|
||||
|
||||
switch (version) {
|
||||
case NGTCP2_PROTO_VER_V1:
|
||||
case NGTCP2_PROTO_VER_V2:
|
||||
break;
|
||||
default:
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Unexpected quic protocol version: " << std::hex << "0x"
|
||||
<< version << std::dec << std::endl;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
|
||||
for (auto s = std::span{in, inlen}; s.size() >= HQ_ALPN_V1.size();
|
||||
s = s.subspan(s[0] + 1)) {
|
||||
if (std::ranges::equal(HQ_ALPN_V1, s.first(HQ_ALPN_V1.size()))) {
|
||||
*out = &s[1];
|
||||
*outlen = s[0];
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Client did not present ALPN " << &HQ_ALPN_V1[1] << std::endl;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
// We don't verify the client certificate. Just request it for the
|
||||
// testing purpose.
|
||||
return 1;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int gen_ticket_cb(SSL *ssl, void *arg) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
auto ver = htonl(ngtcp2_conn_get_negotiated_version(h->conn()));
|
||||
|
||||
if (!SSL_SESSION_set1_ticket_appdata(SSL_get0_session(ssl), &ver,
|
||||
sizeof(ver))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
SSL_TICKET_RETURN decrypt_ticket_cb(SSL *ssl, SSL_SESSION *session,
|
||||
const unsigned char *keyname,
|
||||
size_t keynamelen, SSL_TICKET_STATUS status,
|
||||
void *arg) {
|
||||
switch (status) {
|
||||
case SSL_TICKET_EMPTY:
|
||||
case SSL_TICKET_NO_DECRYPT:
|
||||
return SSL_TICKET_RETURN_IGNORE_RENEW;
|
||||
}
|
||||
|
||||
uint8_t *pver;
|
||||
uint32_t ver;
|
||||
size_t verlen;
|
||||
|
||||
if (!SSL_SESSION_get0_ticket_appdata(
|
||||
session, reinterpret_cast<void **>(&pver), &verlen) ||
|
||||
verlen != sizeof(ver)) {
|
||||
switch (status) {
|
||||
case SSL_TICKET_SUCCESS:
|
||||
return SSL_TICKET_RETURN_IGNORE;
|
||||
case SSL_TICKET_SUCCESS_RENEW:
|
||||
default:
|
||||
return SSL_TICKET_RETURN_IGNORE_RENEW;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&ver, pver, sizeof(ver));
|
||||
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
|
||||
if (ngtcp2_conn_get_client_chosen_version(h->conn()) != ntohl(ver)) {
|
||||
switch (status) {
|
||||
case SSL_TICKET_SUCCESS:
|
||||
return SSL_TICKET_RETURN_IGNORE;
|
||||
case SSL_TICKET_SUCCESS_RENEW:
|
||||
default:
|
||||
return SSL_TICKET_RETURN_IGNORE_RENEW;
|
||||
}
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case SSL_TICKET_SUCCESS:
|
||||
return SSL_TICKET_RETURN_USE;
|
||||
case SSL_TICKET_SUCCESS_RENEW:
|
||||
default:
|
||||
return SSL_TICKET_RETURN_USE_RENEW;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int TLSServerContext::init(const char *private_key_file, const char *cert_file,
|
||||
AppProtocol app_proto) {
|
||||
constexpr static unsigned char sid_ctx[] = "ngtcp2 server";
|
||||
|
||||
ssl_ctx_ = SSL_CTX_new(TLS_server_method());
|
||||
if (!ssl_ctx_) {
|
||||
std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_max_early_data(ssl_ctx_, UINT32_MAX);
|
||||
|
||||
constexpr auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
|
||||
SSL_OP_SINGLE_ECDH_USE |
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE |
|
||||
SSL_OP_NO_ANTI_REPLAY;
|
||||
|
||||
SSL_CTX_set_options(ssl_ctx_, ssl_opts);
|
||||
|
||||
if (SSL_CTX_set_ciphersuites(ssl_ctx_, config.ciphers) != 1) {
|
||||
std::cerr << "SSL_CTX_set_ciphersuites: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) {
|
||||
std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_mode(ssl_ctx_, SSL_MODE_RELEASE_BUFFERS);
|
||||
|
||||
switch (app_proto) {
|
||||
case AppProtocol::H3:
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx_, alpn_select_proto_h3_cb, nullptr);
|
||||
break;
|
||||
case AppProtocol::HQ:
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx_, alpn_select_proto_hq_cb, nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
SSL_CTX_set_default_verify_paths(ssl_ctx_);
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
std::cerr << "SSL_CTX_use_PrivateKey_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) {
|
||||
std::cerr << "SSL_CTX_use_certificate_chain_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_check_private_key(ssl_ctx_) != 1) {
|
||||
std::cerr << "SSL_CTX_check_private_key: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_session_id_context(ssl_ctx_, sid_ctx, sizeof(sid_ctx) - 1);
|
||||
|
||||
if (config.verify_client) {
|
||||
SSL_CTX_set_verify(ssl_ctx_,
|
||||
SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE |
|
||||
SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
verify_cb);
|
||||
}
|
||||
|
||||
SSL_CTX_set_session_ticket_cb(ssl_ctx_, gen_ticket_cb, decrypt_ticket_cb,
|
||||
nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern std::ofstream keylog_file;
|
||||
|
||||
namespace {
|
||||
void keylog_callback(const SSL *ssl, const char *line) {
|
||||
keylog_file.write(line, static_cast<std::streamsize>(strlen(line)));
|
||||
keylog_file.put('\n');
|
||||
keylog_file.flush();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TLSServerContext::enable_keylog() {
|
||||
SSL_CTX_set_keylog_callback(ssl_ctx_, keylog_callback);
|
||||
}
|
||||
54
deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.h
vendored
Normal file
54
deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.h
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_CONTEXT_OSSL_H
|
||||
#define TLS_SERVER_CONTEXT_OSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
class TLSServerContext {
|
||||
public:
|
||||
TLSServerContext();
|
||||
~TLSServerContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file,
|
||||
AppProtocol app_proto);
|
||||
|
||||
SSL_CTX *get_native_handle() const;
|
||||
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_OSSL_H)
|
||||
373
deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.cc
vendored
Normal file
373
deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.cc
vendored
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_server_context_picotls.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_picotls.h>
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
# include <openssl/core_names.h>
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
||||
#include "server_base.h"
|
||||
#include "tls_shared_picotls.h"
|
||||
#include "template.h"
|
||||
|
||||
extern Config config;
|
||||
|
||||
namespace {
|
||||
int on_client_hello_h3_cb(ptls_on_client_hello_t *self, ptls_t *ptls,
|
||||
ptls_on_client_hello_parameters_t *params) {
|
||||
auto &negprotos = params->negotiated_protocols;
|
||||
|
||||
for (size_t i = 0; i < negprotos.count; ++i) {
|
||||
auto &proto = negprotos.list[i];
|
||||
if (std::ranges::equal(H3_ALPN_V1.subspan(1),
|
||||
std::span{proto.base, proto.len})) {
|
||||
if (ptls_set_negotiated_protocol(
|
||||
ptls, reinterpret_cast<char *>(proto.base), proto.len) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return PTLS_ALERT_NO_APPLICATION_PROTOCOL;
|
||||
}
|
||||
|
||||
ptls_on_client_hello_t on_client_hello_h3 = {on_client_hello_h3_cb};
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_client_hello_hq_cb(ptls_on_client_hello_t *self, ptls_t *ptls,
|
||||
ptls_on_client_hello_parameters_t *params) {
|
||||
auto &negprotos = params->negotiated_protocols;
|
||||
|
||||
for (size_t i = 0; i < negprotos.count; ++i) {
|
||||
auto &proto = negprotos.list[i];
|
||||
if (std::ranges::equal(HQ_ALPN_V1.subspan(1),
|
||||
std::span{proto.base, proto.len})) {
|
||||
if (ptls_set_negotiated_protocol(
|
||||
ptls, reinterpret_cast<char *>(proto.base), proto.len) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return PTLS_ALERT_NO_APPLICATION_PROTOCOL;
|
||||
}
|
||||
|
||||
ptls_on_client_hello_t on_client_hello_hq = {on_client_hello_hq_cb};
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
auto ticket_hmac = EVP_sha256();
|
||||
|
||||
std::span<const uint8_t> get_ticket_key_name() {
|
||||
static std::array<uint8_t, 16> key_name;
|
||||
ptls_openssl_random_bytes(key_name.data(), key_name.size());
|
||||
return key_name;
|
||||
}
|
||||
|
||||
std::span<const uint8_t> get_ticket_key() {
|
||||
static std::array<uint8_t, 32> key;
|
||||
ptls_openssl_random_bytes(key.data(), key.size());
|
||||
return key;
|
||||
}
|
||||
|
||||
std::span<const uint8_t> get_ticket_hmac_key() {
|
||||
static std::array<uint8_t, 32> hmac_key;
|
||||
ptls_openssl_random_bytes(hmac_key.data(), hmac_key.size());
|
||||
return hmac_key;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int ticket_key_cb(unsigned char *key_name, unsigned char *iv,
|
||||
EVP_CIPHER_CTX *ctx,
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
EVP_MAC_CTX *hctx,
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
HMAC_CTX *hctx,
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
int enc) {
|
||||
static const auto static_key_name = get_ticket_key_name();
|
||||
static const auto static_key = get_ticket_key();
|
||||
static const auto static_hmac_key = get_ticket_hmac_key();
|
||||
|
||||
if (enc) {
|
||||
ptls_openssl_random_bytes(iv, EVP_MAX_IV_LENGTH);
|
||||
|
||||
std::ranges::copy(static_key_name, key_name);
|
||||
|
||||
if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, static_key.data(),
|
||||
iv)) {
|
||||
return 0;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
auto params = std::to_array({
|
||||
OSSL_PARAM_construct_octet_string(
|
||||
OSSL_MAC_PARAM_KEY, const_cast<uint8_t *>(static_hmac_key.data()),
|
||||
static_hmac_key.size()),
|
||||
OSSL_PARAM_construct_utf8_string(
|
||||
OSSL_MAC_PARAM_DIGEST,
|
||||
const_cast<char *>(EVP_MD_get0_name(ticket_hmac)), 0),
|
||||
OSSL_PARAM_construct_end(),
|
||||
});
|
||||
if (!EVP_MAC_CTX_set_params(hctx, params.data())) {
|
||||
/* TODO Which value should we return on error? */
|
||||
return 0;
|
||||
}
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
if (!HMAC_Init_ex(hctx, static_hmac_key.data(),
|
||||
static_cast<int>(static_hmac_key.size()), ticket_hmac,
|
||||
nullptr)) {
|
||||
return 0;
|
||||
}
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!std::ranges::equal(std::span{key_name, static_key_name.size()},
|
||||
static_key_name)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, static_key.data(),
|
||||
iv)) {
|
||||
return 0;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
auto params = std::to_array({
|
||||
OSSL_PARAM_construct_octet_string(
|
||||
OSSL_MAC_PARAM_KEY, const_cast<uint8_t *>(static_hmac_key.data()),
|
||||
static_hmac_key.size()),
|
||||
OSSL_PARAM_construct_utf8_string(
|
||||
OSSL_MAC_PARAM_DIGEST, const_cast<char *>(EVP_MD_get0_name(ticket_hmac)),
|
||||
0),
|
||||
OSSL_PARAM_construct_end(),
|
||||
});
|
||||
if (!EVP_MAC_CTX_set_params(hctx, params.data())) {
|
||||
/* TODO Which value should we return on error? */
|
||||
return 0;
|
||||
}
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
if (!HMAC_Init_ex(hctx, static_hmac_key.data(),
|
||||
static_cast<int>(static_hmac_key.size()), ticket_hmac,
|
||||
nullptr)) {
|
||||
return 0;
|
||||
}
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
|
||||
return 1;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int encrypt_ticket_cb(ptls_encrypt_ticket_t *encrypt_ticket, ptls_t *ptls,
|
||||
int is_encrypt, ptls_buffer_t *dst, ptls_iovec_t src) {
|
||||
int rv;
|
||||
auto conn_ref =
|
||||
static_cast<ngtcp2_crypto_conn_ref *>(*ptls_get_data_ptr(ptls));
|
||||
auto conn = conn_ref->get_conn(conn_ref);
|
||||
uint32_t ver;
|
||||
|
||||
if (is_encrypt) {
|
||||
ver = htonl(ngtcp2_conn_get_negotiated_version(conn));
|
||||
// TODO Replace std::make_unique with
|
||||
// std::make_unique_for_overwrite when it is available.
|
||||
auto buf = std::make_unique<uint8_t[]>(src.len + sizeof(ver));
|
||||
auto p = std::ranges::copy_n(src.base, as_signed(src.len), buf.get()).out;
|
||||
p = std::ranges::copy_n(reinterpret_cast<uint8_t *>(&ver), sizeof(ver), p)
|
||||
.out;
|
||||
|
||||
src.base = buf.get();
|
||||
src.len = as_unsigned(p - buf.get());
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
rv = ptls_openssl_encrypt_ticket_evp(dst, src, ticket_key_cb);
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
rv = ptls_openssl_encrypt_ticket(dst, src, ticket_key_cb);
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
rv = ptls_openssl_decrypt_ticket_evp(dst, src, ticket_key_cb);
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
rv = ptls_openssl_decrypt_ticket(dst, src, ticket_key_cb);
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dst->off < sizeof(ver)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&ver, dst->base + dst->off - sizeof(ver), sizeof(ver));
|
||||
|
||||
if (ngtcp2_conn_get_client_chosen_version(conn) != ntohl(ver)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dst->off -= sizeof(ver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptls_encrypt_ticket_t encrypt_ticket = {encrypt_ticket_cb};
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
ptls_key_exchange_algorithm_t *key_exchanges[] = {
|
||||
#if PTLS_OPENSSL_HAVE_X25519
|
||||
&ptls_openssl_x25519,
|
||||
#endif // PTLS_OPENSSL_X25519
|
||||
&ptls_openssl_secp256r1,
|
||||
&ptls_openssl_secp384r1,
|
||||
&ptls_openssl_secp521r1,
|
||||
#if PTLS_OPENSSL_HAVE_X25519MLKEM768
|
||||
&ptls_openssl_x25519mlkem768,
|
||||
#endif // PTLS_OPENSSL_HAVE_X25519MLKEM768
|
||||
nullptr,
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
ptls_cipher_suite_t *cipher_suites[] = {
|
||||
&ptls_openssl_aes128gcmsha256,
|
||||
&ptls_openssl_aes256gcmsha384,
|
||||
#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
|
||||
&ptls_openssl_chacha20poly1305sha256,
|
||||
#endif // PTLS_OPENSSL_CHACHA20POLY1305SHA256
|
||||
nullptr,
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TLSServerContext::TLSServerContext()
|
||||
: ctx_{
|
||||
.random_bytes = ptls_openssl_random_bytes,
|
||||
.get_time = &ptls_get_time,
|
||||
.key_exchanges = key_exchanges,
|
||||
.cipher_suites = cipher_suites,
|
||||
.ticket_lifetime = 86400,
|
||||
.require_dhe_on_psk = 1,
|
||||
.server_cipher_preference = 1,
|
||||
.encrypt_ticket = &encrypt_ticket,
|
||||
},
|
||||
sign_cert_{}
|
||||
{}
|
||||
|
||||
TLSServerContext::~TLSServerContext() {
|
||||
if (sign_cert_.key) {
|
||||
ptls_openssl_dispose_sign_certificate(&sign_cert_);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ctx_.certificates.count; ++i) {
|
||||
free(ctx_.certificates.list[i].base);
|
||||
}
|
||||
free(ctx_.certificates.list);
|
||||
}
|
||||
|
||||
ptls_context_t *TLSServerContext::get_native_handle() { return &ctx_; }
|
||||
|
||||
int TLSServerContext::init(const char *private_key_file, const char *cert_file,
|
||||
AppProtocol app_proto) {
|
||||
switch (app_proto) {
|
||||
case AppProtocol::H3:
|
||||
ctx_.on_client_hello = &on_client_hello_h3;
|
||||
|
||||
break;
|
||||
case AppProtocol::HQ:
|
||||
ctx_.on_client_hello = &on_client_hello_hq;
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
if (ngtcp2_crypto_picotls_configure_server_context(&ctx_) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_picotls_configure_server_context failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ptls_load_certificates(&ctx_, cert_file) != 0) {
|
||||
std::cerr << "ptls_load_certificates failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (load_private_key(private_key_file) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.verify_client) {
|
||||
ctx_.require_client_authentication = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TLSServerContext::load_private_key(const char *private_key_file) {
|
||||
auto fp = fopen(private_key_file, "rb");
|
||||
if (fp == nullptr) {
|
||||
std::cerr << "Could not open private key file " << private_key_file << ": "
|
||||
<< strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto fp_d = defer(fclose, fp);
|
||||
|
||||
auto pkey = PEM_read_PrivateKey(fp, nullptr, nullptr, nullptr);
|
||||
if (pkey == nullptr) {
|
||||
std::cerr << "Could not read private key file " << private_key_file
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto pkey_d = defer(EVP_PKEY_free, pkey);
|
||||
|
||||
if (ptls_openssl_init_sign_certificate(&sign_cert_, pkey) != 0) {
|
||||
std::cerr << "ptls_openssl_init_sign_certificate failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx_.sign_certificate = &sign_cert_.super;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TLSServerContext::enable_keylog() { ctx_.log_event = &log_event; }
|
||||
58
deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.h
vendored
Normal file
58
deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.h
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_CONTEXT_PICOTLS_H
|
||||
#define TLS_SERVER_CONTEXT_PICOTLS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <picotls.h>
|
||||
#include <picotls/openssl.h>
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
class TLSServerContext {
|
||||
public:
|
||||
TLSServerContext();
|
||||
~TLSServerContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file,
|
||||
AppProtocol app_proto);
|
||||
|
||||
ptls_context_t *get_native_handle();
|
||||
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
int load_private_key(const char *private_key_file);
|
||||
|
||||
ptls_context_t ctx_;
|
||||
ptls_openssl_sign_certificate_t sign_cert_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_PICOTLS_H)
|
||||
320
deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.cc
vendored
Normal file
320
deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.cc
vendored
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_server_context_quictls.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_quictls.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "server_base.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace {
|
||||
auto _ = []() {
|
||||
if (ngtcp2_crypto_quictls_init() != 0) {
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}();
|
||||
} // namespace
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerContext::TLSServerContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSServerContext::~TLSServerContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX *TLSServerContext::get_native_handle() const { return ssl_ctx_; }
|
||||
|
||||
namespace {
|
||||
int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
// This should be the negotiated version, but we have not set the
|
||||
// negotiated version when this callback is called.
|
||||
auto version = ngtcp2_conn_get_client_chosen_version(h->conn());
|
||||
|
||||
switch (version) {
|
||||
case NGTCP2_PROTO_VER_V1:
|
||||
case NGTCP2_PROTO_VER_V2:
|
||||
break;
|
||||
default:
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Unexpected quic protocol version: " << std::hex << "0x"
|
||||
<< version << std::dec << std::endl;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
|
||||
for (auto s = std::span{in, inlen}; s.size() >= H3_ALPN_V1.size();
|
||||
s = s.subspan(s[0] + 1)) {
|
||||
if (std::ranges::equal(H3_ALPN_V1, s.first(H3_ALPN_V1.size()))) {
|
||||
*out = &s[1];
|
||||
*outlen = s[0];
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Client did not present ALPN " << &H3_ALPN_V1[1] << std::endl;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
// This should be the negotiated version, but we have not set the
|
||||
// negotiated version when this callback is called.
|
||||
auto version = ngtcp2_conn_get_client_chosen_version(h->conn());
|
||||
|
||||
switch (version) {
|
||||
case NGTCP2_PROTO_VER_V1:
|
||||
case NGTCP2_PROTO_VER_V2:
|
||||
break;
|
||||
default:
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Unexpected quic protocol version: " << std::hex << "0x"
|
||||
<< version << std::dec << std::endl;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
|
||||
for (auto s = std::span{in, inlen}; s.size() >= HQ_ALPN_V1.size();
|
||||
s = s.subspan(s[0] + 1)) {
|
||||
if (std::ranges::equal(HQ_ALPN_V1, s.first(HQ_ALPN_V1.size()))) {
|
||||
*out = &s[1];
|
||||
*outlen = s[0];
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Client did not present ALPN " << &HQ_ALPN_V1[1] << std::endl;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
// We don't verify the client certificate. Just request it for the
|
||||
// testing purpose.
|
||||
return 1;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#ifndef LIBRESSL_VERSION_NUMBER
|
||||
namespace {
|
||||
int gen_ticket_cb(SSL *ssl, void *arg) {
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
auto ver = htonl(ngtcp2_conn_get_negotiated_version(h->conn()));
|
||||
|
||||
if (!SSL_SESSION_set1_ticket_appdata(SSL_get0_session(ssl), &ver,
|
||||
sizeof(ver))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
SSL_TICKET_RETURN decrypt_ticket_cb(SSL *ssl, SSL_SESSION *session,
|
||||
const unsigned char *keyname,
|
||||
size_t keynamelen, SSL_TICKET_STATUS status,
|
||||
void *arg) {
|
||||
switch (status) {
|
||||
case SSL_TICKET_EMPTY:
|
||||
case SSL_TICKET_NO_DECRYPT:
|
||||
return SSL_TICKET_RETURN_IGNORE_RENEW;
|
||||
}
|
||||
|
||||
uint8_t *pver;
|
||||
uint32_t ver;
|
||||
size_t verlen;
|
||||
|
||||
if (!SSL_SESSION_get0_ticket_appdata(
|
||||
session, reinterpret_cast<void **>(&pver), &verlen) ||
|
||||
verlen != sizeof(ver)) {
|
||||
switch (status) {
|
||||
case SSL_TICKET_SUCCESS:
|
||||
return SSL_TICKET_RETURN_IGNORE;
|
||||
case SSL_TICKET_SUCCESS_RENEW:
|
||||
default:
|
||||
return SSL_TICKET_RETURN_IGNORE_RENEW;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&ver, pver, sizeof(ver));
|
||||
|
||||
auto conn_ref = static_cast<ngtcp2_crypto_conn_ref *>(SSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
|
||||
if (ngtcp2_conn_get_client_chosen_version(h->conn()) != ntohl(ver)) {
|
||||
switch (status) {
|
||||
case SSL_TICKET_SUCCESS:
|
||||
return SSL_TICKET_RETURN_IGNORE;
|
||||
case SSL_TICKET_SUCCESS_RENEW:
|
||||
default:
|
||||
return SSL_TICKET_RETURN_IGNORE_RENEW;
|
||||
}
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case SSL_TICKET_SUCCESS:
|
||||
return SSL_TICKET_RETURN_USE;
|
||||
case SSL_TICKET_SUCCESS_RENEW:
|
||||
default:
|
||||
return SSL_TICKET_RETURN_USE_RENEW;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
#endif // !defined(LIBRESSL_VERSION_NUMBER)
|
||||
|
||||
int TLSServerContext::init(const char *private_key_file, const char *cert_file,
|
||||
AppProtocol app_proto) {
|
||||
constexpr static unsigned char sid_ctx[] = "ngtcp2 server";
|
||||
|
||||
ssl_ctx_ = SSL_CTX_new(TLS_server_method());
|
||||
if (!ssl_ctx_) {
|
||||
std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_quictls_configure_server_context(ssl_ctx_) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_quictls_configure_server_context failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_max_early_data(ssl_ctx_, UINT32_MAX);
|
||||
|
||||
constexpr auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
|
||||
SSL_OP_SINGLE_ECDH_USE |
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE
|
||||
#ifndef LIBRESSL_VERSION_NUMBER
|
||||
| SSL_OP_NO_ANTI_REPLAY
|
||||
#endif // !defined(LIBRESSL_VERSION_NUMBER)
|
||||
;
|
||||
|
||||
SSL_CTX_set_options(ssl_ctx_, ssl_opts);
|
||||
|
||||
if (SSL_CTX_set_ciphersuites(ssl_ctx_, config.ciphers) != 1) {
|
||||
std::cerr << "SSL_CTX_set_ciphersuites: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) {
|
||||
std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_mode(ssl_ctx_, SSL_MODE_RELEASE_BUFFERS);
|
||||
|
||||
switch (app_proto) {
|
||||
case AppProtocol::H3:
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx_, alpn_select_proto_h3_cb, nullptr);
|
||||
break;
|
||||
case AppProtocol::HQ:
|
||||
SSL_CTX_set_alpn_select_cb(ssl_ctx_, alpn_select_proto_hq_cb, nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
SSL_CTX_set_default_verify_paths(ssl_ctx_);
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
std::cerr << "SSL_CTX_use_PrivateKey_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) {
|
||||
std::cerr << "SSL_CTX_use_certificate_chain_file: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_check_private_key(ssl_ctx_) != 1) {
|
||||
std::cerr << "SSL_CTX_check_private_key: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_CTX_set_session_id_context(ssl_ctx_, sid_ctx, sizeof(sid_ctx) - 1);
|
||||
|
||||
if (config.verify_client) {
|
||||
SSL_CTX_set_verify(ssl_ctx_,
|
||||
SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE |
|
||||
SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
verify_cb);
|
||||
}
|
||||
|
||||
#ifndef LIBRESSL_VERSION_NUMBER
|
||||
SSL_CTX_set_session_ticket_cb(ssl_ctx_, gen_ticket_cb, decrypt_ticket_cb,
|
||||
nullptr);
|
||||
#endif // !defined(LIBRESSL_VERSION_NUMBER)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern std::ofstream keylog_file;
|
||||
|
||||
namespace {
|
||||
void keylog_callback(const SSL *ssl, const char *line) {
|
||||
keylog_file.write(line, static_cast<std::streamsize>(strlen(line)));
|
||||
keylog_file.put('\n');
|
||||
keylog_file.flush();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TLSServerContext::enable_keylog() {
|
||||
SSL_CTX_set_keylog_callback(ssl_ctx_, keylog_callback);
|
||||
}
|
||||
54
deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.h
vendored
Normal file
54
deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.h
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_CONTEXT_QUICTLS_H
|
||||
#define TLS_SERVER_CONTEXT_QUICTLS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
class TLSServerContext {
|
||||
public:
|
||||
TLSServerContext();
|
||||
~TLSServerContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file,
|
||||
AppProtocol app_proto);
|
||||
|
||||
SSL_CTX *get_native_handle() const;
|
||||
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_QUICTLS_H)
|
||||
248
deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.cc
vendored
Normal file
248
deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.cc
vendored
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_server_context_wolfssl.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
|
||||
|
||||
#include "server_base.h"
|
||||
#include "template.h"
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerContext::TLSServerContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSServerContext::~TLSServerContext() {
|
||||
if (ssl_ctx_) {
|
||||
wolfSSL_CTX_free(ssl_ctx_);
|
||||
}
|
||||
}
|
||||
|
||||
WOLFSSL_CTX *TLSServerContext::get_native_handle() const { return ssl_ctx_; }
|
||||
|
||||
namespace {
|
||||
int alpn_select_proto_h3_cb(WOLFSSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
auto conn_ref =
|
||||
static_cast<ngtcp2_crypto_conn_ref *>(wolfSSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
// This should be the negotiated version, but we have not set the
|
||||
// negotiated version when this callback is called.
|
||||
auto version = ngtcp2_conn_get_client_chosen_version(h->conn());
|
||||
|
||||
switch (version) {
|
||||
case NGTCP2_PROTO_VER_V1:
|
||||
case NGTCP2_PROTO_VER_V2:
|
||||
break;
|
||||
default:
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Unexpected quic protocol version: " << std::hex << "0x"
|
||||
<< version << std::dec << std::endl;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
|
||||
for (auto s = std::span{in, inlen}; s.size() >= H3_ALPN_V1.size();
|
||||
s = s.subspan(s[0] + 1)) {
|
||||
if (std::ranges::equal(H3_ALPN_V1, s.first(H3_ALPN_V1.size()))) {
|
||||
*out = &s[1];
|
||||
*outlen = s[0];
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Client did not present ALPN " << &H3_ALPN_V1[1] << std::endl;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int alpn_select_proto_hq_cb(WOLFSSL *ssl, const unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg) {
|
||||
auto conn_ref =
|
||||
static_cast<ngtcp2_crypto_conn_ref *>(wolfSSL_get_app_data(ssl));
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
// This should be the negotiated version, but we have not set the
|
||||
// negotiated version when this callback is called.
|
||||
auto version = ngtcp2_conn_get_client_chosen_version(h->conn());
|
||||
|
||||
switch (version) {
|
||||
case NGTCP2_PROTO_VER_V1:
|
||||
case NGTCP2_PROTO_VER_V2:
|
||||
break;
|
||||
default:
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Unexpected quic protocol version: " << std::hex << "0x"
|
||||
<< version << std::dec << std::endl;
|
||||
}
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
|
||||
for (auto s = std::span{in, inlen}; s.size() >= HQ_ALPN_V1.size();
|
||||
s = s.subspan(s[0] + 1)) {
|
||||
if (std::ranges::equal(HQ_ALPN_V1, s.first(HQ_ALPN_V1.size()))) {
|
||||
*out = &s[1];
|
||||
*outlen = s[0];
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Client did not present ALPN " << &HQ_ALPN_V1[1] << std::endl;
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
// We don't verify the client certificate. Just request it for the
|
||||
// testing purpose.
|
||||
return 1;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int TLSServerContext::init(const char *private_key_file, const char *cert_file,
|
||||
AppProtocol app_proto) {
|
||||
constexpr static unsigned char sid_ctx[] = "ngtcp2 server";
|
||||
|
||||
#ifdef DEBUG_WOLFSSL
|
||||
if (!config.quiet) {
|
||||
/*wolfSSL_Debugging_ON();*/
|
||||
}
|
||||
#endif // defined(DEBUG_WOLFSSL)
|
||||
|
||||
ssl_ctx_ = wolfSSL_CTX_new(wolfTLSv1_3_server_method());
|
||||
if (!ssl_ctx_) {
|
||||
std::cerr << "wolfSSL_CTX_new: "
|
||||
<< wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_wolfssl_configure_server_context(ssl_ctx_) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_wolfssl_configure_server_context failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
wolfSSL_CTX_set_max_early_data(ssl_ctx_, UINT32_MAX);
|
||||
#endif // defined(WOLFSSL_EARLY_DATA)
|
||||
|
||||
constexpr auto ssl_opts =
|
||||
(WOLFSSL_OP_ALL & ~WOLFSSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
|
||||
WOLFSSL_OP_SINGLE_ECDH_USE | WOLFSSL_OP_CIPHER_SERVER_PREFERENCE;
|
||||
|
||||
wolfSSL_CTX_set_options(ssl_ctx_, ssl_opts);
|
||||
|
||||
if (wolfSSL_CTX_set_cipher_list(ssl_ctx_, config.ciphers) != 1) {
|
||||
std::cerr << "wolfSSL_CTX_set_cipher_list: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wolfSSL_CTX_set1_groups_list(ssl_ctx_,
|
||||
const_cast<char *>(config.groups)) != 1) {
|
||||
std::cerr << "wolfSSL_CTX_set1_groups_list(" << config.groups << ") failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
wolfSSL_CTX_set_mode(ssl_ctx_, SSL_MODE_RELEASE_BUFFERS);
|
||||
|
||||
switch (app_proto) {
|
||||
case AppProtocol::H3:
|
||||
wolfSSL_CTX_set_alpn_select_cb(ssl_ctx_, alpn_select_proto_h3_cb, nullptr);
|
||||
break;
|
||||
case AppProtocol::HQ:
|
||||
wolfSSL_CTX_set_alpn_select_cb(ssl_ctx_, alpn_select_proto_hq_cb, nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
wolfSSL_CTX_set_default_verify_paths(ssl_ctx_);
|
||||
|
||||
if (wolfSSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
std::cerr << "wolfSSL_CTX_use_PrivateKey_file: "
|
||||
<< wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wolfSSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) {
|
||||
std::cerr << "wolfSSL_CTX_use_certificate_chain_file: "
|
||||
<< wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wolfSSL_CTX_check_private_key(ssl_ctx_) != 1) {
|
||||
std::cerr << "wolfSSL_CTX_check_private_key: "
|
||||
<< wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
wolfSSL_CTX_set_session_id_context(ssl_ctx_, sid_ctx, sizeof(sid_ctx) - 1);
|
||||
|
||||
if (config.verify_client) {
|
||||
wolfSSL_CTX_set_verify(ssl_ctx_,
|
||||
WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_CLIENT_ONCE |
|
||||
WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
verify_cb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern std::ofstream keylog_file;
|
||||
|
||||
#ifdef HAVE_SECRET_CALLBACK
|
||||
namespace {
|
||||
void keylog_callback(const WOLFSSL *ssl, const char *line) {
|
||||
keylog_file.write(line, static_cast<std::streamsize>(strlen(line)));
|
||||
keylog_file.put('\n');
|
||||
keylog_file.flush();
|
||||
}
|
||||
} // namespace
|
||||
#endif // defined(HAVE_SECRET_CALLBACK)
|
||||
|
||||
void TLSServerContext::enable_keylog() {
|
||||
#ifdef HAVE_SECRET_CALLBACK
|
||||
wolfSSL_CTX_set_keylog_callback(ssl_ctx_, keylog_callback);
|
||||
#endif // defined(HAVE_SECRET_CALLBACK)
|
||||
}
|
||||
55
deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.h
vendored
Normal file
55
deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.h
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_CONTEXT_WOLFSSL_H
|
||||
#define TLS_SERVER_CONTEXT_WOLFSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
class TLSServerContext {
|
||||
public:
|
||||
TLSServerContext();
|
||||
~TLSServerContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file,
|
||||
AppProtocol app_proto);
|
||||
|
||||
WOLFSSL_CTX *get_native_handle() const;
|
||||
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
WOLFSSL_CTX *ssl_ctx_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_WOLFSSL_H)
|
||||
56
deps/ngtcp2/ngtcp2/examples/tls_server_session.h
vendored
Normal file
56
deps/ngtcp2/ngtcp2/examples/tls_server_session.h
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_SESSION_H
|
||||
#define TLS_SERVER_SESSION_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#ifdef WITH_EXAMPLE_QUICTLS
|
||||
# include "tls_server_session_quictls.h"
|
||||
#endif // defined(WITH_EXAMPLE_QUICTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_GNUTLS
|
||||
# include "tls_server_session_gnutls.h"
|
||||
#endif // defined(WITH_EXAMPLE_GNUTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_BORINGSSL
|
||||
# include "tls_server_session_boringssl.h"
|
||||
#endif // defined(WITH_EXAMPLE_BORINGSSL)
|
||||
|
||||
#ifdef WITH_EXAMPLE_PICOTLS
|
||||
# include "tls_server_session_picotls.h"
|
||||
#endif // defined(WITH_EXAMPLE_PICOTLS)
|
||||
|
||||
#ifdef WITH_EXAMPLE_WOLFSSL
|
||||
# include "tls_server_session_wolfssl.h"
|
||||
#endif // defined(WITH_EXAMPLE_WOLFSSL)
|
||||
|
||||
#ifdef WITH_EXAMPLE_OSSL
|
||||
# include "tls_server_session_ossl.h"
|
||||
#endif // defined(WITH_EXAMPLE_OSSL)
|
||||
|
||||
#endif // !defined(TLS_SERVER_SESSION_H)
|
||||
84
deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.cc
vendored
Normal file
84
deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.cc
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2021 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_server_session_boringssl.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
#include "tls_server_context_boringssl.h"
|
||||
#include "server_base.h"
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerSession::TLSServerSession() {}
|
||||
|
||||
TLSServerSession::~TLSServerSession() {}
|
||||
|
||||
int TLSServerSession::init(const TLSServerContext &tls_ctx,
|
||||
HandlerBase *handler) {
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
ssl_ = SSL_new(ssl_ctx);
|
||||
if (!ssl_) {
|
||||
std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_set_app_data(ssl_, handler->conn_ref());
|
||||
SSL_set_accept_state(ssl_);
|
||||
SSL_set_early_data_enabled(ssl_, 1);
|
||||
|
||||
std::array<uint8_t, 128> quic_early_data_ctx;
|
||||
ngtcp2_transport_params params;
|
||||
ngtcp2_transport_params_default(¶ms);
|
||||
params.initial_max_streams_bidi = config.max_streams_bidi;
|
||||
params.initial_max_streams_uni = config.max_streams_uni;
|
||||
params.initial_max_stream_data_bidi_local = config.max_stream_data_bidi_local;
|
||||
params.initial_max_stream_data_bidi_remote =
|
||||
config.max_stream_data_bidi_remote;
|
||||
params.initial_max_stream_data_uni = config.max_stream_data_uni;
|
||||
params.initial_max_data = config.max_data;
|
||||
|
||||
auto quic_early_data_ctxlen = ngtcp2_transport_params_encode(
|
||||
quic_early_data_ctx.data(), quic_early_data_ctx.size(), ¶ms);
|
||||
if (quic_early_data_ctxlen < 0) {
|
||||
std::cerr << "ngtcp2_transport_params_encode: "
|
||||
<< ngtcp2_strerror(static_cast<int>(quic_early_data_ctxlen))
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_set_quic_early_data_context(ssl_, quic_early_data_ctx.data(),
|
||||
as_unsigned(quic_early_data_ctxlen)) !=
|
||||
1) {
|
||||
std::cerr << "SSL_set_quic_early_data_context failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
47
deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.h
vendored
Normal file
47
deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.h
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2021 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_SESSION_BORINGSSL_H
|
||||
#define TLS_SERVER_SESSION_BORINGSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "tls_session_base_quictls.h"
|
||||
|
||||
class TLSServerContext;
|
||||
class HandlerBase;
|
||||
|
||||
class TLSServerSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSServerSession();
|
||||
~TLSServerSession();
|
||||
|
||||
int init(const TLSServerContext &tls_ctx, HandlerBase *handler);
|
||||
// ticket is sent automatically.
|
||||
int send_session_ticket() { return 0; }
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_SESSION_BORINGSSL_H)
|
||||
62
deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.cc
vendored
Normal file
62
deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.cc
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_server_session_ossl.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "tls_server_context_ossl.h"
|
||||
#include "server_base.h"
|
||||
|
||||
TLSServerSession::TLSServerSession() {}
|
||||
|
||||
TLSServerSession::~TLSServerSession() {}
|
||||
|
||||
int TLSServerSession::init(const TLSServerContext &tls_ctx,
|
||||
HandlerBase *handler) {
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
auto ssl = SSL_new(ssl_ctx);
|
||||
if (!ssl) {
|
||||
std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_ossl_ctx_set_ssl(ossl_ctx_, ssl);
|
||||
|
||||
if (ngtcp2_crypto_ossl_configure_server_session(ssl) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_ossl_configure_server_session failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_set_app_data(ssl, handler->conn_ref());
|
||||
SSL_set_accept_state(ssl);
|
||||
SSL_set_quic_tls_early_data_enabled(ssl, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
47
deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.h
vendored
Normal file
47
deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.h
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_SESSION_OSSL_H
|
||||
#define TLS_SERVER_SESSION_OSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "tls_session_base_ossl.h"
|
||||
|
||||
class TLSServerContext;
|
||||
class HandlerBase;
|
||||
|
||||
class TLSServerSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSServerSession();
|
||||
~TLSServerSession();
|
||||
|
||||
int init(const TLSServerContext &tls_ctx, HandlerBase *handler);
|
||||
// ticket is sent automatically.
|
||||
int send_session_ticket() { return 0; }
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_SESSION_OSSL_H)
|
||||
70
deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.cc
vendored
Normal file
70
deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.cc
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_server_session_picotls.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_picotls.h>
|
||||
|
||||
#include "tls_server_context_picotls.h"
|
||||
#include "server_base.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerSession::TLSServerSession() {}
|
||||
|
||||
TLSServerSession::~TLSServerSession() {}
|
||||
|
||||
int TLSServerSession::init(TLSServerContext &tls_ctx, HandlerBase *handler) {
|
||||
cptls_.ptls = ptls_server_new(tls_ctx.get_native_handle());
|
||||
if (!cptls_.ptls) {
|
||||
std::cerr << "ptls_server_new failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ptls_get_data_ptr(cptls_.ptls) = handler->conn_ref();
|
||||
|
||||
cptls_.handshake_properties.additional_extensions =
|
||||
new ptls_raw_extension_t[2]{
|
||||
{
|
||||
.type = UINT16_MAX,
|
||||
},
|
||||
{
|
||||
.type = UINT16_MAX,
|
||||
},
|
||||
};
|
||||
|
||||
if (ngtcp2_crypto_picotls_configure_server_session(&cptls_) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_picotls_configure_server_session failed"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
47
deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.h
vendored
Normal file
47
deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.h
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_SESSION_PICOTLS_H
|
||||
#define TLS_SERVER_SESSION_PICOTLS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "tls_session_base_picotls.h"
|
||||
|
||||
class TLSServerContext;
|
||||
class HandlerBase;
|
||||
|
||||
class TLSServerSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSServerSession();
|
||||
~TLSServerSession();
|
||||
|
||||
int init(TLSServerContext &tls_ctx, HandlerBase *handler);
|
||||
// ticket is sent automatically.
|
||||
int send_session_ticket() { return 0; }
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_SESSION_PICOTLS_H)
|
||||
56
deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.cc
vendored
Normal file
56
deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.cc
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_server_session_quictls.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "tls_server_context_quictls.h"
|
||||
#include "server_base.h"
|
||||
|
||||
TLSServerSession::TLSServerSession() {}
|
||||
|
||||
TLSServerSession::~TLSServerSession() {}
|
||||
|
||||
int TLSServerSession::init(const TLSServerContext &tls_ctx,
|
||||
HandlerBase *handler) {
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
ssl_ = SSL_new(ssl_ctx);
|
||||
if (!ssl_) {
|
||||
std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSL_set_app_data(ssl_, handler->conn_ref());
|
||||
SSL_set_accept_state(ssl_);
|
||||
#ifndef LIBRESSL_VERSION_NUMBER
|
||||
SSL_set_quic_early_data_enabled(ssl_, 1);
|
||||
#endif // !defined(LIBRESSL_VERSION_NUMBER)
|
||||
|
||||
return 0;
|
||||
}
|
||||
47
deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.h
vendored
Normal file
47
deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.h
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_SESSION_QUICTLS_H
|
||||
#define TLS_SERVER_SESSION_QUICTLS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "tls_session_base_quictls.h"
|
||||
|
||||
class TLSServerContext;
|
||||
class HandlerBase;
|
||||
|
||||
class TLSServerSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSServerSession();
|
||||
~TLSServerSession();
|
||||
|
||||
int init(const TLSServerContext &tls_ctx, HandlerBase *handler);
|
||||
// ticket is sent automatically.
|
||||
int send_session_ticket() { return 0; }
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_SESSION_QUICTLS_H)
|
||||
57
deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.cc
vendored
Normal file
57
deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.cc
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_server_session_wolfssl.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "tls_server_context_wolfssl.h"
|
||||
#include "server_base.h"
|
||||
|
||||
TLSServerSession::TLSServerSession() {}
|
||||
|
||||
TLSServerSession::~TLSServerSession() {}
|
||||
|
||||
int TLSServerSession::init(const TLSServerContext &tls_ctx,
|
||||
HandlerBase *handler) {
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
ssl_ = wolfSSL_new(ssl_ctx);
|
||||
if (!ssl_) {
|
||||
std::cerr << "wolfSSL_new: "
|
||||
<< wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
wolfSSL_set_app_data(ssl_, handler->conn_ref());
|
||||
wolfSSL_set_accept_state(ssl_);
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
wolfSSL_set_quic_early_data_enabled(ssl_, 1);
|
||||
#endif // defined(WOLFSSL_EARLY_DATA)
|
||||
// Just use QUIC v1
|
||||
wolfSSL_set_quic_transport_version(ssl_, 0x39);
|
||||
|
||||
return 0;
|
||||
}
|
||||
47
deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.h
vendored
Normal file
47
deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.h
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SERVER_SESSION_WOLFSSL_H
|
||||
#define TLS_SERVER_SESSION_WOLFSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "tls_session_base_wolfssl.h"
|
||||
|
||||
class TLSServerContext;
|
||||
class HandlerBase;
|
||||
|
||||
class TLSServerSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSServerSession();
|
||||
~TLSServerSession();
|
||||
|
||||
int init(const TLSServerContext &tls_ctx, HandlerBase *handler);
|
||||
// ticket is sent automatically.
|
||||
int send_session_ticket() { return 0; }
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_SESSION_WOLFSSL_H)
|
||||
77
deps/ngtcp2/ngtcp2/examples/tls_session_base_ossl.cc
vendored
Normal file
77
deps/ngtcp2/ngtcp2/examples/tls_session_base_ossl.cc
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_session_base_ossl.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "util.h"
|
||||
#include "template.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
using namespace std::literals;
|
||||
|
||||
TLSSessionBase::TLSSessionBase() {
|
||||
ngtcp2_crypto_ossl_ctx_new(&ossl_ctx_, NULL);
|
||||
}
|
||||
|
||||
TLSSessionBase::~TLSSessionBase() {
|
||||
auto ssl = ngtcp2_crypto_ossl_ctx_get_ssl(ossl_ctx_);
|
||||
|
||||
if (ssl) {
|
||||
SSL_set_app_data(ssl, NULL);
|
||||
SSL_free(ssl);
|
||||
}
|
||||
|
||||
ngtcp2_crypto_ossl_ctx_del(ossl_ctx_);
|
||||
}
|
||||
|
||||
ngtcp2_crypto_ossl_ctx *TLSSessionBase::get_native_handle() const {
|
||||
return ossl_ctx_;
|
||||
}
|
||||
|
||||
std::string TLSSessionBase::get_cipher_name() const {
|
||||
return SSL_get_cipher_name(ngtcp2_crypto_ossl_ctx_get_ssl(ossl_ctx_));
|
||||
}
|
||||
|
||||
std::string_view TLSSessionBase::get_negotiated_group() const {
|
||||
auto ssl = ngtcp2_crypto_ossl_ctx_get_ssl(ossl_ctx_);
|
||||
auto name = SSL_get0_group_name(ssl);
|
||||
|
||||
if (!name) {
|
||||
return ""sv;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string TLSSessionBase::get_selected_alpn() const {
|
||||
auto ssl = ngtcp2_crypto_ossl_ctx_get_ssl(ossl_ctx_);
|
||||
const unsigned char *alpn = nullptr;
|
||||
unsigned int alpnlen;
|
||||
|
||||
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||
|
||||
return std::string{alpn, alpn + alpnlen};
|
||||
}
|
||||
56
deps/ngtcp2/ngtcp2/examples/tls_session_base_ossl.h
vendored
Normal file
56
deps/ngtcp2/ngtcp2/examples/tls_session_base_ossl.h
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SESSION_BASE_OSSL_H
|
||||
#define TLS_SESSION_BASE_OSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_ossl.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
class TLSSessionBase {
|
||||
public:
|
||||
TLSSessionBase();
|
||||
~TLSSessionBase();
|
||||
|
||||
ngtcp2_crypto_ossl_ctx *get_native_handle() const;
|
||||
|
||||
std::string get_cipher_name() const;
|
||||
std::string_view get_negotiated_group() const;
|
||||
std::string get_selected_alpn() const;
|
||||
// Keylog is enabled per SSL_CTX.
|
||||
void enable_keylog() {}
|
||||
|
||||
protected:
|
||||
ngtcp2_crypto_ossl_ctx *ossl_ctx_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SESSION_BASE_OSSL_H)
|
||||
56
deps/ngtcp2/ngtcp2/examples/tls_session_base_picotls.cc
vendored
Normal file
56
deps/ngtcp2/ngtcp2/examples/tls_session_base_picotls.cc
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_session_base_picotls.h"
|
||||
|
||||
TLSSessionBase::TLSSessionBase() { ngtcp2_crypto_picotls_ctx_init(&cptls_); }
|
||||
|
||||
TLSSessionBase::~TLSSessionBase() {
|
||||
ngtcp2_crypto_picotls_deconfigure_session(&cptls_);
|
||||
|
||||
delete[] cptls_.handshake_properties.additional_extensions;
|
||||
|
||||
if (cptls_.ptls) {
|
||||
ptls_free(cptls_.ptls);
|
||||
}
|
||||
}
|
||||
|
||||
ngtcp2_crypto_picotls_ctx *TLSSessionBase::get_native_handle() {
|
||||
return &cptls_;
|
||||
}
|
||||
|
||||
std::string TLSSessionBase::get_cipher_name() const {
|
||||
auto cs = ptls_get_cipher(cptls_.ptls);
|
||||
return cs->aead->name;
|
||||
}
|
||||
|
||||
std::string TLSSessionBase::get_selected_alpn() const {
|
||||
auto alpn = ptls_get_negotiated_protocol(cptls_.ptls);
|
||||
|
||||
if (!alpn) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return alpn;
|
||||
}
|
||||
60
deps/ngtcp2/ngtcp2/examples/tls_session_base_picotls.h
vendored
Normal file
60
deps/ngtcp2/ngtcp2/examples/tls_session_base_picotls.h
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2022 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SESSION_BASE_PICOTLS_H
|
||||
#define TLS_SESSION_BASE_PICOTLS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto_picotls.h>
|
||||
|
||||
#include <picotls.h>
|
||||
|
||||
class TLSSessionBase {
|
||||
public:
|
||||
TLSSessionBase();
|
||||
~TLSSessionBase();
|
||||
|
||||
ngtcp2_crypto_picotls_ctx *get_native_handle();
|
||||
|
||||
std::string get_cipher_name() const;
|
||||
std::string_view get_negotiated_group() const {
|
||||
using namespace std::literals;
|
||||
|
||||
return ""sv;
|
||||
}
|
||||
std::string get_selected_alpn() const;
|
||||
// TODO make keylog work with picotls
|
||||
void enable_keylog() {}
|
||||
|
||||
protected:
|
||||
ngtcp2_crypto_picotls_ctx cptls_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SESSION_BASE_PICOTLS_H)
|
||||
102
deps/ngtcp2/ngtcp2/examples/tls_session_base_quictls.cc
vendored
Normal file
102
deps/ngtcp2/ngtcp2/examples/tls_session_base_quictls.cc
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_session_base_quictls.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "util.h"
|
||||
#include "template.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
using namespace std::literals;
|
||||
|
||||
TLSSessionBase::TLSSessionBase() : ssl_{nullptr} {}
|
||||
|
||||
TLSSessionBase::~TLSSessionBase() {
|
||||
if (ssl_) {
|
||||
SSL_free(ssl_);
|
||||
}
|
||||
}
|
||||
|
||||
SSL *TLSSessionBase::get_native_handle() const { return ssl_; }
|
||||
|
||||
std::string TLSSessionBase::get_cipher_name() const {
|
||||
return SSL_get_cipher_name(ssl_);
|
||||
}
|
||||
|
||||
std::string_view TLSSessionBase::get_negotiated_group() const {
|
||||
#ifdef WITH_EXAMPLE_BORINGSSL
|
||||
return SSL_get_group_name(SSL_get_group_id(ssl_));
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
auto name =
|
||||
SSL_group_to_name(ssl_, static_cast<int>(SSL_get_negotiated_group(ssl_)));
|
||||
if (!name) {
|
||||
return ""sv;
|
||||
}
|
||||
|
||||
return name;
|
||||
#elif defined(LIBRESSL_VERSION_NUMBER)
|
||||
return ""sv;
|
||||
#else // !(defined(WITH_EXAMPLE_BORINGSSL) ||
|
||||
// OPENSSL_VERSION_NUMBER >= 0x30000000L ||
|
||||
// defined(LIBRESSL_VERSION_NUMBER))
|
||||
EVP_PKEY *key;
|
||||
|
||||
if (!SSL_get_tmp_key(ssl_, &key)) {
|
||||
return ""sv;
|
||||
}
|
||||
|
||||
auto key_del = defer(EVP_PKEY_free, key);
|
||||
|
||||
auto nid = EVP_PKEY_id(key);
|
||||
if (nid == EVP_PKEY_EC) {
|
||||
auto ec = EVP_PKEY_get1_EC_KEY(key);
|
||||
auto ec_del = defer(EC_KEY_free, ec);
|
||||
|
||||
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
|
||||
}
|
||||
|
||||
auto name = EC_curve_nid2nist(nid);
|
||||
if (!name) {
|
||||
name = OBJ_nid2sn(nid);
|
||||
if (!name) {
|
||||
return ""sv;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
#endif // !(defined(WITH_EXAMPLE_BORINGSSL) ||
|
||||
// OPENSSL_VERSION_NUMBER >= 0x30000000L ||
|
||||
// defined(LIBRESSL_VERSION_NUMBER))
|
||||
}
|
||||
|
||||
std::string TLSSessionBase::get_selected_alpn() const {
|
||||
const unsigned char *alpn = nullptr;
|
||||
unsigned int alpnlen;
|
||||
|
||||
SSL_get0_alpn_selected(ssl_, &alpn, &alpnlen);
|
||||
|
||||
return std::string{alpn, alpn + alpnlen};
|
||||
}
|
||||
54
deps/ngtcp2/ngtcp2/examples/tls_session_base_quictls.h
vendored
Normal file
54
deps/ngtcp2/ngtcp2/examples/tls_session_base_quictls.h
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SESSION_BASE_QUICTLS_H
|
||||
#define TLS_SESSION_BASE_QUICTLS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
class TLSSessionBase {
|
||||
public:
|
||||
TLSSessionBase();
|
||||
~TLSSessionBase();
|
||||
|
||||
SSL *get_native_handle() const;
|
||||
|
||||
std::string get_cipher_name() const;
|
||||
std::string_view get_negotiated_group() const;
|
||||
std::string get_selected_alpn() const;
|
||||
// Keylog is enabled per SSL_CTX.
|
||||
void enable_keylog() {}
|
||||
|
||||
protected:
|
||||
SSL *ssl_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SESSION_BASE_QUICTLS_H)
|
||||
54
deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.cc
vendored
Normal file
54
deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.cc
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_session_base_wolfssl.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
TLSSessionBase::TLSSessionBase() : ssl_{nullptr} {}
|
||||
|
||||
TLSSessionBase::~TLSSessionBase() {
|
||||
if (ssl_) {
|
||||
wolfSSL_free(ssl_);
|
||||
}
|
||||
}
|
||||
|
||||
WOLFSSL *TLSSessionBase::get_native_handle() const { return ssl_; }
|
||||
|
||||
std::string TLSSessionBase::get_cipher_name() const {
|
||||
return wolfSSL_get_cipher_name(ssl_);
|
||||
}
|
||||
|
||||
std::string TLSSessionBase::get_selected_alpn() const {
|
||||
char *alpn = nullptr;
|
||||
unsigned short alpnlen;
|
||||
|
||||
wolfSSL_ALPN_GetProtocol(ssl_, &alpn, &alpnlen);
|
||||
|
||||
return std::string{alpn, alpn + alpnlen};
|
||||
}
|
||||
60
deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.h
vendored
Normal file
60
deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.h
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SESSION_BASE_WOLFSSL_H
|
||||
#define TLS_SESSION_BASE_WOLFSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/quic.h>
|
||||
|
||||
class TLSSessionBase {
|
||||
public:
|
||||
TLSSessionBase();
|
||||
~TLSSessionBase();
|
||||
|
||||
WOLFSSL *get_native_handle() const;
|
||||
|
||||
std::string get_cipher_name() const;
|
||||
std::string_view get_negotiated_group() const {
|
||||
using namespace std::literals;
|
||||
|
||||
return ""sv;
|
||||
}
|
||||
std::string get_selected_alpn() const;
|
||||
// Keylog is enabled per SSL_CTX.
|
||||
void enable_keylog() {}
|
||||
|
||||
protected:
|
||||
WOLFSSL *ssl_;
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SESSION_BASE_WOLFSSL_H)
|
||||
89
deps/ngtcp2/ngtcp2/examples/tls_shared_boringssl.cc
vendored
Normal file
89
deps/ngtcp2/ngtcp2/examples/tls_shared_boringssl.cc
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2024 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_shared_boringssl.h"
|
||||
|
||||
#ifdef HAVE_LIBBROTLI
|
||||
# include <brotli/encode.h>
|
||||
# include <brotli/decode.h>
|
||||
#endif // defined(HAVE_LIBBROTLI)
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
namespace tls {
|
||||
|
||||
#ifdef HAVE_LIBBROTLI
|
||||
int cert_compress(SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) {
|
||||
uint8_t *dest;
|
||||
|
||||
auto compressed_size = BrotliEncoderMaxCompressedSize(in_len);
|
||||
if (compressed_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!CBB_reserve(out, &dest, compressed_size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (BrotliEncoderCompress(BROTLI_MAX_QUALITY, BROTLI_DEFAULT_WINDOW,
|
||||
BROTLI_MODE_GENERIC, in_len, in, &compressed_size,
|
||||
dest) != BROTLI_TRUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!CBB_did_write(out, compressed_size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cert_decompress(SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len,
|
||||
const uint8_t *in, size_t in_len) {
|
||||
uint8_t *dest;
|
||||
auto buf = CRYPTO_BUFFER_alloc(&dest, uncompressed_len);
|
||||
auto len = uncompressed_len;
|
||||
|
||||
if (BrotliDecoderDecompress(in_len, in, &len, dest) !=
|
||||
BROTLI_DECODER_RESULT_SUCCESS) {
|
||||
CRYPTO_BUFFER_free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uncompressed_len != len) {
|
||||
CRYPTO_BUFFER_free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out = buf;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif // defined(HAVE_LIBBROTLI)
|
||||
|
||||
} // namespace tls
|
||||
|
||||
} // namespace ngtcp2
|
||||
51
deps/ngtcp2/ngtcp2/examples/tls_shared_boringssl.h
vendored
Normal file
51
deps/ngtcp2/ngtcp2/examples/tls_shared_boringssl.h
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2024 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 TLS_SHARED_BORINGSSL_H
|
||||
#define TLS_SHARED_BORINGSSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
namespace tls {
|
||||
|
||||
constexpr uint16_t CERTIFICATE_COMPRESSION_ALGO_BROTLI = 2;
|
||||
|
||||
#ifdef HAVE_LIBBROTLI
|
||||
int cert_compress(SSL *ssl, CBB *out, const uint8_t *in, size_t in_len);
|
||||
|
||||
int cert_decompress(SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len,
|
||||
const uint8_t *in, size_t in_len);
|
||||
#endif // defined(HAVE_LIBBROTLI)
|
||||
|
||||
} // namespace tls
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
#endif // !defined(TLS_SHARED_BORINGSSL_H)
|
||||
59
deps/ngtcp2/ngtcp2/examples/tls_shared_picotls.cc
vendored
Normal file
59
deps/ngtcp2/ngtcp2/examples/tls_shared_picotls.cc
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2023 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* 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 "tls_shared_picotls.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <fstream>
|
||||
|
||||
extern std::ofstream keylog_file;
|
||||
|
||||
namespace {
|
||||
void log_event_cb(ptls_log_event_t *self, ptls_t *ptls, const char *type,
|
||||
const char *fmt, ...) {
|
||||
char buf[128];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
auto len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len < 0 || static_cast<size_t>(len) >= sizeof(buf)) {
|
||||
return;
|
||||
}
|
||||
|
||||
char randhex[PTLS_HELLO_RANDOM_SIZE * 2 + 1];
|
||||
|
||||
ptls_hexdump(randhex, ptls_get_client_random(ptls).base,
|
||||
PTLS_HELLO_RANDOM_SIZE);
|
||||
|
||||
keylog_file << type << ' ' << randhex << ' ';
|
||||
keylog_file.write(buf, len);
|
||||
keylog_file << '\n';
|
||||
keylog_file.flush();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ptls_log_event_t log_event = {log_event_cb};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user