mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 15:47:01 +02:00
MEDIUM: quic: implement CHACHA20_POLY1305 for AWS-LC
With AWS-LC, the aead part is covered by the EVP_AEAD API which provides the correct EVP_aead_chacha20_poly1305(), however for header protection it does not provides an EVP_CIPHER for chacha20. This patch implements exceptions in the header protection code and use EVP_CIPHER_CHACHA20 and EVP_CIPHER_CTX_CHACHA20 placeholders so we can use the CRYPTO_chacha_20() primitive manually instead of the EVP_CIPHER API. This requires to check if we are using EVP_CIPHER_CTX_CHACHA20 when doing EVP_CIPHER_CTX_free().
This commit is contained in:
parent
177c84808c
commit
28cb01f8e8
@ -17,6 +17,9 @@
|
|||||||
#error "Must define USE_OPENSSL"
|
#error "Must define USE_OPENSSL"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_OPENSSL_AWSLC)
|
||||||
|
#include <openssl/chacha.h>
|
||||||
|
#endif
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
#include <import/ebtree.h>
|
#include <import/ebtree.h>
|
||||||
@ -38,6 +41,9 @@
|
|||||||
# define QUIC_AEAD_key_length EVP_AEAD_key_length
|
# define QUIC_AEAD_key_length EVP_AEAD_key_length
|
||||||
# define QUIC_AEAD_iv_length EVP_AEAD_nonce_length
|
# define QUIC_AEAD_iv_length EVP_AEAD_nonce_length
|
||||||
|
|
||||||
|
# define EVP_CIPHER_CTX_CHACHA20 ((EVP_CIPHER_CTX *)EVP_aead_chacha20_poly1305())
|
||||||
|
# define EVP_CIPHER_CHACHA20 ((EVP_CIPHER*)EVP_aead_chacha20_poly1305())
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
# define QUIC_AEAD EVP_CIPHER
|
# define QUIC_AEAD EVP_CIPHER
|
||||||
|
@ -150,7 +150,7 @@ static inline const QUIC_AEAD *tls_aead(const SSL_CIPHER *cipher)
|
|||||||
return EVP_aes_256_gcm();
|
return EVP_aes_256_gcm();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(OPENSSL_IS_AWSLC) && (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x4000000fL)
|
#if (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x4000000fL)
|
||||||
/* WT: LibreSSL has an issue with CHACHA20 running in-place till 3.9.2
|
/* WT: LibreSSL has an issue with CHACHA20 running in-place till 3.9.2
|
||||||
* included, but the fix is already identified and will be merged
|
* included, but the fix is already identified and will be merged
|
||||||
* into next major version. Given that on machines without AES-NI
|
* into next major version. Given that on machines without AES-NI
|
||||||
@ -160,7 +160,11 @@ static inline const QUIC_AEAD *tls_aead(const SSL_CIPHER *cipher)
|
|||||||
* Thanks to Theo Buehler for his help!
|
* Thanks to Theo Buehler for his help!
|
||||||
*/
|
*/
|
||||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||||
|
# ifdef QUIC_AEAD_API
|
||||||
|
return EVP_aead_chacha20_poly1305();
|
||||||
|
# else
|
||||||
return EVP_chacha20_poly1305();
|
return EVP_chacha20_poly1305();
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#if !defined(USE_OPENSSL_WOLFSSL) && !defined(OPENSSL_IS_AWSLC)
|
#if !defined(USE_OPENSSL_WOLFSSL) && !defined(OPENSSL_IS_AWSLC)
|
||||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||||
@ -188,8 +192,10 @@ static inline const EVP_MD *tls_md(const SSL_CIPHER *cipher)
|
|||||||
static inline const EVP_CIPHER *tls_hp(const SSL_CIPHER *cipher)
|
static inline const EVP_CIPHER *tls_hp(const SSL_CIPHER *cipher)
|
||||||
{
|
{
|
||||||
switch (SSL_CIPHER_get_id(cipher)) {
|
switch (SSL_CIPHER_get_id(cipher)) {
|
||||||
#if !defined(OPENSSL_IS_AWSLC)
|
|
||||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||||
|
#ifdef QUIC_AEAD_API
|
||||||
|
return EVP_CIPHER_CHACHA20;
|
||||||
|
#else
|
||||||
return EVP_chacha20();
|
return EVP_chacha20();
|
||||||
#endif
|
#endif
|
||||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||||
@ -754,14 +760,24 @@ static inline void quic_tls_ctx_secs_free(struct quic_tls_ctx *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* RX HP protection */
|
/* RX HP protection */
|
||||||
|
#ifdef QUIC_AEAD_API
|
||||||
|
if (ctx->rx.hp_ctx != EVP_CIPHER_CTX_CHACHA20)
|
||||||
|
EVP_CIPHER_CTX_free(ctx->rx.hp_ctx);
|
||||||
|
#else
|
||||||
EVP_CIPHER_CTX_free(ctx->rx.hp_ctx);
|
EVP_CIPHER_CTX_free(ctx->rx.hp_ctx);
|
||||||
|
#endif
|
||||||
/* RX AEAD decryption */
|
/* RX AEAD decryption */
|
||||||
QUIC_AEAD_CTX_free(ctx->rx.ctx);
|
QUIC_AEAD_CTX_free(ctx->rx.ctx);
|
||||||
pool_free(pool_head_quic_tls_iv, ctx->rx.iv);
|
pool_free(pool_head_quic_tls_iv, ctx->rx.iv);
|
||||||
pool_free(pool_head_quic_tls_key, ctx->rx.key);
|
pool_free(pool_head_quic_tls_key, ctx->rx.key);
|
||||||
|
|
||||||
/* TX HP protection */
|
/* TX HP protection */
|
||||||
|
#ifdef QUIC_AEAD_API
|
||||||
|
if (ctx->tx.hp_ctx != EVP_CIPHER_CTX_CHACHA20)
|
||||||
|
EVP_CIPHER_CTX_free(ctx->tx.hp_ctx);
|
||||||
|
#else
|
||||||
EVP_CIPHER_CTX_free(ctx->tx.hp_ctx);
|
EVP_CIPHER_CTX_free(ctx->tx.hp_ctx);
|
||||||
|
#endif
|
||||||
/* TX AEAD encryption */
|
/* TX AEAD encryption */
|
||||||
QUIC_AEAD_CTX_free(ctx->tx.ctx);
|
QUIC_AEAD_CTX_free(ctx->tx.ctx);
|
||||||
pool_free(pool_head_quic_tls_iv, ctx->tx.iv);
|
pool_free(pool_head_quic_tls_iv, ctx->tx.iv);
|
||||||
|
@ -454,7 +454,16 @@ int quic_tls_derive_keys(const QUIC_AEAD *aead, const EVP_CIPHER *hp,
|
|||||||
{
|
{
|
||||||
size_t aead_keylen = (size_t)QUIC_AEAD_key_length(aead);
|
size_t aead_keylen = (size_t)QUIC_AEAD_key_length(aead);
|
||||||
size_t aead_ivlen = (size_t)QUIC_AEAD_iv_length(aead);
|
size_t aead_ivlen = (size_t)QUIC_AEAD_iv_length(aead);
|
||||||
|
#ifdef QUIC_AEAD_API
|
||||||
|
size_t hp_len = 0;
|
||||||
|
|
||||||
|
if (hp == EVP_CIPHER_CHACHA20)
|
||||||
|
hp_len = 32;
|
||||||
|
else if (hp)
|
||||||
|
hp_len = (size_t)EVP_CIPHER_key_length(hp);
|
||||||
|
#else
|
||||||
size_t hp_len = hp ? (size_t)EVP_CIPHER_key_length(hp) : 0;
|
size_t hp_len = hp ? (size_t)EVP_CIPHER_key_length(hp) : 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (aead_keylen > keylen || aead_ivlen > ivlen || hp_len > hp_keylen)
|
if (aead_keylen > keylen || aead_ivlen > ivlen || hp_len > hp_keylen)
|
||||||
return 0;
|
return 0;
|
||||||
@ -599,6 +608,14 @@ int quic_tls_enc_hp_ctx_init(EVP_CIPHER_CTX **hp_ctx,
|
|||||||
{
|
{
|
||||||
EVP_CIPHER_CTX *ctx;
|
EVP_CIPHER_CTX *ctx;
|
||||||
|
|
||||||
|
#ifdef QUIC_AEAD_API
|
||||||
|
|
||||||
|
if (hp == EVP_CIPHER_CHACHA20) {
|
||||||
|
*hp_ctx = EVP_CIPHER_CTX_CHACHA20;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ctx = EVP_CIPHER_CTX_new();
|
ctx = EVP_CIPHER_CTX_new();
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return 0;
|
return 0;
|
||||||
@ -625,6 +642,25 @@ int quic_tls_hp_encrypt(unsigned char *out,
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
#ifdef QUIC_AEAD_API
|
||||||
|
|
||||||
|
if (ctx == EVP_CIPHER_CTX_CHACHA20) {
|
||||||
|
uint32_t counter;
|
||||||
|
/* According to RFC 9001, 5.4.4. ChaCha20-Based Header Protection:
|
||||||
|
* The first 4 bytes of the sampled ciphertext are the block counter.
|
||||||
|
* The remaining 12 bytes are used as the nonce.
|
||||||
|
*/
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
|
counter = (uint32_t)in[0] + (uint32_t)(in[1] << 8) + (uint32_t)(in[2] << 16) + (uint32_t)(in[3] << 24);
|
||||||
|
#else
|
||||||
|
memcpy(&counter, in, sizeof(counter));
|
||||||
|
#endif
|
||||||
|
CRYPTO_chacha_20(out, out, inlen, key, in + sizeof(counter), counter);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, in) ||
|
if (!EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, in) ||
|
||||||
!EVP_EncryptUpdate(ctx, out, &ret, out, inlen) ||
|
!EVP_EncryptUpdate(ctx, out, &ret, out, inlen) ||
|
||||||
!EVP_EncryptFinal_ex(ctx, out, &ret))
|
!EVP_EncryptFinal_ex(ctx, out, &ret))
|
||||||
@ -639,6 +675,14 @@ int quic_tls_dec_hp_ctx_init(EVP_CIPHER_CTX **hp_ctx,
|
|||||||
{
|
{
|
||||||
EVP_CIPHER_CTX *ctx;
|
EVP_CIPHER_CTX *ctx;
|
||||||
|
|
||||||
|
#ifdef QUIC_AEAD_API
|
||||||
|
|
||||||
|
if (hp == EVP_CIPHER_CHACHA20) {
|
||||||
|
*hp_ctx = EVP_CIPHER_CTX_CHACHA20;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ctx = EVP_CIPHER_CTX_new();
|
ctx = EVP_CIPHER_CTX_new();
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return 0;
|
return 0;
|
||||||
@ -665,6 +709,25 @@ int quic_tls_hp_decrypt(unsigned char *out,
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
#ifdef QUIC_AEAD_API
|
||||||
|
if (ctx == EVP_CIPHER_CTX_CHACHA20) {
|
||||||
|
uint32_t counter;
|
||||||
|
|
||||||
|
/* According to RFC 9001, 5.4.4. ChaCha20-Based Header Protection:
|
||||||
|
* The first 4 bytes of the sampled ciphertext are the block counter.
|
||||||
|
* The remaining 12 bytes are used as the nonce.
|
||||||
|
*/
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
|
counter = (uint32_t)in[0] + (uint32_t)(in[1] << 8) + (uint32_t)(in[2] << 16) + (uint32_t)(in[3] << 24);
|
||||||
|
#else
|
||||||
|
memcpy(&counter, in, sizeof(counter));
|
||||||
|
#endif
|
||||||
|
CRYPTO_chacha_20(out, out, inlen, key, in + sizeof(counter), counter);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, in) ||
|
if (!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, in) ||
|
||||||
!EVP_DecryptUpdate(ctx, out, &ret, out, inlen) ||
|
!EVP_DecryptUpdate(ctx, out, &ret, out, inlen) ||
|
||||||
!EVP_DecryptFinal_ex(ctx, out, &ret))
|
!EVP_DecryptFinal_ex(ctx, out, &ret))
|
||||||
|
Loading…
Reference in New Issue
Block a user