[openssl] master update

Richard Levitte levitte at openssl.org
Wed Dec 2 21:11:16 UTC 2020


The branch master has been updated
       via  0a3b330cf09dd3746f4f9c5bb82d9bbcfff809c1 (commit)
       via  f91d003a0ef0c748a11ccdb19c7661a3f2df9ab0 (commit)
       via  0b27381fd544beca44df905991923a7fa374d80a (commit)
      from  4be35545aea9f76e3704fe88bb8f3fc135ceb4c8 (commit)


- Log -----------------------------------------------------------------
commit 0a3b330cf09dd3746f4f9c5bb82d9bbcfff809c1
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Nov 30 10:44:34 2020 +0100

    Add test to demonstrate the app's new engine key loading
    
    This adds a bit of functionality in ossltest, so it can now be used to
    load PEM files.  It takes the file name as key ID, but just to make
    sure faults aren't ignored, it requires all file names to be prefixed
    with 'ot:'.
    
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/13570)

commit f91d003a0ef0c748a11ccdb19c7661a3f2df9ab0
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Nov 30 07:25:46 2020 +0100

    APPS: Adapt load_key() and load_pubkey() for the engine: loader
    
    These two functions react when the FORMAT_ENGINE format is given, and
    use the passed ENGINE |e| and the passed key argument to form a URI
    suitable for the engine: loader.
    
    Co-authored-by: David von Oheimb <david.von.oheimb at siemens.com>
    
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/13570)

