Add FIPS Self test for AES_ECB decrypt

Fixes #14807

Compliance with IG 9.4 requires that an inverse cipher function be
tested if one is implemented. Just running AES_GCM encrypt/decrypt does not meet this
requirement (Since only ECB, CBC, XTS, KW, KWP support the inverse
function during decryption mode).

Added a mode to the cipher test so that the AES_GCM only does an encrypt
and AES_ECB only does a decrypt. TDES still does both.

Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14825)
This commit is contained in:
Shane Lontis 2021-04-12 10:38:16 +10:00
parent 28fd895305
commit 3fed27181a
5 changed files with 87 additions and 31 deletions

View File

@ -267,7 +267,9 @@ Key generation tests used with the "Pairwise_Consistency_Test" type.
"KAT_AsymmetricCipher" uses this to indicate an encrypt or decrypt KAT.
=item "AES_GCM" (B<OSSL_SELF_TEST_DESC_CIPHER_AES_GCM>)
=item "AES_GCM_Encrypt" (B<OSSL_SELF_TEST_DESC_CIPHER_AES_GCM>)
=item "AES_ECB_Decrypt" (B<OSSL_SELF_TEST_DESC_CIPHER_AES_ECB>)
=item "TDES" (B<OSSL_SELF_TEST_DESC_CIPHER_TDES>)

View File

