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 4861b41c8d
commit ae05dd0e79
8 changed files with 125 additions and 608 deletions

View File

@ -374,6 +374,15 @@ if test "x${have_libngtcp2}" = "xno"; then
AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS)
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)
PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.0.0], [have_libnghttp3=yes],
[have_libnghttp3=no])
@ -917,6 +926,7 @@ AC_MSG_NOTICE([summary of build options:
Libev: ${have_libev} (CFLAGS='${LIBEV_CFLAGS}' LIBS='${LIBEV_LIBS}')
Libc-ares: ${have_libcares} (CFLAGS='${LIBCARES_CFLAGS}' LIBS='${LIBCARES_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}')
Libevent(SSL): ${have_libevent_openssl} (CFLAGS='${LIBEVENT_OPENSSL_CFLAGS}' LIBS='${LIBEVENT_OPENSSL_LIBS}')
Jansson: ${have_jansson} (CFLAGS='${JANSSON_CFLAGS}' LIBS='${JANSSON_LIBS}')

View File

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

View File

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

View File

@ -46,6 +46,7 @@
#include <nghttp2/nghttp2.h>
#include <ngtcp2/ngtcp2.h>
#include <ngtcp2/ngtcp2_crypto.h>
#include <ev.h>
@ -328,6 +329,7 @@ struct Client {
ngtcp2_crypto_level rx_crypto_level;
std::vector<uint8_t> server_handshake;
size_t server_handshake_nread;
ngtcp2_crypto_ctx crypto_ctx;
// Client never send CRYPTO in Short packet.
std::array<Crypto, 2> crypto;
size_t max_pktlen;
@ -446,26 +448,23 @@ struct Client {
int quic_recv_crypto_data(ngtcp2_crypto_level crypto_level,
const uint8_t *data, size_t datalen);
int quic_handshake_completed();
int quic_in_encrypt(uint8_t *dest, size_t destlen, const uint8_t *plaintext,
size_t plaintextlen, const uint8_t *key, size_t keylen,
int quic_in_encrypt(uint8_t *dest, const uint8_t *plaintext,
size_t plaintextlen, const uint8_t *key,
const uint8_t *nonce, size_t noncelen, const uint8_t *ad,
size_t adlen);
int quic_in_decrypt(uint8_t *dest, size_t destlen, const uint8_t *ciphertext,
size_t ciphertextlen, const uint8_t *key, size_t keylen,
int quic_in_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,
size_t adlen);
int quic_encrypt(uint8_t *dest, size_t destlen, const uint8_t *plaintext,
size_t plaintextlen, const uint8_t *key, size_t keylen,
int quic_encrypt(uint8_t *dest, const uint8_t *plaintext, size_t plaintextlen,
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,
size_t adlen);
int quic_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);
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_in_hp_mask(uint8_t *dest, const uint8_t *key, const uint8_t *sample);
int quic_hp_mask(uint8_t *dest, const uint8_t *key, const uint8_t *sample);
int quic_recv_stream_data(int64_t stream_id, int fin, const uint8_t *data,
size_t datalen);
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;
}
rv = nghttp3_conn_end_stream(conn_, stream_id);
assert(0 == rv);
client_->on_request(stream_id);
auto req_stat = client_->get_req_stat(stream_id);
assert(req_stat);

View File

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

View File

@ -26,8 +26,6 @@
#include <cassert>
#include <openssl/kdf.h>
#include <ngtcp2/ngtcp2.h>
#include <nghttp3/nghttp3.h>
@ -37,402 +35,6 @@ using namespace nghttp2;
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) {
if (liberr == NGTCP2_ERR_RECV_VERSION_NEGOTIATION) {
return {ErrorType::TransportVersionNegotiation, 0};

View File

@ -27,60 +27,10 @@
#include "nghttp2_config.h"
#include <openssl/ssl.h>
#include "stdint.h"
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 {
Transport,
TransportVersionNegotiation,