diff --git a/tests/api.c b/tests/api.c index d18334ef9..546b6ab04 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35343,6 +35343,53 @@ static void test_wolfSSL_PEM_read(void) #endif } +static void test_wolfssl_EVP_aes_gcm_AAD_2_parts(void) +{ +#if defined(OPENSSL_EXTRA) && !defined(NO_AES) && defined(HAVE_AESGCM) && \ + !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) + const byte iv[12] = { 0 }; + const byte key[16] = { 0 }; + const byte cleartext[16] = { 0 }; + const byte aad[] = {0x01, 0x10, 0x00, 0x2a, 0x08, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0xdc, 0x4d, + 0xad, 0x6b, 0x06, 0x93, 0x4f}; + byte out1Part[16]; + byte outTag1Part[16]; + byte out2Part[16]; + byte outTag2Part[16]; + int len; + EVP_CIPHER_CTX* ctx = NULL; + + printf(testingFmt, "wolfssl_EVP_aes_gcm_AAD_2_parts"); + + /* Send AAD in 1 part */ + AssertNotNull(ctx = EVP_CIPHER_CTX_new()); + AssertIntEQ(EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), 1); + AssertIntEQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv), 1); + AssertIntEQ(EVP_EncryptUpdate(ctx, NULL, &len, aad, sizeof(aad)), 1); + AssertIntEQ(EVP_EncryptUpdate(ctx, out1Part, &len, cleartext, sizeof(cleartext)), 1); + AssertIntEQ(EVP_EncryptFinal_ex(ctx, out1Part, &len), 1); + AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, outTag1Part), 1); + EVP_CIPHER_CTX_free(ctx); + + /* Send AAD in 2 parts */ + AssertNotNull(ctx = EVP_CIPHER_CTX_new()); + AssertIntEQ(EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), 1); + AssertIntEQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv), 1); + AssertIntEQ(EVP_EncryptUpdate(ctx, NULL, &len, aad, 1), 1); + AssertIntEQ(EVP_EncryptUpdate(ctx, NULL, &len, aad + 1, sizeof(aad) - 1), 1); + AssertIntEQ(EVP_EncryptUpdate(ctx, out2Part, &len, cleartext, sizeof(cleartext)), 1); + AssertIntEQ(EVP_EncryptFinal_ex(ctx, out2Part, &len), 1); + AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, outTag2Part), 1); + EVP_CIPHER_CTX_free(ctx); + + AssertIntEQ(XMEMCMP(out1Part, out2Part, sizeof(out1Part)), 0); + AssertIntEQ(XMEMCMP(outTag1Part, outTag2Part, sizeof(outTag1Part)), 0); + + printf(resultFmt, passed); +#endif +} + static void test_wolfssl_EVP_aes_gcm(void) { #if defined(OPENSSL_EXTRA) && !defined(NO_AES) && defined(HAVE_AESGCM) && \ @@ -36738,6 +36785,7 @@ void ApiTest(void) test_wolfSSL_DC_cert(); test_wolfSSL_DES_ncbc(); test_wolfSSL_AES_cbc_encrypt(); + test_wolfssl_EVP_aes_gcm_AAD_2_parts(); test_wolfssl_EVP_aes_gcm(); test_wolfSSL_PKEY_up_ref(); test_wolfSSL_i2d_PrivateKey(); diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 6df054318..b48801340 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -549,6 +549,22 @@ static int evpCipherBlock(WOLFSSL_EVP_CIPHER_CTX *ctx, } #if defined(HAVE_AESGCM) +static int wolfSSL_EVP_CipherUpdate_GCM_AAD(WOLFSSL_EVP_CIPHER_CTX *ctx, + const unsigned char *in, int inl) { + byte* tmp = (byte*)XREALLOC(ctx->gcmAuthIn, + ctx->gcmAuthInSz + inl, NULL, DYNAMIC_TYPE_OPENSSL); + if (tmp) { + ctx->gcmAuthIn = tmp; + XMEMCPY(ctx->gcmAuthIn + ctx->gcmAuthInSz, in, inl); + ctx->gcmAuthInSz += inl; + } + else { + WOLFSSL_MSG("realloc error"); + return MEMORY_E; + } + return 0; +} + static int wolfSSL_EVP_CipherUpdate_GCM(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) @@ -558,47 +574,69 @@ static int wolfSSL_EVP_CipherUpdate_GCM(WOLFSSL_EVP_CIPHER_CTX *ctx, *outl = inl; if (ctx->enc) { if (out) { + if (ctx->gcmAuthIn) { + /* authenticated, non-confidential data */ + XMEMSET(ctx->authTag, 0, ctx->authTagSz); + ret = wc_AesGcmEncrypt(&ctx->cipher.aes, NULL, NULL, 0, + ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, + ctx->gcmAuthIn, ctx->gcmAuthInSz); + /* Reset partial authTag error for AAD*/ + if (ret == AES_GCM_AUTH_E) + ret = 0; + if (ret == 0) { + XFREE(ctx->gcmAuthIn, NULL, DYNAMIC_TYPE_OPENSSL); + ctx->gcmAuthIn = NULL; + ctx->gcmAuthInSz = 0; + } + } + /* encrypt confidential data*/ - ret = wc_AesGcmEncrypt(&ctx->cipher.aes, out, in, inl, - ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, - NULL, 0); + if (ret == 0) + ret = wc_AesGcmEncrypt(&ctx->cipher.aes, out, in, inl, + ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, + NULL, 0); } else { - /* authenticated, non-confidential data */ - XMEMSET(ctx->authTag, 0, ctx->authTagSz); - ret = wc_AesGcmEncrypt(&ctx->cipher.aes, NULL, NULL, 0, - ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, - in, inl); - /* Reset partial authTag error for AAD*/ - if (ret == AES_GCM_AUTH_E) - ret = 0; + ret = wolfSSL_EVP_CipherUpdate_GCM_AAD(ctx, in, inl); } } else { if (out) { byte* tmp; - tmp = (byte*)XREALLOC(ctx->gcmDecryptBuffer, - ctx->gcmDecryptBufferLen + inl, NULL, - DYNAMIC_TYPE_OPENSSL); - if (tmp) { - XMEMCPY(tmp + ctx->gcmDecryptBufferLen, in, inl); - ctx->gcmDecryptBufferLen += inl; - ctx->gcmDecryptBuffer = tmp; - *outl = 0; + + if (ctx->gcmAuthIn) { + /* authenticated, non-confidential data*/ + ret = wc_AesGcmDecrypt(&ctx->cipher.aes, NULL, NULL, 0, + ctx->iv, ctx->ivSz, + ctx->authTag, ctx->authTagSz, + ctx->gcmAuthIn, ctx->gcmAuthInSz); + /* Reset partial authTag error for AAD*/ + if (ret == AES_GCM_AUTH_E) + ret = 0; + if (ret == 0) { + XFREE(ctx->gcmAuthIn, NULL, DYNAMIC_TYPE_OPENSSL); + ctx->gcmAuthIn = NULL; + ctx->gcmAuthInSz = 0; + } } - else { - ret = WOLFSSL_FAILURE; + + if (ret == 0) { + tmp = (byte*)XREALLOC(ctx->gcmDecryptBuffer, + ctx->gcmDecryptBufferLen + inl, NULL, + DYNAMIC_TYPE_OPENSSL); + if (tmp) { + XMEMCPY(tmp + ctx->gcmDecryptBufferLen, in, inl); + ctx->gcmDecryptBufferLen += inl; + ctx->gcmDecryptBuffer = tmp; + *outl = 0; + } + else { + ret = MEMORY_E; + } } } else { - /* authenticated, non-confidential data*/ - ret = wc_AesGcmDecrypt(&ctx->cipher.aes, NULL, NULL, 0, - ctx->iv, ctx->ivSz, - ctx->authTag, ctx->authTagSz, - in, inl); - /* Reset partial authTag error for AAD*/ - if (ret == AES_GCM_AUTH_E) - ret = 0; + ret = wolfSSL_EVP_CipherUpdate_GCM_AAD(ctx, in, inl); } } @@ -4123,6 +4161,11 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD *md) ctx->gcmDecryptBuffer = NULL; } ctx->gcmDecryptBufferLen = 0; + if (ctx->gcmAuthIn) { + XFREE(ctx->gcmAuthIn, NULL, DYNAMIC_TYPE_OPENSSL); + ctx->gcmAuthIn = NULL; + } + ctx->gcmAuthInSz = 0; #endif } diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index e8846609c..e9dd79c5b 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -358,6 +358,8 @@ struct WOLFSSL_EVP_CIPHER_CTX { int gcmDecryptBufferLen; ALIGN16 unsigned char authTag[AES_BLOCK_SIZE]; int authTagSz; + byte* gcmAuthIn; + int gcmAuthInSz; #endif #endif };