From 77969ae0427101d37f64199a798ba224dd6c7e17 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Tue, 22 Sep 2020 21:58:57 +0200 Subject: [PATCH 1/5] Buffer AAD in wolfSSL_EVP_CipherUpdate_GCM so that whole value is hashed --- tests/api.c | 48 ++++++++++++++++++++ wolfcrypt/src/evp.c | 101 ++++++++++++++++++++++++++++++------------ wolfssl/openssl/evp.h | 2 + 3 files changed, 122 insertions(+), 29 deletions(-) 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 }; From 7e38b6bee6f61be1113714cacfc3a45baee914a3 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 25 Sep 2020 11:03:58 +0200 Subject: [PATCH 2/5] Test 2 part GCM data and EVP context re-use --- tests/api.c | 21 ++++++- wolfcrypt/src/evp.c | 134 ++++++++++++++++++------------------------ wolfssl/openssl/evp.h | 4 +- 3 files changed, 77 insertions(+), 82 deletions(-) diff --git a/tests/api.c b/tests/api.c index 546b6ab04..b5f7042ad 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35362,25 +35362,40 @@ static void test_wolfssl_EVP_aes_gcm_AAD_2_parts(void) printf(testingFmt, "wolfssl_EVP_aes_gcm_AAD_2_parts"); - /* Send AAD in 1 part */ + /* Send AAD and data 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(len, sizeof(cleartext)); AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, outTag1Part), 1); EVP_CIPHER_CTX_free(ctx); - /* Send AAD in 2 parts */ + /* Send AAD and data 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_EncryptUpdate(ctx, out2Part, &len, cleartext, 1), 1); + AssertIntEQ(EVP_EncryptUpdate(ctx, out2Part, &len, cleartext + 1, + sizeof(cleartext) - 1), 1); AssertIntEQ(EVP_EncryptFinal_ex(ctx, out2Part, &len), 1); + AssertIntEQ(len, sizeof(cleartext)); AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, outTag2Part), 1); + + AssertIntEQ(XMEMCMP(out1Part, out2Part, sizeof(out1Part)), 0); + AssertIntEQ(XMEMCMP(outTag1Part, outTag2Part, sizeof(outTag1Part)), 0); + + /* Test AAD re-use */ + 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, out1Part, &len, cleartext, sizeof(cleartext)), 1); + AssertIntEQ(EVP_EncryptFinal_ex(ctx, out1Part, &len), 1); + AssertIntEQ(len, sizeof(cleartext)); + AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, outTag1Part), 1); EVP_CIPHER_CTX_free(ctx); AssertIntEQ(XMEMCMP(out1Part, out2Part, sizeof(out1Part)), 0); diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index b48801340..262f256b5 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -572,72 +572,26 @@ static int wolfSSL_EVP_CipherUpdate_GCM(WOLFSSL_EVP_CIPHER_CTX *ctx, int ret = 0; *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; - } + if (out) { + /* Buffer input for one-shot API */ + if (ret == 0) { + byte* tmp; + tmp = (byte*)XREALLOC(ctx->gcmBuffer, + ctx->gcmBufferLen + inl, NULL, + DYNAMIC_TYPE_OPENSSL); + if (tmp) { + XMEMCPY(tmp + ctx->gcmBufferLen, in, inl); + ctx->gcmBufferLen += inl; + ctx->gcmBuffer = tmp; + *outl = 0; + } + else { + ret = MEMORY_E; } - - /* encrypt confidential data*/ - if (ret == 0) - ret = wc_AesGcmEncrypt(&ctx->cipher.aes, out, in, inl, - ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, - NULL, 0); - } - else { - ret = wolfSSL_EVP_CipherUpdate_GCM_AAD(ctx, in, inl); } } else { - if (out) { - byte* tmp; - - 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; - } - } - - 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 { - ret = wolfSSL_EVP_CipherUpdate_GCM_AAD(ctx, in, inl); - } + ret = wolfSSL_EVP_CipherUpdate_GCM_AAD(ctx, in, inl); } if (ret != 0) { @@ -810,25 +764,51 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, case AES_128_GCM_TYPE: case AES_192_GCM_TYPE: case AES_256_GCM_TYPE: - if (!ctx->enc && ctx->gcmDecryptBuffer && - ctx->gcmDecryptBufferLen > 0) { - /* decrypt confidential data*/ - ret = wc_AesGcmDecrypt(&ctx->cipher.aes, out, - ctx->gcmDecryptBuffer, ctx->gcmDecryptBufferLen, - ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, - NULL, 0); + if (ctx->gcmBuffer && + ctx->gcmBufferLen > 0) { + if (ctx->gcmAuthIn) { + /* authenticated, non-confidential data*/ + if (ctx->enc) { + 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); + } + else { + 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 (ctx->enc) + /* encrypt confidential data*/ + ret = wc_AesGcmEncrypt(&ctx->cipher.aes, out, + ctx->gcmBuffer, ctx->gcmBufferLen, + ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, + NULL, 0); + else + /* decrypt confidential data*/ + ret = wc_AesGcmDecrypt(&ctx->cipher.aes, out, + ctx->gcmBuffer, ctx->gcmBufferLen, + ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, + NULL, 0); + if (ret == 0) { ret = WOLFSSL_SUCCESS; - *outl = ctx->gcmDecryptBufferLen; + *outl = ctx->gcmBufferLen; } else { ret = WOLFSSL_FAILURE; *outl = 0; } - XFREE(ctx->gcmDecryptBuffer, NULL, DYNAMIC_TYPE_OPENSSL); - ctx->gcmDecryptBuffer = NULL; - ctx->gcmDecryptBufferLen = 0; + XFREE(ctx->gcmBuffer, NULL, DYNAMIC_TYPE_OPENSSL); + ctx->gcmBuffer = NULL; + ctx->gcmBufferLen = 0; } else { *outl = 0; @@ -4156,11 +4136,11 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD *md) ctx->cipherType = WOLFSSL_EVP_CIPH_TYPE_INIT; /* not yet initialized */ ctx->keyLen = 0; #ifdef HAVE_AESGCM - if (ctx->gcmDecryptBuffer) { - XFREE(ctx->gcmDecryptBuffer, NULL, DYNAMIC_TYPE_OPENSSL); - ctx->gcmDecryptBuffer = NULL; + if (ctx->gcmBuffer) { + XFREE(ctx->gcmBuffer, NULL, DYNAMIC_TYPE_OPENSSL); + ctx->gcmBuffer = NULL; } - ctx->gcmDecryptBufferLen = 0; + ctx->gcmBufferLen = 0; if (ctx->gcmAuthIn) { XFREE(ctx->gcmAuthIn, NULL, DYNAMIC_TYPE_OPENSSL); ctx->gcmAuthIn = NULL; diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index e9dd79c5b..fa1065a9d 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -354,8 +354,8 @@ struct WOLFSSL_EVP_CIPHER_CTX { #define HAVE_WOLFSSL_EVP_CIPHER_CTX_IV int ivSz; #ifdef HAVE_AESGCM - byte* gcmDecryptBuffer; - int gcmDecryptBufferLen; + byte* gcmBuffer; + int gcmBufferLen; ALIGN16 unsigned char authTag[AES_BLOCK_SIZE]; int authTagSz; byte* gcmAuthIn; From 942168c62d4bb4d8d3c72b7739725726b97359f6 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 28 Sep 2020 15:59:50 +0200 Subject: [PATCH 3/5] Add decrypt tests --- tests/api.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/api.c b/tests/api.c index b5f7042ad..778a7a3e3 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35357,11 +35357,13 @@ static void test_wolfssl_EVP_aes_gcm_AAD_2_parts(void) byte outTag1Part[16]; byte out2Part[16]; byte outTag2Part[16]; + byte decryptBuf[16]; int len; EVP_CIPHER_CTX* ctx = NULL; printf(testingFmt, "wolfssl_EVP_aes_gcm_AAD_2_parts"); + /* ENCRYPT */ /* Send AAD and data in 1 part */ AssertNotNull(ctx = EVP_CIPHER_CTX_new()); AssertIntEQ(EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), 1); @@ -35373,6 +35375,21 @@ static void test_wolfssl_EVP_aes_gcm_AAD_2_parts(void) AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, outTag1Part), 1); EVP_CIPHER_CTX_free(ctx); + /* DECRYPT */ + /* Send AAD and data in 1 part */ + AssertNotNull(ctx = EVP_CIPHER_CTX_new()); + AssertIntEQ(EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), 1); + AssertIntEQ(EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv), 1); + AssertIntEQ(EVP_DecryptUpdate(ctx, NULL, &len, aad, sizeof(aad)), 1); + AssertIntEQ(EVP_DecryptUpdate(ctx, decryptBuf, &len, out1Part, sizeof(cleartext)), 1); + AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, outTag1Part), 1); + AssertIntEQ(EVP_DecryptFinal_ex(ctx, decryptBuf, &len), 1); + AssertIntEQ(len, sizeof(cleartext)); + EVP_CIPHER_CTX_free(ctx); + + AssertIntEQ(XMEMCMP(decryptBuf, cleartext, len), 0); + + /* ENCRYPT */ /* Send AAD and data in 2 parts */ AssertNotNull(ctx = EVP_CIPHER_CTX_new()); AssertIntEQ(EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), 1); @@ -35401,6 +35418,37 @@ static void test_wolfssl_EVP_aes_gcm_AAD_2_parts(void) AssertIntEQ(XMEMCMP(out1Part, out2Part, sizeof(out1Part)), 0); AssertIntEQ(XMEMCMP(outTag1Part, outTag2Part, sizeof(outTag1Part)), 0); + /* DECRYPT */ + /* Send AAD and data in 2 parts */ + AssertNotNull(ctx = EVP_CIPHER_CTX_new()); + AssertIntEQ(EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), 1); + AssertIntEQ(EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv), 1); + AssertIntEQ(EVP_DecryptUpdate(ctx, NULL, &len, aad, 1), 1); + AssertIntEQ(EVP_DecryptUpdate(ctx, NULL, &len, aad + 1, sizeof(aad) - 1), 1); + AssertIntEQ(EVP_DecryptUpdate(ctx, decryptBuf, &len, out1Part, 1), 1); + AssertIntEQ(EVP_DecryptUpdate(ctx, decryptBuf, &len, out1Part + 1, + sizeof(cleartext) - 1), 1); + AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, outTag1Part), 1); + AssertIntEQ(EVP_DecryptFinal_ex(ctx, decryptBuf, &len), 1); + AssertIntEQ(len, sizeof(cleartext)); + + AssertIntEQ(XMEMCMP(decryptBuf, cleartext, len), 0); + + /* Test AAD re-use */ + AssertIntEQ(EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), 1); + AssertIntEQ(EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv), 1); + AssertIntEQ(EVP_DecryptUpdate(ctx, decryptBuf, &len, out1Part, 1), 1); + AssertIntEQ(EVP_DecryptUpdate(ctx, decryptBuf, &len, out1Part + 1, + sizeof(cleartext) - 1), 1); + AssertIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, outTag1Part), 1); + AssertIntEQ(EVP_DecryptFinal_ex(ctx, decryptBuf, &len), 1); + AssertIntEQ(len, sizeof(cleartext)); + + AssertIntEQ(XMEMCMP(decryptBuf, cleartext, len), 0); + + /* Test AAD re-use */ + EVP_CIPHER_CTX_free(ctx); + printf(resultFmt, passed); #endif } From 07f6c19156406f8281d962b251670e47453ff602 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 28 Sep 2020 20:42:23 +0200 Subject: [PATCH 4/5] Update EVP_CIPHER to handle multi-part AAD --- wolfcrypt/src/evp.c | 113 ++++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 52 deletions(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 262f256b5..6c8ca3848 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -551,16 +551,18 @@ 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; + if (in && inl > 0) { + 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; } @@ -766,6 +768,7 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, case AES_256_GCM_TYPE: if (ctx->gcmBuffer && ctx->gcmBufferLen > 0) { + ret = 0; if (ctx->gcmAuthIn) { /* authenticated, non-confidential data*/ if (ctx->enc) { @@ -784,18 +787,20 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, } } - if (ctx->enc) - /* encrypt confidential data*/ - ret = wc_AesGcmEncrypt(&ctx->cipher.aes, out, - ctx->gcmBuffer, ctx->gcmBufferLen, - ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, - NULL, 0); - else - /* decrypt confidential data*/ - ret = wc_AesGcmDecrypt(&ctx->cipher.aes, out, - ctx->gcmBuffer, ctx->gcmBufferLen, - ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, - NULL, 0); + if (ret == 0) { + if (ctx->enc) + /* encrypt confidential data*/ + ret = wc_AesGcmEncrypt(&ctx->cipher.aes, out, + ctx->gcmBuffer, ctx->gcmBufferLen, + ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, + NULL, 0); + else + /* decrypt confidential data*/ + ret = wc_AesGcmDecrypt(&ctx->cipher.aes, out, + ctx->gcmBuffer, ctx->gcmBufferLen, + ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, + NULL, 0); + } if (ret == 0) { ret = WOLFSSL_SUCCESS; @@ -5247,41 +5252,45 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD *md) case AES_192_GCM_TYPE : case AES_256_GCM_TYPE : WOLFSSL_MSG("AES GCM"); - if (ctx->enc) { - if (dst){ - /* encrypt confidential data*/ - ret = wc_AesGcmEncrypt(&ctx->cipher.aes, dst, src, len, - ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, - NULL, 0); - } - else { - /* authenticated, non-confidential data */ - ret = wc_AesGcmEncrypt(&ctx->cipher.aes, NULL, NULL, 0, - ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, - src, len); - /* Reset partial authTag error for AAD*/ - if (ret == AES_GCM_AUTH_E) - ret = 0; - } + if (!dst) { + ret = wolfSSL_EVP_CipherUpdate_GCM_AAD(ctx, src, len); } else { - if (dst){ - /* decrypt confidential data*/ - ret = wc_AesGcmDecrypt(&ctx->cipher.aes, dst, src, len, - ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz, - NULL, 0); - } - else { + ret = 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, - src, len); - /* Reset partial authTag error for AAD*/ - if (ret == AES_GCM_AUTH_E) - ret = 0; + if (ctx->enc) { + 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); + } + else { + 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) { + if (ctx->enc) + /* encrypt confidential data*/ + ret = wc_AesGcmEncrypt(&ctx->cipher.aes, dst, src, + len, ctx->iv, ctx->ivSz, ctx->authTag, + ctx->authTagSz, NULL, 0); + else + /* decrypt confidential data*/ + ret = wc_AesGcmDecrypt(&ctx->cipher.aes, dst, src, + len, ctx->iv, ctx->ivSz, ctx->authTag, + ctx->authTagSz, NULL, 0); } } + break; #endif /* HAVE_AESGCM */ #ifdef HAVE_AES_ECB From 78e003e7de98dad6bb772df8de4d9831a4ba26c0 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Tue, 29 Sep 2020 12:24:59 +0200 Subject: [PATCH 5/5] Plug leak --- tests/api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/api.c b/tests/api.c index 778a7a3e3..d5e9d580a 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35514,6 +35514,7 @@ static void test_wolfssl_EVP_aes_gcm(void) AssertIntEQ(1, EVP_EncryptFinal_ex(&en[i], ciphertxt, &len)); ciphertxtSz += len; AssertIntEQ(1, EVP_CIPHER_CTX_ctrl(&en[i], EVP_CTRL_GCM_GET_TAG, AES_BLOCK_SIZE, tag)); + AssertIntEQ(wolfSSL_EVP_CIPHER_CTX_cleanup(&en[i]), 1); EVP_CIPHER_CTX_init(&de[i]); if (i == 0) { @@ -35556,6 +35557,7 @@ static void test_wolfssl_EVP_aes_gcm(void) AssertIntEQ(1, EVP_DecryptUpdate(&de[i], decryptedtxt, &len, ciphertxt, ciphertxtSz)); AssertIntEQ(0, EVP_DecryptFinal_ex(&de[i], decryptedtxt, &len)); AssertIntEQ(0, len); + AssertIntEQ(wolfSSL_EVP_CIPHER_CTX_cleanup(&de[i]), 1); } printf(resultFmt, passed);