diff --git a/configure.ac b/configure.ac index 3fcf05aa..def91ae8 100644 --- a/configure.ac +++ b/configure.ac @@ -461,6 +461,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]) @@ -1026,6 +1035,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}') diff --git a/src/Makefile.am b/src/Makefile.am index ee6652f5..08797fff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,6 +47,7 @@ AM_CPPFLAGS = \ @OPENSSL_CFLAGS@ \ @LIBCARES_CFLAGS@ \ @LIBNGHTTP3_CFLAGS@ \ + @LIBNGTCP2_CRYPTO_OPENSSL_CFLAGS@ \ @LIBNGTCP2_CFLAGS@ \ @JANSSON_CFLAGS@ \ @ZLIB_CFLAGS@ \ @@ -62,6 +63,7 @@ LDADD = $(top_builddir)/lib/libnghttp2.la \ @OPENSSL_LIBS@ \ @LIBCARES_LIBS@ \ @LIBNGHTTP3_LIBS@ \ + @LIBNGTCP2_CRYPTO_OPENSSL_LIBS@ \ @LIBNGTCP2_LIBS@ \ @SYSTEMD_LIBS@ \ @JANSSON_LIBS@ \ diff --git a/src/h2load.cc b/src/h2load.cc index 07b569a3..281b5410 100644 --- a/src/h2load.cc +++ b/src/h2load.cc @@ -2250,6 +2250,8 @@ Options: } } // namespace +extern ngtcp2_crypto_ctx in_crypto_ctx; + int main(int argc, char **argv) { tls::libssl_init(); @@ -2907,6 +2909,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; diff --git a/src/h2load.h b/src/h2load.h index 5a4777d9..6d746b35 100644 --- a/src/h2load.h +++ b/src/h2load.h @@ -46,6 +46,7 @@ #include #include +#include #include @@ -331,6 +332,7 @@ struct Client { ngtcp2_crypto_level rx_crypto_level; std::vector server_handshake; size_t server_handshake_nread; + ngtcp2_crypto_ctx crypto_ctx; // Client never send CRYPTO in Short packet. std::array crypto; size_t max_pktlen; @@ -463,26 +465,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); diff --git a/src/h2load_http3_session.cc b/src/h2load_http3_session.cc index b84ca393..ca4bbe05 100644 --- a/src/h2load_http3_session.cc +++ b/src/h2load_http3_session.cc @@ -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); diff --git a/src/h2load_quic.cc b/src/h2load_quic.cc index 44fe0388..aad45276 100644 --- a/src/h2load_quic.cc +++ b/src/h2load_quic.cc @@ -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(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(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(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(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(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(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(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 initial_secret, secret; + std::array 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(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 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 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(), diff --git a/src/quic.cc b/src/quic.cc index 9a3de297..1abad98a 100644 --- a/src/quic.cc +++ b/src/quic.cc @@ -26,8 +26,6 @@ #include -#include - #include #include @@ -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 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(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(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(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}; diff --git a/src/quic.h b/src/quic.h index b70076e8..1bb3096f 100644 --- a/src/quic.h +++ b/src/quic.h @@ -27,60 +27,10 @@ #include "nghttp2_config.h" -#include +#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,