mirror of https://github.com/openssl/openssl.git
				
				
				
			
		
			
				
	
	
		
			202 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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
 |