Przeglądaj źródła

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@siemens.com>
(Merged from https://github.com/openssl/openssl/pull/13570)
Richard Levitte 6 lat temu
rodzic
commit
0b27381fd5

+ 1 - 0
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.

+ 21 - 0
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

+ 2 - 0
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

+ 1 - 1
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

+ 203 - 0
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

+ 2 - 0
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();
 }