Follow ngtcp2 API changes and use libngtcp2_crypto_openssl

This commit is contained in:
Tatsuhiro Tsujikawa 2019-08-25 10:20:10 +09:00
parent 7aa4bff97b
commit 3dbe3b3e7f
8 changed files with 125 additions and 608 deletions

View File

@ -461,6 +461,15 @@ if test "x${have_libngtcp2}" = "xno"; then
AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS) AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS)
fi fi
# ngtcp2_crypto_openssl (for src)
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OPENSSL],
[libngtcp2_crypto_openssl >= 0.0.0],
[have_libngtcp2_crypto_openssl=yes],
[have_libngtcp2_crypto_openssl=no])
if test "x${have_libngtcp2_crypto_openssl}" = "xno"; then
AC_MSG_NOTICE($LIBNGTCP2_CRYPTO_OPENSSL_PKG_ERRORS)
fi
# nghttp3 (for src) # nghttp3 (for src)
PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.0.0], [have_libnghttp3=yes], PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.0.0], [have_libnghttp3=yes],
[have_libnghttp3=no]) [have_libnghttp3=no])
@ -1026,6 +1035,7 @@ AC_MSG_NOTICE([summary of build options:
Libev: ${have_libev} (CFLAGS='${LIBEV_CFLAGS}' LIBS='${LIBEV_LIBS}') Libev: ${have_libev} (CFLAGS='${LIBEV_CFLAGS}' LIBS='${LIBEV_LIBS}')
Libc-ares: ${have_libcares} (CFLAGS='${LIBCARES_CFLAGS}' LIBS='${LIBCARES_LIBS}') Libc-ares: ${have_libcares} (CFLAGS='${LIBCARES_CFLAGS}' LIBS='${LIBCARES_LIBS}')
libngtcp2: ${have_libngtcp2} (CFLAGS='${LIBNGTCP2_CFLAGS}' LIBS='${LIBNGTCP2_LIBS}') libngtcp2: ${have_libngtcp2} (CFLAGS='${LIBNGTCP2_CFLAGS}' LIBS='${LIBNGTCP2_LIBS}')
libngtcp2_crypto_openssl: ${have_libngtcp2_crypto_openssl} (CFLAGS='${LIBNGTCP2_CRYPTO_OPENSSL_CFLAGS}' LIBS='${LIBNGTCP2_CRYPTO_OPENSSL_LIBS}')
libnghttp3: ${have_libnghttp3} (CFLAGS='${LIBNGHTTP3_CFLAGS}' LIBS='${LIBNGHTTP3_LIBS}') libnghttp3: ${have_libnghttp3} (CFLAGS='${LIBNGHTTP3_CFLAGS}' LIBS='${LIBNGHTTP3_LIBS}')
Libevent(SSL): ${have_libevent_openssl} (CFLAGS='${LIBEVENT_OPENSSL_CFLAGS}' LIBS='${LIBEVENT_OPENSSL_LIBS}') Libevent(SSL): ${have_libevent_openssl} (CFLAGS='${LIBEVENT_OPENSSL_CFLAGS}' LIBS='${LIBEVENT_OPENSSL_LIBS}')
Jansson: ${have_jansson} (CFLAGS='${JANSSON_CFLAGS}' LIBS='${JANSSON_LIBS}') Jansson: ${have_jansson} (CFLAGS='${JANSSON_CFLAGS}' LIBS='${JANSSON_LIBS}')

View File

@ -47,6 +47,7 @@ AM_CPPFLAGS = \
@OPENSSL_CFLAGS@ \ @OPENSSL_CFLAGS@ \
@LIBCARES_CFLAGS@ \ @LIBCARES_CFLAGS@ \
@LIBNGHTTP3_CFLAGS@ \ @LIBNGHTTP3_CFLAGS@ \
@LIBNGTCP2_CRYPTO_OPENSSL_CFLAGS@ \
@LIBNGTCP2_CFLAGS@ \ @LIBNGTCP2_CFLAGS@ \
@JANSSON_CFLAGS@ \ @JANSSON_CFLAGS@ \
@ZLIB_CFLAGS@ \ @ZLIB_CFLAGS@ \
@ -62,6 +63,7 @@ LDADD = $(top_builddir)/lib/libnghttp2.la \
@OPENSSL_LIBS@ \ @OPENSSL_LIBS@ \
@LIBCARES_LIBS@ \ @LIBCARES_LIBS@ \
@LIBNGHTTP3_LIBS@ \ @LIBNGHTTP3_LIBS@ \
@LIBNGTCP2_CRYPTO_OPENSSL_LIBS@ \
@LIBNGTCP2_LIBS@ \ @LIBNGTCP2_LIBS@ \
@SYSTEMD_LIBS@ \ @SYSTEMD_LIBS@ \
@JANSSON_LIBS@ \ @JANSSON_LIBS@ \

View File

@ -2250,6 +2250,8 @@ Options:
} }
} // namespace } // namespace
extern ngtcp2_crypto_ctx in_crypto_ctx;
int main(int argc, char **argv) { int main(int argc, char **argv) {
tls::libssl_init(); tls::libssl_init();
@ -2907,6 +2909,8 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
ngtcp2_crypto_ctx_initial(&in_crypto_ctx);
resolve_host(); resolve_host();
std::cout << "starting benchmark..." << std::endl; std::cout << "starting benchmark..." << std::endl;

View File

@ -46,6 +46,7 @@
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include <ngtcp2/ngtcp2.h> #include <ngtcp2/ngtcp2.h>
#include <ngtcp2/ngtcp2_crypto.h>
#include <ev.h> #include <ev.h>
@ -331,6 +332,7 @@ struct Client {
ngtcp2_crypto_level rx_crypto_level; ngtcp2_crypto_level rx_crypto_level;
std::vector<uint8_t> server_handshake; std::vector<uint8_t> server_handshake;
size_t server_handshake_nread; size_t server_handshake_nread;
ngtcp2_crypto_ctx crypto_ctx;
// Client never send CRYPTO in Short packet. // Client never send CRYPTO in Short packet.
std::array<Crypto, 2> crypto; std::array<Crypto, 2> crypto;
size_t max_pktlen; size_t max_pktlen;
@ -463,26 +465,23 @@ struct Client {
int quic_recv_crypto_data(ngtcp2_crypto_level crypto_level, int quic_recv_crypto_data(ngtcp2_crypto_level crypto_level,
const uint8_t *data, size_t datalen); const uint8_t *data, size_t datalen);
int quic_handshake_completed(); int quic_handshake_completed();
int quic_in_encrypt(uint8_t *dest, size_t destlen, const uint8_t *plaintext, int quic_in_encrypt(uint8_t *dest, const uint8_t *plaintext,
size_t plaintextlen, const uint8_t *key, size_t keylen, size_t plaintextlen, const uint8_t *key,
const uint8_t *nonce, size_t noncelen, const uint8_t *ad, const uint8_t *nonce, size_t noncelen, const uint8_t *ad,
size_t adlen); size_t adlen);
int quic_in_decrypt(uint8_t *dest, size_t destlen, const uint8_t *ciphertext, int quic_in_decrypt(uint8_t *dest, const uint8_t *ciphertext,
size_t ciphertextlen, const uint8_t *key, size_t keylen, size_t ciphertextlen, const uint8_t *key,
const uint8_t *nonce, size_t noncelen, const uint8_t *ad, const uint8_t *nonce, size_t noncelen, const uint8_t *ad,
size_t adlen); size_t adlen);
int quic_encrypt(uint8_t *dest, size_t destlen, const uint8_t *plaintext, int quic_encrypt(uint8_t *dest, const uint8_t *plaintext, size_t plaintextlen,
size_t plaintextlen, const uint8_t *key, size_t keylen, const uint8_t *key, const uint8_t *nonce, size_t noncelen,
const uint8_t *ad, size_t adlen);
int quic_decrypt(uint8_t *dest, const uint8_t *ciphertext,
size_t ciphertextlen, const uint8_t *key,
const uint8_t *nonce, size_t noncelen, const uint8_t *ad, const uint8_t *nonce, size_t noncelen, const uint8_t *ad,
size_t adlen); size_t adlen);
int quic_decrypt(uint8_t *dest, size_t destlen, const uint8_t *ciphertext, int quic_in_hp_mask(uint8_t *dest, const uint8_t *key, const uint8_t *sample);
size_t ciphertextlen, const uint8_t *key, size_t keylen, int quic_hp_mask(uint8_t *dest, const uint8_t *key, const uint8_t *sample);
const uint8_t *nonce, size_t noncelen, const uint8_t *ad,
size_t adlen);
int quic_in_hp_mask(uint8_t *dest, size_t destlen, const uint8_t *key,
size_t keylen, const uint8_t *sample, size_t samplelen);
int quic_hp_mask(uint8_t *dest, size_t destlen, const uint8_t *key,
size_t keylen, const uint8_t *sample, size_t samplelen);
int quic_recv_stream_data(int64_t stream_id, int fin, const uint8_t *data, int quic_recv_stream_data(int64_t stream_id, int fin, const uint8_t *data,
size_t datalen); size_t datalen);
int quic_stream_close(int64_t stream_id, uint64_t app_error_code); int quic_stream_close(int64_t stream_id, uint64_t app_error_code);

View File

@ -83,9 +83,6 @@ int64_t Http3Session::submit_request_internal() {
return rv; return rv;
} }
rv = nghttp3_conn_end_stream(conn_, stream_id);
assert(0 == rv);
client_->on_request(stream_id); client_->on_request(stream_id);
auto req_stat = client_->get_req_stat(stream_id); auto req_stat = client_->get_req_stat(stream_id);
assert(req_stat); assert(req_stat);

View File

@ -37,6 +37,8 @@ namespace {
auto randgen = util::make_mt19937(); auto randgen = util::make_mt19937();
} // namespace } // namespace
ngtcp2_crypto_ctx in_crypto_ctx;
namespace { namespace {
int client_initial(ngtcp2_conn *conn, void *user_data) { int client_initial(ngtcp2_conn *conn, void *user_data) {
auto c = static_cast<Client *>(user_data); auto c = static_cast<Client *>(user_data);
@ -123,156 +125,133 @@ int recv_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
} // namespace } // namespace
namespace { namespace {
ssize_t in_encrypt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, int in_encrypt(ngtcp2_conn *conn, uint8_t *dest, const uint8_t *plaintext,
const uint8_t *plaintext, size_t plaintextlen, size_t plaintextlen, const uint8_t *key, const uint8_t *nonce,
const uint8_t *key, size_t keylen, const uint8_t *nonce,
size_t noncelen, const uint8_t *ad, size_t adlen, size_t noncelen, const uint8_t *ad, size_t adlen,
void *user_data) { void *user_data) {
auto c = static_cast<Client *>(user_data); auto c = static_cast<Client *>(user_data);
auto nwrite = c->quic_in_encrypt(dest, destlen, plaintext, plaintextlen, key, if (c->quic_in_encrypt(dest, plaintext, plaintextlen, key, nonce, noncelen,
keylen, nonce, noncelen, ad, adlen); ad, adlen) != 0) {
if (nwrite < 0) {
return NGTCP2_ERR_CALLBACK_FAILURE; return NGTCP2_ERR_CALLBACK_FAILURE;
} }
return nwrite; return 0;
} }
} // namespace } // namespace
int Client::quic_in_encrypt(uint8_t *dest, size_t destlen, int Client::quic_in_encrypt(uint8_t *dest, const uint8_t *plaintext,
const uint8_t *plaintext, size_t plaintextlen, size_t plaintextlen, const uint8_t *key,
const uint8_t *key, size_t keylen,
const uint8_t *nonce, size_t noncelen, const uint8_t *nonce, size_t noncelen,
const uint8_t *ad, size_t adlen) { const uint8_t *ad, size_t adlen) {
return quic::encrypt(dest, destlen, plaintext, plaintextlen, key, keylen, return ngtcp2_crypto_encrypt(dest, &in_crypto_ctx.aead, plaintext,
nonce, noncelen, ad, adlen, EVP_aes_128_gcm()); plaintextlen, key, nonce, noncelen, ad, adlen);
} }
namespace { namespace {
ssize_t in_decrypt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, int in_decrypt(ngtcp2_conn *conn, uint8_t *dest, const uint8_t *ciphertext,
const uint8_t *ciphertext, size_t ciphertextlen, size_t ciphertextlen, const uint8_t *key, const uint8_t *nonce,
const uint8_t *key, size_t keylen, const uint8_t *nonce,
size_t noncelen, const uint8_t *ad, size_t adlen, size_t noncelen, const uint8_t *ad, size_t adlen,
void *user_data) { void *user_data) {
auto c = static_cast<Client *>(user_data); auto c = static_cast<Client *>(user_data);
auto nwrite = c->quic_in_decrypt(dest, destlen, ciphertext, ciphertextlen, if (c->quic_in_decrypt(dest, ciphertext, ciphertextlen, key, nonce, noncelen,
key, keylen, nonce, noncelen, ad, adlen); ad, adlen) != 0) {
if (nwrite < 0) {
return NGTCP2_ERR_TLS_DECRYPT; return NGTCP2_ERR_TLS_DECRYPT;
} }
return nwrite; return 0;
} }
} // namespace } // namespace
int Client::quic_in_decrypt(uint8_t *dest, size_t destlen, int Client::quic_in_decrypt(uint8_t *dest, const uint8_t *ciphertext,
const uint8_t *ciphertext, size_t ciphertextlen, size_t ciphertextlen, const uint8_t *key,
const uint8_t *key, size_t keylen,
const uint8_t *nonce, size_t noncelen, const uint8_t *nonce, size_t noncelen,
const uint8_t *ad, size_t adlen) { const uint8_t *ad, size_t adlen) {
return quic::decrypt(dest, destlen, ciphertext, ciphertextlen, key, keylen, return ngtcp2_crypto_decrypt(dest, &in_crypto_ctx.aead, ciphertext,
nonce, noncelen, ad, adlen, EVP_aes_128_gcm()); ciphertextlen, key, nonce, noncelen, ad, adlen);
} }
namespace { namespace {
ssize_t encrypt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, int encrypt(ngtcp2_conn *conn, uint8_t *dest, const uint8_t *plaintext,
const uint8_t *plaintext, size_t plaintextlen, size_t plaintextlen, const uint8_t *key, const uint8_t *nonce,
const uint8_t *key, size_t keylen, const uint8_t *nonce, size_t noncelen, const uint8_t *ad, size_t adlen, void *user_data) {
size_t noncelen, const uint8_t *ad, size_t adlen,
void *user_data) {
auto c = static_cast<Client *>(user_data); auto c = static_cast<Client *>(user_data);
auto nwrite = c->quic_encrypt(dest, destlen, plaintext, plaintextlen, key, if (c->quic_encrypt(dest, plaintext, plaintextlen, key, nonce, noncelen, ad,
keylen, nonce, noncelen, ad, adlen); adlen) != 0) {
if (nwrite < 0) {
return NGTCP2_ERR_CALLBACK_FAILURE; return NGTCP2_ERR_CALLBACK_FAILURE;
} }
return nwrite; return 0;
} }
} // namespace } // namespace
int Client::quic_encrypt(uint8_t *dest, size_t destlen, int Client::quic_encrypt(uint8_t *dest, const uint8_t *plaintext,
const uint8_t *plaintext, size_t plaintextlen, size_t plaintextlen, const uint8_t *key,
const uint8_t *key, size_t keylen,
const uint8_t *nonce, size_t noncelen, const uint8_t *nonce, size_t noncelen,
const uint8_t *ad, size_t adlen) { const uint8_t *ad, size_t adlen) {
return quic::encrypt(dest, destlen, plaintext, plaintextlen, key, keylen, return ngtcp2_crypto_encrypt(dest, &quic.crypto_ctx.aead, plaintext,
nonce, noncelen, ad, adlen, quic::aead(ssl)); plaintextlen, key, nonce, noncelen, ad, adlen);
} }
namespace { namespace {
ssize_t decrypt(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, int decrypt(ngtcp2_conn *conn, uint8_t *dest, const uint8_t *ciphertext,
const uint8_t *ciphertext, size_t ciphertextlen, size_t ciphertextlen, const uint8_t *key, const uint8_t *nonce,
const uint8_t *key, size_t keylen, const uint8_t *nonce, size_t noncelen, const uint8_t *ad, size_t adlen, void *user_data) {
size_t noncelen, const uint8_t *ad, size_t adlen,
void *user_data) {
auto c = static_cast<Client *>(user_data); auto c = static_cast<Client *>(user_data);
auto nwrite = c->quic_decrypt(dest, destlen, ciphertext, ciphertextlen, key, if (c->quic_decrypt(dest, ciphertext, ciphertextlen, key, nonce, noncelen, ad,
keylen, nonce, noncelen, ad, adlen); adlen) != 0) {
if (nwrite < 0) {
return NGTCP2_ERR_TLS_DECRYPT; return NGTCP2_ERR_TLS_DECRYPT;
} }
return nwrite; return 0;
} }
} // namespace } // namespace
int Client::quic_decrypt(uint8_t *dest, size_t destlen, int Client::quic_decrypt(uint8_t *dest, const uint8_t *ciphertext,
const uint8_t *ciphertext, size_t ciphertextlen, size_t ciphertextlen, const uint8_t *key,
const uint8_t *key, size_t keylen,
const uint8_t *nonce, size_t noncelen, const uint8_t *nonce, size_t noncelen,
const uint8_t *ad, size_t adlen) { const uint8_t *ad, size_t adlen) {
return quic::decrypt(dest, destlen, ciphertext, ciphertextlen, key, keylen, return ngtcp2_crypto_decrypt(dest, &quic.crypto_ctx.aead, ciphertext,
nonce, noncelen, ad, adlen, quic::aead(ssl)); ciphertextlen, key, nonce, noncelen, ad, adlen);
} }
namespace { namespace {
ssize_t in_hp_mask(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, int in_hp_mask(ngtcp2_conn *conn, uint8_t *dest, const uint8_t *key,
const uint8_t *key, size_t keylen, const uint8_t *sample, const uint8_t *sample, void *user_data) {
size_t samplelen, void *user_data) {
auto c = static_cast<Client *>(user_data); auto c = static_cast<Client *>(user_data);
auto nwrite = if (c->quic_in_hp_mask(dest, key, sample) != 0) {
c->quic_in_hp_mask(dest, destlen, key, keylen, sample, samplelen);
if (nwrite < 0) {
return NGTCP2_ERR_CALLBACK_FAILURE; return NGTCP2_ERR_CALLBACK_FAILURE;
} }
return nwrite; return 0;
} }
} // namespace } // namespace
int Client::quic_in_hp_mask(uint8_t *dest, size_t destlen, const uint8_t *key, int Client::quic_in_hp_mask(uint8_t *dest, const uint8_t *key,
size_t keylen, const uint8_t *sample, const uint8_t *sample) {
size_t samplelen) { return ngtcp2_crypto_hp_mask(dest, &in_crypto_ctx.hp, key, sample);
return quic::hp_mask(dest, destlen, key, keylen, sample, samplelen,
EVP_aes_128_ctr());
} }
namespace { namespace {
ssize_t hp_mask(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, int hp_mask(ngtcp2_conn *conn, uint8_t *dest, const uint8_t *key,
const uint8_t *key, size_t keylen, const uint8_t *sample, const uint8_t *sample, void *user_data) {
size_t samplelen, void *user_data) {
auto c = static_cast<Client *>(user_data); auto c = static_cast<Client *>(user_data);
auto nwrite = c->quic_hp_mask(dest, destlen, key, keylen, sample, samplelen); if (c->quic_hp_mask(dest, key, sample) != 0) {
if (nwrite < 0) {
return NGTCP2_ERR_CALLBACK_FAILURE; return NGTCP2_ERR_CALLBACK_FAILURE;
} }
return nwrite; return 0;
} }
} // namespace } // namespace
int Client::quic_hp_mask(uint8_t *dest, size_t destlen, const uint8_t *key, int Client::quic_hp_mask(uint8_t *dest, const uint8_t *key,
size_t keylen, const uint8_t *sample, const uint8_t *sample) {
size_t samplelen) { return ngtcp2_crypto_hp_mask(dest, &quic.crypto_ctx.hp, key, sample);
return quic::hp_mask(dest, destlen, key, keylen, sample, samplelen,
quic::hp(ssl));
} }
namespace { namespace {
@ -669,71 +648,45 @@ void Client::quic_close_connection() {
} }
int Client::quic_setup_initial_crypto() { int Client::quic_setup_initial_crypto() {
int rv; std::array<uint8_t, 32> tx_secret, rx_secret;
std::array<uint8_t, 32> initial_secret, secret;
auto dcid = ngtcp2_conn_get_dcid(quic.conn); auto dcid = ngtcp2_conn_get_dcid(quic.conn);
rv = quic::derive_initial_secret( if (ngtcp2_crypto_derive_initial_secrets(rx_secret.data(), tx_secret.data(),
initial_secret.data(), initial_secret.size(), dcid->data, dcid->datalen, nullptr, dcid,
reinterpret_cast<const uint8_t *>(NGTCP2_INITIAL_SALT), NGTCP2_CRYPTO_SIDE_CLIENT) != 0) {
str_size(NGTCP2_INITIAL_SALT)); std::cerr << "ngtcp2_crypto_derive_initial_secrets() failed" << std::endl;
if (rv != 0) {
std::cerr << "quic::derive_initial_secret() failed" << std::endl;
return -1; return -1;
} }
auto aead = EVP_aes_128_gcm(); auto aead = &in_crypto_ctx.aead;
auto prf = EVP_sha256(); auto md = &in_crypto_ctx.md;
rv = quic::derive_client_initial_secret(secret.data(), secret.size(),
initial_secret.data(),
initial_secret.size());
if (rv != 0) {
std::cerr << "quic::derive_client_initial_secret() failed" << std::endl;
return -1;
}
std::array<uint8_t, 16> key, iv, hp; std::array<uint8_t, 16> key, iv, hp;
auto keylen = key.size(); auto keylen = ngtcp2_crypto_aead_keylen(aead);
auto ivlen = iv.size(); auto ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
rv = quic::derive_packet_protection_key(key.data(), keylen, iv.data(), ivlen, auto hplen = keylen;
secret.data(), secret.size(), aead,
prf); if (ngtcp2_crypto_derive_packet_protection_key(key.data(), iv.data(), aead,
if (rv != 0) { md, tx_secret.data(),
tx_secret.size()) != 0) {
return -1; return -1;
} }
auto hplen = hp.size(); if (ngtcp2_crypto_derive_header_protection_key(
rv = quic::derive_header_protection_key(hp.data(), hplen, secret.data(), hp.data(), aead, md, tx_secret.data(), tx_secret.size()) != 0) {
secret.size(), aead, prf);
if (rv != 0) {
return -1; return -1;
} }
ngtcp2_conn_install_initial_tx_keys(quic.conn, key.data(), keylen, iv.data(), ngtcp2_conn_install_initial_tx_keys(quic.conn, key.data(), keylen, iv.data(),
ivlen, hp.data(), hplen); ivlen, hp.data(), hplen);
rv = quic::derive_server_initial_secret(secret.data(), secret.size(), if (ngtcp2_crypto_derive_packet_protection_key(key.data(), iv.data(), aead,
initial_secret.data(), md, rx_secret.data(),
initial_secret.size()); rx_secret.size()) != 0) {
if (rv != 0) {
std::cerr << "quic::derive_server_initial_secret() failed" << std::endl;
return -1; return -1;
} }
keylen = key.size(); if (ngtcp2_crypto_derive_header_protection_key(
ivlen = iv.size(); hp.data(), aead, md, rx_secret.data(), rx_secret.size()) != 0) {
rv = quic::derive_packet_protection_key(key.data(), keylen, iv.data(), ivlen,
secret.data(), secret.size(), aead,
prf);
if (rv != 0) {
return -1;
}
hplen = hp.size();
rv = quic::derive_header_protection_key(hp.data(), hplen, secret.data(),
secret.size(), aead, prf);
if (rv != 0) {
return -1; return -1;
} }
@ -744,8 +697,6 @@ int Client::quic_setup_initial_crypto() {
} }
int Client::quic_on_key(int name, const uint8_t *secret, size_t secretlen) { int Client::quic_on_key(int name, const uint8_t *secret, size_t secretlen) {
int rv;
switch (name) { switch (name) {
case SSL_KEY_CLIENT_EARLY_TRAFFIC: case SSL_KEY_CLIENT_EARLY_TRAFFIC:
case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC:
@ -757,28 +708,30 @@ int Client::quic_on_key(int name, const uint8_t *secret, size_t secretlen) {
return 0; return 0;
} }
auto aead = quic::aead(ssl); if (quic.crypto_ctx.aead.native_handle == nullptr) {
auto prf = quic::prf(ssl); ngtcp2_crypto_ctx_tls(&quic.crypto_ctx, ssl);
ngtcp2_conn_set_aead_overhead(
quic.conn, ngtcp2_crypto_aead_taglen(&quic.crypto_ctx.aead));
}
auto aead = &quic.crypto_ctx.aead;
auto md = &quic.crypto_ctx.md;
std::array<uint8_t, 64> key, iv, hp; std::array<uint8_t, 64> key, iv, hp;
auto keylen = key.size(); auto keylen = ngtcp2_crypto_aead_keylen(aead);
auto ivlen = iv.size(); auto ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
rv = quic::derive_packet_protection_key(key.data(), keylen, iv.data(), ivlen, auto hplen = keylen;
secret, secretlen, aead, prf);
if (rv != 0) { if (ngtcp2_crypto_derive_packet_protection_key(key.data(), iv.data(), aead,
md, secret, secretlen) != 0) {
return -1; return -1;
} }
auto hplen = hp.size(); if (ngtcp2_crypto_derive_header_protection_key(hp.data(), aead, md, secret,
rv = quic::derive_header_protection_key(hp.data(), hplen, secret, secretlen, secretlen) != 0) {
aead, prf);
if (rv != 0) {
return -1; return -1;
} }
// TODO Just call this once.
ngtcp2_conn_set_aead_overhead(quic.conn, quic::aead_max_overhead(aead));
switch (name) { switch (name) {
case SSL_KEY_CLIENT_EARLY_TRAFFIC: case SSL_KEY_CLIENT_EARLY_TRAFFIC:
ngtcp2_conn_install_early_keys(quic.conn, key.data(), keylen, iv.data(), ngtcp2_conn_install_early_keys(quic.conn, key.data(), keylen, iv.data(),

View File

@ -26,8 +26,6 @@
#include <cassert> #include <cassert>
#include <openssl/kdf.h>
#include <ngtcp2/ngtcp2.h> #include <ngtcp2/ngtcp2.h>
#include <nghttp3/nghttp3.h> #include <nghttp3/nghttp3.h>
@ -37,402 +35,6 @@ using namespace nghttp2;
namespace quic { namespace quic {
const EVP_CIPHER *aead(SSL *ssl) {
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
case 0x03001301u: // TLS_AES_128_GCM_SHA256
return EVP_aes_128_gcm();
case 0x03001302u: // TLS_AES_256_GCM_SHA384
return EVP_aes_256_gcm();
case 0x03001303u: // TLS_CHACHA20_POLY1305_SHA256
return EVP_chacha20_poly1305();
case 0x03001304u: // TLS_AES_128_CCM_SHA256
return EVP_aes_128_ccm();
default:
assert(0);
}
}
const EVP_CIPHER *hp(SSL *ssl) {
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
case 0x03001301u: // TLS_AES_128_GCM_SHA256
case 0x03001304u: // TLS_AES_128_CCM_SHA256
return EVP_aes_128_ctr();
case 0x03001302u: // TLS_AES_256_GCM_SHA384
return EVP_aes_256_ctr();
case 0x03001303u: // TLS_CHACHA20_POLY1305_SHA256
return EVP_chacha20();
default:
assert(0);
}
}
const EVP_MD *prf(SSL *ssl) {
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
case 0x03001301u: // TLS_AES_128_GCM_SHA256
case 0x03001303u: // TLS_CHACHA20_POLY1305_SHA256
case 0x03001304u: // TLS_AES_128_CCM_SHA256
return EVP_sha256();
case 0x03001302u: // TLS_AES_256_GCM_SHA384
return EVP_sha384();
default:
assert(0);
}
}
namespace {
size_t aead_key_length(const EVP_CIPHER *aead) {
return EVP_CIPHER_key_length(aead);
}
} // namespace
namespace {
size_t aead_nonce_length(const EVP_CIPHER *aead) {
return EVP_CIPHER_iv_length(aead);
}
} // namespace
namespace {
size_t aead_tag_length(const EVP_CIPHER *aead) {
if (aead == EVP_aes_128_gcm() || aead == EVP_aes_256_gcm()) {
return EVP_GCM_TLS_TAG_LEN;
}
if (aead == EVP_chacha20_poly1305()) {
return EVP_CHACHAPOLY_TLS_TAG_LEN;
}
if (aead == EVP_aes_128_ccm()) {
return EVP_CCM_TLS_TAG_LEN;
}
assert(0);
}
} // namespace
size_t aead_max_overhead(const EVP_CIPHER *aead) {
return aead_tag_length(aead);
}
int hkdf_extract(uint8_t *dest, size_t destlen, const uint8_t *secret,
size_t secretlen, const uint8_t *salt, size_t saltlen,
const EVP_MD *prf) {
auto pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
if (pctx == nullptr) {
return -1;
}
auto pctx_d = defer(EVP_PKEY_CTX_free, pctx);
if (EVP_PKEY_derive_init(pctx) != 1 ||
EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) != 1 ||
EVP_PKEY_CTX_set_hkdf_md(pctx, prf) != 1 ||
EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, saltlen) != 1 ||
EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secretlen) != 1 ||
EVP_PKEY_derive(pctx, dest, &destlen) != 1) {
return -1;
}
return 0;
}
int hkdf_expand(uint8_t *dest, size_t destlen, const uint8_t *secret,
size_t secretlen, const uint8_t *info, size_t infolen,
const EVP_MD *prf) {
auto pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
if (pctx == nullptr) {
return -1;
}
auto pctx_d = defer(EVP_PKEY_CTX_free, pctx);
if (EVP_PKEY_derive_init(pctx) != 1 ||
EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) != 1 ||
EVP_PKEY_CTX_set_hkdf_md(pctx, prf) != 1 ||
EVP_PKEY_CTX_set1_hkdf_salt(pctx, "", 0) != 1 ||
EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secretlen) != 1 ||
EVP_PKEY_CTX_add1_hkdf_info(pctx, info, infolen) != 1 ||
EVP_PKEY_derive(pctx, dest, &destlen) != 1) {
return -1;
}
return 0;
}
int hkdf_expand_label(uint8_t *dest, size_t destlen, const uint8_t *secret,
size_t secretlen, const uint8_t *label, size_t labellen,
const EVP_MD *prf) {
std::array<uint8_t, 256> info;
static constexpr const uint8_t LABEL[] = "tls13 ";
auto p = std::begin(info);
*p++ = destlen / 256;
*p++ = destlen % 256;
*p++ = str_size(LABEL) + labellen;
p = std::copy_n(LABEL, str_size(LABEL), p);
p = std::copy_n(label, labellen, p);
*p++ = 0;
return hkdf_expand(dest, destlen, secret, secretlen, info.data(),
p - std::begin(info), prf);
}
int derive_initial_secret(uint8_t *dest, size_t destlen, const uint8_t *secret,
size_t secretlen, const uint8_t *salt,
size_t saltlen) {
return hkdf_extract(dest, destlen, secret, secretlen, salt, saltlen,
EVP_sha256());
}
int derive_client_initial_secret(uint8_t *dest, size_t destlen,
const uint8_t *secret, size_t secretlen) {
static constexpr uint8_t LABEL[] = "client in";
return hkdf_expand_label(dest, destlen, secret, secretlen, LABEL,
str_size(LABEL), EVP_sha256());
}
int derive_server_initial_secret(uint8_t *dest, size_t destlen,
const uint8_t *secret, size_t secretlen) {
static constexpr uint8_t LABEL[] = "server in";
return hkdf_expand_label(dest, destlen, secret, secretlen, LABEL,
str_size(LABEL), EVP_sha256());
}
int derive_packet_protection_key(uint8_t *key, size_t &keylen, uint8_t *iv,
size_t &ivlen, const uint8_t *secret,
size_t secretlen, const EVP_CIPHER *aead,
const EVP_MD *prf) {
int rv;
static constexpr uint8_t KEY_LABEL[] = "quic key";
static constexpr uint8_t IV_LABEL[] = "quic iv";
auto req_keylen = aead_key_length(aead);
if (req_keylen > keylen) {
return -1;
}
keylen = req_keylen;
rv = hkdf_expand_label(key, keylen, secret, secretlen, KEY_LABEL,
str_size(KEY_LABEL), prf);
if (rv != 0) {
return -1;
}
auto req_ivlen = std::max(static_cast<size_t>(8), aead_nonce_length(aead));
if (req_ivlen > ivlen) {
return -1;
}
ivlen = req_ivlen;
rv = hkdf_expand_label(iv, ivlen, secret, secretlen, IV_LABEL,
str_size(IV_LABEL), prf);
if (rv != 0) {
return -1;
}
return 0;
}
int derive_header_protection_key(uint8_t *key, size_t &keylen,
const uint8_t *secret, size_t secretlen,
const EVP_CIPHER *aead, const EVP_MD *prf) {
int rv;
static constexpr uint8_t LABEL[] = "quic hp";
auto req_keylen = aead_key_length(aead);
if (req_keylen > keylen) {
return -1;
}
keylen = req_keylen;
rv = hkdf_expand_label(key, keylen, secret, secretlen, LABEL, str_size(LABEL),
prf);
if (rv != 0) {
return -1;
}
return 0;
}
ssize_t encrypt(uint8_t *dest, size_t destlen, const uint8_t *plaintext,
size_t plaintextlen, const uint8_t *key, size_t keylen,
const uint8_t *nonce, size_t noncelen, const uint8_t *ad,
size_t adlen, const EVP_CIPHER *aead) {
auto taglen = aead_tag_length(aead);
if (destlen < plaintextlen + taglen) {
return -1;
}
auto actx = EVP_CIPHER_CTX_new();
if (actx == nullptr) {
return -1;
}
auto actx_d = defer(EVP_CIPHER_CTX_free, actx);
if (EVP_EncryptInit_ex(actx, aead, nullptr, nullptr, nullptr) != 1) {
return -1;
}
if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, noncelen, nullptr) !=
1) {
return -1;
}
if (aead == EVP_aes_128_ccm() &&
EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, taglen, nullptr) != 1) {
return -1;
}
if (EVP_EncryptInit_ex(actx, nullptr, nullptr, key, nonce) != 1) {
return -1;
}
size_t outlen = 0;
int len;
if (aead == EVP_aes_128_ccm() &&
EVP_EncryptUpdate(actx, nullptr, &len, nullptr, plaintextlen) != 1) {
return -1;
}
if (EVP_EncryptUpdate(actx, nullptr, &len, ad, adlen) != 1) {
return -1;
}
if (EVP_EncryptUpdate(actx, dest, &len, plaintext, plaintextlen) != 1) {
return -1;
}
outlen = len;
if (EVP_EncryptFinal_ex(actx, dest + outlen, &len) != 1) {
return -1;
}
outlen += len;
assert(outlen + taglen <= destlen);
if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_GET_TAG, taglen, dest + outlen) !=
1) {
return -1;
}
outlen += taglen;
return outlen;
}
ssize_t decrypt(uint8_t *dest, size_t destlen, const uint8_t *ciphertext,
size_t ciphertextlen, const uint8_t *key, size_t keylen,
const uint8_t *nonce, size_t noncelen, const uint8_t *ad,
size_t adlen, const EVP_CIPHER *aead) {
auto taglen = aead_tag_length(aead);
if (taglen > ciphertextlen || destlen + taglen < ciphertextlen) {
return -1;
}
ciphertextlen -= taglen;
auto tag = ciphertext + ciphertextlen;
auto actx = EVP_CIPHER_CTX_new();
if (actx == nullptr) {
return -1;
}
auto actx_d = defer(EVP_CIPHER_CTX_free, actx);
if (EVP_DecryptInit_ex(actx, aead, nullptr, nullptr, nullptr) != 1) {
return -1;
}
if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, noncelen, nullptr) !=
1) {
return -1;
}
if (aead == EVP_aes_128_ccm() &&
EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, taglen,
const_cast<uint8_t *>(tag)) != 1) {
return -1;
}
if (EVP_DecryptInit_ex(actx, nullptr, nullptr, key, nonce) != 1) {
return -1;
}
size_t outlen;
int len;
if (aead == EVP_aes_128_ccm() &&
EVP_DecryptUpdate(actx, nullptr, &len, nullptr, ciphertextlen) != 1) {
return -1;
}
if (EVP_DecryptUpdate(actx, nullptr, &len, ad, adlen) != 1) {
return -1;
}
if (EVP_DecryptUpdate(actx, dest, &len, ciphertext, ciphertextlen) != 1) {
return -1;
}
outlen = len;
if (aead == EVP_aes_128_ccm()) {
return outlen;
}
if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, taglen,
const_cast<uint8_t *>(tag)) != 1) {
return -1;
}
if (EVP_DecryptFinal_ex(actx, dest + outlen, &len) != 1) {
return -1;
}
outlen += len;
return outlen;
}
ssize_t hp_mask(uint8_t *dest, size_t destlen, const uint8_t *key,
size_t keylen, const uint8_t *sample, size_t samplelen,
const EVP_CIPHER *cipher) {
static constexpr uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
auto actx = EVP_CIPHER_CTX_new();
if (actx == nullptr) {
return -1;
}
auto actx_d = defer(EVP_CIPHER_CTX_free, actx);
if (EVP_EncryptInit_ex(actx, cipher, nullptr, key, sample) != 1) {
return -1;
}
size_t outlen = 0;
int len;
if (EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, str_size(PLAINTEXT)) !=
1) {
return -1;
}
assert(len == 5);
outlen = len;
if (EVP_EncryptFinal_ex(actx, dest + outlen, &len) != 1) {
return -1;
}
assert(len == 0);
return outlen;
}
Error err_transport(int liberr) { Error err_transport(int liberr) {
if (liberr == NGTCP2_ERR_RECV_VERSION_NEGOTIATION) { if (liberr == NGTCP2_ERR_RECV_VERSION_NEGOTIATION) {
return {ErrorType::TransportVersionNegotiation, 0}; return {ErrorType::TransportVersionNegotiation, 0};

View File

@ -27,60 +27,10 @@
#include "nghttp2_config.h" #include "nghttp2_config.h"
#include <openssl/ssl.h> #include "stdint.h"
namespace quic { namespace quic {
const EVP_CIPHER *aead(SSL *ssl);
const EVP_CIPHER *hp(SSL *ssl);
const EVP_MD *prf(SSL *ssl);
size_t aead_max_overhead(const EVP_CIPHER *aead);
int hkdf_extract(uint8_t *dest, size_t destlen, const uint8_t *secret,
size_t secretlen, const uint8_t *salt, size_t saltlen,
const EVP_MD *prf);
int hkdf_expand(uint8_t *dest, size_t destlen, const uint8_t *secret,
size_t secretlen, const uint8_t *info, size_t infolen,
const EVP_MD *prf);
int hkdf_expand_label(uint8_t *dest, size_t destlen, const uint8_t *secret,
size_t secretlen, const uint8_t *label, size_t labellen,
const EVP_MD *prf);
int derive_initial_secret(uint8_t *dest, size_t destlen, const uint8_t *secret,
size_t secretlen, const uint8_t *salt,
size_t saltlen);
int derive_client_initial_secret(uint8_t *dest, size_t destlen,
const uint8_t *secret, size_t secretlen);
int derive_server_initial_secret(uint8_t *dest, size_t destlen,
const uint8_t *secret, size_t secretlen);
int derive_packet_protection_key(uint8_t *key, size_t &keylen, uint8_t *iv,
size_t &ivlen, const uint8_t *secret,
size_t secretlen, const EVP_CIPHER *aead,
const EVP_MD *prf);
int derive_header_protection_key(uint8_t *key, size_t &keylen,
const uint8_t *secret, size_t secretlen,
const EVP_CIPHER *aead, const EVP_MD *prf);
ssize_t encrypt(uint8_t *dest, size_t destlen, const uint8_t *plaintext,
size_t plaintextlen, const uint8_t *key, size_t keylen,
const uint8_t *nonce, size_t noncelen, const uint8_t *ad,
size_t adlen, const EVP_CIPHER *aead);
ssize_t decrypt(uint8_t *dest, size_t destlen, const uint8_t *ciphertext,
size_t ciphertextlen, const uint8_t *key, size_t keylen,
const uint8_t *nonce, size_t noncelen, const uint8_t *ad,
size_t adlen, const EVP_CIPHER *aead);
ssize_t hp_mask(uint8_t *dest, size_t destlen, const uint8_t *key,
size_t keylen, const uint8_t *sample, size_t samplelen,
const EVP_CIPHER *cipher);
enum class ErrorType { enum class ErrorType {
Transport, Transport,
TransportVersionNegotiation, TransportVersionNegotiation,