Fix IV length bug in EVP AES-GCM code.

In `wolfSSL_EVP_CipherInit`, `ctx`'s `ivSz` field isn't being accounted for.
A common OpenSSL EVP AES-GCM flow looks like this:

- `EVP_CIPHER_CTX_new`
- `EVP_EncryptInit_ex`
- `EVP_CIPHER_CTX_ctrl` with command `EVP_CTRL_GCM_SET_IVLEN` to set the IV
length to 16 (AES block size) instead of the default 12
- `EVP_EncryptInit_ex` again to set the key and IV
- `EVP_EncryptUpdate` however many times
- `EVP_EncryptFinal`

In fact, we test this flow in our unit test `test_wolfssl_EVP_aes_gcm`. However,
in our implementation, the second call to `EVP_EncryptInit_ex` unconditionally
resets the IV length back to 12. This doesn't cause a test failure because
decryption has the same problem, so both sides of the equation have the same
wrong view of the IV.

The solution is to preserve the IV length in wolfSSL_EVP_CipherInit if ctx->ivSz
is non-zero. Otherwise, use the default of 12 (`GCM_NONCE_MID_SZ`).

This was discovered by a user migrating to the compatibility layer. As I
mentioned, it isn't exposed by our testing. It is exposed if you try to use the
same key and IV with OpenSSL and compare the resulting ciphertext with wolfSSL.
They won't be the same and thus won't interoperate.
This commit is contained in:
Hayden Roche 2022-02-03 17:19:35 -08:00
parent 53e64b55e1
commit b850cc89b0

View File

@ -5095,7 +5095,9 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
ctx->keyLen = 16;
ctx->block_size = AES_BLOCK_SIZE;
ctx->authTagSz = AES_BLOCK_SIZE;
ctx->ivSz = GCM_NONCE_MID_SZ;
if (ctx->ivSz == 0) {
ctx->ivSz = GCM_NONCE_MID_SZ;
}
#ifndef WOLFSSL_AESGCM_STREAM
if (key && wc_AesGcmSetKey(&ctx->cipher.aes, key, ctx->keyLen)) {
@ -5103,7 +5105,7 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
return WOLFSSL_FAILURE;
}
#endif /* !WOLFSSL_AESGCM_STREAM */
if (iv && wc_AesGcmSetExtIV(&ctx->cipher.aes, iv, GCM_NONCE_MID_SZ)) {
if (iv && wc_AesGcmSetExtIV(&ctx->cipher.aes, iv, ctx->ivSz)) {
WOLFSSL_MSG("wc_AesGcmSetExtIV() failed");
return WOLFSSL_FAILURE;
}
@ -5111,7 +5113,7 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
/* Initialize with key and IV if available. */
if (wc_AesGcmInit(&ctx->cipher.aes, key,
(key == NULL) ? 0 : ctx->keyLen, iv,
(iv == NULL) ? 0 : GCM_NONCE_MID_SZ) != 0) {
(iv == NULL) ? 0 : ctx->ivSz) != 0) {
WOLFSSL_MSG("wc_AesGcmInit() failed");
return WOLFSSL_FAILURE;
}
@ -5131,7 +5133,9 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
ctx->keyLen = 24;
ctx->block_size = AES_BLOCK_SIZE;
ctx->authTagSz = AES_BLOCK_SIZE;
ctx->ivSz = GCM_NONCE_MID_SZ;
if (ctx->ivSz == 0) {
ctx->ivSz = GCM_NONCE_MID_SZ;
}
#ifndef WOLFSSL_AESGCM_STREAM
if (key && wc_AesGcmSetKey(&ctx->cipher.aes, key, ctx->keyLen)) {
@ -5139,7 +5143,7 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
return WOLFSSL_FAILURE;
}
#endif /* !WOLFSSL_AESGCM_STREAM */
if (iv && wc_AesGcmSetExtIV(&ctx->cipher.aes, iv, GCM_NONCE_MID_SZ)) {
if (iv && wc_AesGcmSetExtIV(&ctx->cipher.aes, iv, ctx->ivSz)) {
WOLFSSL_MSG("wc_AesGcmSetExtIV() failed");
return WOLFSSL_FAILURE;
}
@ -5147,7 +5151,7 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
/* Initialize with key and IV if available. */
if (wc_AesGcmInit(&ctx->cipher.aes, key,
(key == NULL) ? 0 : ctx->keyLen, iv,
(iv == NULL) ? 0 : GCM_NONCE_MID_SZ) != 0) {
(iv == NULL) ? 0 : ctx->ivSz) != 0) {
WOLFSSL_MSG("wc_AesGcmInit() failed");
return WOLFSSL_FAILURE;
}
@ -5167,7 +5171,9 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
ctx->keyLen = 32;
ctx->block_size = AES_BLOCK_SIZE;
ctx->authTagSz = AES_BLOCK_SIZE;
ctx->ivSz = GCM_NONCE_MID_SZ;
if (ctx->ivSz == 0) {
ctx->ivSz = GCM_NONCE_MID_SZ;
}
#ifndef WOLFSSL_AESGCM_STREAM
if (key && wc_AesGcmSetKey(&ctx->cipher.aes, key, ctx->keyLen)) {
@ -5175,7 +5181,7 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
return WOLFSSL_FAILURE;
}
#endif /* !WOLFSSL_AESGCM_STREAM */
if (iv && wc_AesGcmSetExtIV(&ctx->cipher.aes, iv, GCM_NONCE_MID_SZ)) {
if (iv && wc_AesGcmSetExtIV(&ctx->cipher.aes, iv, ctx->ivSz)) {
WOLFSSL_MSG("wc_AesGcmSetExtIV() failed");
return WOLFSSL_FAILURE;
}
@ -5183,7 +5189,7 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
/* Initialize with key and IV if available. */
if (wc_AesGcmInit(&ctx->cipher.aes,
key, (key == NULL) ? 0 : ctx->keyLen,
iv, (iv == NULL) ? 0 : GCM_NONCE_MID_SZ) != 0) {
iv, (iv == NULL) ? 0 : ctx->ivSz) != 0) {
WOLFSSL_MSG("wc_AesGcmInit() failed");
return WOLFSSL_FAILURE;
}
@ -5874,7 +5880,7 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
{
int expectedIvLen;
WOLFSSL_ENTER("wolfSSL_EVP_CIPHER_CTX_set_iv_length");
WOLFSSL_ENTER("wolfSSL_EVP_CIPHER_CTX_set_iv");
if (!ctx || !iv || !ivLen) {
return WOLFSSL_FAILURE;
}
@ -7420,6 +7426,9 @@ int wolfSSL_EVP_CIPHER_CTX_iv_length(const WOLFSSL_EVP_CIPHER_CTX* ctx)
case AES_192_GCM_TYPE :
case AES_256_GCM_TYPE :
WOLFSSL_MSG("AES GCM");
if (ctx->ivSz != 0) {
return ctx->ivSz;
}
return GCM_NONCE_MID_SZ;
#endif
#endif /* (HAVE_FIPS && !HAVE_SELFTEST) || HAVE_FIPS_VERSION >= 2 */