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