From 0b27381fd544beca44df905991923a7fa374d80a Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Fri, 12 Oct 2018 17:02:58 +0200 Subject: 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 (Merged from https://github.com/openssl/openssl/pull/13570) --- apps/include/apps.h | 1 + apps/include/engine_loader.h | 21 +++++ apps/lib/apps.c | 2 + apps/lib/build.info | 2 +- apps/lib/engine_loader.c | 203 +++++++++++++++++++++++++++++++++++++++++++ apps/openssl.c | 2 + 6 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 apps/include/engine_loader.h create mode 100644 apps/lib/engine_loader.c (limited to 'apps') diff --git a/apps/include/apps.h b/apps/include/apps.h index 0848a2e03e..dd2d9cdebd 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. 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 + +/* 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..7d63ff4216 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -39,6 +39,8 @@ #endif #include #include +#include +#include "s_apps.h" #include "apps.h" #ifdef _WIN32 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_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 +# include +# include +# include + +/* + * 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(); } -- cgit v1.2.3