@ -44,7 +44,8 @@ extern "C" {
# define OSSL_SELF_TEST_DESC_PCT_RSA_PKCS1 "RSA"
# define OSSL_SELF_TEST_DESC_PCT_ECDSA "ECDSA"
# define OSSL_SELF_TEST_DESC_PCT_DSA "DSA"
# define OSSL_SELF_TEST_DESC_CIPHER_AES_GCM "AES_GCM"
# define OSSL_SELF_TEST_DESC_CIPHER_AES_GCM "AES_GCM_Encrypt"
# define OSSL_SELF_TEST_DESC_CIPHER_AES_ECB "AES_ECB_Decrypt"
# define OSSL_SELF_TEST_DESC_CIPHER_TDES "TDES"
# define OSSL_SELF_TEST_DESC_ASYM_RSA_ENC "RSA_Encrypt"
# define OSSL_SELF_TEST_DESC_ASYM_RSA_DEC "RSA_Decrypt"

View File

@ -40,9 +40,14 @@ typedef struct st_kat_st {
size_t expected_len;
} ST_KAT;
#define CIPHER_MODE_ENCRYPT 1
#define CIPHER_MODE_DECRYPT 2
#define CIPHER_MODE_ALL (CIPHER_MODE_ENCRYPT | CIPHER_MODE_DECRYPT)
typedef ST_KAT ST_KAT_DIGEST;
typedef struct st_kat_cipher_st {
ST_KAT base;
int mode;
const unsigned char *key;
size_t key_len;
const unsigned char *iv;
@ -215,6 +220,20 @@ static const unsigned char aes_256_gcm_tag[] = {
0x14, 0xd9, 0xc5, 0x1e, 0x1d, 0xa4, 0x74, 0xab
};
/* AES-ECB test data */
static const unsigned char aes_128_ecb_key[] = {
0x10, 0xa5, 0x88, 0x69, 0xd7, 0x4b, 0xe5, 0xa3,
0x74, 0xcf, 0x86, 0x7c, 0xfb, 0x47, 0x38, 0x59
};
static const unsigned char aes_128_ecb_pt[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char aes_128_ecb_ct[] = {
0x6d, 0x25, 0x1e, 0x69, 0x44, 0xb0, 0x51, 0xe0,
0x4e, 0xaa, 0x6f, 0xb4, 0xdb, 0xf7, 0x84, 0x65
};
static const ST_KAT_CIPHER st_kat_cipher_tests[] = {
#ifndef OPENSSL_NO_DES
{
@ -224,6 +243,7 @@ static const ST_KAT_CIPHER st_kat_cipher_tests[] = {
ITM(des_ede3_cbc_pt),
ITM(des_ede3_cbc_ct)
},
CIPHER_MODE_ENCRYPT | CIPHER_MODE_DECRYPT,
ITM(des_ede3_cbc_key),
ITM(des_ede3_cbc_iv),
},
@ -233,12 +253,23 @@ static const ST_KAT_CIPHER st_kat_cipher_tests[] = {
OSSL_SELF_TEST_DESC_CIPHER_AES_GCM,
"AES-256-GCM",
ITM(aes_256_gcm_pt),
ITM(aes_256_gcm_ct),
ITM(aes_256_gcm_ct)
},
CIPHER_MODE_ENCRYPT,
ITM(aes_256_gcm_key),
ITM(aes_256_gcm_iv),
ITM(aes_256_gcm_aad),
ITM(aes_256_gcm_tag)
},
{
{
OSSL_SELF_TEST_DESC_CIPHER_AES_ECB,
"AES-128-ECB",
ITM(aes_128_ecb_pt),
ITM(aes_128_ecb_ct)
},
CIPHER_MODE_DECRYPT,
ITM(aes_128_ecb_key)
}
};

View File

@ -85,7 +85,7 @@ static int cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
static int self_test_cipher(const ST_KAT_CIPHER *t, OSSL_SELF_TEST *st,
OSSL_LIB_CTX *libctx)
{
int ret = 0, encrypt = 1, len, ct_len = 0, pt_len = 0;
int ret = 0, encrypt = 1, len = 0, ct_len = 0, pt_len = 0;
EVP_CIPHER_CTX *ctx = NULL;
EVP_CIPHER *cipher = NULL;
unsigned char ct_buf[256] = { 0 };
@ -96,39 +96,47 @@ static int self_test_cipher(const ST_KAT_CIPHER *t, OSSL_SELF_TEST *st,
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
goto err;
cipher = EVP_CIPHER_fetch(libctx, t->base.algorithm, "");
cipher = EVP_CIPHER_fetch(libctx, t->base.algorithm, NULL);
if (cipher == NULL)
goto err;
/* Encrypt plain text message */
if (!cipher_init(ctx, cipher, t, encrypt)
|| !EVP_CipherUpdate(ctx, ct_buf, &len, t->base.pt, t->base.pt_len)
|| !EVP_CipherFinal_ex(ctx, ct_buf + len, &ct_len))
goto err;
OSSL_SELF_TEST_oncorrupt_byte(st, ct_buf);
ct_len += len;
if (ct_len != (int)t->base.expected_len
|| memcmp(t->base.expected, ct_buf, ct_len) != 0)
goto err;
if (t->tag != NULL) {
unsigned char tag[16] = { 0 };
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, t->tag_len, tag)
|| memcmp(tag, t->tag, t->tag_len) != 0)
if ((t->mode & CIPHER_MODE_ENCRYPT) != 0) {
if (!cipher_init(ctx, cipher, t, encrypt)
|| !EVP_CipherUpdate(ctx, ct_buf, &len, t->base.pt,
t->base.pt_len)
|| !EVP_CipherFinal_ex(ctx, ct_buf + len, &ct_len))
goto err;
OSSL_SELF_TEST_oncorrupt_byte(st, ct_buf);
ct_len += len;
if (ct_len != (int)t->base.expected_len
|| memcmp(t->base.expected, ct_buf, ct_len) != 0)
goto err;
if (t->tag != NULL) {
unsigned char tag[16] = { 0 };
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, t->tag_len,
tag)
|| memcmp(tag, t->tag, t->tag_len) != 0)
goto err;
}
}
if (!(cipher_init(ctx, cipher, t, !encrypt)
&& EVP_CipherUpdate(ctx, pt_buf, &len, ct_buf, ct_len)
&& EVP_CipherFinal_ex(ctx, pt_buf + len, &pt_len)))
goto err;
pt_len += len;
if (pt_len != (int)t->base.pt_len
|| memcmp(pt_buf, t->base.pt, pt_len) != 0)
goto err;
/* Decrypt cipher text */
if ((t->mode & CIPHER_MODE_DECRYPT) != 0) {
if (!(cipher_init(ctx, cipher, t, !encrypt)
&& EVP_CipherUpdate(ctx, pt_buf, &len,
t->base.expected, t->base.expected_len)
&& EVP_CipherFinal_ex(ctx, pt_buf + len, &pt_len)))
goto err;
OSSL_SELF_TEST_oncorrupt_byte(st, pt_buf);
pt_len += len;
if (pt_len != (int)t->base.pt_len
|| memcmp(pt_buf, t->base.pt, pt_len) != 0)
goto err;
}
ret = 1;
err:

View File

@ -24,7 +24,7 @@ use platform;
plan skip_all => "Test only supported in a fips build" if disabled("fips");
plan tests => 24;
plan tests => 26;
my $infile = bldtop_file('providers', platform->dso('fips'));
my $fipskey = $ENV{FIPSKEY} // '00';
@ -191,6 +191,20 @@ ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infi
'-section_name', 'fips_sect', '-corrupt_desc', 'SHA3'])),
"fipsinstall fails when the digest result is corrupted");
# corrupt cipher encrypt test
ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
'-provider_name', 'fips', '-mac_name', 'HMAC',
'-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
'-section_name', 'fips_sect', '-corrupt_desc', 'AES_GCM_Encrypt'])),
"fipsinstall fails when the AES_GCM result is corrupted");
# corrupt cipher decrypt test
ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
'-provider_name', 'fips', '-mac_name', 'HMAC',
'-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
'-section_name', 'fips_sect', '-corrupt_desc', 'AES_ECB_Decrypt'])),
"fipsinstall fails when the AES_ECB result is corrupted");
# corrupt DRBG
ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
'-provider_name', 'fips', '-mac_name', 'HMAC',