Commit 0e11020a0a for openssl.org

commit 0e11020a0a644ce640848b75d47b77e518b0344b
Author: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Date:   Fri Aug 28 10:23:47 2026 +0200

    apps: test enc app opaque symmetric key options

    Add a new test recipe covering the enc app skey handling: an opaque key
    imported via -skeymgmt/-skeyopt raw bytes produces the same AES
    ciphertext as the equivalent raw -K key and decrypts back, the raw key
    and skeyopt options are mutually exclusive, and unknown skeymgmt names
    or malformed skeyopt values are rejected.  With module support, the
    fake-cipher provider covers a full encrypt/decrypt roundtrip through a
    provider-implemented cipher, including defaulting the skeymgmt name to
    the cipher name when -skeymgmt is not given.

    Assisted-by: Claude:claude-fable-5
    Reviewed-by: Daniel Kubec <kubec@openssl.foundation>
    Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    Merge-date: Mon Sep  7 13:28:07 2026
    Merged-from: https://github.com/openssl/openssl/pull/32570

diff --git a/test/recipes/20-test_enc_skey.t b/test/recipes/20-test_enc_skey.t
new file mode 100644
index 0000000000..c5305cbeb3
--- /dev/null
+++ b/test/recipes/20-test_enc_skey.t
@@ -0,0 +1,121 @@
+#! /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 File::Compare qw/compare/;
+use OpenSSL::Test qw/:DEFAULT bldtop_dir with/;
+use OpenSSL::Test::Utils;
+
+setup("test_enc_skey");
+
+# The opaque key roundtrip through a provider-implemented cipher needs the
+# loadable fake-cipher provider, which is only built with module support.
+my $fake_cipher = !disabled('module');
+
+plan tests => 2 + ($fake_cipher ? 1 : 0);
+
+my $key = "000102030405060708090a0b0c0d0e0f";
+my $iv = "00112233445566778899aabbccddeeff";
+my $plain = "plain.txt";
+
+open my $fh, ">", $plain or die "Cannot write $plain: $!";
+print $fh "Opaque symmetric key test payload." x 4, "\n";
+close $fh;
+
+# Helper: run enc expecting a non-zero (failure) exit code, and check that
+# stderr matches a regular expression.
+sub enc_fails {
+    my ($testtext, $re, @args) = @_;
+
+    my $stderr_file = "enc_skey_err.txt";
+    my $err = '';
+
+    with({ exit_checker => sub { return shift != 0; } },
+        sub {
+            ok(run(app(['openssl', 'enc', @args], stderr => $stderr_file)),
+               $testtext);
+        });
+
+    if (open(my $fh, '<', $stderr_file)) {
+        $err = do { local $/; <$fh> };
+        close($fh);
+    }
+    ok($err =~ $re, "$testtext: stderr matches");
+    unlink($stderr_file) if -f $stderr_file;
+}
+
+subtest "enc with an opaque key matches raw key encryption" => sub {
+    plan tests => 5;
+
+    ok(run(app(['openssl', 'enc', '-aes-128-cbc', '-e',
+                '-skeymgmt', 'AES', '-skeyopt', "hexraw-bytes:$key",
+                '-iv', $iv, '-in', $plain, '-out', 'enc_skey.bin'])),
+       "encrypt with an opaque key built from -skeyopt raw bytes");
+    ok(run(app(['openssl', 'enc', '-aes-128-cbc', '-e',
+                '-K', $key, '-iv', $iv,
+                '-in', $plain, '-out', 'enc_raw.bin'])),
+       "encrypt with the same raw key");
+    is(compare('enc_skey.bin', 'enc_raw.bin'), 0,
+       "opaque and raw key encryption produce the same ciphertext");
+    ok(run(app(['openssl', 'enc', '-aes-128-cbc', '-d',
+                '-skeymgmt', 'AES', '-skeyopt', "hexraw-bytes:$key",
+                '-iv', $iv, '-in', 'enc_skey.bin', '-out', 'dec_skey.txt'])),
+       "decrypt with the opaque key");
+    is(compare('dec_skey.txt', $plain), 0,
+       "decryption with the opaque key recovers the plaintext");
+};
+
+subtest "enc opaque key error handling" => sub {
+    plan tests => 8;
+
+    enc_fails("a raw key and -skeyopt together are rejected",
+              qr/Either a raw key or the skeyopt\/skeyuri args must be used/,
+              '-aes-128-cbc', '-e', '-K', $key, '-iv', $iv,
+              '-skeyopt', "hexraw-bytes:$key", '-in', $plain);
+    enc_fails("an unknown -skeymgmt is rejected",
+              qr/Error creating opaque key object for skeymgmt NoSuchMgmt/,
+              '-aes-128-cbc', '-e', '-skeymgmt', 'NoSuchMgmt',
+              '-skeyopt', "hexraw-bytes:$key", '-iv', $iv, '-in', $plain);
+    enc_fails("an unknown -skeyopt parameter is rejected",
+              qr/Parameter unknown 'nosuchopt:1'/,
+              '-aes-128-cbc', '-e', '-skeymgmt', 'AES',
+              '-skeyopt', 'nosuchopt:1', '-iv', $iv, '-in', $plain);
+    enc_fails("a malformed -skeyopt without a value is rejected",
+              qr/Parameter error 'raw-bytes'/,
+              '-aes-128-cbc', '-e', '-skeymgmt', 'AES',
+              '-skeyopt', 'raw-bytes', '-iv', $iv, '-in', $plain);
+};
+
+# The fake-cipher provider names both its cipher and its skey management
+# "fake_cipher", so it also covers defaulting the skeymgmt name to the
+# cipher name when -skeymgmt is not given.
+if ($fake_cipher) {
+    subtest "enc with an opaque key from the fake-cipher provider" => sub {
+        plan tests => 4;
+
+        $ENV{OPENSSL_MODULES} = bldtop_dir("test");
+        my @prov = ('-provider-path', bldtop_dir("test"),
+                    '-provider', 'fake-cipher', '-provider', 'default');
+
+        ok(run(app(['openssl', 'enc', @prov, '-fake_cipher', '-e',
+                    '-skeyopt', 'key_name:testkey',
+                    '-skeyopt', "hexraw-bytes:$key",
+                    '-in', $plain, '-out', 'enc_fake.bin'])),
+           "encrypt with an opaque key without -skeymgmt");
+        isnt(compare('enc_fake.bin', $plain), 0,
+             "the fake cipher transformed the plaintext");
+        ok(run(app(['openssl', 'enc', @prov, '-fake_cipher', '-d',
+                    '-skeyopt', "hexraw-bytes:$key",
+                    '-in', 'enc_fake.bin', '-out', 'dec_fake.txt'])),
+           "decrypt with the opaque key without -skeymgmt");
+        is(compare('dec_fake.txt', $plain), 0,
+           "decryption with the opaque key recovers the plaintext");
+    };
+}