diff --git a/tests/api.c b/tests/api.c index e4f669215..0deca96df 100644 --- a/tests/api.c +++ b/tests/api.c @@ -36004,6 +36004,116 @@ 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]; + 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); + 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); + + /* 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); + 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, 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); + 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 +} + static void test_wolfssl_EVP_aes_gcm(void) { #if defined(OPENSSL_EXTRA) && !defined(NO_AES) && defined(HAVE_AESGCM) && \ @@ -36065,6 +36175,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) { @@ -36107,6 +36218,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); @@ -37399,6 +37511,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 519157867..3b5f1b47e 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -553,6 +553,24 @@ 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) { + 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; +} + static int wolfSSL_EVP_CipherUpdate_GCM(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) @@ -560,50 +578,26 @@ static int wolfSSL_EVP_CipherUpdate_GCM(WOLFSSL_EVP_CIPHER_CTX *ctx, int ret = 0; *outl = inl; - if (ctx->enc) { - if (out) { - /* encrypt confidential data*/ - 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; - } - } - else { - if (out) { + if (out) { + /* Buffer input for one-shot API */ + if (ret == 0) { byte* tmp; - tmp = (byte*)XREALLOC(ctx->gcmDecryptBuffer, - ctx->gcmDecryptBufferLen + inl, NULL, + tmp = (byte*)XREALLOC(ctx->gcmBuffer, + ctx->gcmBufferLen + inl, NULL, DYNAMIC_TYPE_OPENSSL); if (tmp) { - XMEMCPY(tmp + ctx->gcmDecryptBufferLen, in, inl); - ctx->gcmDecryptBufferLen += inl; - ctx->gcmDecryptBuffer = tmp; + XMEMCPY(tmp + ctx->gcmBufferLen, in, inl); + ctx->gcmBufferLen += inl; + ctx->gcmBuffer = tmp; *outl = 0; } else { - ret = WOLFSSL_FAILURE; + 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; - } + } + else { + ret = wolfSSL_EVP_CipherUpdate_GCM_AAD(ctx, in, inl); } if (ret != 0) { @@ -776,25 +770,54 @@ 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) { + ret = 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 (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; @@ -4054,11 +4077,16 @@ 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; + } + ctx->gcmAuthInSz = 0; #endif } @@ -5176,41 +5204,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 diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index e8846609c..fa1065a9d 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -354,10 +354,12 @@ 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; + int gcmAuthInSz; #endif #endif };