aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssl/test
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssl/test')
-rw-r--r--crypto/openssl/test/cmsapitest.c48
-rw-r--r--crypto/openssl/test/evp_extra_test.c140
-rw-r--r--crypto/openssl/test/recipes/80-test_cmsapi.t3
-rw-r--r--crypto/openssl/test/recipes/80-test_cmsapi_data/cms_pwri_kek_oob.derbin0 -> 193 bytes
-rw-r--r--crypto/openssl/test/recipes/80-test_pkcs12.t13
-rw-r--r--crypto/openssl/test/recipes/80-test_pkcs12_data/pbmac1_256_256.bad-key-len.p12bin0 -> 2803 bytes
-rw-r--r--crypto/openssl/test/recipes/80-test_pkcs12_data/pbmac1_256_256.good-shorter-key-len.p12bin0 -> 2803 bytes
7 files changed, 196 insertions, 8 deletions
diff --git a/crypto/openssl/test/cmsapitest.c b/crypto/openssl/test/cmsapitest.c
index 0752d14df09c..d908bc6fc4c4 100644
--- a/crypto/openssl/test/cmsapitest.c
+++ b/crypto/openssl/test/cmsapitest.c
@@ -21,6 +21,7 @@ static X509 *cert = NULL;
static EVP_PKEY *privkey = NULL;
static char *derin = NULL;
static char *too_long_iv_cms_in = NULL;
+static char *pwri_kek_oob_der_in = NULL;
static int test_encrypt_decrypt(const EVP_CIPHER *cipher)
{
@@ -512,7 +513,48 @@ end:
return ret;
}
-OPT_TEST_DECLARE_USAGE("certfile privkeyfile derfile\n")
+/*
+ * CMS EnvelopedData with a single PasswordRecipientInfo using
+ * id-alg-PWRI-KEK and an AES-128-CFB key encryption cipher
+ * (1-byte effective block size). The encryptedKey OCTET STRING is
+ * only two bytes long, so the wrapped key buffer is shorter than
+ * the seven octets read by the check-byte test in kek_unwrap_key().
+ * Prior to CVE-2026-9076 this triggered an out-of-bounds heap read;
+ * CMS_decrypt() must now fail cleanly.
+ */
+static int test_pwri_kek_unwrap_short_encrypted_key(void)
+{
+ BIO *in = NULL;
+ CMS_ContentInfo *cms = NULL;
+ unsigned long err = 0;
+ int ret = 0;
+
+ if (!TEST_ptr(in = BIO_new_file(pwri_kek_oob_der_in, "rb"))
+ || !TEST_ptr(cms = d2i_CMS_bio(in, NULL)))
+ goto end;
+
+ /*
+ * The unwrap is attempted eagerly inside CMS_decrypt_set1_password().
+ * It must fail cleanly (no OOB read) and report CMS_R_UNWRAP_FAILURE.
+ */
+ if (!TEST_false(CMS_decrypt_set1_password(cms,
+ (unsigned char *)"password", -1)))
+ goto end;
+
+ err = ERR_peek_last_error();
+ if (!TEST_int_eq(ERR_GET_LIB(err), ERR_LIB_CMS)
+ || !TEST_int_eq(ERR_GET_REASON(err), CMS_R_UNWRAP_FAILURE))
+ goto end;
+
+ ERR_clear_error();
+ ret = 1;
+end:
+ CMS_ContentInfo_free(cms);
+ BIO_free(in);
+ return ret;
+}
+
+OPT_TEST_DECLARE_USAGE("certfile privkeyfile derfile tooLongIVpem pwriKekOobDer\n")
int setup_tests(void)
{
@@ -527,7 +569,8 @@ int setup_tests(void)
if (!TEST_ptr(certin = test_get_argument(0))
|| !TEST_ptr(privkeyin = test_get_argument(1))
|| !TEST_ptr(derin = test_get_argument(2))
- || !TEST_ptr(too_long_iv_cms_in = test_get_argument(3)))
+ || !TEST_ptr(too_long_iv_cms_in = test_get_argument(3))
+ || !TEST_ptr(pwri_kek_oob_der_in = test_get_argument(4)))
return 0;
certbio = BIO_new_file(certin, "r");
@@ -564,6 +607,7 @@ int setup_tests(void)
ADD_TEST(test_encrypted_data_aead);
ADD_ALL_TESTS(test_d2i_CMS_decode, 2);
ADD_TEST(test_cms_aesgcm_iv_too_long);
+ ADD_TEST(test_pwri_kek_unwrap_short_encrypted_key);
return 1;
}
diff --git a/crypto/openssl/test/evp_extra_test.c b/crypto/openssl/test/evp_extra_test.c
index eec9364f42ba..8fb5b216feb4 100644
--- a/crypto/openssl/test/evp_extra_test.c
+++ b/crypto/openssl/test/evp_extra_test.c
@@ -6528,6 +6528,142 @@ static int test_aes_rc4_keylen_change_cve_2023_5363(void)
}
#endif
+static int test_aes_gcm_siv_empty_data(void)
+{
+ unsigned char key[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 };
+ unsigned char nonce[12] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11,
+ 0x22, 0x33, 0x44, 0x55 };
+ unsigned char aad[33] = "this AAD was never authenticated";
+ unsigned char zero_tag[16] = { 0 };
+ unsigned char real_tag[16];
+ unsigned char out[16];
+ int outl, ret = 0;
+ EVP_CIPHER_CTX *ctx = NULL;
+ EVP_CIPHER *c = EVP_CIPHER_fetch(NULL, "AES-128-GCM-SIV", NULL);
+
+ if (c == NULL) {
+ return TEST_skip("AES-128-GCM-SIV cipher is not available");
+ }
+
+ /* Compute the CORRECT tag for (key,nonce,aad,pt="") via encrypt */
+ ctx = EVP_CIPHER_CTX_new();
+ if (!TEST_ptr(ctx)
+ || !TEST_true(EVP_EncryptInit_ex2(ctx, c, key, nonce, NULL))
+ || !TEST_true(EVP_EncryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) /* AAD */
+ || !TEST_true(EVP_EncryptUpdate(ctx, out, &outl, aad, 0)) /* empty PT, out!=NULL */
+ || !TEST_true(EVP_EncryptFinal_ex(ctx, out, &outl))
+ || !TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, real_tag)))
+ goto err;
+ EVP_CIPHER_CTX_free(ctx);
+
+ /* SANITY: decrypt with CORRECT tag and an explicit empty-PT Update */
+ ctx = EVP_CIPHER_CTX_new();
+ if (!TEST_ptr(ctx)
+ || !TEST_true(EVP_DecryptInit_ex2(ctx, c, key, nonce, NULL))
+ || !TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, real_tag))
+ || !TEST_true(EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)))
+ || !TEST_true(EVP_DecryptUpdate(ctx, out, &outl, aad, 0)) /* force aes_gcm_siv_decrypt(len=0) */
+ || !TEST_true(EVP_DecryptFinal_ex(ctx, out, &outl)))
+ goto err;
+ EVP_CIPHER_CTX_free(ctx);
+
+ /* FORGERY A: AAD only, NO ciphertext Update, ALL-ZERO tag */
+ ctx = EVP_CIPHER_CTX_new();
+ if (!TEST_ptr(ctx)
+ || !TEST_true(EVP_DecryptInit_ex2(ctx, c, key, nonce, NULL))
+ || !TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, zero_tag))
+ || !TEST_true(EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) /* AAD only, out==NULL */
+ || !TEST_false(EVP_DecryptFinal_ex(ctx, out, &outl)))
+ goto err;
+ EVP_CIPHER_CTX_free(ctx);
+
+ /* FORGERY B: no AAD, no Update at all, ALL-ZERO tag */
+ ctx = EVP_CIPHER_CTX_new();
+ if (!TEST_ptr(ctx)
+ || !TEST_true(EVP_DecryptInit_ex2(ctx, c, key, nonce, NULL))
+ || !TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, zero_tag))
+ || !TEST_false(EVP_DecryptFinal_ex(ctx, out, &outl)))
+ goto err;
+ EVP_CIPHER_CTX_free(ctx);
+
+ /* CONTROL: AAD only, NO ciphertext Update, CORRECT tag */
+ ctx = EVP_CIPHER_CTX_new();
+ if (!TEST_ptr(ctx)
+ || !TEST_true(EVP_DecryptInit_ex2(ctx, c, key, nonce, NULL))
+ || !TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, real_tag))
+ || !TEST_true(EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)))
+ || !TEST_true(EVP_DecryptFinal_ex(ctx, out, &outl)))
+ goto err;
+ EVP_CIPHER_CTX_free(ctx);
+ ctx = NULL;
+
+ ret = 1;
+err:
+ EVP_CIPHER_CTX_free(ctx);
+
+ EVP_CIPHER_free(c);
+ return ret;
+}
+
+/*
+ * AES-SIV reuse-without-rekey:
+ * msg1: legit non-empty CT, tag verifies, final_ret=0
+ * msg2: no reinit (or reinit with key=NULL), set forged tag,
+ * AAD only, DecryptFinal -> does stale final_ret leak through?
+ */
+static int test_aes_siv_ctx_reuse(void)
+{
+ unsigned char key[32] = { 7 }; /* AES-128-SIV => 2*16 */
+ unsigned char pt[9] = "payload!";
+ unsigned char ct[9], tagbuf[16], out[16], zero16[16] = { 0 };
+ unsigned char aad[14] = "forged header";
+ int outl, ret = 0;
+ EVP_CIPHER_CTX *e = NULL, *d = NULL;
+ EVP_CIPHER *c = EVP_CIPHER_fetch(NULL, "AES-128-SIV", NULL);
+
+ if (c == NULL) {
+ return TEST_skip("AES-128-SIV cipher is not available");
+ }
+
+ /* produce a valid (ct,tag) for msg1 */
+ e = EVP_CIPHER_CTX_new();
+ if (!TEST_ptr(e)
+ || !TEST_true(EVP_EncryptInit_ex2(e, c, key, NULL, NULL))
+ || !TEST_true(EVP_EncryptUpdate(e, NULL, &outl, (unsigned char *)"hdr1", 4))
+ || !TEST_true(EVP_EncryptUpdate(e, ct, &outl, pt, sizeof(pt)))
+ || !TEST_true(EVP_EncryptFinal_ex(e, out, &outl))
+ || !TEST_true(EVP_CIPHER_CTX_ctrl(e, EVP_CTRL_AEAD_GET_TAG, 16, tagbuf))) {
+ EVP_CIPHER_CTX_free(e);
+ goto err;
+ }
+ EVP_CIPHER_CTX_free(e);
+
+ /* msg1 decrypt */
+ d = EVP_CIPHER_CTX_new();
+ if (!TEST_ptr(d)
+ || !TEST_true(EVP_DecryptInit_ex2(d, c, key, NULL, NULL))
+ || !TEST_true(EVP_CIPHER_CTX_ctrl(d, EVP_CTRL_AEAD_SET_TAG, 16, tagbuf))
+ || !TEST_true(EVP_DecryptUpdate(d, NULL, &outl, (unsigned char *)"hdr1", 4))
+ || !TEST_true(EVP_DecryptUpdate(d, out, &outl, ct, sizeof(ct)))
+ || !TEST_true(EVP_DecryptFinal_ex(d, out, &outl)))
+ goto err;
+
+ /* msg2 on SAME ctx, reinit with key=NULL => initkey skipped, final_ret should be reset */
+ if (!TEST_true(EVP_DecryptInit_ex2(d, NULL, NULL, NULL, NULL))
+ || !TEST_true(EVP_CIPHER_CTX_ctrl(d, EVP_CTRL_AEAD_SET_TAG, 16, zero16))
+ || !TEST_true(EVP_DecryptUpdate(d, NULL, &outl, aad, sizeof(aad))) /* forged AAD */
+ || !TEST_false(EVP_DecryptFinal_ex(d, out, &outl)))
+ goto err;
+
+ ret = 1;
+
+err:
+ EVP_CIPHER_CTX_free(d);
+ EVP_CIPHER_free(c);
+ return ret;
+}
+
static int test_invalid_ctx_for_digest(void)
{
int ret;
@@ -6987,6 +7123,10 @@ int setup_tests(void)
ADD_TEST(test_aes_rc4_keylen_change_cve_2023_5363);
#endif
+ /* Test cases for CVE-2026-45446 */
+ ADD_TEST(test_aes_gcm_siv_empty_data);
+ ADD_TEST(test_aes_siv_ctx_reuse);
+
ADD_TEST(test_invalid_ctx_for_digest);
ADD_TEST(test_evp_cipher_negative_length);
diff --git a/crypto/openssl/test/recipes/80-test_cmsapi.t b/crypto/openssl/test/recipes/80-test_cmsapi.t
index 8d9371e005c0..3d1dae846464 100644
--- a/crypto/openssl/test/recipes/80-test_cmsapi.t
+++ b/crypto/openssl/test/recipes/80-test_cmsapi.t
@@ -19,5 +19,6 @@ plan tests => 1;
ok(run(test(["cmsapitest", srctop_file("test", "certs", "servercert.pem"),
srctop_file("test", "certs", "serverkey.pem"),
srctop_file("test", "recipes", "80-test_cmsapi_data", "encryptedData.der"),
- srctop_file("test", "recipes", "80-test_cmsapi_data", "encDataWithTooLongIV.pem")])),
+ srctop_file("test", "recipes", "80-test_cmsapi_data", "encDataWithTooLongIV.pem"),
+ srctop_file("test", "recipes", "80-test_cmsapi_data", "cms_pwri_kek_oob.der")])),
"running cmsapitest");
diff --git a/crypto/openssl/test/recipes/80-test_cmsapi_data/cms_pwri_kek_oob.der b/crypto/openssl/test/recipes/80-test_cmsapi_data/cms_pwri_kek_oob.der
new file mode 100644
index 000000000000..c3ef3abd10e6
--- /dev/null
+++ b/crypto/openssl/test/recipes/80-test_cmsapi_data/cms_pwri_kek_oob.der
Binary files differ
diff --git a/crypto/openssl/test/recipes/80-test_pkcs12.t b/crypto/openssl/test/recipes/80-test_pkcs12.t
index d258b7eb0e47..56ab93803e7a 100644
--- a/crypto/openssl/test/recipes/80-test_pkcs12.t
+++ b/crypto/openssl/test/recipes/80-test_pkcs12.t
@@ -56,7 +56,7 @@ $ENV{OPENSSL_WIN32_UTF8}=1;
my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0);
-plan tests => $no_fips ? 53 : 59;
+plan tests => $no_fips ? 55 : 61;
# Test different PKCS#12 formats
ok(run(test(["pkcs12_format_test"])), "test pkcs12 formats");
@@ -205,8 +205,11 @@ for my $instance (sort keys %pbmac1_tests) {
}
}
-# Test pbmac1 pkcs12 good files, RFC 9579
-for my $file ("pbmac1_256_256.good.p12", "pbmac1_512_256.good.p12", "pbmac1_512_512.good.p12")
+# Test pbmac1 pkcs12 good files, RFC 9579, and one extra with shorter key
+# length
+for my $file ("pbmac1_256_256.good.p12", "pbmac1_512_256.good.p12",
+ "pbmac1_512_512.good.p12",
+ "pbmac1_256_256.good-shorter-key-len.p12")
{
my $path = srctop_file("test", "recipes", "80-test_pkcs12_data", $file);
ok(run(app(["openssl", "pkcs12", "-in", $path, "-password", "pass:1234", "-noenc"])),
@@ -235,12 +238,12 @@ unless ($no_fips) {
}
}
-# Test pbmac1 pkcs12 bad files, RFC 9579 and CVE-2025-11187
+# Test pbmac1 pkcs12 bad files, RFC 9579, CVE-2025-11187 and CVE-2026-34181
for my $file ("pbmac1_256_256.bad-iter.p12", "pbmac1_256_256.bad-salt.p12",
"pbmac1_256_256.no-len.p12", "pbmac1_256_256.bad-len.p12",
"pbmac1_256_256.bad-salt-type.p12", "pbmac1_256_256.negative-len.p12",
"pbmac1_256_256.no-salt.p12", "pbmac1_256_256.very-big-len.p12",
- "pbmac1_256_256.zero-len.p12")
+ "pbmac1_256_256.zero-len.p12", "pbmac1_256_256.bad-key-len.p12")
{
my $path = srctop_file("test", "recipes", "80-test_pkcs12_data", $file);
with({ exit_checker => sub { return shift == 1; } },
diff --git a/crypto/openssl/test/recipes/80-test_pkcs12_data/pbmac1_256_256.bad-key-len.p12 b/crypto/openssl/test/recipes/80-test_pkcs12_data/pbmac1_256_256.bad-key-len.p12
new file mode 100644
index 000000000000..7162fd187179
--- /dev/null
+++ b/crypto/openssl/test/recipes/80-test_pkcs12_data/pbmac1_256_256.bad-key-len.p12
Binary files differ
diff --git a/crypto/openssl/test/recipes/80-test_pkcs12_data/pbmac1_256_256.good-shorter-key-len.p12 b/crypto/openssl/test/recipes/80-test_pkcs12_data/pbmac1_256_256.good-shorter-key-len.p12
new file mode 100644
index 000000000000..3c202dd58d7f
--- /dev/null
+++ b/crypto/openssl/test/recipes/80-test_pkcs12_data/pbmac1_256_256.good-shorter-key-len.p12
Binary files differ