commit 0b27381fd544beca44df905991923a7fa374d80a
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri Oct 12 17:02:58 2018 +0200

    APPS: Add OSSL_STORE loader for engine keys
    
    The idea is to be able to have our apps load engine keys using a URI:
    
        org.openssl.engine:{engineid}:{keyid}
    
    This is legacy, but added for the time being to support keys given to
    the application like this:
    
        -engine {engineid} -key {keyid} -keyform ENGINE
    
    This latter form is recognised internally, and rewritten into the URI
    form.
    
    Reviewed-by: David von Oheimb <david.von.oheimb at siemens.com>
    (Merged from https://github.com/openssl/openssl/pull/13570)

-----------------------------------------------------------------------

Summary of changes:
 apps/cmp.c                       |   6 +-
 apps/include/apps.h              |   6 +-
 apps/include/engine_loader.h     |  21 ++++
 apps/lib/apps.c                  |  69 +++++++------
 apps/lib/build.info              |   2 +-
 apps/lib/engine.c                |  59 +++++-------
 apps/lib/engine_loader.c         | 203 +++++++++++++++++++++++++++++++++++++++
 apps/openssl.c                   |   2 +
 doc/man1/openssl-ca.pod.in       |   4 +-
 doc/man1/openssl-cmp.pod.in      |  46 +++++----
 doc/man1/openssl-cms.pod.in      |   4 +-
 doc/man1/openssl-dgst.pod.in     |   6 +-
 doc/man1/openssl-ec.pod.in       |   6 +-
 doc/man1/openssl-list.pod.in     |   1 -
 doc/man1/openssl-pkcs12.pod.in   |  20 ++--
 doc/man1/openssl-pkey.pod.in     |   6 +-
 doc/man1/openssl-pkeyutl.pod.in  |   8 +-
 doc/man1/openssl-req.pod.in      |   6 +-
 doc/man1/openssl-rsa.pod.in      |   6 +-
 doc/man1/openssl-rsautl.pod.in   |   6 +-
 doc/man1/openssl-s_client.pod.in |   8 +-
 doc/man1/openssl-s_server.pod.in |  18 +++-
 doc/man1/openssl-smime.pod.in    |   6 +-
 doc/man1/openssl-spkac.pod.in    |   8 +-
 doc/man1/openssl-ts.pod.in       |   6 +-
 doc/man1/openssl-verify.pod.in   |   2 +
 doc/man1/openssl-x509.pod.in     |  10 +-
 doc/man1/openssl.pod             |  41 ++++++--
 engines/e_ossltest.c             |  44 +++++++++
 test/recipes/90-test_store.t     |  41 +++++++-
 30 files changed, 510 insertions(+), 161 deletions(-)
 create mode 100644 apps/include/engine_loader.h
 create mode 100644 apps/lib/engine_loader.c

diff --git a/apps/cmp.c b/apps/cmp.c
index c9bbbb32ba..d57c67c644 100644
--- a/apps/cmp.c
+++ b/apps/cmp.c
@@ -409,11 +409,7 @@ const OPTIONS cmp_options[] = {
     {"engine", OPT_ENGINE, 's',
      "Use crypto engine with given identifier, possibly a hardware device."},
     {OPT_MORE_STR, 0, 0,
-     "Engines may be defined in OpenSSL config file engine section."},
-    {OPT_MORE_STR, 0, 0,
-     "Options like -key specifying keys held in the engine can give key IDs"},
-    {OPT_MORE_STR, 0, 0,
-     "prefixed by 'engine:', e.g. '-key engine:pkcs11:object=mykey;pin-value=1234'"},
+     "Engines may also be defined in OpenSSL config file engine section."},
 #endif
     OPT_PROV_OPTIONS,
 
diff --git a/apps/include/apps.h b/apps/include/apps.h
index 0848a2e03e..ddfa3c8383 100644
--- a/apps/include/apps.h
+++ b/apps/include/apps.h
@@ -36,6 +36,7 @@
 # include "opt.h"
 # include "fmt.h"
 # include "platform.h"
+# include "engine_loader.h"
 
 /*
  * quick macro when you need to pass an unsigned char instead of a char.
@@ -155,10 +156,7 @@ ENGINE *setup_engine_methods(const char *id, unsigned int methods, int debug);
 void release_engine(ENGINE *e);
 int init_engine(ENGINE *e);
 int finish_engine(ENGINE *e);
-EVP_PKEY *load_engine_private_key(ENGINE *e, const char *keyid,
-                                  const char *pass, const char *desc);
-EVP_PKEY *load_engine_public_key(ENGINE *e, const char *keyid,
-                                 const char *pass, const char *desc);
+char *make_engine_uri(ENGINE *e, const char *key_id, const char *desc);
 
 int get_legacy_pkey_id(OSSL_LIB_CTX *libctx, const char *algname, ENGINE *e);
 
diff --git a/apps/include/engine_loader.h b/apps/include/engine_loader.h
new file mode 100644
index 0000000000..11598639a5
--- /dev/null
+++ b/apps/include/engine_loader.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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
+ */
+#ifndef HEADER_ENGINE_LOADER_H
+# define HEADER_ENGINE_LOADER_H
+
+# include <openssl/store.h>
+
+/* this is a private URI scheme */
+# define ENGINE_SCHEME          "org.openssl.engine"
+# define ENGINE_SCHEME_COLON    (ENGINE_SCHEME ":")
+
+int setup_engine_loader(void);
+void destroy_engine_loader(void);
+
+#endif
diff --git a/apps/lib/apps.c b/apps/lib/apps.c
index 766002b6b0..699802044d 100644
--- a/apps/lib/apps.c
+++ b/apps/lib/apps.c
@@ -39,6 +39,8 @@
 #endif
 #include <openssl/bn.h>
 #include <openssl/ssl.h>
+#include <openssl/store.h>
+#include "s_apps.h"
 #include "apps.h"
 
 #ifdef _WIN32
@@ -558,25 +560,18 @@ EVP_PKEY *load_key(const char *uri, int format, int may_stdin,
                    const char *pass, ENGINE *e, const char *desc)
 {
     EVP_PKEY *pkey = NULL;
+    char *allocated_uri = NULL;
 
     if (desc == NULL)
         desc = "private key";
 
     if (format == FORMAT_ENGINE) {
-        if (e == NULL) {
-            BIO_printf(bio_err, "No engine specified for loading %s\n", desc);
-        } else {
-            pkey = load_engine_private_key(e, uri, pass, desc);
-            if (pkey == NULL) {
-                BIO_printf(bio_err, "Cannot load %s from engine\n", desc);
-                ERR_print_errors(bio_err);
-            }
-        }
-    } else {
-        (void)load_key_certs_crls(uri, may_stdin, pass, desc,
-                                  &pkey, NULL, NULL, NULL, NULL, NULL, NULL);
+        uri = allocated_uri = make_engine_uri(e, uri, desc);
     }
+    (void)load_key_certs_crls(uri, may_stdin, pass, desc,
+                              &pkey, NULL, NULL, NULL, NULL, NULL, NULL);
 
+    OPENSSL_free(allocated_uri);
     return pkey;
 }
 
@@ -584,25 +579,18 @@ EVP_PKEY *load_pubkey(const char *uri, int format, int maybe_stdin,
                       const char *pass, ENGINE *e, const char *desc)
 {
     EVP_PKEY *pkey = NULL;
+    char *allocated_uri = NULL;
 
     if (desc == NULL)
         desc = "public key";
 
     if (format == FORMAT_ENGINE) {
-        if (e == NULL) {
-            BIO_printf(bio_err, "No engine specified for loading %s\n", desc);
-        } else {
-            pkey = load_engine_public_key(e, uri, pass, desc);
-            if (pkey == NULL) {
-                BIO_printf(bio_err, "Cannot load %s from engine\n", desc);
-                ERR_print_errors(bio_err);
-            }
-        }
-    } else {
-        (void)load_key_certs_crls(uri, maybe_stdin, pass, desc,
-                                  NULL, &pkey, NULL, NULL, NULL, NULL, NULL);
+        uri = allocated_uri = make_engine_uri(e, uri, desc);
     }
+    (void)load_key_certs_crls(uri, maybe_stdin, pass, desc,
+                              NULL, &pkey, NULL, NULL, NULL, NULL, NULL);
 
+    OPENSSL_free(allocated_uri);
     return pkey;
 }
 
@@ -715,14 +703,25 @@ int load_key_certs_crls(const char *uri, int maybe_stdin,
         pparams != NULL ? "params" : pcert != NULL ? "cert" :
         pcrl != NULL ? "CRL" : pcerts != NULL ? "certs" :
         pcrls != NULL ? "CRLs" : NULL;
+    int cnt_expectations = 0;
+    int expect = 0;
     /* TODO make use of the engine reference 'eng' when loading pkeys */
 
-    if (ppkey != NULL)
+    if (ppkey != NULL) {
         *ppkey = NULL;
-    if (ppubkey != NULL)
+        cnt_expectations++;
+        expect = OSSL_STORE_INFO_PKEY;
+    }
+    if (ppubkey != NULL) {
         *ppubkey = NULL;
-    if (pcert != NULL)
+        cnt_expectations++;
+        expect = OSSL_STORE_INFO_PUBKEY;
+    }
+    if (pcert != NULL) {
         *pcert = NULL;
+        cnt_expectations++;
+        expect = OSSL_STORE_INFO_CERT;
+    }
     if (failed == NULL) {
         BIO_printf(bio_err, "Internal error: nothing to load into from %s\n",
                    uri != NULL ? uri : "<stdin>");
@@ -733,13 +732,22 @@ int load_key_certs_crls(const char *uri, int maybe_stdin,
             && (*pcerts = sk_X509_new_null()) == NULL) {
         BIO_printf(bio_err, "Out of memory loading");
         goto end;
+    } else {
+        cnt_expectations++;
+        expect = OSSL_STORE_INFO_CERT;
     }
-    if (pcrl != NULL)
+    if (pcrl != NULL) {
         *pcrl = NULL;
+        cnt_expectations++;
+        expect = OSSL_STORE_INFO_CRL;
+    }
     if (pcrls != NULL && *pcrls == NULL
             && (*pcrls = sk_X509_CRL_new_null()) == NULL) {
         BIO_printf(bio_err, "Out of memory loading");
         goto end;
+    } else {
+        cnt_expectations++;
+        expect = OSSL_STORE_INFO_CRL;
     }
 
     uidata.password = pass;
@@ -767,6 +775,11 @@ int load_key_certs_crls(const char *uri, int maybe_stdin,
         goto end;
     }
 
+    if (cnt_expectations != 1)
+        expect = 0;
+    if (!OSSL_STORE_expect(ctx, expect))
+        goto end;
+
     failed = NULL;
     while (!OSSL_STORE_eof(ctx)) {
         OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);
diff --git a/apps/lib/build.info b/apps/lib/build.info
index 9930ad6212..93d0a99df9 100644
--- a/apps/lib/build.info
+++ b/apps/lib/build.info
@@ -10,7 +10,7 @@ ENDIF
 # Source for libapps
 $LIBAPPSSRC=apps.c apps_ui.c opt.c fmt.c s_cb.c s_socket.c app_rand.c \
         columns.c app_params.c names.c app_provider.c app_x509.c http_server.c \
-        engine.c
+        engine.c engine_loader.c
 
 IF[{- !$disabled{apps} -}]
   LIBS{noinst}=../libapps.a
diff --git a/apps/lib/engine.c b/apps/lib/engine.c
index 4d9adc2818..e4a65b04e2 100644
--- a/apps/lib/engine.c
+++ b/apps/lib/engine.c
@@ -102,48 +102,37 @@ int finish_engine(ENGINE *e)
     return rv;
 }
 
-EVP_PKEY *load_engine_private_key(ENGINE *e, const char *keyid,
-                                  const char *pass, const char *desc)
+char *make_engine_uri(ENGINE *e, const char *key_id, const char *desc)
 {
-    EVP_PKEY *rv = NULL;
+    char *new_uri = NULL;
 
 #ifndef OPENSSL_NO_ENGINE
-    if (init_engine(e)) {
-        PW_CB_DATA cb_data;
-
-        cb_data.password = pass;
-        cb_data.prompt_info = keyid;
-
-        rv = ENGINE_load_private_key(e, keyid,
-                                     (UI_METHOD *)get_ui_method(), &cb_data);
-        finish_engine(e);
-    }
-#else
-    BIO_printf(bio_err, "Engines not supported for loading %s\n", desc);
-#endif
-    return rv;
-}
-
-EVP_PKEY *load_engine_public_key(ENGINE *e, const char *keyid,
-                                 const char *pass, const char *desc)
-{
-    EVP_PKEY *rv = NULL;
-
-#ifndef OPENSSL_NO_ENGINE
-    if (init_engine(e)) {
-        PW_CB_DATA cb_data;
-
-        cb_data.password = pass;
-        cb_data.prompt_info = keyid;
-
-        rv = ENGINE_load_public_key(e, keyid,
-                                    (UI_METHOD *)get_ui_method(), &cb_data);
-        finish_engine(e);
+    if (e == NULL) {
+        BIO_printf(bio_err, "No engine specified for loading %s\n", desc);
+    } else if (key_id == NULL) {
+        BIO_printf(bio_err, "No engine key id specified for loading %s\n", desc);
+    } else {
+        const char *engineid = ENGINE_get_id(e);
+        size_t uri_sz =
+            sizeof(ENGINE_SCHEME_COLON) - 1
+            + strlen(engineid)
+            + 1 /* : */
+            + strlen(key_id)
+            + 1 /* \0 */
+            ;
+
+        new_uri = OPENSSL_malloc(uri_sz);
+        if (new_uri != NULL) {
+            OPENSSL_strlcpy(new_uri, ENGINE_SCHEME_COLON, uri_sz);
+            OPENSSL_strlcat(new_uri, engineid, uri_sz);
+            OPENSSL_strlcat(new_uri, ":", uri_sz);
+            OPENSSL_strlcat(new_uri, key_id, uri_sz);
+        }
     }
 #else
     BIO_printf(bio_err, "Engines not supported for loading %s\n", desc);
 #endif
-    return rv;
+    return new_uri;
 }
 
 int get_legacy_pkey_id(OSSL_LIB_CTX *libctx, const char *algname, ENGINE *e)
diff --git a/apps/lib/engine_loader.c b/apps/lib/engine_loader.c
new file mode 100644
index 0000000000..2b4480000c
--- /dev/null
+++ b/apps/lib/engine_loader.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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
+ */
+
+/*
+ * Here is an STORE loader for ENGINE backed keys.  It relies on deprecated
+ * functions, and therefore need to have deprecation warnings suppressed.
+ * This file is not compiled at all in a '--api=3 no-deprecated' configuration.
+ */
+#define OPENSSL_SUPPRESS_DEPRECATED
+
+#include "apps.h"
+
+#ifndef OPENSSL_NO_ENGINE
+
+# include <stdarg.h>
+# include <string.h>
+# include <openssl/engine.h>
+# include <openssl/store.h>
+
+/*
+ * Support for legacy private engine keys via the 'org.openssl.engine:' scheme
+ *
+ * org.openssl.engine:{engineid}:{keyid}
+ *
+ * Note: we ONLY support ENGINE_load_private_key() and ENGINE_load_public_key()
+ * Note 2: This scheme has a precedent in code in PKIX-SSH. for exactly
+ * this sort of purpose.
+ */
+
+/* Local definition of OSSL_STORE_LOADER_CTX */
+struct ossl_store_loader_ctx_st {
+    ENGINE *e;                   /* Structural reference */
+    char *keyid;
+    int expected;
+    int loaded;                  /* 0 = key not loaded yet, 1 = key loaded */
+};
+
+static OSSL_STORE_LOADER_CTX *OSSL_STORE_LOADER_CTX_new(ENGINE *e, char *keyid)
+{
+    OSSL_STORE_LOADER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+    if (ctx != NULL) {
+        ctx->e = e;
+        ctx->keyid = keyid;
+    }
+    return ctx;
+}
+
+static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx)
+{
+    if (ctx != NULL) {
+        ENGINE_free(ctx->e);
+        OPENSSL_free(ctx->keyid);
+        OPENSSL_free(ctx);
+    }
+}
+
+static OSSL_STORE_LOADER_CTX *engine_open(const OSSL_STORE_LOADER *loader,
+                                          const char *uri,
+                                          const UI_METHOD *ui_method,
+                                          void *ui_data)
+{
+    const char *p = uri, *q;
+    ENGINE *e = NULL;
+    char *keyid = NULL;
+    OSSL_STORE_LOADER_CTX *ctx = NULL;
+
+    if (strncasecmp(p, ENGINE_SCHEME_COLON, sizeof(ENGINE_SCHEME_COLON) - 1)
+        != 0)
+        return NULL;
+    p += sizeof(ENGINE_SCHEME_COLON) - 1;
+
+    /* Look for engine ID */
+    q = strchr(p, ':');
+    if (q != NULL                /* There is both an engine ID and a key ID */
+        && p[0] != ':'           /* The engine ID is at least one character */
+        && q[1] != '\0') {       /* The key ID is at least one character */
+        char engineid[256];
+        size_t engineid_l = q - p;
+
+        strncpy(engineid, p, engineid_l);
+        engineid[engineid_l] = '\0';
+        e = ENGINE_by_id(engineid);
+
+        keyid = OPENSSL_strdup(q + 1);
+    }
+
+    if (e != NULL)
+        ctx = OSSL_STORE_LOADER_CTX_new(e, keyid);
+
+    if (ctx == NULL) {
+        OPENSSL_free(keyid);
+        ENGINE_free(e);
+    }
+
+    return ctx;
+}
+
+static int engine_expect(OSSL_STORE_LOADER_CTX *ctx, int expected)
+{
+    if (expected == 0
+        || expected == OSSL_STORE_INFO_PUBKEY
+        || expected == OSSL_STORE_INFO_PKEY) {
+        ctx->expected = expected;
+        return 1;
+    }
+    return 0;
+}
+
+static OSSL_STORE_INFO *engine_load(OSSL_STORE_LOADER_CTX *ctx,
+                                    const UI_METHOD *ui_method, void *ui_data)
+{
+    EVP_PKEY *pkey = NULL, *pubkey = NULL;
+    OSSL_STORE_INFO *info = NULL;
+
+    if (ctx->loaded == 0) {
+        if (ENGINE_init(ctx->e)) {
+            if (ctx->expected == 0
+                || ctx->expected == OSSL_STORE_INFO_PKEY)
+                pkey =
+                    ENGINE_load_private_key(ctx->e, ctx->keyid,
+                                            (UI_METHOD *)ui_method, ui_data);
+            if ((pkey == NULL && ctx->expected == 0)
+                || ctx->expected == OSSL_STORE_INFO_PUBKEY)
+                pubkey =
+                    ENGINE_load_public_key(ctx->e, ctx->keyid,
+                                           (UI_METHOD *)ui_method, ui_data);
+            ENGINE_finish(ctx->e);
+        }
+    }
+
+    ctx->loaded = 1;
+
+    if (pubkey != NULL)
+        info = OSSL_STORE_INFO_new_PUBKEY(pubkey);
+    else if (pkey != NULL)
+        info = OSSL_STORE_INFO_new_PKEY(pkey);
+    if (info == NULL) {
+        EVP_PKEY_free(pkey);
+        EVP_PKEY_free(pubkey);
+    }
+    return info;
+}
+
+static int engine_eof(OSSL_STORE_LOADER_CTX *ctx)
+{
+    return ctx->loaded != 0;
+}
+
+static int engine_error(OSSL_STORE_LOADER_CTX *ctx)
+{
+    return 0;
+}
+
+static int engine_close(OSSL_STORE_LOADER_CTX *ctx)
+{
+    OSSL_STORE_LOADER_CTX_free(ctx);
+    return 1;
+}
+
+int setup_engine_loader(void)
+{
+    OSSL_STORE_LOADER *loader = NULL;
+
+    if ((loader = OSSL_STORE_LOADER_new(NULL, ENGINE_SCHEME)) == NULL
+        || !OSSL_STORE_LOADER_set_open(loader, engine_open)
+        || !OSSL_STORE_LOADER_set_expect(loader, engine_expect)
+        || !OSSL_STORE_LOADER_set_load(loader, engine_load)
+        || !OSSL_STORE_LOADER_set_eof(loader, engine_eof)
+        || !OSSL_STORE_LOADER_set_error(loader, engine_error)
+        || !OSSL_STORE_LOADER_set_close(loader, engine_close)
+        || !OSSL_STORE_register_loader(loader)) {
+        OSSL_STORE_LOADER_free(loader);
+        loader = NULL;
+    }
+
+    return loader != NULL;
+}
+
+void destroy_engine_loader(void)
+{
+    OSSL_STORE_LOADER *loader = OSSL_STORE_unregister_loader(ENGINE_SCHEME);
+    OSSL_STORE_LOADER_free(loader);
+}
+
+#else  /* !OPENSSL_NO_ENGINE */
+
+int setup_engine_loader(void)
+{
+    return 0;
+}
+
+void destroy_engine_loader(void)
+{
+}
+
+#endif
diff --git a/apps/openssl.c b/apps/openssl.c
index 307303b257..9d697a8836 100644
--- a/apps/openssl.c
+++ b/apps/openssl.c
@@ -68,6 +68,7 @@ static int apps_startup(void)
         return 0;
 
     (void)setup_ui_method();
+    (void)setup_engine_loader();
 
     /*
      * NOTE: This is an undocumented feature required for testing only.
@@ -89,6 +90,7 @@ static void apps_shutdown(void)
 {
     app_providers_cleanup();
     OSSL_LIB_CTX_free(app_get0_libctx());
+    destroy_engine_loader();
     destroy_ui_method();
 }
 
diff --git a/doc/man1/openssl-ca.pod.in b/doc/man1/openssl-ca.pod.in
index b1d437a5c0..64a7054d63 100644
--- a/doc/man1/openssl-ca.pod.in
+++ b/doc/man1/openssl-ca.pod.in
@@ -33,7 +33,7 @@ B<openssl> B<ca>
 [B<-days> I<arg>]
 [B<-md> I<arg>]
 [B<-policy> I<arg>]
-[B<-keyfile> I<arg>]
+[B<-keyfile> I<filename>|I<uri>]
 [B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-key> I<arg>]
 [B<-passin> I<arg>]
@@ -148,7 +148,7 @@ The CA certificate, which must match with B<-keyfile>.
 The format of the data in certificate input files.
 This option has no effect and is retained for backward compatibility only.
 
-=item B<-keyfile> I<filename>
+=item B<-keyfile> I<filename>|I<uri>
 
 The CA private key to sign requests with. This must match with B<-cert>.
 
diff --git a/doc/man1/openssl-cmp.pod.in b/doc/man1/openssl-cmp.pod.in
index 291535b7a1..0993186158 100644
--- a/doc/man1/openssl-cmp.pod.in
+++ b/doc/man1/openssl-cmp.pod.in
@@ -21,7 +21,7 @@ Generic message options:
 
 Certificate enrollment options:
 
-[B<-newkey> I<filename>]
+[B<-newkey> I<filename>|I<uri>]
 [B<-newkeypass> I<arg>]
 [B<-subject> I<name>]
 [B<-issuer> I<name>]
@@ -90,7 +90,7 @@ TLS connection options:
 
 [B<-tls_used>]
 [B<-tls_cert> I<filename>]
-[B<-tls_key> I<filename>]
+[B<-tls_key> I<filename>|I<uri>]
 [B<-tls_keypass> I<arg>]
 [B<-tls_extra> I<filenames>]
 [B<-tls_trusted> I<filenames>]
@@ -139,6 +139,8 @@ Certificate verification options, for both CMP and TLS:
 
 {- $OpenSSL::safe::opt_v_synopsis -}
 
+=for openssl ifdef engine
+
 =head1 DESCRIPTION
 
 The B<cmp> command is a client implementation for the Certificate
@@ -241,9 +243,9 @@ e.g., C<1.2.3.4:int:56789>.
 
 =over 4
 
-=item B<-newkey> I<filename>
+=item B<-newkey> I<filename>|I<uri>
 
-The file containing the private or public key for the certificate requested
+The source of the private or public key for the certificate requested
 in Initialization Request (IR), Certification Request(CR), or
 Key Update Request (KUR).
 Default is the public key in the PKCS#10 CSR given with the B<-csr> option,
@@ -701,6 +703,7 @@ Default value is PEM.
 
 The format of the key input.
 The only value with effect is B<ENGINE>.
+See L<openssl(1)/Format Options> for details.
 
 =item B<-otherpass> I<arg>
 
@@ -712,27 +715,24 @@ If not given here, the password will be prompted for if needed.
 
 For more information about the format of B<arg> see the
 B<PASS PHRASE ARGUMENTS> section in L<openssl(1)>.
+
+{- $OpenSSL::safe::opt_engine_item -}
+
+=back
+
 {- output_off() if $disabled{"deprecated-3.0"}; "" -}
+As an alternative to using this combination:
 
-=item B<-engine> I<id>
+    -engine {engineid} -key {keyid} -keyform ENGINE
 
-Specifying a crypto engine B<id> will lead to obtaining a functional
-reference to the specified engine, initializing it if needed.
-The engine will be used for all algorithms supported for keys
-prefixed by C<engine:>.
-Engines may be defined in the OpenSSL config file as usual in an engine section.
+... it's also possible to just give the key ID in URI form to B<-key>,
+like this:
 
-Options specifying keys, like B<-key>, B<-newkey>, B<-tls_key> can prefix
-C<engine:> to engine-specific identifiers for security tokens objects held by
-the engine.
- The following example utilizes the RFC 7512 PKCS #11 URI scheme
-as supported, e.g., by libp11:
-C<-key engine:pkcs11:object=my-private-key;type=private;pin-value=1234>
+    -key org.openssl.engine:{engineid}:{keyid}
 
+This applies to all options specifying keys: B<-key>, B<-newkey>, and
+B<-tls_key>.
 {- output_on() if $disabled{"deprecated-3.0"}; "" -}
-{- $OpenSSL::safe::opt_provider_item -}
-
-=back
 
 =head2 TLS connection options
 
@@ -749,7 +749,7 @@ Client's TLS certificate.
 If the file includes further certs they are used (along with B<-untrusted>
 certs) for constructing the client cert chain provided to the TLS server.
 
-=item B<-tls_key> I<filename>
+=item B<-tls_key> I<filename>|I<uri>
 
 Private key for the client's TLS certificate.
 
@@ -1162,6 +1162,12 @@ and the above genm call reduces to
 L<openssl-genrsa(1)>, L<openssl-ecparam(1)>, L<openssl-list(1)>,
 L<openssl-req(1)>, L<openssl-x509(1)>, L<x509v3_config(5)>
 
+=head1 HISTORY
+
+The B<cmp> application was added in OpenSSL 3.0.
+
+The B<-engine option> was deprecated in OpenSSL 3.0.
+
 =head1 COPYRIGHT
 
 Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man1/openssl-cms.pod.in b/doc/man1/openssl-cms.pod.in
index db1dc75978..fc2bae1bce 100644
--- a/doc/man1/openssl-cms.pod.in
+++ b/doc/man1/openssl-cms.pod.in
@@ -72,7 +72,7 @@ B<openssl> B<cms>
 [B<-secretkey> I<key>]
 [B<-secretkeyid> I<id>]
 [B<-econtent_type> I<type>]
-[B<-inkey> I<file>]
+[B<-inkey> I<filename>|I<uri>]
 [B<-keyopt> I<name>:I<parameter>]
 [B<-passin> I<arg>]
 [B<-to> I<addr>]
@@ -466,7 +466,7 @@ Set the encapsulated content type to I<type> if not supplied the B<Data> type
 is used. The I<type> argument can be any valid OID name in either text or
 numerical format.
 
-=item B<-inkey> I<file>
+=item B<-inkey> I<filename>|I<uri>
 
 The private key to use when signing or decrypting. This must match the
 corresponding certificate. If this option is not specified then the
diff --git a/doc/man1/openssl-dgst.pod.in b/doc/man1/openssl-dgst.pod.in
index 533f30725c..6276fab434 100644
--- a/doc/man1/openssl-dgst.pod.in
+++ b/doc/man1/openssl-dgst.pod.in
@@ -19,7 +19,7 @@ B<openssl> B<dgst>|I<digest>
 [B<-xoflen> I<length>]
 [B<-r>]
 [B<-out> I<filename>]
-[B<-sign> I<filename>]
+[B<-sign> I<filename>|I<uri>]
 [B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-passin> I<arg>]
 [B<-verify> I<filename>]
@@ -100,9 +100,9 @@ Used by programs like L<sha1sum(1)>.
 
 Filename to output to, or standard output by default.
 
-=item B<-sign> I<filename>
+=item B<-sign> I<filename>|I<uri>
 
-Digitally sign the digest using the private key in "filename". Note this option
+Digitally sign the digest using the given private key. Note this option
 does not support Ed25519 or Ed448 private keys. Use the L<openssl-pkeyutl(1)>
 command instead for this.
 
diff --git a/doc/man1/openssl-ec.pod.in b/doc/man1/openssl-ec.pod.in
index 6f07607e53..2ba107d031 100644
--- a/doc/man1/openssl-ec.pod.in
+++ b/doc/man1/openssl-ec.pod.in
@@ -15,7 +15,7 @@ B<openssl> B<ec>
 [B<-help>]
 [B<-inform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-outform> B<DER>|B<PEM>]
-[B<-in> I<filename>]
+[B<-in> I<filename>|I<uri>]
 [B<-passin> I<arg>]
 [B<-out> I<filename>]
 [B<-passout> I<arg>]
@@ -65,9 +65,9 @@ See L<openssl(1)/Format Options> for details.
 Private keys are an SEC1 private key or PKCS#8 format.
 Public keys are a B<SubjectPublicKeyInfo> as specified in IETF RFC 3280.
 
-=item B<-in> I<filename>
+=item B<-in> I<filename>|I<uri>
 
-This specifies the input filename to read a key from or standard input if this
+This specifies the input to read a key from or standard input if this
 option is not specified. If the key is encrypted a pass phrase will be
 prompted for.
 
diff --git a/doc/man1/openssl-list.pod.in b/doc/man1/openssl-list.pod.in
index 45e58da870..7d7ba6504e 100644
--- a/doc/man1/openssl-list.pod.in
+++ b/doc/man1/openssl-list.pod.in
@@ -158,7 +158,6 @@ This option is deprecated.
 
 Display a list of loaded engines.
 
-{- output_on() if $disabled{"deprecated-3.0"}; "" -}
 =item B<-disabled>
 
 Display a list of disabled features, those that were compiled out
diff --git a/doc/man1/openssl-pkcs12.pod.in b/doc/man1/openssl-pkcs12.pod.in
index e5da1ec980..db9f65a984 100644
--- a/doc/man1/openssl-pkcs12.pod.in
+++ b/doc/man1/openssl-pkcs12.pod.in
@@ -12,12 +12,12 @@ B<openssl> B<pkcs12>
 [B<-export>]
 [B<-chain>]
 [B<-untrusted> I<filename>]
-[B<-inkey> I<file_or_id>]
+[B<-inkey> I<filename>|I<uri>]
 [B<-certfile> I<filename>]
 [B<-passcerts> I<arg>]
 [B<-name> I<name>]
 [B<-caname> I<name>]
-[B<-in> I<filename>]
+[B<-in> I<filename>|I<uri>]
 [B<-out> I<filename>]
 [B<-noout>]
 [B<-nomacver>]
@@ -86,12 +86,13 @@ The default encryption algorithm is AES-256-CBC with PBKDF2 for key derivation.
 
 Print out a usage message.
 
-=item B<-in> I<filename>
+=item B<-in> I<filename>|I<uri>
 
 This specifies the input filename or URI.
 Standard input is used by default.
 Without the B<-export> option this is a PKCS#12 file to be parsed.
-With the B<-export> option this is a file with certificates and possibly a key.
+With the B<-export> option this is a file with certificates and possibly a key,
+or a URI that refers to a key accessed via an engine.
 
 =item B<-out> I<filename>
 
@@ -206,12 +207,13 @@ The order doesn't matter but one private key and
 its corresponding certificate should be present. If additional
 certificates are present they will also be included in the PKCS#12 file.
 
-=item B<-inkey> I<file_or_id>
+=item B<-inkey> I<filename>|I<uri>
 
-File to read private key from for PKCS12 output.
-If not present then the input file (B<-in> argument) must contain a private key.
-If no engine is used, the argument is taken as a file; if an engine is
-specified, the argument is given to the engine as a key identifier.
+The private key input for PKCS12 output. If this option is not specified then
+the input file (B<-in> argument) must contain a private key.
+If no engine is used, the argument is taken as a file;
+if the B<-engine> option is used or the URI has prefix C<org.openssl.engine:>
+then the rest of the URI is taken as key identifier for the given engine.
 
 =item B<-name> I<friendlyname>
 
diff --git a/doc/man1/openssl-pkey.pod.in b/doc/man1/openssl-pkey.pod.in
index 2b55497bdd..b1afeb534b 100644
--- a/doc/man1/openssl-pkey.pod.in
+++ b/doc/man1/openssl-pkey.pod.in
@@ -15,7 +15,7 @@ B<openssl> B<pkey>
 [B<-help>]
 [B<-inform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-outform> B<DER>|B<PEM>]
-[B<-in> I<filename>]
+[B<-in> I<filename>|I<uri>]
 [B<-passin> I<arg>]
 [B<-out> I<filename>]
 [B<-passout> I<arg>]
@@ -58,9 +58,9 @@ See L<openssl(1)/Format Options> for details.
 The key output formats; the default is B<PEM>.
 See L<openssl(1)/Format Options> for details.
 
-=item B<-in> I<filename>
+=item B<-in> I<filename>|I<uri>
 
-This specifies the input filename to read a key from or standard input if this
+This specifies the input to read a key from or standard input if this
 option is not specified. If the key is encrypted a pass phrase will be
 prompted for.
 
diff --git a/doc/man1/openssl-pkeyutl.pod.in b/doc/man1/openssl-pkeyutl.pod.in
index 8fce576abe..a35c4dae65 100644
--- a/doc/man1/openssl-pkeyutl.pod.in
+++ b/doc/man1/openssl-pkeyutl.pod.in
@@ -14,7 +14,7 @@ B<openssl> B<pkeyutl>
 [B<-digest> I<algorithm>]
 [B<-out> I<file>]
 [B<-sigfile> I<file>]
-[B<-inkey> I<file>]
+[B<-inkey> I<filename>|I<uri>]
 [B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-passin> I<arg>]
 [B<-peerkey> I<file>]
@@ -85,9 +85,9 @@ default.
 
 Signature file, required for B<-verify> operations only
 
-=item B<-inkey> I<file>
+=item B<-inkey> I<filename>|I<uri>
 
-The input key file, by default it should be a private key.
+The input key, by default it should be a private key.
 
 =item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
 
@@ -184,10 +184,12 @@ B<-verifyrecover> option when an ASN1 structure is signed.
 
 {- $OpenSSL::safe::opt_engine_item -}
 
+{- output_off() if $disabled{"deprecated-3.0"}; "" -}
 =item B<-engine_impl>
 
 When used with the B<-engine> option, it specifies to also use
 engine I<id> for crypto operations.
+{- output_on() if $disabled{"deprecated-3.0"}; "" -}
 
 {- $OpenSSL::safe::opt_r_item -}
 
diff --git a/doc/man1/openssl-req.pod.in b/doc/man1/openssl-req.pod.in
index 91a40cc89c..8fa5191702 100644
--- a/doc/man1/openssl-req.pod.in
+++ b/doc/man1/openssl-req.pod.in
@@ -25,7 +25,7 @@ B<openssl> B<req>
 [B<-pkeyopt> I<opt>:I<value>]
 [B<-noenc>]
 [B<-nodes>]
-[B<-key> I<filename>]
+[B<-key> I<filename>|I<uri>]
 [B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-keyout> I<filename>]
 [B<-keygen_engine> I<id>]
@@ -181,9 +181,9 @@ options supported depends on the public key algorithm used and its
 implementation.
 See L<openssl-genpkey(1)/KEY GENERATION OPTIONS> for more details.
 
-=item B<-key> I<filename>
+=item B<-key> I<filename>|I<uri>
 
-This specifies the file to read the private key from. It also
+This specifies the private key to use. It also
 accepts PKCS#8 format private keys for PEM format files.
 
 =item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
diff --git a/doc/man1/openssl-rsa.pod.in b/doc/man1/openssl-rsa.pod.in
index 63fac355ee..f2e7f3474c 100644
--- a/doc/man1/openssl-rsa.pod.in
+++ b/doc/man1/openssl-rsa.pod.in
@@ -15,7 +15,7 @@ B<openssl> B<rsa>
 [B<-help>]
 [B<-inform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-outform> B<DER>|B<PEM>]
-[B<-in> I<filename>]
+[B<-in> I<filename>|I<uri>]
 [B<-passin> I<arg>]
 [B<-out> I<filename>]
 [B<-passout> I<arg>]
@@ -74,9 +74,9 @@ See L<openssl(1)/Format Options> for details.
 When writing a private key, use the traditional PKCS#1 format
 instead of the PKCS#8 format.
 
-=item B<-in> I<filename>
+=item B<-in> I<filename>|I<uri>
 
-This specifies the input filename to read a key from or standard input if this
+This specifies the input to read a key from or standard input if this
 option is not specified. If the key is encrypted a pass phrase will be
 prompted for.
 
diff --git a/doc/man1/openssl-rsautl.pod.in b/doc/man1/openssl-rsautl.pod.in
index e573e493df..fed453b940 100644
--- a/doc/man1/openssl-rsautl.pod.in
+++ b/doc/man1/openssl-rsautl.pod.in
@@ -13,7 +13,7 @@ B<openssl> B<rsautl>
 [B<-passin> I<arg>]
 [B<-rev>]
 [B<-out> I<file>]
-[B<-inkey> I<file>]
+[B<-inkey> I<filename>|I<uri>]
 [B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-pubin>]
 [B<-certin>]
@@ -71,9 +71,9 @@ Reverse the order of the input.
 Specifies the output filename to write to or standard output by
 default.
 
-=item B<-inkey> I<file>
+=item B<-inkey> I<filename>|I<uri>
 
-The input key file, by default it should be an RSA private key.
+The input key, by default it should be an RSA private key.
 
 =item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
 
diff --git a/doc/man1/openssl-s_client.pod.in b/doc/man1/openssl-s_client.pod.in
index 8ea0703e2b..ddaa69c1b7 100644
--- a/doc/man1/openssl-s_client.pod.in
+++ b/doc/man1/openssl-s_client.pod.in
@@ -35,7 +35,7 @@ B<openssl> B<s_client>
 [B<-CRL> I<filename>]
 [B<-CRLform> B<DER>|B<PEM>]
 [B<-crl_download>]
-[B<-key> I<filename>]
+[B<-key> I<filename>|I<uri>]
 [B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-pass> I<arg>]
 [B<-chainCAfile> I<filename>]
@@ -269,9 +269,9 @@ See L<openssl(1)/Format Options> for details.
 
 Download CRL from distribution points in the certificate.
 
-=item B<-key> I<keyfile>
+=item B<-key> I<filename>|I<uri>
 
-The client private key file to use.
+The client private key to use.
 If not specified then the certificate file will be used to read also the key.
 
 =item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
@@ -786,9 +786,11 @@ Set the minimal acceptable length, in bits, for B<N>.
 
 {- $OpenSSL::safe::opt_engine_item -}
 
+{- output_off() if $disabled{"deprecated-3.0"}; "" -}
 =item B<-ssl_client_engine> I<id>
 
 Specify engine to be used for client certificate operations.
+{- output_on() if $disabled{"deprecated-3.0"}; "" -}
 
 {- $OpenSSL::safe::opt_v_item -}
 
diff --git a/doc/man1/openssl-s_server.pod.in b/doc/man1/openssl-s_server.pod.in
index 431fc235fa..e568fbab0a 100644
--- a/doc/man1/openssl-s_server.pod.in
+++ b/doc/man1/openssl-s_server.pod.in
@@ -24,14 +24,14 @@ B<openssl> B<s_server>
 [B<-cert_chain> I<infile>]
 [B<-build_chain>]
 [B<-serverinfo> I<val>]
-[B<-key> I<infile>]
-[B<-key2> I<infile>]
+[B<-key> I<filename>|I<uri>]
+[B<-key2> I<filename>|I<uri>]
 [B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-pass> I<val>]
 [B<-dcert> I<infile>]
 [B<-dcertform> B<DER>|B<PEM>|B<P12>]
 [B<-dcert_chain> I<infile>]
-[B<-dkey> I<infile>]
+[B<-dkey> I<filename>|I<uri>]
 [B<-dkeyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-dpass> I<val>]
 [B<-nbio_test>]
@@ -220,6 +220,10 @@ certificate and some require a certificate with a certain public key type:
 for example the DSS cipher suites require a certificate containing a DSS
 (DSA) key. If not specified then the filename F<server.pem> will be used.
 
+=item B<-cert2> I<infile>
+
+The certificate file to use for servername; default is C<server2.pem>.
+
 =item B<-certform> B<DER>|B<PEM>|B<P12>
 
 The server certificate file format.
@@ -244,11 +248,15 @@ followed by "length" bytes of extension data).  If the client sends
 an empty TLS ClientHello extension matching the type, the corresponding
 ServerHello extension will be returned.
 
-=item B<-key> I<infile>
+=item B<-key> I<filename>|I<uri>
 
 The private key to use. If not specified then the certificate file will
 be used.
 
+=item B<-key2> I<filename>|I<uri>
+
+The private Key file to use for servername if not given via B<-cert2>.
+
 =item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
 
 The key format; the default is B<PEM>.
@@ -261,7 +269,7 @@ The private key and certificate file password source.
 For more information about the format of I<val>,
 see L<openssl(1)/Pass Phrase Options>.
 
-=item B<-dcert> I<infile>, B<-dkey> I<infile>
+=item B<-dcert> I<infile>, B<-dkey> I<filename>|I<uri>
 
 Specify an additional certificate and private key, these behave in the
 same manner as the B<-cert> and B<-key> options except there is no default
diff --git a/doc/man1/openssl-smime.pod.in b/doc/man1/openssl-smime.pod.in
index 09f0150b51..aa2dfaf8c5 100644
--- a/doc/man1/openssl-smime.pod.in
+++ b/doc/man1/openssl-smime.pod.in
@@ -34,7 +34,7 @@ B<openssl> B<smime>
 [B<-outform> B<DER>|B<PEM>|B<SMIME>]
 [B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-passin> I<arg>]
-[B<-inkey> I<file_or_id>]
+[B<-inkey> I<filename>|I<uri>]
 [B<-out> I<file>]
 [B<-content> I<file>]
 [B<-to> I<addr>]
@@ -259,15 +259,13 @@ Don't include any signed attributes when signing.
 The recipients certificate when decrypting a message. This certificate
 must match one of the recipients of the message or an error occurs.
 
-=item B<-inkey> I<file_or_id>
+=item B<-inkey> I<filename>|I<uri>
 
 The private key to use when signing or decrypting. This must match the
 corresponding certificate. If this option is not specified then the
 private key must be included in the certificate file specified with
 the B<-recip> or B<-signer> file. When signing this option can be used
 multiple times to specify successive keys.
-If no engine is used, the argument is taken as a file; if an engine is
-specified, the argument is given to the engine as a key identifier.
 
 =item B<-passin> I<arg>
 
diff --git a/doc/man1/openssl-spkac.pod.in b/doc/man1/openssl-spkac.pod.in
index e354a4c9ce..31df6b3b59 100644
--- a/doc/man1/openssl-spkac.pod.in
+++ b/doc/man1/openssl-spkac.pod.in
@@ -15,7 +15,7 @@ B<openssl> B<spkac>
 [B<-help>]
 [B<-in> I<filename>]
 [B<-out> I<filename>]
-[B<-key> I<keyfile>]
+[B<-key> I<filename>|I<uri>]
 [B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>]
 [B<-passin> I<arg>]
 [B<-challenge> I<string>]
@@ -52,10 +52,10 @@ option is not specified. Ignored if the B<-key> option is used.
 Specifies the output filename to write to or standard output by
 default.
 
-=item B<-key> I<keyfile>
+=item B<-key> I<filename>|I<uri>
 
-Create an SPKAC file using the private key in I<keyfile>. The
-B<-in>, B<-noout>, B<-spksect> and B<-verify> options are ignored if
+Create an SPKAC file using the private key specified by I<filename> or I<uri>.
+The B<-in>, B<-noout>, B<-spksect> and B<-verify> options are ignored if
 present.
 
 =item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
diff --git a/doc/man1/openssl-ts.pod.in b/doc/man1/openssl-ts.pod.in
index 86478958c1..c74f71b10a 100644
--- a/doc/man1/openssl-ts.pod.in
+++ b/doc/man1/openssl-ts.pod.in
@@ -32,7 +32,7 @@ B<-reply>
 [B<-queryfile> I<request.tsq>]
 [B<-passin> I<password_src>]
 [B<-signer> I<tsa_cert.pem>]
-[B<-inkey> I<file_or_id>]
+[B<-inkey> I<filename>|I<uri>]
 [B<-I<digest>>]
 [B<-chain> I<certs_file.pem>]
 [B<-tspolicy> I<object_id>]
@@ -225,12 +225,10 @@ timeStamping. The extended key usage must also be critical, otherwise
 the certificate is going to be refused. Overrides the B<signer_cert>
 variable of the config file. (Optional)
 
-=item B<-inkey> I<file_or_id>
+=item B<-inkey> I<filename>|I<uri>
 
 The signer private key of the TSA in PEM format. Overrides the
 B<signer_key> config file option. (Optional)
-If no engine is used, the argument is taken as a file; if an engine is
-specified, the argument is given to the engine as a key identifier.
 
 =item B<-I<digest>>
 
diff --git a/doc/man1/openssl-verify.pod.in b/doc/man1/openssl-verify.pod.in
index c404be74bf..9e3e49b2d7 100644
--- a/doc/man1/openssl-verify.pod.in
+++ b/doc/man1/openssl-verify.pod.in
@@ -79,9 +79,11 @@ Names and values of these options are algorithm-specific.
 {- $OpenSSL::safe::opt_name_item -}
 
 {- $OpenSSL::safe::opt_engine_item -}
+{- output_off() if $disabled{"deprecated-3.0"}; "" -}
 To load certificates or CRLs that require engine support, specify the
 B<-engine> option before any of the
 B<-trusted>, B<-untrusted> or B<-CRLfile> options.
+{- output_on() if $disabled{"deprecated-3.0"}; "" -}
 
 {- $OpenSSL::safe::opt_trust_item -}
 
diff --git a/doc/man1/openssl-x509.pod.in b/doc/man1/openssl-x509.pod.in
index e3e1fd2004..ffa2ab4aed 100644
--- a/doc/man1/openssl-x509.pod.in
+++ b/doc/man1/openssl-x509.pod.in
@@ -45,13 +45,13 @@ B<openssl> B<x509>
 [B<-setalias> I<arg>]
 [B<-days> I<arg>]
 [B<-set_serial> I<n>]
-[B<-signkey> I<arg>]
+[B<-signkey> I<filename>|I<uri>]
 [B<-badsig>]
 [B<-passin> I<arg>]
 [B<-x509toreq>]
 [B<-req>]
 [B<-CA> I<filename>]
-[B<-CAkey> I<filename>]
+[B<-CAkey> I<filename>|I<uri>]
 [B<-CAcreateserial>]
 [B<-CAserial> I<filename>]
 [B<-new>]
@@ -351,10 +351,10 @@ can thus behave like a "mini CA".
 
 =over 4
 
-=item B<-signkey> I<arg>
+=item B<-signkey> I<filename>|I<uri>
 
 This option causes the input file to be self signed using the supplied
-private key or engine.
+private key.
 
 It sets the issuer name to the subject name (i.e., makes it self-issued)
 and changes the public key to the supplied value (unless overridden by
@@ -442,7 +442,7 @@ of the CA and it is digitally signed using the CAs private key.
 This option is normally combined with the B<-req> option. Without the
 B<-req> option the input is a certificate which must be self signed.
 
-=item B<-CAkey> I<filename>
+=item B<-CAkey> I<filename>|I<uri>
 
 Sets the CA private key to sign a certificate with. If this option is
 not specified then it is assumed that the CA private key is present in
diff --git a/doc/man1/openssl.pod b/doc/man1/openssl.pod
index bd3a9db226..0bb37d415d 100644
--- a/doc/man1/openssl.pod
+++ b/doc/man1/openssl.pod
@@ -527,6 +527,10 @@ of formats.
 Since OpenSSL 3.0 keys, single certificates, and CRLs can be read from
 files in any of the B<DER>, B<PEM> or B<P12> formats,
 while specifying their input format is no more needed.
+In order to access a key via an engine the input format B<ENGINE> may be used;
+alternatively the key identifier in the <uri> argument of the respective key
+option may be preceded by C<org.openssl.engine:>.
+See L<openssl(1)/Engine Options> for an example usage of the latter.
 
 The list of acceptable formats, and the default, is
 described in each command documentation.  The list of formats is
@@ -543,9 +547,7 @@ A binary format, encoded or parsed according to Distinguished Encoding Rules
 
 Used to specify that the cryptographic material is in an OpenSSL B<engine>.
 An engine must be configured or specified using the B<-engine> option.
-In addition, the B<-input> flag can be used to name a specific object in
-the engine.
-A password, such as the B<-passin> flag often must be specified as well.
+A password or PIN may be supplied to the engine using the B<-passin> option.
 
 =item B<P12>
 
@@ -1300,13 +1302,38 @@ respectively.
 
 =item B<-engine> I<id>
 
-Use the engine identified by I<id> and use all the methods it
-implements (algorithms, key storage, etc.), unless specified otherwise in
-the command-specific documentation or it is configured to do so, as described
-in L<config(5)/Engine Configuration Module>.
+Load the engine identified by I<id> and use all the methods it implements
+(algorithms, key storage, etc.), unless specified otherwise in the
+command-specific documentation or it is configured to do so, as described in
+L<config(5)/Engine Configuration>.
+
+The engine will be used for key ids specified with B<-key> and similar
+options when an option like B<-keyform engine> is given.
 
 =back
 
+Options specifying keys, like B<-key> and similar, can use the generic
+OpenSSL engine key loading URI scheme C<org.openssl.engine:> to retrieve
+private keys and public keys.  The URI syntax is as follows, in simplified
+form:
+
+    org.openssl.engine:{engineid}:{keyid}
+
+Where C<{engineid}> is the identity/name of the engine, and C<{keyid}> is a
+key identifier that's acceptable by that engine.  For example, when using an
+engine that interfaces against a PKCS#11 implementation, the generic key URI
+would be something like this (this happens to be an example for the PKCS#11
+engine that's part of OpenSC):
+
+    -key org.openssl.engine:pkcs11:label_some-private-key
+
+As a third possibility, for engines and providers that have implemented
+their own L<OSSL_STORE_LOADER(3)>, C<org.openssl.engine:> should not be
+necessary.  For a PKCS#11 implementation that has implemented such a loader,
+the PKCS#11 URI as defined in RFC 7512 should be possible to use directly:
+
+    -key pkcs11:object=some-private-key;pin-value=1234
+
 =head1 ENVIRONMENT
 
 The OpenSSL library can be take some configuration parameters from the
diff --git a/engines/e_ossltest.c b/engines/e_ossltest.c
index df2a3e14e8..15a7d75f1e 100644
--- a/engines/e_ossltest.c
+++ b/engines/e_ossltest.c
@@ -37,9 +37,14 @@
 #include <openssl/aes.h>
 #include <openssl/rand.h>
 #include <openssl/crypto.h>
+#include <openssl/pem.h>
 
 #include "e_ossltest_err.c"
 
+#ifdef _WIN32
+# define strncasecmp _strnicmp
+#endif
+
 /* Engine Id and Name */
 static const char *engine_ossltest_id = "ossltest";
 static const char *engine_ossltest_name = "OpenSSL Test engine support";
@@ -317,6 +322,43 @@ static void destroy_ciphers(void)
     _hidden_aes_128_cbc = NULL;
 }
 
+/* Key loading */
+static EVP_PKEY *load_key(ENGINE *eng, const char *key_id, int pub,
+                          UI_METHOD *ui_method, void *ui_data)
+{
+    BIO *in;
+    EVP_PKEY *key;
+
+    if (strncasecmp(key_id, "ot:", 3) != 0)
+        return NULL;
+    key_id += 3;
+
+    fprintf(stderr, "[ossltest]Loading %s key %s\n",
+            pub ? "Public" : "Private", key_id);
+    in = BIO_new_file(key_id, "r");
+    if (!in)
+        return NULL;
+    if (pub)
+        key = PEM_read_bio_PUBKEY(in, NULL, 0, NULL);
+    else
+        key = PEM_read_bio_PrivateKey(in, NULL, 0, NULL);
+    BIO_free(in);
+    return key;
+}
+
+static EVP_PKEY *ossltest_load_privkey(ENGINE *eng, const char *key_id,
+                                       UI_METHOD *ui_method, void *ui_data)
+{
+    return load_key(eng, key_id, 0, ui_method, ui_data);
+}
+
+static EVP_PKEY *ossltest_load_pubkey(ENGINE *eng, const char *key_id,
+                                      UI_METHOD *ui_method, void *ui_data)
+{
+    return load_key(eng, key_id, 1, ui_method, ui_data);
+}
+
+
 static int bind_ossltest(ENGINE *e)
 {
     /* Ensure the ossltest error handling is set up */
@@ -328,6 +370,8 @@ static int bind_ossltest(ENGINE *e)
         || !ENGINE_set_ciphers(e, ossltest_ciphers)
         || !ENGINE_set_RAND(e, ossltest_rand_method())
         || !ENGINE_set_destroy_function(e, ossltest_destroy)
+        || !ENGINE_set_load_privkey_function(e, ossltest_load_privkey)
+        || !ENGINE_set_load_pubkey_function(e, ossltest_load_pubkey)
         || !ENGINE_set_init_function(e, ossltest_init)
         || !ENGINE_set_finish_function(e, ossltest_finish)) {
         OSSLTESTerr(OSSLTEST_F_BIND_OSSLTEST, OSSLTEST_R_INIT_FAILED);
diff --git a/test/recipes/90-test_store.t b/test/recipes/90-test_store.t
index 05e4b341f5..a36a59fd8b 100644
--- a/test/recipes/90-test_store.t
+++ b/test/recipes/90-test_store.t
@@ -9,7 +9,8 @@
 use File::Spec::Functions;
 use File::Copy;
 use MIME::Base64;
-use OpenSSL::Test qw(:DEFAULT srctop_file srctop_dir bldtop_file data_file);
+use OpenSSL::Test qw(:DEFAULT srctop_file srctop_dir bldtop_file bldtop_dir
+                     data_file);
 use OpenSSL::Test::Utils;
 
 my $test_name = "test_store";
@@ -31,6 +32,9 @@ my @src_files =
       "test/testrsapub.pem",
       "test/testcrl.pem",
       "apps/server.pem" );
+my @src_rsa_files =
+    ( "test/testrsa.pem",
+      "test/testrsapub.pem" );
 my @generated_files =
     (
      ### generated from the source files
@@ -106,11 +110,46 @@ my $n = scalar @methods
         + 3
         + 11 );
 
+my $do_test_ossltest_store =
+    !(disabled("engine") || disabled("dynamic-engine"));
+
+if ($do_test_ossltest_store) {
+    # test loading with apps 'org.openssl.engine:' loader, using the
+    # ossltest engine.
+    $n += 4 * scalar @src_rsa_files;
+}
+
 plan skip_all => "No plan" if $n == 0;
 
 plan tests => $n;
 
 indir "store_$$" => sub {
+    if ($do_test_ossltest_store) {
+        # ossltest loads PEM files, with names prefixed with 'ot:'.
+        # This prefix ensures that the files are, in fact, loaded through
+        # that engine and not mistakenly going through the 'file:' loader.
+
+        my $engine_scheme = 'org.openssl.engine:';
+        $ENV{OPENSSL_ENGINES} = bldtop_dir("engines");
+
+        foreach (@src_rsa_files) {
+            my $file = srctop_file($_);
+            my $file_abs = to_abs_file($file);
+            my @pubin = $_ =~ m|pub\.pem$| ? ("-pubin") : ();
+
+            ok(run(app(["openssl", "rsa", "-text", "-noout", @pubin,
+                        "-engine", "ossltest", "-inform", "engine",
+                        "-in", "ot:$file"])));
+            ok(run(app(["openssl", "rsa", "-text", "-noout", @pubin,
+                        "-engine", "ossltest", "-inform", "engine",
+                        "-in", "ot:$file_abs"])));
+            ok(run(app(["openssl", "rsa", "-text", "-noout", @pubin,
+                        "-in", "${engine_scheme}ossltest:ot:$file"])));
+            ok(run(app(["openssl", "rsa", "-text", "-noout", @pubin,
+                        "-in", "${engine_scheme}ossltest:ot:$file_abs"])));
+        }
+    }
+
  SKIP:
     {
         init() or die "init failed";


More information about the openssl-commits mailing list