--- /dev/null
+/*
+ * 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;
+}
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
--- /dev/null
+#! /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");
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));
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));
}