From 9f47999002f5c5724f82f898242596ee6eed1183 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 2 Sep 2022 11:15:40 +0200 Subject: [PATCH 1/3] Add ChaCha20 as available cipher in the EVP API. - wire the wc_ChaCha_* implementation into the EVP API as `wolfSSL_EVP_chacha20` - follow IV conversions of OpenSSL - add test case - have QUIC support use this for header protection when CHACHA20_POLY1305 has been negotiated in the handshake. --- src/quic.c | 2 +- src/ssl.c | 10 +++++ tests/api.c | 63 ++++++++++++++++++++++++++++ wolfcrypt/src/evp.c | 96 +++++++++++++++++++++++++++++++++++++++++++ wolfssl/openssl/evp.h | 15 ++++++- 5 files changed, 183 insertions(+), 3 deletions(-) diff --git a/src/quic.c b/src/quic.c index 470ff5c6d..b964aa155 100644 --- a/src/quic.c +++ b/src/quic.c @@ -1006,7 +1006,7 @@ const WOLFSSL_EVP_CIPHER* wolfSSL_quic_get_hp(WOLFSSL* ssl) #endif #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) case TLS_CHACHA20_POLY1305_SHA256: - evp_cipher = wolfSSL_EVP_chacha20_poly1305(); + evp_cipher = wolfSSL_EVP_chacha20(); break; #endif #if defined(WOLFSSL_AES_COUNTER) && defined(WOLFSSL_AES_128) diff --git a/src/ssl.c b/src/ssl.c index cc4a13608..2bcd1788d 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -38918,6 +38918,11 @@ int wolfSSL_RAND_poll(void) break; #endif +#ifdef HAVE_CHACHA + case CHACHA20_TYPE: + break; +#endif + case NULL_CIPHER_TYPE : WOLFSSL_MSG("NULL"); break; @@ -39007,6 +39012,11 @@ int wolfSSL_RAND_poll(void) break; #endif +#ifdef HAVE_CHACHA + case CHACHA20_TYPE: + break; +#endif + case NULL_CIPHER_TYPE : WOLFSSL_MSG("NULL"); break; diff --git a/tests/api.c b/tests/api.c index add8b76a5..41c00bb1c 100644 --- a/tests/api.c +++ b/tests/api.c @@ -52094,6 +52094,68 @@ static int test_wolfssl_EVP_chacha20_poly1305(void) return 0; } +static int test_wolfssl_EVP_chacha20(void) +{ +#if defined(OPENSSL_EXTRA) && defined(HAVE_CHACHA) + byte key[CHACHA_MAX_KEY_SZ]; + byte iv [WOLFSSL_EVP_CHACHA_IV_BYTES]; + byte plainText[] = {0xDE, 0xAD, 0xBE, 0xEF}; + byte cipherText[sizeof(plainText)]; + byte decryptedText[sizeof(plainText)]; + EVP_CIPHER_CTX* ctx; + int outSz; + + printf(testingFmt, "test_wolfssl_EVP_chacha20"); + + /* Encrypt. */ + AssertNotNull((ctx = EVP_CIPHER_CTX_new())); + AssertIntEQ(EVP_EncryptInit_ex(ctx, EVP_chacha20(), NULL, NULL, + NULL), WOLFSSL_SUCCESS); + /* Any tag length must fail - not an AEAD cipher. */ + AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE, NULL), WOLFSSL_FAILURE); + AssertIntEQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv), WOLFSSL_SUCCESS); + AssertIntEQ(EVP_EncryptUpdate(ctx, cipherText, &outSz, plainText, + sizeof(plainText)), WOLFSSL_SUCCESS); + AssertIntEQ(outSz, sizeof(plainText)); + AssertIntEQ(EVP_EncryptFinal_ex(ctx, cipherText, &outSz), WOLFSSL_SUCCESS); + AssertIntEQ(outSz, 0); + EVP_CIPHER_CTX_free(ctx); + + /* Decrypt. */ + AssertNotNull((ctx = EVP_CIPHER_CTX_new())); + AssertIntEQ(EVP_DecryptInit_ex(ctx, EVP_chacha20(), NULL, NULL, + NULL), WOLFSSL_SUCCESS); + AssertIntEQ(EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv), WOLFSSL_SUCCESS); + AssertIntEQ(EVP_DecryptUpdate(ctx, decryptedText, &outSz, cipherText, + sizeof(cipherText)), WOLFSSL_SUCCESS); + AssertIntEQ(outSz, sizeof(cipherText)); + AssertIntEQ(EVP_DecryptFinal_ex(ctx, decryptedText, &outSz), + WOLFSSL_SUCCESS); + AssertIntEQ(outSz, 0); + EVP_CIPHER_CTX_free(ctx); + + /* Test partial Inits. CipherInit() allow setting of key and iv + * in separate calls. */ + AssertNotNull((ctx = EVP_CIPHER_CTX_new())); + AssertIntEQ(wolfSSL_EVP_CipherInit(ctx, EVP_chacha20(), + key, NULL, 1), WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_EVP_CipherInit(ctx, NULL, NULL, iv, 1), + WOLFSSL_SUCCESS); + AssertIntEQ(EVP_DecryptUpdate(ctx, decryptedText, &outSz, cipherText, + sizeof(cipherText)), WOLFSSL_SUCCESS); + AssertIntEQ(outSz, sizeof(cipherText)); + AssertIntEQ(EVP_DecryptFinal_ex(ctx, decryptedText, &outSz), + WOLFSSL_SUCCESS); + AssertIntEQ(outSz, 0); + EVP_CIPHER_CTX_free(ctx); + + printf(resultFmt, passed); +#endif + + return 0; +} + static int test_wolfSSL_EVP_PKEY_hkdf(void) { #if defined(OPENSSL_EXTRA) && defined(HAVE_HKDF) @@ -57991,6 +58053,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfssl_EVP_aes_gcm_AAD_2_parts), TEST_DECL(test_wolfssl_EVP_aes_gcm), TEST_DECL(test_wolfssl_EVP_chacha20_poly1305), + TEST_DECL(test_wolfssl_EVP_chacha20), TEST_DECL(test_wolfSSL_EVP_PKEY_hkdf), TEST_DECL(test_wolfSSL_PKEY_up_ref), TEST_DECL(test_wolfSSL_EVP_Cipher_extra), diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 4559bc795..81b4fd9b0 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -166,6 +166,10 @@ static const char EVP_CHACHA20_POLY1305[] = "CHACHA20-POLY1305"; #endif +#ifdef HAVE_CHACHA + static const char EVP_CHACHA20[] = "CHACHA20"; +#endif + static const char EVP_NULL[] = "NULL"; #define EVP_CIPHER_TYPE_MATCHES(x, y) (XSTRCMP(x,y) == 0) @@ -246,6 +250,9 @@ int wolfSSL_EVP_Cipher_key_length(const WOLFSSL_EVP_CIPHER* c) #endif #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) case CHACHA20_POLY1305_TYPE: return 32; + #endif + #ifdef HAVE_CHACHA + case CHACHA20_TYPE: return CHACHA_MAX_KEY_SZ; #endif default: return 0; @@ -702,6 +709,16 @@ int wolfSSL_EVP_CipherUpdate(WOLFSSL_EVP_CIPHER_CTX *ctx, return WOLFSSL_SUCCESS; } } +#endif +#ifdef HAVE_CHACHA + case CHACHA20_TYPE: + /* CHACHAFIXME */ + if (wc_Chacha_Process(&ctx->cipher.chacha, out, in, inl) != 0) { + WOLFSSL_MSG("wc_ChaCha_Process failed"); + return WOLFSSL_FAILURE; + } + *outl = inl; + return WOLFSSL_SUCCESS; #endif default: /* fall-through */ @@ -1298,6 +1315,11 @@ static unsigned int cipherType(const WOLFSSL_EVP_CIPHER *cipher) return CHACHA20_POLY1305_TYPE; #endif +#ifdef HAVE_CHACHA + else if (EVP_CIPHER_TYPE_MATCHES(cipher, EVP_CHACHA20)) + return CHACHA20_TYPE; +#endif + else return 0; } @@ -1371,6 +1393,12 @@ int wolfSSL_EVP_CIPHER_block_size(const WOLFSSL_EVP_CIPHER *cipher) case CHACHA20_POLY1305_TYPE: return 1; #endif + +#ifdef HAVE_CHACHA + case CHACHA20_TYPE: + return 1; +#endif + default: return 0; } @@ -1443,6 +1471,10 @@ unsigned long WOLFSSL_CIPHER_mode(const WOLFSSL_EVP_CIPHER *cipher) case CHACHA20_POLY1305_TYPE: return WOLFSSL_EVP_CIPH_STREAM_CIPHER | WOLFSSL_EVP_CIPH_FLAG_AEAD_CIPHER; + #endif + #ifdef HAVE_CHACHA + case CHACHA20_TYPE: + return WOLFSSL_EVP_CIPH_STREAM_CIPHER; #endif default: return 0; @@ -4176,6 +4208,10 @@ static const struct cipher{ {CHACHA20_POLY1305_TYPE, EVP_CHACHA20_POLY1305, NID_chacha20_poly1305}, #endif +#ifdef HAVE_CHACHA + {CHACHA20_TYPE, EVP_CHACHA20, NID_chacha20}, +#endif + { 0, NULL, 0} }; @@ -4275,6 +4311,9 @@ const WOLFSSL_EVP_CIPHER *wolfSSL_EVP_get_cipherbyname(const char *name) #endif #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) {EVP_CHACHA20_POLY1305, "chacha20-poly1305"}, +#endif +#ifdef HAVE_CHACHA + {EVP_CHACHA20, "chacha20"}, #endif { NULL, NULL} }; @@ -4394,6 +4433,11 @@ const WOLFSSL_EVP_CIPHER *wolfSSL_EVP_get_cipherbynid(int id) return wolfSSL_EVP_chacha20_poly1305(); #endif +#ifdef HAVE_CHACHA + case NID_chacha20: + return wolfSSL_EVP_chacha20(); +#endif + default: WOLFSSL_MSG("Bad cipher id value"); } @@ -5298,6 +5342,14 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) } #endif +#ifdef HAVE_CHACHA + const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_chacha20(void) + { + WOLFSSL_ENTER("wolfSSL_EVP_chacha20"); + return EVP_CHACHA20; + } +#endif + const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_enc_null(void) { WOLFSSL_ENTER("wolfSSL_EVP_enc_null"); @@ -6652,6 +6704,40 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) } } #endif +#ifdef HAVE_CHACHA + if (ctx->cipherType == CHACHA20_TYPE || + (type && EVP_CIPHER_TYPE_MATCHES(type, EVP_CHACHA20))) { + WOLFSSL_MSG("EVP_CHACHA20"); + ctx->cipherType = CHACHA20_TYPE; + ctx->flags &= ~WOLFSSL_EVP_CIPH_MODE; + ctx->keyLen = CHACHA_MAX_KEY_SZ; + ctx->block_size = 1; + ctx->ivSz = WOLFSSL_EVP_CHACHA_IV_BYTES; + if (enc == 0 || enc == 1) { + ctx->enc = (byte) enc; + } + if (key != NULL && wc_Chacha_SetKey(&ctx->cipher.chacha, + key, ctx->keyLen) != 0) { + WOLFSSL_MSG("wc_Chacha_SetKey() failed"); + return WOLFSSL_FAILURE; + } + if (iv != NULL) { + /* a bit silly. chacha takes an iv+counter and internally + * combines them to a new iv. EVP is given exactly *one* iv, + * so to pass it into chacha, we have to revert that first. + * The counter comes first in little-endian */ + word32 counter = (uint32_t)iv[0] + (uint32_t)(iv[1] << 8) + + (uint32_t)(iv[2] << 16) + (uint32_t)(iv[3] << 24); + if (wc_Chacha_SetIV(&ctx->cipher.chacha, + iv + sizeof(counter), counter) != 0) { + + WOLFSSL_MSG("wc_Chacha_SetIV() failed"); + return WOLFSSL_FAILURE; + } + } +/* CHACHAFIXME */ + } +#endif #ifndef NO_DES3 if (ctx->cipherType == DES_CBC_TYPE || (type && EVP_CIPHER_TYPE_MATCHES(type, EVP_DES_CBC))) { @@ -8423,6 +8509,11 @@ int wolfSSL_EVP_CIPHER_CTX_iv_length(const WOLFSSL_EVP_CIPHER_CTX* ctx) WOLFSSL_MSG("CHACHA20 POLY1305"); return CHACHA20_POLY1305_AEAD_IV_SIZE; #endif /* HAVE_CHACHA HAVE_POLY1305 */ +#ifdef HAVE_CHACHA + case CHACHA20_TYPE: + WOLFSSL_MSG("CHACHA20"); + return WOLFSSL_EVP_CHACHA_IV_BYTES; +#endif /* HAVE_CHACHA */ case NULL_CIPHER_TYPE : WOLFSSL_MSG("NULL"); @@ -8512,6 +8603,11 @@ int wolfSSL_EVP_CIPHER_iv_length(const WOLFSSL_EVP_CIPHER* cipher) return CHACHA20_POLY1305_AEAD_IV_SIZE; #endif +#ifdef HAVE_CHACHA + if (XSTRCMP(name, EVP_CHACHA20) == 0) + return WOLFSSL_EVP_CHACHA_IV_BYTES; +#endif + (void)name; return 0; diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index 98a61cc51..df706e8aa 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -139,6 +139,11 @@ WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_rc2_cbc(void); #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_chacha20_poly1305(void); #endif +#ifdef HAVE_CHACHA +/* ChaCha IV + counter is set as one IV in EVP */ +#define WOLFSSL_EVP_CHACHA_IV_BYTES (CHACHA_IV_BYTES + sizeof(word32)) +WOLFSSL_API const WOLFSSL_EVP_CIPHER* wolfSSL_EVP_chacha20(void); +#endif typedef union { @@ -212,6 +217,9 @@ typedef union { #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) ChaChaPoly_Aead chachaPoly; #endif +#ifdef HAVE_CHACHA + ChaCha chacha; +#endif } WOLFSSL_Cipher; #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) @@ -282,7 +290,8 @@ enum { AES_256_OFB_TYPE = 35, AES_128_XTS_TYPE = 36, AES_256_XTS_TYPE = 37, - CHACHA20_POLY1305_TYPE = 38 + CHACHA20_POLY1305_TYPE = 38, + CHACHA20_TYPE = 39 }; enum { @@ -357,7 +366,8 @@ enum { NID_aes_256_xts = 914, NID_camellia_128_cbc = 751, NID_camellia_256_cbc = 753, - NID_chacha20_poly1305 = 1018 + NID_chacha20_poly1305 = 1018, + NID_chacha20 = 1019 }; enum { @@ -898,6 +908,7 @@ WOLFSSL_API int wolfSSL_EVP_SignInit_ex(WOLFSSL_EVP_MD_CTX* ctx, #define EVP_des_ede3_cbc wolfSSL_EVP_des_ede3_cbc #define EVP_des_ede3_ecb wolfSSL_EVP_des_ede3_ecb #define EVP_rc4 wolfSSL_EVP_rc4 +#define EVP_chacha20 wolfSSL_EVP_chacha20 #define EVP_chacha20_poly1305 wolfSSL_EVP_chacha20_poly1305 #define EVP_enc_null wolfSSL_EVP_enc_null From 9b319b37829f20e54366524f91f913b10aa5c634 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 5 Sep 2022 10:00:46 +0200 Subject: [PATCH 2/3] Remove dependency on POLY1305 on testing CHACHA20 only. --- tests/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index 41c00bb1c..dd40f5d84 100644 --- a/tests/api.c +++ b/tests/api.c @@ -52113,7 +52113,7 @@ static int test_wolfssl_EVP_chacha20(void) NULL), WOLFSSL_SUCCESS); /* Any tag length must fail - not an AEAD cipher. */ AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, - CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE, NULL), WOLFSSL_FAILURE); + 16, NULL), WOLFSSL_FAILURE); AssertIntEQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv), WOLFSSL_SUCCESS); AssertIntEQ(EVP_EncryptUpdate(ctx, cipherText, &outSz, plainText, sizeof(plainText)), WOLFSSL_SUCCESS); From 5927c4063a9a58f1244dec47bd3380d162359751 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 6 Sep 2022 10:05:17 +0200 Subject: [PATCH 3/3] Removing FIXME comments after the fixing has been done. doh. --- wolfcrypt/src/evp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 81b4fd9b0..7edaad81d 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -712,7 +712,6 @@ int wolfSSL_EVP_CipherUpdate(WOLFSSL_EVP_CIPHER_CTX *ctx, #endif #ifdef HAVE_CHACHA case CHACHA20_TYPE: - /* CHACHAFIXME */ if (wc_Chacha_Process(&ctx->cipher.chacha, out, in, inl) != 0) { WOLFSSL_MSG("wc_ChaCha_Process failed"); return WOLFSSL_FAILURE; @@ -6735,7 +6734,6 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) return WOLFSSL_FAILURE; } } -/* CHACHAFIXME */ } #endif #ifndef NO_DES3