From 700bab46aa6772cd56cc697d2d68daf45de68d56 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> Date: Sat, 27 Jun 2020 22:09:25 +0900 Subject: [PATCH] Reuse cipher context --- Makefile.am | 2 +- crypto/gnutls/gnutls.c | 158 ++++++++----- crypto/includes/ngtcp2/ngtcp2_crypto.h | 117 ++++++++-- crypto/openssl/openssl.c | 167 ++++++++----- crypto/shared.c | 264 ++++++++++++++++----- crypto/shared.h | 23 +- examples/client.cc | 34 ++- examples/client.h | 5 +- examples/server.cc | 104 +++++++-- examples/server.h | 5 +- lib/includes/ngtcp2/ngtcp2.h | 294 ++++++++++++++++------- lib/ngtcp2_conn.c | 309 ++++++++++++++++--------- lib/ngtcp2_conn.h | 16 +- lib/ngtcp2_crypto.c | 18 +- lib/ngtcp2_crypto.h | 10 +- lib/ngtcp2_pkt.c | 22 +- lib/ngtcp2_pkt.h | 3 +- lib/ngtcp2_ppe.c | 5 +- tests/ngtcp2_conn_test.c | 223 ++++++++++-------- tests/ngtcp2_pkt_test.c | 15 +- tests/ngtcp2_test_helper.c | 29 +-- tests/ngtcp2_test_helper.h | 4 +- 22 files changed, 1238 insertions(+), 589 deletions(-) diff --git a/Makefile.am b/Makefile.am index 6c91d570..223f112a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,6 +39,6 @@ clang-format: CLANGFORMAT=`git config --get clangformat.binary`; \ test -z $${CLANGFORMAT} && CLANGFORMAT="clang-format"; \ $${CLANGFORMAT} -i lib/*.{c,h} tests/*.{c,h} lib/includes/ngtcp2/*.h \ - crypto/*.c crypto/openssl/*.c crypto/gnutls/*.c \ + crypto/*.{c,h} crypto/openssl/*.c crypto/gnutls/*.c \ crypto/includes/ngtcp2/*.h \ examples/*.{cc,h} diff --git a/crypto/gnutls/gnutls.c b/crypto/gnutls/gnutls.c index 3d4dc8ed..4d19f860 100644 --- a/crypto/gnutls/gnutls.c +++ b/crypto/gnutls/gnutls.c @@ -145,6 +145,82 @@ size_t ngtcp2_crypto_aead_taglen(const ngtcp2_crypto_aead *aead) { (gnutls_cipher_algorithm_t)aead->native_handle); } +int ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx, + const ngtcp2_crypto_aead *aead, + const uint8_t *key, size_t noncelen) { + gnutls_cipher_algorithm_t cipher = + (gnutls_cipher_algorithm_t)aead->native_handle; + gnutls_aead_cipher_hd_t hd; + gnutls_datum_t _key; + + (void)noncelen; + + _key.data = (void *)key; + _key.size = (unsigned int)ngtcp2_crypto_aead_keylen(aead); + + if (gnutls_aead_cipher_init(&hd, cipher, &_key) != 0) { + return -1; + } + + aead_ctx->native_handle = hd; + + return 0; +} + +int ngtcp2_crypto_aead_ctx_decrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx, + const ngtcp2_crypto_aead *aead, + const uint8_t *key, size_t noncelen) { + gnutls_cipher_algorithm_t cipher = + (gnutls_cipher_algorithm_t)aead->native_handle; + gnutls_aead_cipher_hd_t hd; + gnutls_datum_t _key; + + (void)noncelen; + + _key.data = (void *)key; + _key.size = (unsigned int)ngtcp2_crypto_aead_keylen(aead); + + if (gnutls_aead_cipher_init(&hd, cipher, &_key) != 0) { + return -1; + } + + aead_ctx->native_handle = hd; + + return 0; +} + +void ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx) { + if (aead_ctx->native_handle) { + gnutls_aead_cipher_deinit(aead_ctx->native_handle); + } +} + +int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx, + const ngtcp2_crypto_cipher *cipher, + const uint8_t *key) { + gnutls_cipher_algorithm_t _cipher = + (gnutls_cipher_algorithm_t)cipher->native_handle; + gnutls_cipher_hd_t hd; + gnutls_datum_t _key; + + _key.data = (void *)key; + _key.size = (unsigned int)gnutls_cipher_get_key_size(_cipher); + + if (gnutls_cipher_init(&hd, _cipher, &_key, NULL) != 0) { + return -1; + } + + cipher_ctx->native_handle = hd; + + return 0; +} + +void ngtcp2_crypto_cipher_ctx_free(ngtcp2_crypto_cipher_ctx *cipher_ctx) { + if (cipher_ctx->native_handle) { + gnutls_cipher_deinit(cipher_ctx->native_handle); + } +} + int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md, const uint8_t *secret, size_t secretlen, const uint8_t *salt, size_t saltlen) { @@ -175,42 +251,34 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen, } int ngtcp2_crypto_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { gnutls_cipher_algorithm_t cipher = (gnutls_cipher_algorithm_t)aead->native_handle; - gnutls_aead_cipher_hd_t hd = NULL; - gnutls_datum_t _key; - size_t taglen = ngtcp2_crypto_aead_taglen(aead); + gnutls_aead_cipher_hd_t hd = aead_ctx->native_handle; + size_t taglen = gnutls_cipher_get_tag_size(cipher); size_t ciphertextlen = plaintextlen + taglen; - int rv = 0; - - _key.data = (void *)key; - _key.size = (unsigned int)ngtcp2_crypto_aead_keylen(aead); - if (gnutls_aead_cipher_init(&hd, cipher, &_key) != 0 || - gnutls_aead_cipher_encrypt(hd, nonce, noncelen, ad, adlen, taglen, + if (gnutls_aead_cipher_encrypt(hd, nonce, noncelen, ad, adlen, taglen, plaintext, plaintextlen, dest, &ciphertextlen) != 0) { - rv = -1; + return -1; } - gnutls_aead_cipher_deinit(hd); - - return rv; + return 0; } int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { gnutls_cipher_algorithm_t cipher = (gnutls_cipher_algorithm_t)aead->native_handle; + gnutls_aead_cipher_hd_t hd = aead_ctx->native_handle; size_t taglen = gnutls_cipher_get_tag_size(cipher); - gnutls_aead_cipher_hd_t hd = NULL; - gnutls_datum_t _key; - int rv = 0; size_t plaintextlen; if (taglen > ciphertextlen) { @@ -219,81 +287,59 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, plaintextlen = ciphertextlen - taglen; - _key.data = (void *)key; - _key.size = (unsigned int)ngtcp2_crypto_aead_keylen(aead); - - if (gnutls_aead_cipher_init(&hd, cipher, &_key) != 0 || - gnutls_aead_cipher_decrypt(hd, nonce, noncelen, ad, adlen, taglen, + if (gnutls_aead_cipher_decrypt(hd, nonce, noncelen, ad, adlen, taglen, ciphertext, ciphertextlen, dest, &plaintextlen) != 0) { - rv = -1; + return -1; } - gnutls_aead_cipher_deinit(hd); - - return rv; + return 0; } int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key, const uint8_t *sample) { + const ngtcp2_crypto_cipher_ctx *hp_ctx, + const uint8_t *sample) { gnutls_cipher_algorithm_t cipher = (gnutls_cipher_algorithm_t)hp->native_handle; - int rv = 0; + gnutls_cipher_hd_t hd = hp_ctx->native_handle; switch (cipher) { case GNUTLS_CIPHER_AES_128_CBC: case GNUTLS_CIPHER_AES_256_CBC: { - gnutls_cipher_hd_t hd = NULL; - gnutls_datum_t _hp_key; uint8_t iv[16]; - gnutls_datum_t _iv; uint8_t buf[16]; - _hp_key.data = (void *)hp_key; - _hp_key.size = (unsigned int)gnutls_cipher_get_key_size(cipher); - /* Emulate one block AES-ECB by invalidating the effect of IV */ memset(iv, 0, sizeof(iv)); - _iv.data = iv; - _iv.size = 16; - if (gnutls_cipher_init(&hd, cipher, &_hp_key, &_iv) != 0 || - gnutls_cipher_encrypt2(hd, sample, 16, buf, sizeof(buf)) != 0) { - rv = -1; + gnutls_cipher_set_iv(hd, iv, sizeof(iv)); + + if (gnutls_cipher_encrypt2(hd, sample, 16, buf, sizeof(buf)) != 0) { + return -1; } memcpy(dest, buf, 5); - gnutls_cipher_deinit(hd); } break; case GNUTLS_CIPHER_CHACHA20_32: { - gnutls_cipher_hd_t hd = NULL; static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00"; - gnutls_datum_t _hp_key; - gnutls_datum_t _iv; uint8_t buf[5 + 16]; size_t buflen = sizeof(buf); - _hp_key.data = (void *)hp_key; - _hp_key.size = (unsigned int)gnutls_cipher_get_key_size(cipher); - - _iv.data = (void *)sample; - _iv.size = 16; + gnutls_cipher_set_iv(hd, (void *)sample, 16); - if (gnutls_cipher_init(&hd, cipher, &_hp_key, &_iv) != 0 || - gnutls_cipher_encrypt2(hd, PLAINTEXT, sizeof(PLAINTEXT) - 1, buf, + if (gnutls_cipher_encrypt2(hd, PLAINTEXT, sizeof(PLAINTEXT) - 1, buf, buflen) != 0) { - rv = -1; + return -1; } memcpy(dest, buf, 5); - gnutls_cipher_deinit(hd); } break; default: assert(0); } - return rv; + return 0; } static gnutls_record_encryption_level_t diff --git a/crypto/includes/ngtcp2/ngtcp2_crypto.h b/crypto/includes/ngtcp2/ngtcp2_crypto.h index 3197c5dc..4b6885a0 100644 --- a/crypto/includes/ngtcp2/ngtcp2_crypto.h +++ b/crypto/includes/ngtcp2/ngtcp2_crypto.h @@ -210,8 +210,9 @@ NGTCP2_EXTERN int ngtcp2_crypto_derive_packet_protection_key( */ NGTCP2_EXTERN int ngtcp2_crypto_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *plaintext, - size_t plaintextlen, const uint8_t *key, + size_t plaintextlen, const uint8_t *nonce, size_t noncelen, const uint8_t *ad, size_t adlen); @@ -227,9 +228,10 @@ NGTCP2_EXTERN int ngtcp2_crypto_encrypt(uint8_t *dest, */ NGTCP2_EXTERN int ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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); + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen); /** * @function @@ -243,11 +245,13 @@ ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, * * This function returns 0 if it succeeds, or -1. */ -NGTCP2_EXTERN int -ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, - 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); +NGTCP2_EXTERN int ngtcp2_crypto_decrypt(uint8_t *dest, + const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *ciphertext, + size_t ciphertextlen, + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen); /** * @function @@ -261,9 +265,10 @@ ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, */ NGTCP2_EXTERN int ngtcp2_crypto_decrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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); + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen); /** * @function @@ -277,7 +282,7 @@ ngtcp2_crypto_decrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, */ NGTCP2_EXTERN int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const uint8_t *key, + const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample); /** @@ -290,10 +295,10 @@ NGTCP2_EXTERN int ngtcp2_crypto_hp_mask(uint8_t *dest, * This function returns 0 if it succeeds, or * :enum:`NGTCP2_ERR_CALLBACK_FAILURE`. */ -NGTCP2_EXTERN int ngtcp2_crypto_hp_mask_cb(uint8_t *dest, - const ngtcp2_crypto_cipher *hp, - const uint8_t *key, - const uint8_t *sample); +NGTCP2_EXTERN int +ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp, + const ngtcp2_crypto_cipher_ctx *hp_ctx, + const uint8_t *sample); /** * @function @@ -381,10 +386,12 @@ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_tx_key( * The derived packet protection key for decryption is written to the * buffer pointed by |rx_key|. The derived packet protection IV for * decryption is written to the buffer pointed by |rx_iv|. + * |rx_aead_ctx| must be constructed with |rx_key|. * * The derived packet protection key for encryption is written to the * buffer pointed by |tx_key|. The derived packet protection IV for * encryption is written to the buffer pointed by |tx_iv|. + * |tx_aead_ctx| must be constructed with |rx_key|. * * |current_rx_secret| and |current_tx_secret| are the current traffic * secrets for decryption and encryption. |secretlen| specifies the @@ -397,12 +404,12 @@ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_tx_key( * * This function returns 0 if it succeeds, or -1. */ -NGTCP2_EXTERN int -ngtcp2_crypto_update_key(ngtcp2_conn *conn, uint8_t *rx_secret, - uint8_t *tx_secret, uint8_t *rx_key, uint8_t *rx_iv, - uint8_t *tx_key, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen); +NGTCP2_EXTERN int ngtcp2_crypto_update_key( + ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_key, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_key, uint8_t *tx_iv, + const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, + size_t secretlen); /** * @function @@ -415,8 +422,9 @@ ngtcp2_crypto_update_key(ngtcp2_conn *conn, uint8_t *rx_secret, * :enum:`NGTCP2_ERR_CALLBACK_FAILURE`. */ NGTCP2_EXTERN int ngtcp2_crypto_update_key_cb( - ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *rx_key, - uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv, + ngtcp2_conn *conn, 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, void *user_data); @@ -543,6 +551,69 @@ ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid, const ngtcp2_cid *odcid, const uint8_t *token, size_t tokenlen); +/** + * @function + * + * `ngtcp2_crypto_aead_ctx_encrypt_init` initializes |aead_ctx| with + * new AEAD cipher context object for encryption which is constructed + * to use |key| as encryption key. |aead| specifies AEAD cipher to + * use. |noncelen| is the length of nonce. + * + * This function returns 0 if it succeeds, or -1. + */ +NGTCP2_EXTERN int +ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx, + const ngtcp2_crypto_aead *aead, + const uint8_t *key, size_t noncelen); + +/** + * @function + * + * `ngtcp2_crypto_aead_ctx_decrypt_init` initializes |aead_ctx| with + * new AEAD cipher context object for decryption which is constructed + * to use |key| as encryption key. |aead| specifies AEAD cipher to + * use. |noncelen| is the length of nonce. + * + * This function returns 0 if it succeeds, or -1. + */ +NGTCP2_EXTERN int +ngtcp2_crypto_aead_ctx_decrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx, + const ngtcp2_crypto_aead *aead, + const uint8_t *key, size_t noncelen); + +/** + * @function + * + * `ngtcp2_crypto_aead_ctx_free` frees up resources used by + * |aead_ctx|. This function does not free the memory pointed by + * |aead_ctx| itself. + */ +NGTCP2_EXTERN void +ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx); + +/** + * @function + * + * `ngtcp2_crypto_delete_crypto_aead_ctx_cb` deletes the given |aead_ctx|. + * + * This function can be directly passed to delete_crypto_aead_ctx + * field in ngtcp2_callbacks. + */ +NGTCP2_EXTERN void ngtcp2_crypto_delete_crypto_aead_ctx_cb( + ngtcp2_conn *conn, ngtcp2_crypto_aead_ctx *aead_ctx, void *user_data); + +/** + * @function + * + * `ngtcp2_crypto_delete_crypto_cipher_ctx_cb` deletes the given + * |cipher_ctx|. + * + * This function can be directly passed to delete_crypto_cipher_ctx + * field in ngtcp2_callbacks. + */ +NGTCP2_EXTERN void ngtcp2_crypto_delete_crypto_cipher_ctx_cb( + ngtcp2_conn *conn, ngtcp2_crypto_cipher_ctx *cipher_ctx, void *user_data); + #ifdef __cplusplus } #endif diff --git a/crypto/openssl/openssl.c b/crypto/openssl/openssl.c index 60e7250e..d1937441 100644 --- a/crypto/openssl/openssl.c +++ b/crypto/openssl/openssl.c @@ -173,6 +173,92 @@ size_t ngtcp2_crypto_aead_taglen(const ngtcp2_crypto_aead *aead) { return crypto_aead_taglen(aead->native_handle); } +int ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx, + const ngtcp2_crypto_aead *aead, + const uint8_t *key, size_t noncelen) { + const EVP_CIPHER *cipher = aead->native_handle; + EVP_CIPHER_CTX *actx; + + actx = EVP_CIPHER_CTX_new(); + if (actx == NULL) { + return -1; + } + + if (!EVP_EncryptInit_ex(actx, cipher, NULL, NULL, NULL) || + !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, (int)noncelen, + NULL) || + (cipher == EVP_aes_128_ccm() && + !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, + (int)crypto_aead_taglen(cipher), NULL)) || + !EVP_EncryptInit_ex(actx, NULL, NULL, key, NULL)) { + EVP_CIPHER_CTX_free(actx); + return -1; + } + + aead_ctx->native_handle = actx; + + return 0; +} + +int ngtcp2_crypto_aead_ctx_decrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx, + const ngtcp2_crypto_aead *aead, + const uint8_t *key, size_t noncelen) { + const EVP_CIPHER *cipher = aead->native_handle; + EVP_CIPHER_CTX *actx; + + actx = EVP_CIPHER_CTX_new(); + if (actx == NULL) { + return -1; + } + + if (!EVP_DecryptInit_ex(actx, cipher, NULL, NULL, NULL) || + !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, (int)noncelen, + NULL) || + (cipher == EVP_aes_128_ccm() && + !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, + (int)crypto_aead_taglen(cipher), NULL)) || + !EVP_DecryptInit_ex(actx, NULL, NULL, key, NULL)) { + EVP_CIPHER_CTX_free(actx); + return -1; + } + + aead_ctx->native_handle = actx; + + return 0; +} + +void ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx) { + if (aead_ctx->native_handle) { + EVP_CIPHER_CTX_free(aead_ctx->native_handle); + } +} + +int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx, + const ngtcp2_crypto_cipher *cipher, + const uint8_t *key) { + EVP_CIPHER_CTX *actx; + + actx = EVP_CIPHER_CTX_new(); + if (actx == NULL) { + return -1; + } + + if (!EVP_EncryptInit_ex(actx, cipher->native_handle, NULL, key, NULL)) { + EVP_CIPHER_CTX_free(actx); + return -1; + } + + cipher_ctx->native_handle = actx; + + return 0; +} + +void ngtcp2_crypto_cipher_ctx_free(ngtcp2_crypto_cipher_ctx *cipher_ctx) { + if (cipher_ctx->native_handle) { + EVP_CIPHER_CTX_free(cipher_ctx->native_handle); + } +} + int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md, const uint8_t *secret, size_t secretlen, const uint8_t *salt, size_t saltlen) { @@ -226,26 +312,18 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen, } int ngtcp2_crypto_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { const EVP_CIPHER *cipher = aead->native_handle; size_t taglen = crypto_aead_taglen(cipher); - EVP_CIPHER_CTX *actx; - int rv = 0; + EVP_CIPHER_CTX *actx = aead_ctx->native_handle; int len; - actx = EVP_CIPHER_CTX_new(); - if (actx == NULL) { - return -1; - } + (void)noncelen; - if (!EVP_EncryptInit_ex(actx, cipher, NULL, NULL, NULL) || - !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, (int)noncelen, - NULL) || - (cipher == EVP_aes_128_ccm() && - !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, (int)taglen, NULL)) || - !EVP_EncryptInit_ex(actx, NULL, NULL, key, nonce) || + if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, nonce) || (cipher == EVP_aes_128_ccm() && !EVP_EncryptUpdate(actx, NULL, &len, NULL, (int)plaintextlen)) || !EVP_EncryptUpdate(actx, NULL, &len, ad, (int)adlen) || @@ -253,25 +331,25 @@ int ngtcp2_crypto_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, !EVP_EncryptFinal_ex(actx, dest + len, &len) || !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_GET_TAG, (int)taglen, dest + plaintextlen)) { - rv = -1; + return -1; } - EVP_CIPHER_CTX_free(actx); - - return rv; + return 0; } int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { const EVP_CIPHER *cipher = aead->native_handle; size_t taglen = crypto_aead_taglen(cipher); - EVP_CIPHER_CTX *actx; - int rv = 0; + EVP_CIPHER_CTX *actx = aead_ctx->native_handle; int len; const uint8_t *tag; + (void)noncelen; + if (taglen > ciphertextlen) { return -1; } @@ -279,56 +357,37 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, ciphertextlen -= taglen; tag = ciphertext + ciphertextlen; - actx = EVP_CIPHER_CTX_new(); - if (actx == NULL) { - return -1; - } - - if (!EVP_DecryptInit_ex(actx, cipher, NULL, NULL, NULL) || - !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, (int)noncelen, - NULL) || - (cipher == EVP_aes_128_ccm() && - !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, (int)taglen, - (uint8_t *)tag)) || - !EVP_DecryptInit_ex(actx, NULL, NULL, key, nonce) || + if (!EVP_DecryptInit_ex(actx, NULL, NULL, NULL, nonce) || + !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, (int)taglen, + (uint8_t *)tag) || (cipher == EVP_aes_128_ccm() && !EVP_DecryptUpdate(actx, NULL, &len, NULL, (int)ciphertextlen)) || !EVP_DecryptUpdate(actx, NULL, &len, ad, (int)adlen) || !EVP_DecryptUpdate(actx, dest, &len, ciphertext, (int)ciphertextlen) || (cipher != EVP_aes_128_ccm() && - (!EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, (int)taglen, - (uint8_t *)tag) || - !EVP_DecryptFinal_ex(actx, dest + ciphertextlen, &len)))) { - rv = -1; + !EVP_DecryptFinal_ex(actx, dest + ciphertextlen, &len))) { + return -1; } - EVP_CIPHER_CTX_free(actx); - - return rv; + return 0; } int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key, const uint8_t *sample) { + const ngtcp2_crypto_cipher_ctx *hp_ctx, + const uint8_t *sample) { static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00"; - const EVP_CIPHER *cipher = hp->native_handle; - EVP_CIPHER_CTX *actx; - int rv = 0; + EVP_CIPHER_CTX *actx = hp_ctx->native_handle; int len; - actx = EVP_CIPHER_CTX_new(); - if (actx == NULL) { - return -1; - } + (void)hp; - if (!EVP_EncryptInit_ex(actx, cipher, NULL, hp_key, sample) || + if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) || !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT) - 1) || !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len)) { - rv = -1; + return -1; } - EVP_CIPHER_CTX_free(actx); - - return rv; + return 0; } static OSSL_ENCRYPTION_LEVEL diff --git a/crypto/shared.c b/crypto/shared.c index bea088e8..08aa5e2b 100644 --- a/crypto/shared.c +++ b/crypto/shared.c @@ -153,9 +153,11 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, const ngtcp2_crypto_ctx *ctx; const ngtcp2_crypto_aead *aead; const ngtcp2_crypto_md *md; + const ngtcp2_crypto_cipher *hp; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; void *tls = ngtcp2_conn_get_tls_native_handle(conn); uint8_t keybuf[64], ivbuf[64], hp_keybuf[64]; - size_t keylen; size_t ivlen; int rv; @@ -185,7 +187,7 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, aead = &ctx->aead; md = &ctx->md; - keylen = ngtcp2_crypto_aead_keylen(aead); + hp = &ctx->hp; ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); if (ngtcp2_crypto_derive_packet_protection_key(key, iv, hp_key, aead, md, @@ -193,40 +195,54 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, return -1; } + if (ngtcp2_crypto_aead_ctx_decrypt_init(&aead_ctx, aead, key, ivlen) != 0) { + goto fail; + } + + if (ngtcp2_crypto_cipher_ctx_encrypt_init(&hp_ctx, hp, hp_key) != 0) { + goto fail; + } + switch (level) { case NGTCP2_CRYPTO_LEVEL_EARLY: - rv = ngtcp2_conn_install_early_key(conn, key, iv, hp_key, keylen, ivlen); + rv = ngtcp2_conn_install_early_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { - return -1; + goto fail; } break; case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: - rv = ngtcp2_conn_install_rx_handshake_key(conn, key, iv, hp_key, keylen, - ivlen); + rv = ngtcp2_conn_install_rx_handshake_key(conn, &aead_ctx, iv, ivlen, + &hp_ctx); if (rv != 0) { - return -1; + goto fail; } break; case NGTCP2_CRYPTO_LEVEL_APP: if (!ngtcp2_conn_is_server(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); if (rv != 0) { - return -1; + goto fail; } } - rv = ngtcp2_conn_install_rx_key(conn, secret, key, iv, hp_key, secretlen, - keylen, ivlen); + rv = ngtcp2_conn_install_rx_key(conn, secret, secretlen, &aead_ctx, iv, + ivlen, &hp_ctx); if (rv != 0) { - return -1; + goto fail; } break; default: - return -1; + goto fail; } return 0; + +fail: + ngtcp2_crypto_cipher_ctx_free(&hp_ctx); + ngtcp2_crypto_aead_ctx_free(&aead_ctx); + + return -1; } int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, @@ -237,9 +253,11 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, const ngtcp2_crypto_ctx *ctx; const ngtcp2_crypto_aead *aead; const ngtcp2_crypto_md *md; + const ngtcp2_crypto_cipher *hp; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; void *tls = ngtcp2_conn_get_tls_native_handle(conn); uint8_t keybuf[64], ivbuf[64], hp_keybuf[64]; - size_t keylen; size_t ivlen; int rv; @@ -269,7 +287,7 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, aead = &ctx->aead; md = &ctx->md; - keylen = ngtcp2_crypto_aead_keylen(aead); + hp = &ctx->hp; ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); if (ngtcp2_crypto_derive_packet_protection_key(key, iv, hp_key, aead, md, @@ -277,40 +295,54 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, return -1; } + if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, aead, key, ivlen) != 0) { + goto fail; + } + + if (ngtcp2_crypto_cipher_ctx_encrypt_init(&hp_ctx, hp, hp_key) != 0) { + goto fail; + } + switch (level) { case NGTCP2_CRYPTO_LEVEL_EARLY: - rv = ngtcp2_conn_install_early_key(conn, key, iv, hp_key, keylen, ivlen); + rv = ngtcp2_conn_install_early_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { - return -1; + goto fail; } break; case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: if (ngtcp2_conn_is_server(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); if (rv != 0) { - return -1; + goto fail; } } - rv = ngtcp2_conn_install_tx_handshake_key(conn, key, iv, hp_key, keylen, - ivlen); + rv = ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, iv, ivlen, + &hp_ctx); if (rv != 0) { - return -1; + goto fail; } break; case NGTCP2_CRYPTO_LEVEL_APP: - rv = ngtcp2_conn_install_tx_key(conn, secret, key, iv, hp_key, secretlen, - keylen, ivlen); + rv = ngtcp2_conn_install_tx_key(conn, secret, secretlen, &aead_ctx, iv, + ivlen, &hp_ctx); if (rv != 0) { - return -1; + goto fail; } break; default: - return -1; + goto fail; } return 0; + +fail: + ngtcp2_crypto_cipher_ctx_free(&hp_ctx); + ngtcp2_crypto_aead_ctx_free(&aead_ctx); + + return -1; } int ngtcp2_crypto_derive_and_install_initial_key( @@ -329,7 +361,13 @@ int ngtcp2_crypto_derive_and_install_initial_key( uint8_t tx_hp_keybuf[NGTCP2_CRYPTO_INITIAL_KEYLEN]; ngtcp2_crypto_ctx ctx; ngtcp2_crypto_aead retry_aead; + ngtcp2_crypto_aead_ctx rx_aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx rx_hp_ctx = {0}; + ngtcp2_crypto_aead_ctx tx_aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx tx_hp_ctx = {0}; + ngtcp2_crypto_aead_ctx retry_aead_ctx = {0}; int rv; + int server = ngtcp2_conn_is_server(conn); ngtcp2_crypto_ctx_initial(&ctx); @@ -366,8 +404,8 @@ int ngtcp2_crypto_derive_and_install_initial_key( if (ngtcp2_crypto_derive_initial_secrets( rx_secret, tx_secret, initial_secret, client_dcid, - ngtcp2_conn_is_server(conn) ? NGTCP2_CRYPTO_SIDE_SERVER - : NGTCP2_CRYPTO_SIDE_CLIENT) != 0) { + server ? NGTCP2_CRYPTO_SIDE_SERVER : NGTCP2_CRYPTO_SIDE_CLIENT) != + 0) { return -1; } @@ -383,27 +421,69 @@ int ngtcp2_crypto_derive_and_install_initial_key( return -1; } - rv = ngtcp2_conn_install_initial_key( - conn, rx_key, rx_iv, rx_hp_key, tx_key, tx_iv, tx_hp_key, - NGTCP2_CRYPTO_INITIAL_KEYLEN, NGTCP2_CRYPTO_INITIAL_IVLEN); + if (ngtcp2_crypto_aead_ctx_decrypt_init(&rx_aead_ctx, &ctx.aead, rx_key, + NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) { + goto fail; + } + + if (ngtcp2_crypto_cipher_ctx_encrypt_init(&rx_hp_ctx, &ctx.hp, rx_hp_key) != + 0) { + goto fail; + } + + if (ngtcp2_crypto_aead_ctx_encrypt_init(&tx_aead_ctx, &ctx.aead, tx_key, + NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) { + goto fail; + } + + if (ngtcp2_crypto_cipher_ctx_encrypt_init(&tx_hp_ctx, &ctx.hp, tx_hp_key) != + 0) { + goto fail; + } + + if (!server && !ngtcp2_conn_after_retry(conn)) { + ngtcp2_crypto_aead_retry(&retry_aead); + + if (ngtcp2_crypto_aead_ctx_encrypt_init( + &retry_aead_ctx, &retry_aead, (const uint8_t *)NGTCP2_RETRY_KEY, + sizeof(NGTCP2_RETRY_NONCE) - 1) != 0) { + goto fail; + } + } + + rv = ngtcp2_conn_install_initial_key(conn, &rx_aead_ctx, rx_iv, &rx_hp_ctx, + &tx_aead_ctx, tx_iv, &tx_hp_ctx, + NGTCP2_CRYPTO_INITIAL_IVLEN); if (rv != 0) { - return -1; + goto fail; } - ngtcp2_conn_set_retry_aead(conn, ngtcp2_crypto_aead_retry(&retry_aead)); + if (retry_aead_ctx.native_handle) { + ngtcp2_conn_set_retry_aead(conn, &retry_aead, &retry_aead_ctx); + } return 0; + +fail: + ngtcp2_crypto_aead_ctx_free(&retry_aead_ctx); + ngtcp2_crypto_cipher_ctx_free(&tx_hp_ctx); + ngtcp2_crypto_aead_ctx_free(&tx_aead_ctx); + ngtcp2_crypto_cipher_ctx_free(&rx_hp_ctx); + ngtcp2_crypto_aead_ctx_free(&rx_aead_ctx); + + return -1; } -int ngtcp2_crypto_update_key(ngtcp2_conn *conn, uint8_t *rx_secret, - uint8_t *tx_secret, uint8_t *rx_key, - uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, - size_t secretlen) { +int ngtcp2_crypto_update_key( + ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_key, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_key, uint8_t *tx_iv, + const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, + size_t secretlen) { const ngtcp2_crypto_ctx *ctx = ngtcp2_conn_get_crypto_ctx(conn); const ngtcp2_crypto_aead *aead = &ctx->aead; const ngtcp2_crypto_md *md = &ctx->md; + size_t ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); if (ngtcp2_crypto_update_traffic_secret(rx_secret, md, current_rx_secret, secretlen) != 0) { @@ -425,51 +505,69 @@ int ngtcp2_crypto_update_key(ngtcp2_conn *conn, uint8_t *rx_secret, return -1; } + if (ngtcp2_crypto_aead_ctx_decrypt_init(rx_aead_ctx, aead, rx_key, ivlen) != + 0) { + return -1; + } + + if (ngtcp2_crypto_aead_ctx_encrypt_init(tx_aead_ctx, aead, tx_key, ivlen) != + 0) { + ngtcp2_crypto_aead_ctx_free(rx_aead_ctx); + rx_aead_ctx->native_handle = NULL; + return -1; + } + return 0; } int ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { - if (ngtcp2_crypto_encrypt(dest, aead, plaintext, plaintextlen, key, nonce, - noncelen, ad, adlen) != 0) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { + if (ngtcp2_crypto_encrypt(dest, aead, aead_ctx, plaintext, plaintextlen, + nonce, noncelen, ad, adlen) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } int ngtcp2_crypto_decrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { - if (ngtcp2_crypto_decrypt(dest, aead, ciphertext, ciphertextlen, key, nonce, - noncelen, ad, adlen) != 0) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { + if (ngtcp2_crypto_decrypt(dest, aead, aead_ctx, ciphertext, ciphertextlen, + nonce, noncelen, ad, adlen) != 0) { return NGTCP2_ERR_TLS_DECRYPT; } return 0; } int ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key, const uint8_t *sample) { - if (ngtcp2_crypto_hp_mask(dest, hp, hp_key, sample) != 0) { + const ngtcp2_crypto_cipher_ctx *hp_ctx, + const uint8_t *sample) { + if (ngtcp2_crypto_hp_mask(dest, hp, hp_ctx, sample) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } -int ngtcp2_crypto_update_key_cb(ngtcp2_conn *conn, uint8_t *rx_secret, - uint8_t *tx_secret, uint8_t *rx_key, - uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, - size_t secretlen, void *user_data) { +int ngtcp2_crypto_update_key_cb( + ngtcp2_conn *conn, 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, void *user_data) { + uint8_t rx_key[64]; + uint8_t tx_key[64]; (void)conn; (void)user_data; - if (ngtcp2_crypto_update_key(conn, rx_secret, tx_secret, rx_key, rx_iv, - tx_key, tx_iv, current_rx_secret, - current_tx_secret, secretlen) != 0) { + if (ngtcp2_crypto_update_key(conn, rx_secret, tx_secret, rx_aead_ctx, rx_key, + rx_iv, tx_aead_ctx, tx_key, tx_iv, + current_rx_secret, current_tx_secret, + secretlen) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; @@ -509,6 +607,8 @@ ngtcp2_ssize ngtcp2_crypto_write_connection_close(uint8_t *dest, size_t destlen, uint8_t tx_hp_key[NGTCP2_CRYPTO_INITIAL_KEYLEN]; ngtcp2_crypto_ctx ctx; ngtcp2_ssize spktlen; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; ngtcp2_crypto_ctx_initial(&ctx); @@ -524,13 +624,28 @@ ngtcp2_ssize ngtcp2_crypto_write_connection_close(uint8_t *dest, size_t destlen, return -1; } + if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &ctx.aead, tx_key, + NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) { + spktlen = -1; + goto end; + } + + if (ngtcp2_crypto_cipher_ctx_encrypt_init(&hp_ctx, &ctx.hp, tx_hp_key) != 0) { + spktlen = -1; + goto end; + } + spktlen = ngtcp2_pkt_write_connection_close( dest, destlen, dcid, scid, error_code, ngtcp2_crypto_encrypt_cb, - &ctx.aead, tx_key, tx_iv, ngtcp2_crypto_hp_mask_cb, &ctx.hp, tx_hp_key); + &ctx.aead, &aead_ctx, tx_iv, ngtcp2_crypto_hp_mask_cb, &ctx.hp, &hp_ctx); if (spktlen < 0) { - return -1; + spktlen = -1; } +end: + ngtcp2_crypto_cipher_ctx_free(&hp_ctx); + ngtcp2_crypto_aead_ctx_free(&aead_ctx); + return spktlen; } @@ -541,15 +656,25 @@ ngtcp2_ssize ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen, const uint8_t *token, size_t tokenlen) { ngtcp2_crypto_aead aead; ngtcp2_ssize spktlen; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; ngtcp2_crypto_aead_retry(&aead); - spktlen = ngtcp2_pkt_write_retry(dest, destlen, dcid, scid, odcid, token, - tokenlen, ngtcp2_crypto_encrypt_cb, &aead); - if (spktlen < 0) { + if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &aead, + (const uint8_t *)NGTCP2_RETRY_KEY, + NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) { return -1; } + spktlen = + ngtcp2_pkt_write_retry(dest, destlen, dcid, scid, odcid, token, tokenlen, + ngtcp2_crypto_encrypt_cb, &aead, &aead_ctx); + if (spktlen < 0) { + spktlen = -1; + } + + ngtcp2_crypto_aead_ctx_free(&aead_ctx); + return spktlen; } @@ -639,3 +764,20 @@ int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn, return 0; } + +void ngtcp2_crypto_delete_crypto_aead_ctx_cb(ngtcp2_conn *conn, + ngtcp2_crypto_aead_ctx *aead_ctx, + void *user_data) { + (void)conn; + (void)user_data; + + ngtcp2_crypto_aead_ctx_free(aead_ctx); +} + +void ngtcp2_crypto_delete_crypto_cipher_ctx_cb( + ngtcp2_conn *conn, ngtcp2_crypto_cipher_ctx *cipher_ctx, void *user_data) { + (void)conn; + (void)user_data; + + ngtcp2_crypto_cipher_ctx_free(cipher_ctx); +} diff --git a/crypto/shared.h b/crypto/shared.h index a904f699..b70513af 100644 --- a/crypto/shared.h +++ b/crypto/shared.h @@ -110,7 +110,6 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, */ int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls); - /** * @function * @@ -165,4 +164,26 @@ int ngtcp2_crypto_derive_and_install_initial_key( uint8_t *tx_key, uint8_t *tx_iv, uint8_t *tx_hp, const ngtcp2_cid *client_dcid); +/** + * @function + * + * `ngtcp2_crypto_cipher_ctx_encrypt_init` initializes |cipher_ctx| + * with new cipher context object for encryption which is constructed + * to use |key| as encryption key. |cipher| specifies cipher to use. + * + * This function returns 0 if it succeeds, or -1. + */ +int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx, + const ngtcp2_crypto_cipher *cipher, + const uint8_t *key); + +/** + * @function + * + * `ngtcp2_crypto_cipher_ctx_free` frees up resources used by + * |cipher_ctx|. This function does not free the memory pointed by + * |cipher_ctx| itself. + */ +void ngtcp2_crypto_cipher_ctx_free(ngtcp2_crypto_cipher_ctx *cipher_ctx); + #endif /* NGTCP2_SHARED_H */ diff --git a/examples/client.cc b/examples/client.cc index d5b6cec2..0c10f4cb 100644 --- a/examples/client.cc +++ b/examples/client.cc @@ -657,8 +657,8 @@ int remove_connection_id(ngtcp2_conn *conn, const ngtcp2_cid *cid, namespace { int do_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key, const uint8_t *sample) { - if (ngtcp2_crypto_hp_mask(dest, hp, hp_key, sample) != 0) { + const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) { + if (ngtcp2_crypto_hp_mask(dest, hp, hp_ctx, sample) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -672,14 +672,16 @@ int do_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, namespace { int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, - uint8_t *rx_key, uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv, + 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, void *user_data) { auto c = static_cast<Client *>(user_data); - if (c->update_key(rx_secret, tx_secret, rx_key, rx_iv, tx_key, tx_iv, - current_rx_secret, current_tx_secret, secretlen) != 0) { + if (c->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, + tx_iv, current_rx_secret, current_tx_secret, + secretlen) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -883,6 +885,8 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, nullptr, // dcid_status nullptr, // handshake_confirmed ::recv_new_token, + ngtcp2_crypto_delete_crypto_aead_ctx_cb, + ngtcp2_crypto_delete_crypto_cipher_ctx_cb, }; auto dis = std::uniform_int_distribution<uint8_t>( @@ -1424,8 +1428,9 @@ void Client::start_key_update_timer() { ev_timer_start(loop_, &key_update_timer_); } -int Client::update_key(uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *rx_key, - uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv, +int Client::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) { if (!config.quiet) { @@ -1439,17 +1444,22 @@ int Client::update_key(uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *rx_key, ++nkey_update_; - if (ngtcp2_crypto_update_key(conn_, rx_secret, tx_secret, rx_key, rx_iv, - tx_key, tx_iv, current_rx_secret, - current_tx_secret, secretlen) != 0) { + std::array<uint8_t, 64> rx_key, tx_key; + + if (ngtcp2_crypto_update_key(conn_, rx_secret, tx_secret, rx_aead_ctx, + rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(), + tx_iv, current_rx_secret, current_tx_secret, + secretlen) != 0) { return -1; } if (!config.quiet && config.show_secret) { std::cerr << "application_traffic rx secret " << nkey_update_ << std::endl; - debug::print_secrets(rx_secret, secretlen, rx_key, keylen, rx_iv, ivlen); + debug::print_secrets(rx_secret, secretlen, rx_key.data(), keylen, rx_iv, + ivlen); std::cerr << "application_traffic tx secret " << nkey_update_ << std::endl; - debug::print_secrets(tx_secret, secretlen, tx_key, keylen, tx_iv, ivlen); + debug::print_secrets(tx_secret, secretlen, tx_key.data(), keylen, tx_iv, + ivlen); } return 0; diff --git a/examples/client.h b/examples/client.h index 77a1e9f2..db3b2660 100644 --- a/examples/client.h +++ b/examples/client.h @@ -236,8 +236,9 @@ public: 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, uint8_t *rx_key, - uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv, + 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(); diff --git a/examples/server.cc b/examples/server.cc index a3736325..0e7a8798 100644 --- a/examples/server.cc +++ b/examples/server.cc @@ -847,8 +847,8 @@ int Handler::handshake_completed() { namespace { int do_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key, const uint8_t *sample) { - if (ngtcp2_crypto_hp_mask(dest, hp, hp_key, sample) != 0) { + const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) { + if (ngtcp2_crypto_hp_mask(dest, hp, hp_ctx, sample) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1090,13 +1090,15 @@ int remove_connection_id(ngtcp2_conn *conn, const ngtcp2_cid *cid, namespace { int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, - uint8_t *rx_key, uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv, + 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, void *user_data) { auto h = static_cast<Handler *>(user_data); - if (h->update_key(rx_secret, tx_secret, rx_key, rx_iv, tx_key, tx_iv, - current_rx_secret, current_tx_secret, secretlen) != 0) { + if (h->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, + tx_iv, current_rx_secret, current_tx_secret, + secretlen) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; @@ -1507,8 +1509,13 @@ int Handler::init(const Endpoint &ep, const sockaddr *sa, socklen_t salen, nullptr, // select_preferred_addr ::stream_reset, ::extend_max_remote_streams_bidi, - nullptr, // extend_max_remote_streams_uni, + nullptr, // extend_max_remote_streams_uni ::extend_max_stream_data, + nullptr, // dcid_status + nullptr, // handshake_confirmed + nullptr, // recv_new_token + ngtcp2_crypto_delete_crypto_aead_ctx_cb, + ngtcp2_crypto_delete_crypto_cipher_ctx_cb, }; auto dis = std::uniform_int_distribution<uint8_t>(0, 255); @@ -1996,8 +2003,9 @@ int Handler::recv_stream_data(uint32_t flags, int64_t stream_id, return 0; } -int Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *rx_key, - uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv, +int Handler::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) { auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_); @@ -2007,17 +2015,22 @@ int Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *rx_key, ++nkey_update_; - if (ngtcp2_crypto_update_key(conn_, rx_secret, tx_secret, rx_key, rx_iv, - tx_key, tx_iv, current_rx_secret, - current_tx_secret, secretlen) != 0) { + std::array<uint8_t, 64> rx_key, tx_key; + + if (ngtcp2_crypto_update_key(conn_, rx_secret, tx_secret, rx_aead_ctx, + rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(), + tx_iv, current_rx_secret, current_tx_secret, + secretlen) != 0) { return -1; } if (!config.quiet && config.show_secret) { std::cerr << "application_traffic rx secret " << nkey_update_ << std::endl; - debug::print_secrets(rx_secret, secretlen, rx_key, keylen, rx_iv, ivlen); + debug::print_secrets(rx_secret, secretlen, rx_key.data(), keylen, rx_iv, + ivlen); std::cerr << "application_traffic tx secret " << nkey_update_ << std::endl; - debug::print_secrets(tx_secret, secretlen, tx_key, keylen, tx_iv, ivlen); + debug::print_secrets(tx_secret, secretlen, tx_key.data(), keylen, tx_iv, + ivlen); } return 0; @@ -2731,9 +2744,20 @@ int Server::generate_retry_token(uint8_t *token, size_t &tokenlen, generate_retry_token_aad(aad.data(), aad.size(), sa, salen, retry_scid); token[0] = RETRY_TOKEN_MAGIC; - if (ngtcp2_crypto_encrypt(token + 1, &token_aead_, plaintext.data(), - plaintextlen, key.data(), iv.data(), ivlen, - aad.data(), aadlen) != 0) { + + ngtcp2_crypto_aead_ctx aead_ctx; + if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &token_aead_, key.data(), + ivlen) != 0) { + return -1; + } + + auto rv = ngtcp2_crypto_encrypt(token + 1, &token_aead_, &aead_ctx, + plaintext.data(), plaintextlen, iv.data(), + ivlen, aad.data(), aadlen); + + ngtcp2_crypto_aead_ctx_free(&aead_ctx); + + if (rv != 0) { return -1; } @@ -2796,11 +2820,21 @@ int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, auto aadlen = generate_retry_token_aad(aad.data(), aad.size(), sa, salen, &hd->dcid); + ngtcp2_crypto_aead_ctx aead_ctx; + if (ngtcp2_crypto_aead_ctx_decrypt_init(&aead_ctx, &token_aead_, key.data(), + ivlen) != 0) { + return -1; + } + std::array<uint8_t, MAX_RETRY_TOKENLEN> plaintext; - if (ngtcp2_crypto_decrypt(plaintext.data(), &token_aead_, ciphertext, - ciphertextlen, key.data(), iv.data(), ivlen, - aad.data(), aadlen) != 0) { + auto rv = ngtcp2_crypto_decrypt(plaintext.data(), &token_aead_, &aead_ctx, + ciphertext, ciphertextlen, iv.data(), ivlen, + aad.data(), aadlen); + + ngtcp2_crypto_aead_ctx_free(&aead_ctx); + + if (rv != 0) { if (!config.quiet) { std::cerr << "Could not decrypt token" << std::endl; } @@ -2907,10 +2941,20 @@ int Server::generate_token(uint8_t *token, size_t &tokenlen, auto plaintextlen = std::distance(std::begin(plaintext), p); + ngtcp2_crypto_aead_ctx aead_ctx; + if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &token_aead_, key.data(), + ivlen) != 0) { + return -1; + } + token[0] = TOKEN_MAGIC; - if (ngtcp2_crypto_encrypt(token + 1, &token_aead_, plaintext.data(), - plaintextlen, key.data(), iv.data(), ivlen, - aad.data(), aadlen) != 0) { + auto rv = ngtcp2_crypto_encrypt(token + 1, &token_aead_, &aead_ctx, + plaintext.data(), plaintextlen, iv.data(), + ivlen, aad.data(), aadlen); + + ngtcp2_crypto_aead_ctx_free(&aead_ctx); + + if (rv != 0) { return -1; } @@ -2972,11 +3016,21 @@ int Server::verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa, return -1; } + ngtcp2_crypto_aead_ctx aead_ctx; + if (ngtcp2_crypto_aead_ctx_decrypt_init(&aead_ctx, &token_aead_, key.data(), + ivlen) != 0) { + return -1; + } + std::array<uint8_t, MAX_TOKENLEN> plaintext; - if (ngtcp2_crypto_decrypt(plaintext.data(), &token_aead_, ciphertext, - ciphertextlen, key.data(), iv.data(), ivlen, - aad.data(), aadlen) != 0) { + auto rv = ngtcp2_crypto_decrypt(plaintext.data(), &token_aead_, &aead_ctx, + ciphertext, ciphertextlen, iv.data(), ivlen, + aad.data(), aadlen); + + ngtcp2_crypto_aead_ctx_free(&aead_ctx); + + if (rv != 0) { if (!config.quiet) { std::cerr << "Could not decrypt token" << std::endl; } diff --git a/examples/server.h b/examples/server.h index 7aa9de3a..8b1dff95 100644 --- a/examples/server.h +++ b/examples/server.h @@ -268,8 +268,9 @@ public: void set_tls_alert(uint8_t alert); - int update_key(uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *rx_key, - uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv, + 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); diff --git a/lib/includes/ngtcp2/ngtcp2.h b/lib/includes/ngtcp2/ngtcp2.h index f6a4dbac..8e0cbcf1 100644 --- a/lib/includes/ngtcp2/ngtcp2.h +++ b/lib/includes/ngtcp2/ngtcp2.h @@ -190,6 +190,15 @@ typedef struct ngtcp2_mem { "\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97\x86\xf1\x9c\x61\x11\xe0\x43\x90" \ "\xa8\x99" +/* NGTCP2_RETRY_KEY is an encryption key to create integrity tag of + Retry packet. */ +#define NGTCP2_RETRY_KEY \ + "\xcc\xce\x18\x7e\xd0\x9a\x09\xd0\x57\x28\x15\x5a\x6c\xb9\x6b\xe1" + +/* NGTCP2_RETRY_NONCE is nonce used when generating integrity tag of + Retry packet. */ +#define NGTCP2_RETRY_NONCE "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c" + /* NGTCP2_HP_MASKLEN is the length of header protection mask. */ #define NGTCP2_HP_MASKLEN 5 @@ -805,6 +814,30 @@ typedef struct ngtcp2_crypto_cipher { void *native_handle; } ngtcp2_crypto_cipher; +/** + * @struct + * + * `ngtcp2_crypto_aead_ctx` is a wrapper around native AEAD cipher + * context object. It should be initialized with a specific key. + * ngtcp2 library reuses this context object to encrypt or decrypt + * multiple packets. + */ +typedef struct ngtcp2_crypto_aead_ctx { + void *native_handle; +} ngtcp2_crypto_aead_ctx; + +/** + * @struct + * + * `ngtcp2_crypto_cipher_ctx` is a wrapper around native cipher + * context object. It should be initialized with a specific key. + * ngtcp2 library reuses this context object to encrypt or decrypt + * multiple packet headers. + */ +typedef struct ngtcp2_crypto_cipher_ctx { + void *native_handle; +} ngtcp2_crypto_cipher_ctx; + /** * @function * @@ -1206,9 +1239,10 @@ typedef int (*ngtcp2_recv_retry)(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, * :type:`ngtcp2_encrypt` is invoked when the ngtcp2 library asks the * application to encrypt packet payload. The packet payload to * encrypt is passed as |plaintext| of length |plaintextlen|. The - * encryption key is passed as |key|. The nonce is passed as |nonce| - * of length |noncelen|. The ad, Additional Data to AEAD, is passed - * as |ad| of length |adlen|. + * AEAD cipher is |aead|. |aead_ctx| is the AEAD cipher context + * object which is initialized with encryption key. The nonce is + * passed as |nonce| of length |noncelen|. The ad, Additional Data to + * AEAD, is passed as |ad| of length |adlen|. * * The implementation of this callback must encrypt |plaintext| using * the negotiated cipher suite and write the ciphertext into the @@ -1222,9 +1256,10 @@ typedef int (*ngtcp2_recv_retry)(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, * return immediately. */ typedef int (*ngtcp2_encrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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); + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen); /** * @functypedef @@ -1232,7 +1267,8 @@ typedef int (*ngtcp2_encrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, * :type:`ngtcp2_decrypt` is invoked when the ngtcp2 library asks the * application to decrypt packet payload. The packet payload to * decrypt is passed as |ciphertext| of length |ciphertextlen|. The - * decryption key is passed as |key| of length |keylen|. The nonce is + * AEAD cipher is |aead|. |aead_ctx| is the AEAD cipher context + * object which is initialized with decryption key. The nonce is * passed as |nonce| of length |noncelen|. The ad, Additional Data to * AEAD, is passed as |ad| of length |adlen|. * @@ -1249,16 +1285,19 @@ typedef int (*ngtcp2_encrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, * makes the library call return immediately. */ typedef int (*ngtcp2_decrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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); + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen); /** * @functypedef * * :type:`ngtcp2_hp_mask` is invoked when the ngtcp2 library asks the * application to produce mask to encrypt or decrypt packet header. - * The key is passed as |hp_key|. The sample is passed as |sample|. + * The encryption cipher is |hp|. |hp_ctx| is the cipher context + * object which is initialized with header protection key. The sample + * is passed as |sample|. * * The implementation of this callback must produce a mask using the * header protection cipher suite specified by QUIC specification and @@ -1271,7 +1310,8 @@ typedef int (*ngtcp2_decrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, * return immediately. */ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key, const uint8_t *sample); + const ngtcp2_crypto_cipher_ctx *hp_ctx, + const uint8_t *sample); /** * @enum @@ -1506,28 +1546,31 @@ typedef int (*ngtcp2_remove_connection_id)(ngtcp2_conn *conn, * * :type:`ngtcp2_update_key` is a callback function which tells the * application that it must generate new packet protection keying - * materials. The current set of secrets are given as - * |current_rx_secret| and |current_tx_secret| of length |secretlen|. - * They are decryption and encryption secrets respectively. + * materials and AEAD cipher context objects with new keys. The + * current set of secrets are given as |current_rx_secret| and + * |current_tx_secret| of length |secretlen|. They are decryption and + * encryption secrets respectively. * * The application has to generate new secrets and keys for both - * encryption and decryption, and write decryption secret, key and IV - * to the buffer pointed by |rx_secret|, |rx_key| and |rx_iv| - * respectively. Similarly, write encryption secret, key and IV to - * the buffer pointed by |tx_secret|, |tx_key| and |tx_iv|. All given + * encryption and decryption, and write decryption secret and IV to + * the buffer pointed by |rx_secret| and |rx_iv| respectively. It + * also has to create new AEAD cipher context object with new + * decryption key and initialize |rx_aead_ctx| with it. Similarly, + * write encryption secret and IV to the buffer pointed by |tx_secret| + * and |tx_iv|. Create new AEAD cipher context object with new + * encryption key and initialize |tx_aead_ctx| with it. All given * buffers have the enough capacity to store secret, key and IV. * * The callback function must return 0 if it succeeds. Returning * :enum:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. */ -typedef int (*ngtcp2_update_key)(ngtcp2_conn *conn, uint8_t *rx_secret, - uint8_t *tx_secret, uint8_t *rx_key, - uint8_t *rx_iv, uint8_t *tx_key, - uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, - size_t secretlen, void *user_data); +typedef int (*ngtcp2_update_key)( + ngtcp2_conn *conn, 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, void *user_data); /** * @functypedef @@ -1614,6 +1657,26 @@ typedef int (*ngtcp2_connection_id_status)(ngtcp2_conn *conn, int type, typedef int (*ngtcp2_recv_new_token)(ngtcp2_conn *conn, const ngtcp2_vec *token, void *user_data); +/** + * @functypedef + * + * :type:`ngtcp2_delete_crypto_aead_ctx` is a callback function which + * must delete the native object pointed by |aead_ctx|->native_handle. + */ +typedef void (*ngtcp2_delete_crypto_aead_ctx)(ngtcp2_conn *conn, + ngtcp2_crypto_aead_ctx *aead_ctx, + void *user_data); + +/** + * @functypedef + * + * :type:`ngtcp2_delete_crypto_cipher_ctx` is a callback function + * which must delete the native object pointed by + * |cipher_ctx|->native_handle. + */ +typedef void (*ngtcp2_delete_crypto_cipher_ctx)( + ngtcp2_conn *conn, ngtcp2_crypto_cipher_ctx *cipher_ctx, void *user_data); + typedef struct ngtcp2_conn_callbacks { /** * client_initial is a callback function which is invoked when @@ -1800,6 +1863,16 @@ typedef struct ngtcp2_conn_callbacks { * token is received from server. This field is ignored by server. */ ngtcp2_recv_new_token recv_new_token; + /** + * delete_crypto_aead_ctx is a callback function which deletes a + * given AEAD cipher context object. + */ + ngtcp2_delete_crypto_aead_ctx delete_crypto_aead_ctx; + /** + * delete_crypto_cipher_ctx is a callback function which deletes a + * given cipher context object. + */ + ngtcp2_delete_crypto_cipher_ctx delete_crypto_cipher_ctx; } ngtcp2_conn_callbacks; /** @@ -1826,9 +1899,9 @@ typedef struct ngtcp2_conn_callbacks { NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_connection_close( uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid, uint64_t error_code, ngtcp2_encrypt encrypt, - const ngtcp2_crypto_aead *aead, const uint8_t *key, const uint8_t *iv, - ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key); + const ngtcp2_crypto_aead *aead, const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp, + const ngtcp2_crypto_cipher_ctx *hp_ctx); /** * @function @@ -1837,6 +1910,8 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_connection_close( * by |dest| whose length is |destlen|. |odcid| specifies Original * Destination Connection ID. |token| specifies Retry Token, and * |tokenlen| specifies its length. |aead| must be AEAD_AES_128_GCM. + * |aead_ctx| must be initialized with :macro:`NGTCP2_RETRY_KEY` as an + * encryption key. * * This function returns the number of bytes written to the buffer, or * one of the following negative error codes: @@ -1849,7 +1924,8 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_connection_close( NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_retry( uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid, const ngtcp2_cid *odcid, const uint8_t *token, - size_t tokenlen, ngtcp2_encrypt encrypt, const ngtcp2_crypto_aead *aead); + size_t tokenlen, ngtcp2_encrypt encrypt, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx); /** * @function @@ -1989,12 +2065,21 @@ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn); * @function * * `ngtcp2_conn_install_initial_key` installs packet protection keying - * materials for Initial packets. |rx_key| of length |keylen|, IV - * |rx_iv| of length |rx_ivlen|, and packet header protection key - * |rx_hp_key| of length |keylen| to decrypt incoming Initial packets. - * Similarly, |tx_key|, |tx_iv| and |tx_hp_key| are for encrypt - * outgoing packets and are the same length with the rx counterpart . - * If they have already been set, they are overwritten. + * materials for Initial packets. |rx_aead_ctx| is AEAD cipher + * context object and must be initialized with decryption key, IV + * |rx_iv| of length |rx_ivlen|, and packet header protection cipher + * context object |rx_hp_ctx| to decrypt incoming Initial packets. + * Similarly, |tx_aead_ctx|, |tx_iv| and |tx_hp_ctx| are for + * encrypting outgoing packets and are the same length with the + * decryption counterpart . If they have already been set, they are + * overwritten. + * + * If this function succeeds, |conn| takes ownership of |rx_aead_ctx|, + * |rx_hp_ctx|, |tx_aead_ctx|, and |tx_hp_ctx|. + * :type:`ngtcp2_delete_crypto_aead_ctx` and + * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete + * these objects when they are no longer used. If this function + * fails, the caller is responsible to delete them. * * After receiving Retry packet, the DCID most likely changes. In * that case, client application must generate these keying materials @@ -2007,49 +2092,62 @@ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn); * Out of memory. */ NGTCP2_EXTERN int ngtcp2_conn_install_initial_key( - ngtcp2_conn *conn, const uint8_t *rx_key, const uint8_t *rx_iv, - const uint8_t *rx_hp_key, const uint8_t *tx_key, const uint8_t *tx_iv, - const uint8_t *tx_hp_key, size_t keylen, size_t ivlen); + ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *rx_aead_ctx, + const uint8_t *rx_iv, const ngtcp2_crypto_cipher_ctx *rx_hp_ctx, + const ngtcp2_crypto_aead_ctx *tx_aead_ctx, const uint8_t *tx_iv, + const ngtcp2_crypto_cipher_ctx *tx_hp_ctx, size_t ivlen); /** * @function * * `ngtcp2_conn_install_rx_handshake_key` installs packet protection - * keying materials for decrypting incoming Handshake packets. |key| - * of length |keylen|, IV |iv| of length |ivlen|, and packet header - * protection key |hp_key| of length |keylen| to decrypt incoming + * keying materials for decrypting incoming Handshake packets. + * |aead_ctx| is AEAD cipher context object which must be initialized + * with decryption key, IV |iv| of length |ivlen|, and packet header + * protection cipher context object |hp_ctx| to decrypt incoming * Handshake packets. * + * If this function succeeds, |conn| takes ownership of |aead_ctx|, + * and |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and + * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete + * these objects when they are no longer used. If this function + * fails, the caller is responsible to delete them. + * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :enum:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int -ngtcp2_conn_install_rx_handshake_key(ngtcp2_conn *conn, const uint8_t *key, - const uint8_t *iv, const uint8_t *hp_key, - size_t keylen, size_t ivlen); +NGTCP2_EXTERN int ngtcp2_conn_install_rx_handshake_key( + ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx); /** * @function * * `ngtcp2_conn_install_tx_handshake_key` installs packet protection - * keying materials for encrypting outgoing Handshake packets. |key| - * of length |keylen|, IV |iv| of length |ivlen|, and packet header - * protection key |hp_key| of length |keylen| to encrypt outgoing + * keying materials for encrypting outgoing Handshake packets. + * |aead_ctx| is AEAD cipher context object which must be initialized + * with encryption key, IV |iv| of length |ivlen|, and packet header + * protection cipher context object |hp_ctx| to encrypt outgoing * Handshake packets. * + * If this function succeeds, |conn| takes ownership of |aead_ctx| and + * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and + * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete + * these objects when they are no longer used. If this function + * fails, the caller is responsible to delete them. + * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :enum:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int -ngtcp2_conn_install_tx_handshake_key(ngtcp2_conn *conn, const uint8_t *key, - const uint8_t *iv, const uint8_t *hp_key, - size_t keylen, size_t ivlen); +NGTCP2_EXTERN int ngtcp2_conn_install_tx_handshake_key( + ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx); /** * @function @@ -2074,10 +2172,16 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_aead_overhead(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_install_early_key` installs packet protection key - * |key| of length |keylen|, IV |iv| of length |ivlen|, and packet - * header protection key |hp_key| of length |keylen| to encrypt (for - * client)or decrypt (for server) 0RTT packets. + * `ngtcp2_conn_install_early_key` installs packet protection AEAD + * cipher context object |aead_ctx|, IV |iv| of length |ivlen|, and + * packet header protection cipher context object |hp_ctx| to encrypt + * (for client) or decrypt (for server) 0RTT packets. + * + * If this function succeeds, |conn| takes ownership of |aead_ctx| and + * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and + * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete + * these objects when they are no longer used. If this function + * fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -2085,11 +2189,9 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_aead_overhead(ngtcp2_conn *conn); * :enum:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, - const uint8_t *key, - const uint8_t *iv, - const uint8_t *hp_key, - size_t keylen, size_t ivlen); +NGTCP2_EXTERN int ngtcp2_conn_install_early_key( + ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx); /** * @function @@ -2097,9 +2199,16 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, * `ngtcp2_conn_install_rx_key` installs packet protection keying * materials for decrypting Short packets. |secret| of length * |secretlen| is the decryption secret which is used to derive keying - * materials passed to this function. |key| of length |keylen|, IV - * |iv| of length |ivlen|, and packet header protection key |hp_key| - * of length |keylen| to decrypt incoming Short packets. + * materials passed to this function. |aead_ctx| is AEAD cipher + * context object which must be initialized with decryption key, IV + * |iv| of length |ivlen|, and packet header protection cipher context + * object |hp_ctx| to decrypt incoming Short packets. + * + * If this function succeeds, |conn| takes ownership of |aead_ctx| and + * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and + * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete + * these objects when they are no longer used. If this function + * fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -2107,11 +2216,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, * :enum:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int -ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret, - const uint8_t *key, const uint8_t *iv, - const uint8_t *hp_key, size_t secretlen, - size_t keylen, size_t ivlen); +NGTCP2_EXTERN int ngtcp2_conn_install_rx_key( + ngtcp2_conn *conn, const uint8_t *secret, size_t secretlen, + const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv, size_t ivlen, + const ngtcp2_crypto_cipher_ctx *hp_ctx); /** * @function @@ -2119,9 +2227,16 @@ ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret, * `ngtcp2_conn_install_tx_key` installs packet protection keying * materials for encrypting Short packets. |secret| of length * |secretlen| is the encryption secret which is used to derive keying - * materials passed to this function. |key| of length |keylen|, IV - * |iv| of length |ivlen|, and packet header protection key |hp_key| - * of length |keylen| to encrypt outgoing Short packets. + * materials passed to this function. |aead_ctx| is AEAD cipher + * context object which must be initialized with encryption key, IV + * |iv| of length |ivlen|, and packet header protection cipher context + * object |hp_ctx| to encrypt outgoing Short packets. + * + * If this function succeeds, |conn| takes ownership of |aead_ctx| and + * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and + * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete + * these objects when they are no longer used. If this function + * fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -2129,11 +2244,10 @@ ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret, * :enum:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int -ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, - const uint8_t *key, const uint8_t *iv, - const uint8_t *hp_key, size_t secretlen, - size_t keylen, size_t ivlen); +NGTCP2_EXTERN int ngtcp2_conn_install_tx_key( + ngtcp2_conn *conn, const uint8_t *secret, size_t secretlen, + const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv, size_t ivlen, + const ngtcp2_crypto_cipher_ctx *hp_ctx); /** * @function @@ -2980,13 +3094,21 @@ NGTCP2_EXTERN void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn, /** * @function * - * `ngtcp2_conn_set_retry_aead` sets |aead| for Retry integrity tag - * verification. It must be AEAD_AES_128_GCM. This function must be - * called if |conn| is initialized as client. Server does not verify - * the tag and has no need to call this function. + * `ngtcp2_conn_set_retry_aead` sets |aead| and |aead_ctx| for Retry + * integrity tag verification. |aead| must be AEAD_AES_128_GCM. + * |aead_ctx| must be initialized with :macro:`NGTCP2_RETRY_KEY` as + * encryption key. This function must be called if |conn| is + * initialized as client. Server does not verify the tag and has no + * need to call this function. + * + * If this function succeeds, |conn| takes ownership of |aead_ctx|. + * :type:`ngtcp2_delete_crypto_aead_ctx` will be called to delete this + * object when it is no longer used. If this function fails, the + * caller is responsible to delete it. */ -NGTCP2_EXTERN void ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn, - const ngtcp2_crypto_aead *aead); +NGTCP2_EXTERN void +ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx); /** * @function @@ -3039,6 +3161,14 @@ NGTCP2_EXTERN int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, */ NGTCP2_EXTERN int ngtcp2_conn_is_server(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_after_retry` returns nonzero if |conn| as a client has + * received Retry packet from server and successfully validated it. + */ +NGTCP2_EXTERN int ngtcp2_conn_after_retry(ngtcp2_conn *conn); + /** * @function * diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c index 3b189655..e8f56210 100644 --- a/lib/ngtcp2_conn.c +++ b/lib/ngtcp2_conn.c @@ -359,6 +359,29 @@ static int conn_call_deactivate_dcid(ngtcp2_conn *conn, conn, NGTCP2_CONNECTION_ID_STATUS_TYPE_DEACTIVATE, dcid); } +static void conn_call_delete_crypto_aead_ctx(ngtcp2_conn *conn, + ngtcp2_crypto_aead_ctx *aead_ctx) { + if (!aead_ctx->native_handle) { + return; + } + + assert(conn->callbacks.delete_crypto_aead_ctx); + + conn->callbacks.delete_crypto_aead_ctx(conn, aead_ctx, conn->user_data); +} + +static void +conn_call_delete_crypto_cipher_ctx(ngtcp2_conn *conn, + ngtcp2_crypto_cipher_ctx *cipher_ctx) { + if (!cipher_ctx->native_handle) { + return; + } + + assert(conn->callbacks.delete_crypto_cipher_ctx); + + conn->callbacks.delete_crypto_cipher_ctx(conn, cipher_ctx, conn->user_data); +} + static int crypto_offset_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { return *(int64_t *)lhs < *(int64_t *)rhs; @@ -458,9 +481,6 @@ static void pktns_free(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) { ngtcp2_frame_chain_list_del(pktns->tx.frq, mem); - ngtcp2_vec_del(pktns->crypto.rx.hp_key, mem); - ngtcp2_vec_del(pktns->crypto.tx.hp_key, mem); - ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, mem); ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, mem); @@ -944,13 +964,71 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { ngtcp2_qlog_end(&conn->qlog); + if (conn->early.ckm) { + conn_call_delete_crypto_aead_ctx(conn, &conn->early.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->early.hp_ctx); + + if (conn->crypto.key_update.old_rx_ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->crypto.key_update.old_rx_ckm->aead_ctx); + } + if (conn->crypto.key_update.new_rx_ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->crypto.key_update.new_rx_ckm->aead_ctx); + } + if (conn->crypto.key_update.new_tx_ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->crypto.key_update.new_tx_ckm->aead_ctx); + } + + if (conn->pktns.crypto.rx.ckm) { + conn_call_delete_crypto_aead_ctx(conn, + &conn->pktns.crypto.rx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->pktns.crypto.rx.hp_ctx); + + if (conn->pktns.crypto.tx.ckm) { + conn_call_delete_crypto_aead_ctx(conn, + &conn->pktns.crypto.tx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->pktns.crypto.tx.hp_ctx); + + if (conn->hs_pktns) { + if (conn->hs_pktns->crypto.rx.ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->hs_pktns->crypto.rx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->hs_pktns->crypto.rx.hp_ctx); + + if (conn->hs_pktns->crypto.tx.ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->hs_pktns->crypto.tx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->hs_pktns->crypto.tx.hp_ctx); + } + if (conn->in_pktns) { + if (conn->in_pktns->crypto.rx.ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->in_pktns->crypto.rx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->in_pktns->crypto.rx.hp_ctx); + + if (conn->in_pktns->crypto.tx.ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->in_pktns->crypto.tx.ckm->aead_ctx); + } + conn_call_delete_crypto_cipher_ctx(conn, &conn->in_pktns->crypto.tx.hp_ctx); + } + + conn_call_delete_crypto_aead_ctx(conn, &conn->crypto.retry_aead_ctx); + ngtcp2_mem_free(conn->mem, conn->crypto.decrypt_buf.base); ngtcp2_mem_free(conn->mem, conn->local.settings.token.base); ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem); ngtcp2_crypto_km_del(conn->crypto.key_update.new_rx_ckm, conn->mem); ngtcp2_crypto_km_del(conn->crypto.key_update.new_tx_ckm, conn->mem); - ngtcp2_vec_del(conn->early.hp_key, conn->mem); ngtcp2_crypto_km_del(conn->early.ckm, conn->mem); pktns_free(&conn->pktns, conn->mem); @@ -1771,7 +1849,7 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, cc.aead = pktns->crypto.ctx.aead; cc.hp = pktns->crypto.ctx.hp; cc.ckm = pktns->crypto.tx.ckm; - cc.hp_key = pktns->crypto.tx.hp_key; + cc.hp_ctx = pktns->crypto.tx.hp_ctx; cc.encrypt = conn->callbacks.encrypt; cc.hp_mask = conn->callbacks.hp_mask; @@ -2034,6 +2112,11 @@ static void conn_discard_pktns(ngtcp2_conn *conn, ngtcp2_pktns **ppktns, conn->cstat.last_tx_pkt_ts[pktns->rtb.pktns_id] = UINT64_MAX; conn->cstat.loss_time[pktns->rtb.pktns_id] = UINT64_MAX; + conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.rx.ckm->aead_ctx); + conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.rx.hp_ctx); + conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx); + conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.tx.hp_ctx); + pktns_del(pktns, conn->mem); *ppktns = NULL; @@ -2523,7 +2606,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, ? NGTCP2_PKT_FLAG_KEY_PHASE : NGTCP2_PKT_FLAG_NONE; cc->ckm = pktns->crypto.tx.ckm; - cc->hp_key = pktns->crypto.tx.hp_key; + cc->hp_ctx = pktns->crypto.tx.hp_ctx; /* transport parameter is only valid after handshake completion which means we don't know how many connection ID that remote @@ -2544,7 +2627,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, } hd_flags = NGTCP2_PKT_FLAG_LONG_FORM; cc->ckm = conn->early.ckm; - cc->hp_key = conn->early.hp_key; + cc->hp_ctx = conn->early.hp_ctx; break; default: /* Unreachable */ @@ -3139,7 +3222,7 @@ ngtcp2_conn_write_single_frame_pkt(ngtcp2_conn *conn, uint8_t *dest, cc.aead = pktns->crypto.ctx.aead; cc.hp = pktns->crypto.ctx.hp; cc.ckm = pktns->crypto.tx.ckm; - cc.hp_key = pktns->crypto.tx.hp_key; + cc.hp_ctx = pktns->crypto.tx.hp_ctx; cc.encrypt = conn->callbacks.encrypt; cc.hp_mask = conn->callbacks.hp_mask; @@ -3671,7 +3754,8 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, retry.odcid = conn->dcid.current.cid; rv = ngtcp2_pkt_verify_retry_tag(&retry, pkt, pktlen, conn->callbacks.encrypt, - &conn->crypto.retry_aead); + &conn->crypto.retry_aead, + &conn->crypto.retry_aead_ctx); if (rv != 0) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "unable to verify Retry packet integrity"); @@ -4032,7 +4116,7 @@ static ngtcp2_ssize decrypt_pkt(uint8_t *dest, const ngtcp2_crypto_aead *aead, ngtcp2_crypto_create_nonce(nonce, ckm->iv.base, ckm->iv.len, pkt_num); - rv = decrypt(dest, aead, payload, payloadlen, ckm->key.base, nonce, + rv = decrypt(dest, aead, &ckm->aead_ctx, payload, payloadlen, nonce, ckm->iv.len, ad, adlen); if (rv != 0) { @@ -4066,7 +4150,7 @@ static ngtcp2_ssize decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, size_t destlen, const ngtcp2_crypto_cipher *hp, const uint8_t *pkt, size_t pktlen, size_t pkt_num_offset, ngtcp2_crypto_km *ckm, - const ngtcp2_vec *hp_key, + const ngtcp2_crypto_cipher_ctx *hp_ctx, ngtcp2_hp_mask hp_mask) { size_t sample_offset; uint8_t *p = dest; @@ -4086,7 +4170,7 @@ static ngtcp2_ssize decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, size_t destlen, sample_offset = pkt_num_offset + 4; - rv = hp_mask(mask, hp, hp_key->base, pkt + sample_offset); + rv = hp_mask(mask, hp, hp_ctx, pkt + sample_offset); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -4355,7 +4439,7 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn, ngtcp2_crypto_aead *aead; ngtcp2_crypto_cipher *hp; ngtcp2_crypto_km *ckm; - const ngtcp2_vec *hp_key; + ngtcp2_crypto_cipher_ctx *hp_ctx; ngtcp2_hp_mask hp_mask; ngtcp2_decrypt decrypt; size_t aead_overhead; @@ -4584,14 +4668,14 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn, aead = &pktns->crypto.ctx.aead; hp = &pktns->crypto.ctx.hp; ckm = pktns->crypto.rx.ckm; - hp_key = pktns->crypto.rx.hp_key; + hp_ctx = &pktns->crypto.rx.hp_ctx; assert(ckm); assert(hp_mask); assert(decrypt); nwrite = decrypt_hp(&hd, plain_hdpkt, sizeof(plain_hdpkt), hp, pkt, pktlen, - (size_t)nread, ckm, hp_key, hp_mask); + (size_t)nread, ckm, hp_ctx, hp_mask); if (nwrite < 0) { if (ngtcp2_err_is_fatal((int)nwrite)) { return nwrite; @@ -6212,7 +6296,8 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_crypto_km *rx_ckm = pktns->crypto.rx.ckm; ngtcp2_crypto_km *tx_ckm = pktns->crypto.tx.ckm; ngtcp2_crypto_km *new_rx_ckm, *new_tx_ckm; - size_t secretlen, keylen, ivlen; + ngtcp2_crypto_aead_ctx rx_aead_ctx = {0}, tx_aead_ctx = {0}; + size_t secretlen, ivlen; if ((conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) && (tx_ckm->use_count >= pktns->crypto.ctx.max_encryption || @@ -6233,17 +6318,16 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { } secretlen = rx_ckm->secret.len; - keylen = rx_ckm->key.len; ivlen = rx_ckm->iv.len; rv = ngtcp2_crypto_km_nocopy_new(&conn->crypto.key_update.new_rx_ckm, - secretlen, keylen, ivlen, conn->mem); + secretlen, ivlen, conn->mem); if (rv != 0) { return rv; } rv = ngtcp2_crypto_km_nocopy_new(&conn->crypto.key_update.new_tx_ckm, - secretlen, keylen, ivlen, conn->mem); + secretlen, ivlen, conn->mem); if (rv != 0) { return rv; } @@ -6254,21 +6338,27 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { assert(conn->callbacks.update_key); rv = conn->callbacks.update_key( - conn, new_rx_ckm->secret.base, new_tx_ckm->secret.base, - new_rx_ckm->key.base, new_rx_ckm->iv.base, new_tx_ckm->key.base, - new_tx_ckm->iv.base, rx_ckm->secret.base, tx_ckm->secret.base, secretlen, - conn->user_data); + conn, new_rx_ckm->secret.base, new_tx_ckm->secret.base, &rx_aead_ctx, + new_rx_ckm->iv.base, &tx_aead_ctx, new_tx_ckm->iv.base, + rx_ckm->secret.base, tx_ckm->secret.base, secretlen, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } + new_rx_ckm->aead_ctx = rx_aead_ctx; + new_tx_ckm->aead_ctx = tx_aead_ctx; + if (!(rx_ckm->flags & NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE)) { new_rx_ckm->flags |= NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE; new_tx_ckm->flags |= NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE; } - ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem); - conn->crypto.key_update.old_rx_ckm = NULL; + if (conn->crypto.key_update.old_rx_ckm) { + conn_call_delete_crypto_aead_ctx( + conn, &conn->crypto.key_update.old_rx_ckm->aead_ctx); + ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem); + conn->crypto.key_update.old_rx_ckm = NULL; + } return 0; } @@ -6291,7 +6381,11 @@ static void conn_rotate_keys(ngtcp2_conn *conn, int64_t pkt_num) { conn->crypto.key_update.new_rx_ckm = NULL; pktns->crypto.rx.ckm->pkt_num = pkt_num; + assert(pktns->crypto.tx.ckm); + + conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx); ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem); + pktns->crypto.tx.ckm = conn->crypto.key_update.new_tx_ckm; conn->crypto.key_update.new_tx_ckm = NULL; pktns->crypto.tx.ckm->pkt_num = pktns->tx.last_pkt_num + 1; @@ -6586,7 +6680,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_crypto_aead *aead; ngtcp2_crypto_cipher *hp; ngtcp2_crypto_km *ckm; - const ngtcp2_vec *hp_key; + ngtcp2_crypto_cipher_ctx *hp_ctx; uint8_t plain_hdpkt[1500]; ngtcp2_hp_mask hp_mask; ngtcp2_decrypt decrypt; @@ -6635,7 +6729,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, pktns = conn->hs_pktns; ckm = pktns->crypto.rx.ckm; - hp_key = pktns->crypto.rx.hp_key; + hp_ctx = &pktns->crypto.rx.hp_ctx; hp_mask = conn->callbacks.hp_mask; decrypt = conn->callbacks.decrypt; aead_overhead = conn->crypto.aead_overhead; @@ -6647,7 +6741,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, pktns = &conn->pktns; ckm = conn->early.ckm; - hp_key = conn->early.hp_key; + hp_ctx = &conn->early.hp_ctx; hp_mask = conn->callbacks.hp_mask; decrypt = conn->callbacks.decrypt; aead_overhead = conn->crypto.aead_overhead; @@ -6668,7 +6762,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, pktns = &conn->pktns; ckm = pktns->crypto.rx.ckm; - hp_key = pktns->crypto.rx.hp_key; + hp_ctx = &pktns->crypto.rx.hp_ctx; hp_mask = conn->callbacks.hp_mask; decrypt = conn->callbacks.decrypt; aead_overhead = conn->crypto.aead_overhead; @@ -6678,7 +6772,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, hp = &pktns->crypto.ctx.hp; nwrite = decrypt_hp(&hd, plain_hdpkt, sizeof(plain_hdpkt), hp, pkt, pktlen, - (size_t)nread, ckm, hp_key, hp_mask); + (size_t)nread, ckm, hp_ctx, hp_mask); if (nwrite < 0) { if (ngtcp2_err_is_fatal((int)nwrite)) { return nwrite; @@ -7990,155 +8084,158 @@ size_t ngtcp2_conn_get_aead_overhead(ngtcp2_conn *conn) { return conn->crypto.aead_overhead; } -int ngtcp2_conn_install_initial_key(ngtcp2_conn *conn, const uint8_t *rx_key, - const uint8_t *rx_iv, - const uint8_t *rx_hp_key, - const uint8_t *tx_key, const uint8_t *tx_iv, - const uint8_t *tx_hp_key, size_t keylen, - size_t ivlen) { +int ngtcp2_conn_install_initial_key( + ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *rx_aead_ctx, + const uint8_t *rx_iv, const ngtcp2_crypto_cipher_ctx *rx_hp_ctx, + const ngtcp2_crypto_aead_ctx *tx_aead_ctx, const uint8_t *tx_iv, + const ngtcp2_crypto_cipher_ctx *tx_hp_ctx, size_t ivlen) { ngtcp2_pktns *pktns = conn->in_pktns; int rv; assert(pktns); - if (pktns->crypto.rx.hp_key) { - ngtcp2_vec_del(pktns->crypto.rx.hp_key, conn->mem); - pktns->crypto.rx.hp_key = NULL; - } + conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.rx.hp_ctx); + pktns->crypto.rx.hp_ctx.native_handle = NULL; + if (pktns->crypto.rx.ckm) { + conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.rx.ckm->aead_ctx); ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem); pktns->crypto.rx.ckm = NULL; } - if (pktns->crypto.tx.hp_key) { - ngtcp2_vec_del(pktns->crypto.tx.hp_key, conn->mem); - pktns->crypto.tx.hp_key = NULL; - } + + conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.tx.hp_ctx); + pktns->crypto.tx.hp_ctx.native_handle = NULL; + if (pktns->crypto.tx.ckm) { + conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx); ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem); pktns->crypto.tx.ckm = NULL; } - rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, rx_key, keylen, - rx_iv, ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, NULL, rx_iv, ivlen, + conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_vec_new(&pktns->crypto.rx.hp_key, rx_hp_key, keylen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, NULL, tx_iv, ivlen, + conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, tx_key, keylen, - tx_iv, ivlen, conn->mem); - if (rv != 0) { - return rv; - } + /* Take owner ship after we are sure that no failure occurs, so that + caller can delete these contexts on failure. */ + pktns->crypto.rx.ckm->aead_ctx = *rx_aead_ctx; + pktns->crypto.rx.hp_ctx = *rx_hp_ctx; + pktns->crypto.tx.ckm->aead_ctx = *tx_aead_ctx; + pktns->crypto.tx.hp_ctx = *tx_hp_ctx; - return ngtcp2_vec_new(&pktns->crypto.tx.hp_key, tx_hp_key, keylen, conn->mem); + return 0; } -int ngtcp2_conn_install_rx_handshake_key(ngtcp2_conn *conn, const uint8_t *key, - const uint8_t *iv, - const uint8_t *hp_key, size_t keylen, - size_t ivlen) { +int ngtcp2_conn_install_rx_handshake_key( + ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx) { ngtcp2_pktns *pktns = conn->hs_pktns; int rv; assert(pktns); - assert(!pktns->crypto.rx.hp_key); + assert(!pktns->crypto.rx.hp_ctx.native_handle); assert(!pktns->crypto.rx.ckm); - rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, key, keylen, iv, - ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, aead_ctx, iv, ivlen, + conn->mem); if (rv != 0) { return rv; } - return ngtcp2_vec_new(&pktns->crypto.rx.hp_key, hp_key, keylen, conn->mem); + pktns->crypto.rx.hp_ctx = *hp_ctx; + + return 0; } -int ngtcp2_conn_install_tx_handshake_key(ngtcp2_conn *conn, const uint8_t *key, - const uint8_t *iv, - const uint8_t *hp_key, size_t keylen, - size_t ivlen) { +int ngtcp2_conn_install_tx_handshake_key( + ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx) { ngtcp2_pktns *pktns = conn->hs_pktns; int rv; assert(pktns); - assert(!pktns->crypto.tx.hp_key); + assert(!pktns->crypto.tx.hp_ctx.native_handle); assert(!pktns->crypto.tx.ckm); - rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, key, keylen, iv, - ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, aead_ctx, iv, ivlen, + conn->mem); if (rv != 0) { return rv; } - return ngtcp2_vec_new(&pktns->crypto.tx.hp_key, hp_key, keylen, conn->mem); + pktns->crypto.tx.hp_ctx = *hp_ctx; + + return 0; } -int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, const uint8_t *key, - const uint8_t *iv, const uint8_t *hp_key, - size_t keylen, size_t ivlen) { +int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, + const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, + const ngtcp2_crypto_cipher_ctx *hp_ctx) { int rv; - assert(!conn->early.hp_key); + assert(!conn->early.hp_ctx.native_handle); assert(!conn->early.ckm); - rv = ngtcp2_crypto_km_new(&conn->early.ckm, NULL, 0, key, keylen, iv, ivlen, + rv = ngtcp2_crypto_km_new(&conn->early.ckm, NULL, 0, aead_ctx, iv, ivlen, conn->mem); if (rv != 0) { return rv; } - return ngtcp2_vec_new(&conn->early.hp_key, hp_key, keylen, conn->mem); + conn->early.hp_ctx = *hp_ctx; + + return 0; } int ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret, - const uint8_t *key, const uint8_t *iv, - const uint8_t *hp_key, size_t secretlen, - size_t keylen, size_t ivlen) { + size_t secretlen, + const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, + const ngtcp2_crypto_cipher_ctx *hp_ctx) { ngtcp2_pktns *pktns = &conn->pktns; int rv; - assert(!pktns->crypto.rx.hp_key); + assert(!pktns->crypto.rx.hp_ctx.native_handle); assert(!pktns->crypto.rx.ckm); - rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, secret, secretlen, key, - keylen, iv, ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, secret, secretlen, aead_ctx, + iv, ivlen, conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_vec_new(&pktns->crypto.rx.hp_key, hp_key, keylen, conn->mem); - if (rv != 0) { - return rv; - } + pktns->crypto.rx.hp_ctx = *hp_ctx; return 0; } int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, - const uint8_t *key, const uint8_t *iv, - const uint8_t *hp_key, size_t secretlen, - size_t keylen, size_t ivlen) { + size_t secretlen, + const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, + const ngtcp2_crypto_cipher_ctx *hp_ctx) { ngtcp2_pktns *pktns = &conn->pktns; int rv; - assert(!pktns->crypto.tx.hp_key); + assert(!pktns->crypto.tx.hp_ctx.native_handle); assert(!pktns->crypto.tx.ckm); - rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, secret, secretlen, key, - keylen, iv, ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, secret, secretlen, aead_ctx, + iv, ivlen, conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_vec_new(&pktns->crypto.tx.hp_key, hp_key, keylen, conn->mem); - if (rv != 0) { - return rv; - } + pktns->crypto.tx.hp_ctx = *hp_ctx; conn->remote.transport_params = conn->remote.pending_transport_params; conn_sync_stream_id_limit(conn); @@ -9642,8 +9739,12 @@ const ngtcp2_crypto_ctx *ngtcp2_conn_get_initial_crypto_ctx(ngtcp2_conn *conn) { } void ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn, - const ngtcp2_crypto_aead *aead) { + const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx) { + assert(!conn->crypto.retry_aead_ctx.native_handle); + conn->crypto.retry_aead = *aead; + conn->crypto.retry_aead_ctx = *aead_ctx; } void ngtcp2_conn_set_crypto_ctx(ngtcp2_conn *conn, @@ -9685,6 +9786,10 @@ int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, int64_t stream_id) { int ngtcp2_conn_is_server(ngtcp2_conn *conn) { return conn->server; } +int ngtcp2_conn_after_retry(ngtcp2_conn *conn) { + return (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) != 0; +} + void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, const uint8_t *data) { memcpy(pcent->data, data, sizeof(pcent->data)); @@ -9710,13 +9815,12 @@ void ngtcp2_settings_default(ngtcp2_settings *settings) { ngtcp2_ssize ngtcp2_pkt_write_connection_close( uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid, uint64_t error_code, ngtcp2_encrypt encrypt, - const ngtcp2_crypto_aead *aead, const uint8_t *key, const uint8_t *iv, - ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key) { + const ngtcp2_crypto_aead *aead, const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp, + const ngtcp2_crypto_cipher_ctx *hp_ctx) { ngtcp2_pkt_hd hd; ngtcp2_crypto_km ckm; ngtcp2_crypto_cc cc; - ngtcp2_vec hp_key_vec; ngtcp2_ppe ppe; ngtcp2_frame fr = {0}; int rv; @@ -9726,9 +9830,8 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close( NGTCP2_PROTO_VER, /* len = */ 0); ngtcp2_vec_init(&ckm.secret, NULL, 0); - ngtcp2_vec_init(&ckm.key, key, 16); ngtcp2_vec_init(&ckm.iv, iv, 12); - ngtcp2_vec_init(&hp_key_vec, hp_key, 16); + ckm.aead_ctx = *aead_ctx; ckm.pkt_num = 0; ckm.flags = NGTCP2_CRYPTO_KM_FLAG_NONE; @@ -9736,7 +9839,7 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close( cc.aead = *aead; cc.hp = *hp; cc.ckm = &ckm; - cc.hp_key = &hp_key_vec; + cc.hp_ctx = *hp_ctx; cc.encrypt = encrypt; cc.hp_mask = hp_mask; diff --git a/lib/ngtcp2_conn.h b/lib/ngtcp2_conn.h index 4b32e19b..0271e230 100644 --- a/lib/ngtcp2_conn.h +++ b/lib/ngtcp2_conn.h @@ -236,16 +236,16 @@ typedef struct { /* ckm is a cryptographic key, and iv to encrypt outgoing packets. */ ngtcp2_crypto_km *ckm; - /* hp_key is header protection key. */ - ngtcp2_vec *hp_key; + /* hp_ctx is cipher context for packet header protection. */ + ngtcp2_crypto_cipher_ctx hp_ctx; } tx; struct { /* ckm is a cryptographic key, and iv to decrypt incoming packets. */ ngtcp2_crypto_km *ckm; - /* hp_key is header protection key. */ - ngtcp2_vec *hp_key; + /* hp_ctx is cipher context for packet header protection. */ + ngtcp2_crypto_cipher_ctx hp_ctx; } rx; ngtcp2_strm strm; @@ -355,7 +355,7 @@ struct ngtcp2_conn { struct { ngtcp2_crypto_km *ckm; - ngtcp2_vec *hp_key; + ngtcp2_crypto_cipher_ctx hp_ctx; } early; struct { @@ -435,8 +435,12 @@ struct ngtcp2_conn { size_t aead_overhead; /* decrypt_buf is a buffer which is used to write decrypted data. */ ngtcp2_vec decrypt_buf; - /* retry_aead is AEAD to verify Retry packet integrity. */ + /* retry_aead is AEAD to verify Retry packet integrity. It is + used by client only. */ ngtcp2_crypto_aead retry_aead; + /* retry_aead_ctx is AEAD cipher context to verify Retry packet + integrity. It is used by client only. */ + ngtcp2_crypto_aead_ctx retry_aead_ctx; /* tls_error is TLS related error. */ int tls_error; } crypto; diff --git a/lib/ngtcp2_crypto.c b/lib/ngtcp2_crypto.c index 26eacb87..5cfe145e 100644 --- a/lib/ngtcp2_crypto.c +++ b/lib/ngtcp2_crypto.c @@ -32,10 +32,11 @@ #include "ngtcp2_conn.h" int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret, - size_t secretlen, const uint8_t *key, size_t keylen, + size_t secretlen, + const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv, size_t ivlen, const ngtcp2_mem *mem) { - int rv = ngtcp2_crypto_km_nocopy_new(pckm, secretlen, keylen, ivlen, mem); + int rv = ngtcp2_crypto_km_nocopy_new(pckm, secretlen, ivlen, mem); if (rv != 0) { return rv; } @@ -43,19 +44,20 @@ int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret, if (secretlen) { memcpy((*pckm)->secret.base, secret, secretlen); } - memcpy((*pckm)->key.base, key, keylen); + if (aead_ctx) { + (*pckm)->aead_ctx = *aead_ctx; + } memcpy((*pckm)->iv.base, iv, ivlen); return 0; } int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen, - size_t keylen, size_t ivlen, - const ngtcp2_mem *mem) { + size_t ivlen, const ngtcp2_mem *mem) { size_t len; uint8_t *p; - len = sizeof(ngtcp2_crypto_km) + secretlen + keylen + ivlen; + len = sizeof(ngtcp2_crypto_km) + secretlen + ivlen; *pckm = ngtcp2_mem_malloc(mem, len); if (*pckm == NULL) { @@ -66,11 +68,9 @@ int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen, (*pckm)->secret.base = p; (*pckm)->secret.len = secretlen; p += secretlen; - (*pckm)->key.base = p; - (*pckm)->key.len = keylen; - p += keylen; (*pckm)->iv.base = p; (*pckm)->iv.len = ivlen; + (*pckm)->aead_ctx.native_handle = NULL; (*pckm)->pkt_num = -1; (*pckm)->use_count = 0; (*pckm)->flags = NGTCP2_CRYPTO_KM_FLAG_NONE; diff --git a/lib/ngtcp2_crypto.h b/lib/ngtcp2_crypto.h index 1cc144e8..b1baf30a 100644 --- a/lib/ngtcp2_crypto.h +++ b/lib/ngtcp2_crypto.h @@ -50,7 +50,7 @@ typedef enum { typedef struct { ngtcp2_vec secret; - ngtcp2_vec key; + ngtcp2_crypto_aead_ctx aead_ctx; ngtcp2_vec iv; /* pkt_num is a packet number of a packet which uses this keying material. For encryption key, it is the lowest packet number of @@ -75,7 +75,8 @@ typedef struct { * store secret is update keys. Only 1RTT key can be updated. */ int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret, - size_t secretlen, const uint8_t *key, size_t keylen, + size_t secretlen, + const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv, size_t ivlen, const ngtcp2_mem *mem); @@ -84,8 +85,7 @@ int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret, * it does not copy secret, key and IV. */ int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen, - size_t keylen, size_t ivlen, - const ngtcp2_mem *mem); + size_t ivlen, const ngtcp2_mem *mem); void ngtcp2_crypto_km_del(ngtcp2_crypto_km *ckm, const ngtcp2_mem *mem); @@ -93,7 +93,7 @@ typedef struct { ngtcp2_crypto_aead aead; ngtcp2_crypto_cipher hp; ngtcp2_crypto_km *ckm; - const ngtcp2_vec *hp_key; + ngtcp2_crypto_cipher_ctx hp_ctx; size_t aead_overhead; ngtcp2_encrypt encrypt; ngtcp2_decrypt decrypt; diff --git a/lib/ngtcp2_pkt.c b/lib/ngtcp2_pkt.c index fb9ce8fb..e2d4371e 100644 --- a/lib/ngtcp2_pkt.c +++ b/lib/ngtcp2_pkt.c @@ -2066,16 +2066,12 @@ ngtcp2_pkt_write_stateless_reset(uint8_t *dest, size_t destlen, return p - dest; } -static const uint8_t retry_key[] = - "\xcc\xce\x18\x7e\xd0\x9a\x09\xd0\x57\x28\x15\x5a\x6c\xb9\x6b\xe1"; -static const uint8_t retry_nonce[] = - "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c"; - ngtcp2_ssize ngtcp2_pkt_write_retry(uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid, const ngtcp2_cid *odcid, const uint8_t *token, size_t tokenlen, - ngtcp2_encrypt encrypt, const ngtcp2_crypto_aead *aead) { + ngtcp2_encrypt encrypt, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx) { ngtcp2_pkt_hd hd; uint8_t pseudo_retry[1500]; ngtcp2_ssize pseudo_retrylen; @@ -2106,8 +2102,10 @@ ngtcp2_pkt_write_retry(uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid, } /* OpenSSL does not like NULL plaintext. */ - rv = encrypt(tag, aead, (const uint8_t *)"", 0, retry_key, retry_nonce, - sizeof(retry_nonce) - 1, pseudo_retry, (size_t)pseudo_retrylen); + rv = encrypt(tag, aead, aead_ctx, (const uint8_t *)"", 0, + (const uint8_t *)NGTCP2_RETRY_NONCE, + sizeof(NGTCP2_RETRY_NONCE) - 1, pseudo_retry, + (size_t)pseudo_retrylen); if (rv != 0) { return rv; } @@ -2160,7 +2158,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_pseudo_retry( int ngtcp2_pkt_verify_retry_tag(const ngtcp2_pkt_retry *retry, const uint8_t *pkt, size_t pktlen, ngtcp2_encrypt encrypt, - const ngtcp2_crypto_aead *aead) { + const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx) { uint8_t pseudo_retry[1500]; size_t pseudo_retrylen; uint8_t *p = pseudo_retry; @@ -2181,8 +2180,9 @@ int ngtcp2_pkt_verify_retry_tag(const ngtcp2_pkt_retry *retry, pseudo_retrylen = (size_t)(p - pseudo_retry); /* OpenSSL does not like NULL plaintext. */ - rv = encrypt(tag, aead, (const uint8_t *)"", 0, retry_key, retry_nonce, - sizeof(retry_nonce) - 1, pseudo_retry, pseudo_retrylen); + rv = encrypt(tag, aead, aead_ctx, (const uint8_t *)"", 0, + (const uint8_t *)NGTCP2_RETRY_NONCE, + sizeof(NGTCP2_RETRY_NONCE) - 1, pseudo_retry, pseudo_retrylen); if (rv != 0) { return rv; } diff --git a/lib/ngtcp2_pkt.h b/lib/ngtcp2_pkt.h index caf4152c..7348cb9a 100644 --- a/lib/ngtcp2_pkt.h +++ b/lib/ngtcp2_pkt.h @@ -1120,6 +1120,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_pseudo_retry( int ngtcp2_pkt_verify_retry_tag(const ngtcp2_pkt_retry *retry, const uint8_t *pkt, size_t pktlen, ngtcp2_encrypt encrypt, - const ngtcp2_crypto_aead *aead); + const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx); #endif /* NGTCP2_PKT_H */ diff --git a/lib/ngtcp2_ppe.c b/lib/ngtcp2_ppe.c index c1856d0f..e2c47fd0 100644 --- a/lib/ngtcp2_ppe.c +++ b/lib/ngtcp2_ppe.c @@ -123,7 +123,7 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) { ngtcp2_crypto_create_nonce(ppe->nonce, cc->ckm->iv.base, cc->ckm->iv.len, ppe->pkt_num); - rv = cc->encrypt(payload, &cc->aead, payload, payloadlen, cc->ckm->key.base, + rv = cc->encrypt(payload, &cc->aead, &cc->ckm->aead_ctx, payload, payloadlen, ppe->nonce, cc->ckm->iv.len, buf->begin, ppe->hdlen); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; @@ -134,8 +134,7 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) { /* TODO Check that we have enough space to get sample */ assert(ppe->sample_offset + NGTCP2_HP_SAMPLELEN <= ngtcp2_buf_len(buf)); - rv = cc->hp_mask(mask, &cc->hp, cc->hp_key->base, - buf->begin + ppe->sample_offset); + rv = cc->hp_mask(mask, &cc->hp, &cc->hp_ctx, buf->begin + ppe->sample_offset); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } diff --git a/tests/ngtcp2_conn_test.c b/tests/ngtcp2_conn_test.c index 47559d28..55bb60d4 100644 --- a/tests/ngtcp2_conn_test.c +++ b/tests/ngtcp2_conn_test.c @@ -38,14 +38,15 @@ #include "ngtcp2_rcvry.h" static int null_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { (void)dest; (void)aead; + (void)aead_ctx; (void)plaintext; (void)plaintextlen; - (void)key; (void)nonce; (void)noncelen; (void)ad; @@ -60,13 +61,14 @@ static int null_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, } static int null_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { (void)dest; (void)aead; + (void)aead_ctx; (void)ciphertext; - (void)key; (void)nonce; (void)noncelen; (void)ad; @@ -77,14 +79,15 @@ static int null_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, } static int fail_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { (void)dest; (void)aead; + (void)aead_ctx; (void)ciphertext; (void)ciphertextlen; - (void)key; (void)nonce; (void)noncelen; (void)ad; @@ -93,9 +96,10 @@ static int fail_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, } static int null_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key, const uint8_t *sample) { + const ngtcp2_crypto_cipher_ctx *hp_ctx, + const uint8_t *sample) { (void)hp; - (void)hp_key; + (void)hp_ctx; (void)sample; memcpy(dest, NGTCP2_FAKE_HP_MASK, sizeof(NGTCP2_FAKE_HP_MASK) - 1); return 0; @@ -113,9 +117,7 @@ static int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, } static uint8_t null_secret[32]; -static uint8_t null_key[16]; static uint8_t null_iv[16]; -static uint8_t null_hp_key[16]; static uint8_t null_data[4096]; static ngtcp2_path null_path = {{1, (uint8_t *)"0", NULL}, {1, (uint8_t *)"0", NULL}}; @@ -149,25 +151,31 @@ static int client_initial(ngtcp2_conn *conn, void *user_data) { } static int client_initial_early_data(ngtcp2_conn *conn, void *user_data) { + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; + (void)user_data; ngtcp2_conn_submit_crypto_data(conn, NGTCP2_CRYPTO_LEVEL_INITIAL, null_data, 217); - ngtcp2_conn_install_early_key(conn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); + ngtcp2_conn_install_early_key(conn, &aead_ctx, null_iv, sizeof(null_iv), + &hp_ctx); return 0; } static int recv_client_initial(ngtcp2_conn *conn, const ngtcp2_cid *dcid, void *user_data) { + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; + (void)conn; (void)dcid; (void)user_data; - ngtcp2_conn_install_early_key(conn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); + ngtcp2_conn_install_early_key(conn, &aead_ctx, null_iv, sizeof(null_iv), + &hp_ctx); return 0; } @@ -189,6 +197,9 @@ static int recv_crypto_data_server_early_data(ngtcp2_conn *conn, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data) { + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; + (void)offset; (void)crypto_level; (void)data; @@ -200,14 +211,13 @@ static int recv_crypto_data_server_early_data(ngtcp2_conn *conn, ngtcp2_conn_submit_crypto_data(conn, NGTCP2_CRYPTO_LEVEL_INITIAL, null_data, 179); - ngtcp2_conn_install_rx_handshake_key(conn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_install_tx_handshake_key(conn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); + ngtcp2_conn_install_rx_handshake_key(conn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); + ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); - ngtcp2_conn_install_tx_key(conn, null_secret, null_key, null_iv, null_hp_key, - sizeof(null_secret), sizeof(null_key), - sizeof(null_iv)); + ngtcp2_conn_install_tx_key(conn, null_secret, sizeof(null_secret), &aead_ctx, + null_iv, sizeof(null_iv), &hp_ctx); conn->callbacks.recv_crypto_data = recv_crypto_data; @@ -215,8 +225,9 @@ static int recv_crypto_data_server_early_data(ngtcp2_conn *conn, } static int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, - uint8_t *rx_key, uint8_t *rx_iv, uint8_t *tx_key, - uint8_t *tx_iv, const uint8_t *current_rx_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, void *user_data) { (void)conn; @@ -228,9 +239,9 @@ static int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, memset(rx_secret, 0xff, sizeof(null_secret)); memset(tx_secret, 0xff, sizeof(null_secret)); - memset(rx_key, 0xff, sizeof(null_key)); + rx_aead_ctx->native_handle = NULL; memset(rx_iv, 0xff, sizeof(null_iv)); - memset(tx_key, 0xff, sizeof(null_key)); + tx_aead_ctx->native_handle = NULL; memset(tx_iv, 0xff, sizeof(null_iv)); return 0; @@ -384,6 +395,8 @@ static void setup_default_server(ngtcp2_conn **pconn) { ngtcp2_settings settings; ngtcp2_cid dcid, scid; ngtcp2_transport_params *params; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; dcid_init(&dcid); scid_init(&scid); @@ -400,16 +413,14 @@ static void setup_default_server(ngtcp2_conn **pconn) { ngtcp2_conn_server_new(pconn, &dcid, &scid, &null_path, NGTCP2_PROTO_VER_MAX, &cb, &settings, /* mem = */ NULL, NULL); - ngtcp2_conn_install_rx_handshake_key(*pconn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_install_tx_handshake_key(*pconn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_install_rx_key(*pconn, null_secret, null_key, null_iv, - null_hp_key, sizeof(null_secret), sizeof(null_key), - sizeof(null_iv)); - ngtcp2_conn_install_tx_key(*pconn, null_secret, null_key, null_iv, - null_hp_key, sizeof(null_secret), sizeof(null_key), - sizeof(null_iv)); + ngtcp2_conn_install_rx_handshake_key(*pconn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); + ngtcp2_conn_install_tx_handshake_key(*pconn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); + ngtcp2_conn_install_rx_key(*pconn, null_secret, sizeof(null_secret), + &aead_ctx, null_iv, sizeof(null_iv), &hp_ctx); + ngtcp2_conn_install_tx_key(*pconn, null_secret, sizeof(null_secret), + &aead_ctx, null_iv, sizeof(null_iv), &hp_ctx); ngtcp2_conn_set_aead_overhead(*pconn, NGTCP2_FAKE_AEAD_OVERHEAD); (*pconn)->state = NGTCP2_CS_POST_HANDSHAKE; (*pconn)->flags |= NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED | @@ -435,6 +446,8 @@ static void setup_default_client(ngtcp2_conn **pconn) { ngtcp2_settings settings; ngtcp2_cid dcid, scid; ngtcp2_transport_params *params; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; dcid_init(&dcid); scid_init(&scid); @@ -450,16 +463,14 @@ static void setup_default_client(ngtcp2_conn **pconn) { ngtcp2_conn_client_new(pconn, &dcid, &scid, &null_path, NGTCP2_PROTO_VER_MAX, &cb, &settings, /* mem = */ NULL, NULL); - ngtcp2_conn_install_rx_handshake_key(*pconn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_install_tx_handshake_key(*pconn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_install_rx_key(*pconn, null_secret, null_key, null_iv, - null_hp_key, sizeof(null_secret), sizeof(null_key), - sizeof(null_iv)); - ngtcp2_conn_install_tx_key(*pconn, null_secret, null_key, null_iv, - null_hp_key, sizeof(null_secret), sizeof(null_key), - sizeof(null_iv)); + ngtcp2_conn_install_rx_handshake_key(*pconn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); + ngtcp2_conn_install_tx_handshake_key(*pconn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); + ngtcp2_conn_install_rx_key(*pconn, null_secret, sizeof(null_secret), + &aead_ctx, null_iv, sizeof(null_iv), &hp_ctx); + ngtcp2_conn_install_tx_key(*pconn, null_secret, sizeof(null_secret), + &aead_ctx, null_iv, sizeof(null_iv), &hp_ctx); ngtcp2_conn_set_aead_overhead(*pconn, NGTCP2_FAKE_AEAD_OVERHEAD); (*pconn)->state = NGTCP2_CS_POST_HANDSHAKE; (*pconn)->flags |= NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED | @@ -485,6 +496,8 @@ static void setup_handshake_server(ngtcp2_conn **pconn) { ngtcp2_conn_callbacks cb; ngtcp2_settings settings; ngtcp2_cid dcid, scid; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; dcid_init(&dcid); scid_init(&scid); @@ -501,13 +514,12 @@ static void setup_handshake_server(ngtcp2_conn **pconn) { ngtcp2_conn_server_new(pconn, &dcid, &scid, &null_path, NGTCP2_PROTO_VER_MAX, &cb, &settings, /* mem = */ NULL, NULL); - ngtcp2_conn_install_initial_key(*pconn, null_key, null_iv, null_hp_key, - null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_install_rx_handshake_key(*pconn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_install_tx_handshake_key(*pconn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); + ngtcp2_conn_install_initial_key(*pconn, &aead_ctx, null_iv, &hp_ctx, + &aead_ctx, null_iv, &hp_ctx, sizeof(null_iv)); + ngtcp2_conn_install_rx_handshake_key(*pconn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); + ngtcp2_conn_install_tx_handshake_key(*pconn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); ngtcp2_conn_set_aead_overhead(*pconn, NGTCP2_FAKE_AEAD_OVERHEAD); } @@ -516,6 +528,8 @@ static void setup_handshake_client(ngtcp2_conn **pconn) { ngtcp2_settings settings; ngtcp2_cid rcid, scid; ngtcp2_crypto_aead retry_aead = {0}; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; rcid_init(&rcid); scid_init(&scid); @@ -531,10 +545,9 @@ static void setup_handshake_client(ngtcp2_conn **pconn) { ngtcp2_conn_client_new(pconn, &rcid, &scid, &null_path, NGTCP2_PROTO_VER_MAX, &cb, &settings, /* mem = */ NULL, NULL); - ngtcp2_conn_install_initial_key(*pconn, null_key, null_iv, null_hp_key, - null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_set_retry_aead(*pconn, &retry_aead); + ngtcp2_conn_install_initial_key(*pconn, &aead_ctx, null_iv, &hp_ctx, + &aead_ctx, null_iv, &hp_ctx, sizeof(null_iv)); + ngtcp2_conn_set_retry_aead(*pconn, &retry_aead, &aead_ctx); } static void setup_early_server(ngtcp2_conn **pconn) { @@ -542,6 +555,8 @@ static void setup_early_server(ngtcp2_conn **pconn) { ngtcp2_settings settings; ngtcp2_transport_params *params; ngtcp2_cid dcid, scid; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; dcid_init(&dcid); scid_init(&scid); @@ -558,9 +573,8 @@ static void setup_early_server(ngtcp2_conn **pconn) { ngtcp2_conn_server_new(pconn, &dcid, &scid, &null_path, NGTCP2_PROTO_VER_MAX, &cb, &settings, /* mem = */ NULL, NULL); - ngtcp2_conn_install_initial_key(*pconn, null_key, null_iv, null_hp_key, - null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); + ngtcp2_conn_install_initial_key(*pconn, &aead_ctx, null_iv, &hp_ctx, + &aead_ctx, null_iv, &hp_ctx, sizeof(null_iv)); ngtcp2_conn_set_aead_overhead(*pconn, NGTCP2_FAKE_AEAD_OVERHEAD); params = &(*pconn)->remote.transport_params; params->initial_max_stream_data_bidi_local = 64 * 1024; @@ -579,6 +593,8 @@ static void setup_early_client(ngtcp2_conn **pconn) { ngtcp2_settings settings; ngtcp2_transport_params params; ngtcp2_cid rcid, scid; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; rcid_init(&rcid); scid_init(&scid); @@ -594,9 +610,8 @@ static void setup_early_client(ngtcp2_conn **pconn) { ngtcp2_conn_client_new(pconn, &rcid, &scid, &null_path, NGTCP2_PROTO_VER_MAX, &cb, &settings, /* mem = */ NULL, NULL); - ngtcp2_conn_install_initial_key(*pconn, null_key, null_iv, null_hp_key, - null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); + ngtcp2_conn_install_initial_key(*pconn, &aead_ctx, null_iv, &hp_ctx, + &aead_ctx, null_iv, &hp_ctx, sizeof(null_iv)); ngtcp2_conn_set_aead_overhead(*pconn, NGTCP2_FAKE_AEAD_OVERHEAD); memset(¶ms, 0, sizeof(params)); @@ -2254,6 +2269,7 @@ void test_ngtcp2_conn_recv_retry(void) { ngtcp2_vec datav; ngtcp2_strm *strm; ngtcp2_crypto_aead aead = {0}; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; dcid_init(&dcid); setup_handshake_client(&conn); @@ -2263,9 +2279,9 @@ void test_ngtcp2_conn_recv_retry(void) { CU_ASSERT(spktlen > 0); - spktlen = ngtcp2_pkt_write_retry(buf, sizeof(buf), &conn->oscid, &dcid, - ngtcp2_conn_get_dcid(conn), token, - strsize(token), null_encrypt, &aead); + spktlen = ngtcp2_pkt_write_retry( + buf, sizeof(buf), &conn->oscid, &dcid, ngtcp2_conn_get_dcid(conn), token, + strsize(token), null_encrypt, &aead, &aead_ctx); CU_ASSERT(spktlen > 0); @@ -2297,9 +2313,9 @@ void test_ngtcp2_conn_recv_retry(void) { CU_ASSERT(spktlen > 0); - spktlen = ngtcp2_pkt_write_retry(buf, sizeof(buf), &conn->oscid, &dcid, - ngtcp2_conn_get_dcid(conn), token, - strsize(token), null_encrypt, &aead); + spktlen = ngtcp2_pkt_write_retry( + buf, sizeof(buf), &conn->oscid, &dcid, ngtcp2_conn_get_dcid(conn), token, + strsize(token), null_encrypt, &aead, &aead_ctx); CU_ASSERT(spktlen > 0); @@ -2338,9 +2354,9 @@ void test_ngtcp2_conn_recv_retry(void) { CU_ASSERT(spktlen > 0); CU_ASSERT(119 == datalen); - spktlen = ngtcp2_pkt_write_retry(buf, sizeof(buf), &conn->oscid, &dcid, - ngtcp2_conn_get_dcid(conn), token, - strsize(token), null_encrypt, &aead); + spktlen = ngtcp2_pkt_write_retry( + buf, sizeof(buf), &conn->oscid, &dcid, ngtcp2_conn_get_dcid(conn), token, + strsize(token), null_encrypt, &aead, &aead_ctx); CU_ASSERT(spktlen > 0); @@ -3549,8 +3565,7 @@ void test_ngtcp2_conn_recv_early_data(void) { pktlen = write_single_frame_0rtt_pkt( conn, buf, sizeof(buf), &rcid, ngtcp2_conn_get_dcid(conn), ++pkt_num, - conn->version, &fr, null_key, null_iv, null_hp_key, sizeof(null_key), - sizeof(null_iv)); + conn->version, &fr, null_iv, sizeof(null_iv)); memset(&ud, 0, sizeof(ud)); rv = ngtcp2_conn_read_pkt(conn, &null_path, buf, pktlen, ++t); @@ -3583,8 +3598,7 @@ void test_ngtcp2_conn_recv_early_data(void) { pktlen = write_single_frame_0rtt_pkt( conn, buf, sizeof(buf), &rcid, ngtcp2_conn_get_dcid(conn), ++pkt_num, - conn->version, &fr, null_key, null_iv, null_hp_key, sizeof(null_key), - sizeof(null_iv)); + conn->version, &fr, null_iv, sizeof(null_iv)); rv = ngtcp2_conn_read_pkt(conn, &null_path, buf, pktlen, ++t); @@ -3613,10 +3627,10 @@ void test_ngtcp2_conn_recv_early_data(void) { fr.stream.data[0].len = 999; fr.stream.data[0].base = null_data; - pktlen += write_single_frame_0rtt_pkt( - conn, buf + pktlen, sizeof(buf) - pktlen, &rcid, - ngtcp2_conn_get_dcid(conn), ++pkt_num, conn->version, &fr, null_key, - null_iv, null_hp_key, sizeof(null_key), sizeof(null_iv)); + pktlen += + write_single_frame_0rtt_pkt(conn, buf + pktlen, sizeof(buf) - pktlen, + &rcid, ngtcp2_conn_get_dcid(conn), ++pkt_num, + conn->version, &fr, null_iv, sizeof(null_iv)); rv = ngtcp2_conn_read_pkt(conn, &null_path, buf, pktlen, ++t); @@ -4753,6 +4767,8 @@ void test_ngtcp2_conn_handshake_probe(void) { ngtcp2_rtb_entry *ent; ngtcp2_ksl_it it; int rv; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; /* Retransmit first Initial on PTO timer */ setup_handshake_client(&conn); @@ -4808,10 +4824,10 @@ void test_ngtcp2_conn_handshake_probe(void) { CU_ASSERT(ent->flags & NGTCP2_RTB_FLAG_PROBE); CU_ASSERT(sizeof(buf) == ent->pktlen); - ngtcp2_conn_install_rx_handshake_key(conn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_install_tx_handshake_key(conn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); + ngtcp2_conn_install_rx_handshake_key(conn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); + ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); ngtcp2_conn_set_aead_overhead(conn, NGTCP2_FAKE_AEAD_OVERHEAD); rv = ngtcp2_conn_on_loss_detection_timer(conn, ++t); @@ -5273,6 +5289,8 @@ void test_ngtcp2_conn_send_initial_token(void) { ngtcp2_ssize spktlen, shdlen; ngtcp2_tstamp t = 0; ngtcp2_pkt_hd hd; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; rcid_init(&rcid); scid_init(&scid); @@ -5291,10 +5309,9 @@ void test_ngtcp2_conn_send_initial_token(void) { ngtcp2_conn_client_new(&conn, &rcid, &scid, &null_path, NGTCP2_PROTO_VER_MAX, &cb, &settings, /* mem = */ NULL, NULL); - ngtcp2_conn_install_initial_key(conn, null_key, null_iv, null_hp_key, - null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_set_retry_aead(conn, &retry_aead); + ngtcp2_conn_install_initial_key(conn, &aead_ctx, null_iv, &hp_ctx, &aead_ctx, + null_iv, &hp_ctx, sizeof(null_iv)); + ngtcp2_conn_set_retry_aead(conn, &retry_aead, &aead_ctx); spktlen = ngtcp2_conn_write_pkt(conn, NULL, buf, sizeof(buf), ++t); @@ -5415,6 +5432,8 @@ void test_ngtcp2_conn_write_connection_close(void) { ngtcp2_ssize spktlen, shdlen; ngtcp2_pkt_hd hd; const uint8_t *p; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; /* Client only Initial key */ setup_handshake_client(&conn); @@ -5443,8 +5462,8 @@ void test_ngtcp2_conn_write_connection_close(void) { CU_ASSERT(spktlen > 0); - ngtcp2_conn_install_tx_handshake_key(conn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); + ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); ngtcp2_conn_set_aead_overhead(conn, NGTCP2_FAKE_AEAD_OVERHEAD); spktlen = ngtcp2_conn_write_connection_close(conn, NULL, buf, sizeof(buf), @@ -5463,11 +5482,10 @@ void test_ngtcp2_conn_write_connection_close(void) { /* Client has all keys and has not confirmed handshake */ setup_handshake_client(&conn); - ngtcp2_conn_install_tx_handshake_key(conn, null_key, null_iv, null_hp_key, - sizeof(null_key), sizeof(null_iv)); - ngtcp2_conn_install_tx_key(conn, null_secret, null_key, null_iv, null_hp_key, - sizeof(null_secret), sizeof(null_key), - sizeof(null_iv)); + ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, null_iv, + sizeof(null_iv), &hp_ctx); + ngtcp2_conn_install_tx_key(conn, null_secret, sizeof(null_secret), &aead_ctx, + null_iv, sizeof(null_iv), &hp_ctx); ngtcp2_conn_set_aead_overhead(conn, NGTCP2_FAKE_AEAD_OVERHEAD); conn->state = NGTCP2_CS_POST_HANDSHAKE; @@ -5539,9 +5557,8 @@ void test_ngtcp2_conn_write_connection_close(void) { /* Server has all keys and has not confirmed handshake */ setup_handshake_server(&conn); - ngtcp2_conn_install_tx_key(conn, null_secret, null_key, null_iv, null_hp_key, - sizeof(null_secret), sizeof(null_key), - sizeof(null_iv)); + ngtcp2_conn_install_tx_key(conn, null_secret, sizeof(null_secret), &aead_ctx, + null_iv, sizeof(null_iv), &hp_ctx); conn->state = NGTCP2_CS_POST_HANDSHAKE; @@ -5599,19 +5616,21 @@ void test_ngtcp2_pkt_write_connection_close(void) { ngtcp2_cid dcid, scid; ngtcp2_crypto_aead aead = {0}; ngtcp2_crypto_cipher hp_mask = {0}; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; + ngtcp2_crypto_cipher_ctx hp_ctx = {0}; dcid_init(&dcid); scid_init(&scid); spktlen = ngtcp2_pkt_write_connection_close( buf, sizeof(buf), &dcid, &scid, NGTCP2_INVALID_TOKEN, null_encrypt, &aead, - null_key, null_iv, null_hp_mask, &hp_mask, null_hp_key); + &aead_ctx, null_iv, null_hp_mask, &hp_mask, &hp_ctx); CU_ASSERT(spktlen > 0); spktlen = ngtcp2_pkt_write_connection_close( buf, 16, &dcid, &scid, NGTCP2_INVALID_TOKEN, null_encrypt, &aead, - null_key, null_iv, null_hp_mask, &hp_mask, null_hp_key); + &aead_ctx, null_iv, null_hp_mask, &hp_mask, &hp_ctx); CU_ASSERT(NGTCP2_ERR_NOBUF == spktlen); } diff --git a/tests/ngtcp2_pkt_test.c b/tests/ngtcp2_pkt_test.c index 670fb187..c1c304df 100644 --- a/tests/ngtcp2_pkt_test.c +++ b/tests/ngtcp2_pkt_test.c @@ -34,15 +34,15 @@ #include "ngtcp2_vec.h" static int null_retry_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { (void)dest; (void)aead; + (void)aead_ctx; (void)plaintext; (void)plaintextlen; - (void)key; (void)nonce; (void)noncelen; (void)ad; @@ -1259,6 +1259,7 @@ void test_ngtcp2_pkt_write_retry(void) { ngtcp2_ssize nread; int rv; ngtcp2_crypto_aead aead = {0}; + ngtcp2_crypto_aead_ctx aead_ctx = {0}; uint8_t tag[NGTCP2_RETRY_TAGLEN] = {0}; scid_init(&scid); @@ -1269,9 +1270,9 @@ void test_ngtcp2_pkt_write_retry(void) { token[i] = (uint8_t)i; } - spktlen = - ngtcp2_pkt_write_retry(buf, sizeof(buf), &dcid, &scid, &odcid, token, - sizeof(token), null_retry_encrypt, &aead); + spktlen = ngtcp2_pkt_write_retry(buf, sizeof(buf), &dcid, &scid, &odcid, + token, sizeof(token), null_retry_encrypt, + &aead, &aead_ctx); CU_ASSERT(spktlen > 0); diff --git a/tests/ngtcp2_test_helper.c b/tests/ngtcp2_test_helper.c index 231e37c3..87f14c39 100644 --- a/tests/ngtcp2_test_helper.c +++ b/tests/ngtcp2_test_helper.c @@ -83,14 +83,15 @@ size_t ngtcp2_t_encode_ack_frame(uint8_t *out, uint64_t largest_ack, } static int null_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx, 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) { + const uint8_t *nonce, size_t noncelen, + const uint8_t *ad, size_t adlen) { (void)dest; (void)aead; + (void)aead_ctx; (void)plaintext; (void)plaintextlen; - (void)key; (void)nonce; (void)noncelen; (void)ad; @@ -100,9 +101,10 @@ static int null_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, } static int null_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const uint8_t *hp_key, const uint8_t *sample) { + const ngtcp2_crypto_cipher_ctx *hp_ctx, + const uint8_t *sample) { (void)hp; - (void)hp_key; + (void)hp_ctx; (void)sample; memcpy(dest, NGTCP2_FAKE_HP_MASK, sizeof(NGTCP2_FAKE_HP_MASK) - 1); return 0; @@ -129,7 +131,6 @@ size_t write_single_frame_pkt_flags(ngtcp2_conn *conn, uint8_t *out, cc.encrypt = null_encrypt; cc.hp_mask = null_hp_mask; cc.ckm = conn->pktns.crypto.rx.ckm; - cc.hp_key = conn->pktns.crypto.rx.hp_key; cc.aead_overhead = NGTCP2_FAKE_AEAD_OVERHEAD; ngtcp2_pkt_hd_init(&hd, flags, NGTCP2_PKT_SHORT, dcid, NULL, pkt_num, 4, @@ -167,7 +168,6 @@ size_t write_pkt_flags(ngtcp2_conn *conn, uint8_t *out, size_t outlen, cc.encrypt = null_encrypt; cc.hp_mask = null_hp_mask; cc.ckm = conn->pktns.crypto.rx.ckm; - cc.hp_key = conn->pktns.crypto.rx.hp_key; cc.aead_overhead = NGTCP2_FAKE_AEAD_OVERHEAD; ngtcp2_pkt_hd_init(&hd, flags, NGTCP2_PKT_SHORT, dcid, NULL, pkt_num, 4, @@ -201,7 +201,6 @@ size_t write_single_frame_pkt_without_conn_id(ngtcp2_conn *conn, uint8_t *out, cc.encrypt = null_encrypt; cc.hp_mask = null_hp_mask; cc.ckm = conn->pktns.crypto.rx.ckm; - cc.hp_key = conn->pktns.crypto.rx.hp_key; cc.aead_overhead = NGTCP2_FAKE_AEAD_OVERHEAD; ngtcp2_pkt_hd_init(&hd, NGTCP2_PKT_FLAG_NONE, NGTCP2_PKT_SHORT, NULL, NULL, @@ -234,12 +233,10 @@ size_t write_single_frame_handshake_pkt(ngtcp2_conn *conn, uint8_t *out, switch (pkt_type) { case NGTCP2_PKT_INITIAL: cc.ckm = conn->in_pktns->crypto.rx.ckm; - cc.hp_key = conn->in_pktns->crypto.rx.hp_key; cc.aead_overhead = NGTCP2_INITIAL_AEAD_OVERHEAD; break; case NGTCP2_PKT_HANDSHAKE: cc.ckm = conn->hs_pktns->crypto.rx.ckm; - cc.hp_key = conn->hs_pktns->crypto.rx.hp_key; cc.aead_overhead = NGTCP2_FAKE_AEAD_OVERHEAD; break; default: @@ -274,7 +271,6 @@ size_t write_single_frame_initial_pkt(ngtcp2_conn *conn, uint8_t *out, cc.encrypt = null_encrypt; cc.hp_mask = null_hp_mask; cc.ckm = conn->in_pktns->crypto.rx.ckm; - cc.hp_key = conn->in_pktns->crypto.rx.hp_key; cc.aead_overhead = NGTCP2_INITIAL_AEAD_OVERHEAD; ngtcp2_pkt_hd_init(&hd, NGTCP2_PKT_FLAG_LONG_FORM, NGTCP2_PKT_INITIAL, dcid, @@ -296,18 +292,15 @@ size_t write_single_frame_0rtt_pkt(ngtcp2_conn *conn, uint8_t *out, size_t outlen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid, int64_t pkt_num, uint32_t version, ngtcp2_frame *fr, - const uint8_t *key, const uint8_t *iv, - const uint8_t *hp_key, size_t keylen, - size_t ivlen) { + const uint8_t *iv, size_t ivlen) { ngtcp2_crypto_km *ckm; - ngtcp2_vec hp_keyv; ngtcp2_crypto_cc cc; ngtcp2_ppe ppe; ngtcp2_pkt_hd hd; int rv; ngtcp2_ssize n; - rv = ngtcp2_crypto_km_new(&ckm, NULL, 0, key, keylen, iv, ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&ckm, NULL, 0, NULL, iv, ivlen, conn->mem); assert(rv == 0); @@ -315,7 +308,6 @@ size_t write_single_frame_0rtt_pkt(ngtcp2_conn *conn, uint8_t *out, cc.encrypt = null_encrypt; cc.hp_mask = null_hp_mask; cc.ckm = ckm; - cc.hp_key = ngtcp2_vec_init(&hp_keyv, hp_key, keylen); cc.aead_overhead = NGTCP2_FAKE_AEAD_OVERHEAD; ngtcp2_pkt_hd_init(&hd, NGTCP2_PKT_FLAG_LONG_FORM, NGTCP2_PKT_0RTT, dcid, @@ -352,17 +344,14 @@ size_t write_handshake_pkt(ngtcp2_conn *conn, uint8_t *out, size_t outlen, switch (pkt_type) { case NGTCP2_PKT_INITIAL: cc.ckm = conn->in_pktns->crypto.rx.ckm; - cc.hp_key = conn->in_pktns->crypto.rx.hp_key; cc.aead_overhead = NGTCP2_INITIAL_AEAD_OVERHEAD; break; case NGTCP2_PKT_HANDSHAKE: cc.ckm = conn->hs_pktns->crypto.rx.ckm; - cc.hp_key = conn->hs_pktns->crypto.rx.hp_key; cc.aead_overhead = NGTCP2_FAKE_AEAD_OVERHEAD; break; case NGTCP2_PKT_0RTT: cc.ckm = conn->early.ckm; - cc.hp_key = conn->early.hp_key; cc.aead_overhead = NGTCP2_FAKE_AEAD_OVERHEAD; break; default: diff --git a/tests/ngtcp2_test_helper.h b/tests/ngtcp2_test_helper.h index 2318e56c..f283cbe2 100644 --- a/tests/ngtcp2_test_helper.h +++ b/tests/ngtcp2_test_helper.h @@ -163,9 +163,7 @@ size_t write_single_frame_0rtt_pkt(ngtcp2_conn *conn, uint8_t *out, size_t outlen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid, int64_t pkt_num, uint32_t version, ngtcp2_frame *fr, - const uint8_t *key, const uint8_t *iv, - const uint8_t *hp_key, size_t keylen, - size_t ivlen); + const uint8_t *iv, size_t ivlen); /* * write_handshake_pkt writes an unprotected QUIC handshake packet -- GitLab