Commit baf4156f70 for openssl.org

commit baf4156f7052cf5fa08aaf5187dc1f5d25e49664
Author: slontis <shane.lontis@oracle.com>
Date:   Thu Feb 5 09:41:29 2026 +1100

    AES-WRAP: Add tests

    Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
    Reviewed-by: Paul Dale <paul.dale@oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/29940)

diff --git a/test/aeswrap_test.c b/test/aeswrap_test.c
new file mode 100644
index 0000000000..539536f4a8
--- /dev/null
+++ b/test/aeswrap_test.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "testutil.h"
+
+/* Test that calling EVP_CipherUpdate() twice fails for AES_WRAP_PAD */
+static int aeswrap_multi_update_fail_test(void)
+{
+    int ret = 0;
+    EVP_CIPHER_CTX *ctx = NULL;
+    EVP_CIPHER *cipher = NULL;
+    uint8_t in[32] = { 0 }; /* multiple of 8 */
+    uint8_t out[64];
+    int outlen = sizeof(in) + 8;
+    uint8_t key[32] = { 0 };
+
+    if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
+        || !TEST_ptr(cipher = EVP_CIPHER_fetch(NULL, "AES-256-WRAP-PAD", NULL))
+        || !TEST_int_eq(EVP_CipherInit_ex2(ctx, cipher, key, NULL, 1, NULL), 1)
+        || !TEST_int_eq(EVP_CipherUpdate(ctx, out, &outlen, in, sizeof(in)), 1)
+        || !TEST_int_eq(EVP_CipherUpdate(ctx, out, &outlen, in, sizeof(in)), 0))
+        goto err;
+    ret = 1;
+err:
+    EVP_CIPHER_free(cipher);
+    EVP_CIPHER_CTX_free(ctx);
+    return ret;
+}
+
+/* Test that an invalid input size fails when padding is not enabled */
+static int aeswrap_input_size_fail_test(void)
+{
+    int ret = 0;
+    EVP_CIPHER_CTX *ctx = NULL;
+    EVP_CIPHER *cipher = NULL;
+    uint8_t in[32] = { 0 }; /* multiple of 8 */
+    uint8_t out[64];
+    int outlen = sizeof(in) + 8;
+    uint8_t key[32] = { 0 };
+
+    if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
+        || !TEST_ptr(cipher = EVP_CIPHER_fetch(NULL, "AES-256-WRAP", NULL))
+        || !TEST_int_eq(EVP_CipherInit_ex2(ctx, cipher, key, NULL, 1, NULL), 1)
+        || !TEST_int_eq(EVP_CipherUpdate(ctx, out, &outlen, in, 7), 0))
+        goto err;
+    ret = 1;
+err:
+    EVP_CIPHER_free(cipher);
+    EVP_CIPHER_CTX_free(ctx);
+    return ret;
+}
+
+int setup_tests(void)
+{
+    ADD_TEST(aeswrap_input_size_fail_test);
+    ADD_TEST(aeswrap_multi_update_fail_test);
+    return 1;
+}
diff --git a/test/build.info b/test/build.info
index 25ca119973..8ba5587bb3 100644
--- a/test/build.info
+++ b/test/build.info
@@ -312,6 +312,11 @@ IF[{- !$disabled{tests} -}]
     DEPEND[ml_dsa_test]=../libcrypto.a libtestutil.a
   ENDIF

+  PROGRAMS{noinst}=aeswrap_test
+  SOURCE[aeswrap_test]=aeswrap_test.c
+  INCLUDE[aeswrap_test]=../include ../apps/include
+  DEPEND[aeswrap_test]=../libcrypto.a libtestutil.a
+
   SOURCE[v3nametest]=v3nametest.c
   INCLUDE[v3nametest]=../include ../apps/include
   DEPEND[v3nametest]=../libcrypto libtestutil.a
diff --git a/test/recipes/05-test_aes_wrap.t b/test/recipes/05-test_aes_wrap.t
new file mode 100644
index 0000000000..474e8fdace
--- /dev/null
+++ b/test/recipes/05-test_aes_wrap.t
@@ -0,0 +1,18 @@
+#! /usr/bin/env perl
+# Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+use warnings;
+
+use OpenSSL::Test::Simple;
+use OpenSSL::Test;
+use OpenSSL::Test::Utils;
+
+setup("test_aeswrap");
+
+simple_test("test_aeswrap", "aeswrap_test", "aeswrap");
diff --git a/test/recipes/15-test_ml_dsa_codecs.t b/test/recipes/15-test_ml_dsa_codecs.t
index 07f0b37b7c..c8b26366e4 100644
--- a/test/recipes/15-test_ml_dsa_codecs.t
+++ b/test/recipes/15-test_ml_dsa_codecs.t
@@ -26,7 +26,7 @@ my @formats = qw(seed-priv priv-only seed-only oqskeypair bare-seed bare-priv);
 plan skip_all => "ML-DSA isn't supported in this build"
     if disabled("ml-dsa");

-plan tests => @algs * (23 + 10 * @formats);
+plan tests => @algs * (26 + 10 * @formats);
 my $seed = join ("", map {sprintf "%02x", $_} (0..31));
 my $weed = join ("", map {sprintf "%02x", $_} (1..32));
 my $ikme = join ("", map {sprintf "%02x", $_} (0..31));
@@ -212,4 +212,17 @@ foreach my $alg (@algs) {
     ok(!run(app([qw(openssl pkey -provparam ml-dsa.prefer_seed=no),
                  qw(-inform DER -noout -in), $mash])),
         sprintf("reject real private and mutated public: %s", $alg));
+
+    # 3 wrapping tests
+    my $wrapped = sprintf('wrapped-%s.bin', $alg);
+    my $unwrapped = sprintf('unwrapped-%s.bin', $alg);
+    my $aes_key = '0102030405060708091011121314151617181920212223242526272829303132';
+    ok(run(app([qw(openssl enc -pbkdf2 -id-aes256-wrap-pad -k), $aes_key,
+                   '-in', $real, '-out', $wrapped])),
+        sprintf("AES Wrap private: %s", $alg));
+    ok(run(app([qw(openssl enc -d -pbkdf2 -id-aes256-wrap-pad -k), $aes_key,
+                   '-in', $wrapped, '-out', $unwrapped])),
+        sprintf("AES Unwrap private: %s", $alg));
+    ok(!compare($unwrapped, $real),
+        sprintf("Unwrapped DER match: %s, %s", $alg, $real));
 }