diff --git a/tests/api.c b/tests/api.c index 88b033206..20d7a059f 100644 --- a/tests/api.c +++ b/tests/api.c @@ -52049,6 +52049,24 @@ static int test_wolfssl_EVP_chacha20_poly1305(void) 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_poly1305(), + key, NULL, 1), WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_EVP_CipherInit(ctx, NULL, NULL, iv, 1), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_EVP_CipherUpdate(ctx, NULL, &outSz, + aad, sizeof(aad)), WOLFSSL_SUCCESS); + AssertIntEQ(outSz, sizeof(aad)); + 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 diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 818dacac8..5434999ed 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -5625,6 +5625,13 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) #endif /* HAVE_AESGCM && WOLFSSL_AESGCM_STREAM */ #endif /* not FIPS or FIPS v2+ */ ctx->cipherType = WOLFSSL_EVP_CIPH_TYPE_INIT; /* not yet initialized */ +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + if (ctx->key) { + ForceZero(ctx->key, ctx->keyLen); + XFREE(ctx->key, NULL, DYNAMIC_TYPE_OPENSSL); + ctx->key = NULL; + } +#endif ctx->keyLen = 0; #ifdef HAVE_AESGCM if (ctx->gcmBuffer) { @@ -6619,8 +6626,23 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) ctx->enc = (byte) enc; } - if (key != NULL && iv != NULL && wc_ChaCha20Poly1305_Init( - &ctx->cipher.chachaPoly, key, iv, enc) != 0) { + /* wolfSSL_EVP_CipherInit() may be called multiple times to + * set key or iv alone. A common use case is to set key + * and then init with another iv again and again after + * update/finals. We need to preserve the key for those calls + * since wc_ChaCha20Poly1305_Init() does not. */ + if (key != NULL) { + if (!ctx->key) { + ctx->key = (byte*)XMALLOC(ctx->keyLen, NULL, + DYNAMIC_TYPE_OPENSSL); + if (!ctx->key) { + return MEMORY_E; + } + } + XMEMCPY(ctx->key, key, ctx->keyLen); + } + if ((ctx->key != NULL && iv != NULL) && wc_ChaCha20Poly1305_Init( + &ctx->cipher.chachaPoly, ctx->key, iv, ctx->enc) != 0) { WOLFSSL_MSG("wc_ChaCha20Poly1305_Init() failed"); return WOLFSSL_FAILURE; } diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index c6cab8496..98a61cc51 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -431,6 +431,9 @@ struct WOLFSSL_EVP_CIPHER_CTX { byte* gcmAuthIn; int gcmAuthInSz; #endif +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + byte* key; /* used in partial Init()s */ +#endif #if defined(HAVE_AESGCM) || (defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) #ifdef HAVE_AESGCM ALIGN16 unsigned char authTag[AES_BLOCK_SIZE];