| /* |
| * Copyright 2018-2022 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 |
| */ |
| |
| /* |
| * 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 (!CHECK_AND_SKIP_CASE_PREFIX(p, ENGINE_SCHEME_COLON)) |
| return NULL; |
| |
| /* 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 && keyid != 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 |