]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Opaque keys support for the openssl command line
authorDmitry Belyavskiy <beldmit@gmail.com>
Thu, 9 Jan 2025 12:54:38 +0000 (13:54 +0100)
committerDmitry Belyavskiy <beldmit@gmail.com>
Sat, 15 Feb 2025 17:51:30 +0000 (18:51 +0100)
Support EVP_SKEY object for the `enc` command.
Support EVP_SKEYMGMT for the `list` command.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26753)

apps/enc.c
apps/list.c
doc/man1/openssl-enc.pod.in
doc/man1/openssl-list.pod.in

index e7421ad896e3b92e37010bb07b722d8ccbe6d408..e08ac5563f5e67b6b8477d7b40fb009533d0b201 100644 (file)
@@ -49,7 +49,8 @@ typedef enum OPTION_choice {
     OPT_NOPAD, OPT_SALT, OPT_NOSALT, OPT_DEBUG, OPT_UPPER_P, OPT_UPPER_A,
     OPT_A, OPT_Z, OPT_BUFSIZE, OPT_K, OPT_KFILE, OPT_UPPER_K, OPT_NONE,
     OPT_UPPER_S, OPT_IV, OPT_MD, OPT_ITER, OPT_PBKDF2, OPT_CIPHER,
-    OPT_SALTLEN, OPT_R_ENUM, OPT_PROV_ENUM
+    OPT_SALTLEN, OPT_R_ENUM, OPT_PROV_ENUM,
+    OPT_SKEYOPT, OPT_SKEYMGMT
 } OPTION_CHOICE;
 
 const OPTIONS enc_options[] = {
@@ -105,6 +106,8 @@ const OPTIONS enc_options[] = {
 #ifndef OPENSSL_NO_ZLIB
     {"z", OPT_Z, '-', "Compress or decompress encrypted data using zlib"},
 #endif
+    {"skeyopt", OPT_SKEYOPT, 's', "Key options as opt:value for opaque symmetric key handling"},
+    {"skeymgmt", OPT_SKEYMGMT, 's', "Symmetric key management name for opaque symmetric key handling"},
     {"", OPT_CIPHER, '-', "Any supported cipher"},
 
     OPT_R_OPTIONS,
@@ -134,6 +137,7 @@ int enc_main(int argc, char **argv)
     int base64 = 0, informat = FORMAT_BINARY, outformat = FORMAT_BINARY;
     int ret = 1, inl, nopad = 0;
     unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
+    int rawkey_set = 0;
     unsigned char *buff = NULL, salt[EVP_MAX_IV_LENGTH];
     int saltlen = 0;
     int pbkdf2 = 0;
@@ -150,6 +154,10 @@ int enc_main(int argc, char **argv)
     BIO *bbrot = NULL;
     int do_zstd = 0;
     BIO *bzstd = NULL;
+    STACK_OF(OPENSSL_STRING) *skeyopts = NULL;
+    const char *skeymgmt = NULL;
+    EVP_SKEY *skey = NULL;
+    EVP_SKEYMGMT *mgmt = NULL;
 
     /* first check the command name */
     if (strcmp(argv[0], "base64") == 0)
@@ -310,6 +318,17 @@ int enc_main(int argc, char **argv)
         case OPT_NONE:
             cipher = NULL;
             break;
+        case OPT_SKEYOPT:
+            if ((skeyopts == NULL &&
+                 (skeyopts = sk_OPENSSL_STRING_new_null()) == NULL) ||
+                sk_OPENSSL_STRING_push(skeyopts, opt_arg()) == 0) {
+                BIO_printf(bio_err, "%s: out of memory\n", prog);
+                goto end;
+            }
+            break;
+        case OPT_SKEYMGMT:
+            skeymgmt = opt_arg();
+            break;
         case OPT_R_CASES:
             if (!opt_rand(o))
                 goto end;
@@ -391,7 +410,7 @@ int enc_main(int argc, char **argv)
         str = pass;
     }
 
-    if ((str == NULL) && (cipher != NULL) && (hkey == NULL)) {
+    if ((str == NULL) && (cipher != NULL) && (hkey == NULL) && (skeyopts == NULL)) {
         if (1) {
 #ifndef OPENSSL_NO_UI_CONSOLE
             for (;;) {
@@ -571,6 +590,7 @@ int enc_main(int argc, char **argv)
                 /* split and move data back to global buffer */
                 memcpy(key, tmpkeyiv, iklen);
                 memcpy(iv, tmpkeyiv+iklen, ivlen);
+                rawkey_set = 1;
             } else {
                 BIO_printf(bio_err, "*** WARNING : "
                                     "deprecated key derivation used.\n"
@@ -581,6 +601,7 @@ int enc_main(int argc, char **argv)
                     BIO_printf(bio_err, "EVP_BytesToKey failed\n");
                     goto end;
                 }
+                rawkey_set = 1;
             }
             /*
              * zero the complete buffer or the string passed from the command
@@ -618,6 +639,16 @@ int enc_main(int argc, char **argv)
             }
             /* wiping secret data as we no longer need it */
             cleanse(hkey);
+            rawkey_set = 1;
+        }
+
+        /*
+         * At this moment we know whether we trying to use raw bytes as the key
+         * or an opaque symmetric key. We do not allow both options simultaneously.
+         */
+        if (rawkey_set > 0 && skeyopts != NULL) {
+            BIO_printf(bio_err, "Either a raw key or the 'skeyopt' args must be used.\n");
+            goto end;
         }
 
         if ((benc = BIO_new(BIO_f_cipher())) == NULL)
@@ -633,24 +664,51 @@ int enc_main(int argc, char **argv)
         if (wrap == 1)
             EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
 
-        if (!EVP_CipherInit_ex(ctx, cipher, e, NULL, NULL, enc)) {
-            BIO_printf(bio_err, "Error setting cipher %s\n",
-                       EVP_CIPHER_get0_name(cipher));
-            ERR_print_errors(bio_err);
-            goto end;
+        if (rawkey_set) {
+            if (!EVP_CipherInit_ex(ctx, cipher, e, key,
+                                   (hiv == NULL && wrap == 1 ? NULL : iv), enc)) {
+                BIO_printf(bio_err, "Error setting cipher %s\n",
+                           EVP_CIPHER_get0_name(cipher));
+                ERR_print_errors(bio_err);
+                goto end;
+            }
+        } else {
+            OSSL_PARAM *params = NULL;
+
+            mgmt = EVP_SKEYMGMT_fetch(app_get0_libctx(),
+                                      skeymgmt != NULL ? skeymgmt : EVP_CIPHER_name(cipher),
+                                      app_get0_propq());
+            if (mgmt == NULL)
+                goto end;
+
+            params = app_params_new_from_opts(skeyopts,
+                                              EVP_SKEYMGMT_get0_imp_settable_params(mgmt));
+            if (params == NULL)
+                goto end;
+
+            skey = EVP_SKEY_import(app_get0_libctx(), EVP_SKEYMGMT_get0_name(mgmt),
+                                   app_get0_propq(), OSSL_SKEYMGMT_SELECT_ALL, params);
+            OSSL_PARAM_free(params);
+            if (skey == NULL) {
+                BIO_printf(bio_err, "Error creating opaque key object for skeymgmt %s\n",
+                           skeymgmt ? skeymgmt : EVP_CIPHER_name(cipher));
+                ERR_print_errors(bio_err);
+                goto end;
+            }
+
+            if (!EVP_CipherInit_SKEY(ctx, cipher, skey,
+                                     (hiv == NULL && wrap == 1 ? NULL : iv),
+                                     EVP_CIPHER_get_iv_length(cipher), enc, NULL)) {
+                BIO_printf(bio_err, "Error setting an opaque key for cipher %s\n",
+                           EVP_CIPHER_get0_name(cipher));
+                ERR_print_errors(bio_err);
+                goto end;
+            }
         }
 
         if (nopad)
             EVP_CIPHER_CTX_set_padding(ctx, 0);
 
-        if (!EVP_CipherInit_ex(ctx, NULL, NULL, key,
-                               (hiv == NULL && wrap == 1 ? NULL : iv), enc)) {
-            BIO_printf(bio_err, "Error setting cipher %s\n",
-                       EVP_CIPHER_get0_name(cipher));
-            ERR_print_errors(bio_err);
-            goto end;
-        }
-
         if (debug) {
             BIO_set_callback_ex(benc, BIO_debug_callback_ex);
             BIO_set_callback_arg(benc, (char *)bio_err);
@@ -716,6 +774,9 @@ int enc_main(int argc, char **argv)
     }
  end:
     ERR_print_errors(bio_err);
+    sk_OPENSSL_STRING_free(skeyopts);
+    EVP_SKEYMGMT_free(mgmt);
+    EVP_SKEY_free(skey);
     OPENSSL_free(strbuf);
     OPENSSL_free(buff);
     BIO_free(in);
index 36c8f24d3459169391c3795b290b65714dcd4588..b8baee37357072e68f37cd08d29b3ac97af7b1cf 100644 (file)
@@ -58,6 +58,7 @@ IS_FETCHABLE(mac, EVP_MAC)
 IS_FETCHABLE(kdf, EVP_KDF)
 IS_FETCHABLE(rand, EVP_RAND)
 IS_FETCHABLE(keymgmt, EVP_KEYMGMT)
+IS_FETCHABLE(skeymgmt, EVP_SKEYMGMT)
 IS_FETCHABLE(signature, EVP_SIGNATURE)
 IS_FETCHABLE(kem, EVP_KEM)
 IS_FETCHABLE(asym_cipher, EVP_ASYM_CIPHER)
@@ -692,6 +693,61 @@ static void list_keymanagers(void)
     sk_EVP_KEYMGMT_pop_free(km_stack, EVP_KEYMGMT_free);
 }
 
+DEFINE_STACK_OF(EVP_SKEYMGMT)
+static int skeymanager_cmp(const EVP_SKEYMGMT * const *a,
+                           const EVP_SKEYMGMT * const *b)
+{
+    return strcmp(OSSL_PROVIDER_get0_name(EVP_SKEYMGMT_get0_provider(*a)),
+                  OSSL_PROVIDER_get0_name(EVP_SKEYMGMT_get0_provider(*b)));
+}
+
+static void collect_skeymanagers(EVP_SKEYMGMT *km, void *stack)
+{
+    STACK_OF(EVP_SKEYMGMT) *km_stack = stack;
+
+    if (is_skeymgmt_fetchable(km)
+            && sk_EVP_SKEYMGMT_push(km_stack, km) > 0)
+        EVP_SKEYMGMT_up_ref(km);
+}
+
+static void list_skeymanagers(void)
+{
+    int i;
+    STACK_OF(EVP_SKEYMGMT) *km_stack = sk_EVP_SKEYMGMT_new(skeymanager_cmp);
+
+    EVP_SKEYMGMT_do_all_provided(app_get0_libctx(), collect_skeymanagers,
+                                 km_stack);
+    sk_EVP_SKEYMGMT_sort(km_stack);
+
+    for (i = 0; i < sk_EVP_SKEYMGMT_num(km_stack); i++) {
+        EVP_SKEYMGMT *k = sk_EVP_SKEYMGMT_value(km_stack, i);
+        STACK_OF(OPENSSL_CSTRING) *names = NULL;
+
+        if (select_name != NULL && !EVP_SKEYMGMT_is_a(k, select_name))
+            continue;
+
+        names = sk_OPENSSL_CSTRING_new(name_cmp);
+        if (names != NULL && EVP_SKEYMGMT_names_do_all(k, collect_names, names)) {
+            const char *desc = EVP_SKEYMGMT_get0_description(k);
+
+            BIO_printf(bio_out, "  Name: ");
+            if (desc != NULL)
+                BIO_printf(bio_out, "%s", desc);
+            else
+                BIO_printf(bio_out, "%s", sk_OPENSSL_CSTRING_value(names, 0));
+            BIO_printf(bio_out, "\n");
+            BIO_printf(bio_out, "    Type: Provider Algorithm\n");
+            BIO_printf(bio_out, "    IDs: ");
+            print_names(bio_out, names);
+            BIO_printf(bio_out, " @ %s\n",
+                       OSSL_PROVIDER_get0_name(EVP_SKEYMGMT_get0_provider(k)));
+
+        }
+        sk_OPENSSL_CSTRING_free(names);
+    }
+    sk_EVP_SKEYMGMT_pop_free(km_stack, EVP_SKEYMGMT_free);
+}
+
 DEFINE_STACK_OF(EVP_SIGNATURE)
 static int signature_cmp(const EVP_SIGNATURE * const *a,
                          const EVP_SIGNATURE * const *b)
@@ -1549,6 +1605,7 @@ typedef enum HELPLIST_CHOICE {
     OPT_PK_ALGORITHMS, OPT_PK_METHOD, OPT_DISABLED,
     OPT_KDF_ALGORITHMS, OPT_RANDOM_INSTANCES, OPT_RANDOM_GENERATORS,
     OPT_ENCODERS, OPT_DECODERS, OPT_KEYMANAGERS, OPT_KEYEXCHANGE_ALGORITHMS,
+    OPT_SKEYMANAGERS,
     OPT_KEM_ALGORITHMS, OPT_SIGNATURE_ALGORITHMS,
     OPT_TLS_SIGNATURE_ALGORITHMS, OPT_ASYM_CIPHER_ALGORITHMS,
     OPT_STORE_LOADERS, OPT_PROVIDER_INFO, OPT_OBJECTS,
@@ -1603,6 +1660,7 @@ const OPTIONS list_options[] = {
     {"encoders", OPT_ENCODERS, '-', "List of encoding methods" },
     {"decoders", OPT_DECODERS, '-', "List of decoding methods" },
     {"key-managers", OPT_KEYMANAGERS, '-', "List of key managers" },
+    {"skey-managers", OPT_SKEYMANAGERS, '-', "List of symmetric key managers" },
     {"key-exchange-algorithms", OPT_KEYEXCHANGE_ALGORITHMS, '-',
      "List of key exchange algorithms" },
     {"kem-algorithms", OPT_KEM_ALGORITHMS, '-',
@@ -1677,6 +1735,7 @@ int list_main(int argc, char **argv)
         unsigned int encoder_algorithms:1;
         unsigned int decoder_algorithms:1;
         unsigned int keymanager_algorithms:1;
+        unsigned int skeymanager_algorithms:1;
         unsigned int signature_algorithms:1;
         unsigned int tls_signature_algorithms:1;
         unsigned int keyexchange_algorithms:1;
@@ -1750,6 +1809,9 @@ opthelp:
         case OPT_KEYMANAGERS:
             todo.keymanager_algorithms = 1;
             break;
+        case OPT_SKEYMANAGERS:
+            todo.skeymanager_algorithms = 1;
+            break;
         case OPT_SIGNATURE_ALGORITHMS:
             todo.signature_algorithms = 1;
             break;
@@ -1890,6 +1952,8 @@ opthelp:
         MAYBE_ADD_NL(list_decoders());
     if (todo.keymanager_algorithms)
         MAYBE_ADD_NL(list_keymanagers());
+    if (todo.skeymanager_algorithms)
+        MAYBE_ADD_NL(list_skeymanagers());
     if (todo.signature_algorithms)
         MAYBE_ADD_NL(list_signatures());
     if (todo.tls_signature_algorithms)
index 33fe72d282a41399808a8db1a3084f7715aa7ecd..9fb56f1c12ac10b42c8e4e4ae6433beec9d1f088 100644 (file)
@@ -39,6 +39,8 @@ B<openssl> B<enc>|I<cipher>
 [B<-v>]
 [B<-debug>]
 [B<-none>]
+[B<-skeymgmt> I<skeymgmt>]
+[B<-skeyopt> I<opt>:I<value>]
 {- $OpenSSL::safe::opt_engine_synopsis -}{- $OpenSSL::safe::opt_r_synopsis -}
 {- $OpenSSL::safe::opt_provider_synopsis -}
 
@@ -217,6 +219,21 @@ or zlib-dynamic option.
 
 Use NULL cipher (no encryption or decryption of input).
 
+=item B<-skeymgmt> I<skeymgmt>
+
+Some providers may support opaque symmetric keys objects. To use them, we need
+to know the name of the B<EVP_SKEYMGMT> to be used. If not specified, the name
+of the cipher will be used.
+
+To find out the name of the suitable symmetric key management,
+please refer to the output of the C<openssl list -skey-managers> command.
+
+=item B<-skeyopt> I<opt>:I<value>
+
+To obtain an existing opaque symmetric key or generate a new one, key
+options are specified as opt:value. These options can't be used together with
+any options implying raw key directly or indirectly.
+
 {- $OpenSSL::safe::opt_r_item -}
 
 {- $OpenSSL::safe::opt_provider_item -}
@@ -477,6 +494,10 @@ The B<openssl enc> command only supports a fixed number of algorithms with
 certain parameters. So if, for example, you want to use RC2 with a
 76 bit key or RC4 with an 84 bit key you can't use this program.
 
+=head1 SEE ALSO
+
+L<openssl-list(1)>, L<EVP_SKEY(3)>
+
 =head1 HISTORY
 
 The default digest was changed from MD5 to SHA256 in OpenSSL 1.1.0.
@@ -487,6 +508,8 @@ The B<-ciphers> and B<-engine> options were deprecated in OpenSSL 3.0.
 
 The B<-saltlen> option was added in OpenSSL 3.2.
 
+The B<-skeymgmt> and B<-skeyopt> options were added in OpenSSL 3.5.
+
 =head1 COPYRIGHT
 
 Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved.
index 602f6636769a88e5d6c7ea5fa1cd05b3e4ccdf1e..9d51567f4faba370a9d95b79d1dd0479f0d1bf65 100644 (file)
@@ -30,6 +30,7 @@ B<openssl list>
 -}[B<-encoders>]
 [B<-decoders>]
 [B<-key-managers>]
+[B<-skey-managers>]
 [B<-key-exchange-algorithms>]
 [B<-kem-algorithms>]
 [B<-tls-groups>]
@@ -100,6 +101,8 @@ Display lists of all algorithms.  These include:
 
 =item Key managers
 
+=item Symmetric key managers
+
 =item Message authentication code algorithms (MAC)
 
 =item Random number generators (RNG, DRBG)
@@ -187,6 +190,10 @@ Display a list of public key methods.
 
 Display a list of key managers.
 
+=item B<-skey-managers>
+
+Display a list of symmetric key managers.
+
 =item B<-key-exchange-algorithms>
 
 Display a list of key exchange algorithms.
@@ -305,6 +312,8 @@ In both cases, C<bar> is the name of the provider.
 The B<-engines>, B<-digest-commands>, and B<-cipher-commands> options
 were deprecated in OpenSSL 3.0.
 
+The B<-skey-managers> option was added in OpenSSL 3.5.
+
 =head1 COPYRIGHT
 
 Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved.