1 /* 2 * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* 11 * Here is an STORE loader for ENGINE backed keys. It relies on deprecated 12 * functions, and therefore need to have deprecation warnings suppressed. 13 * This file is not compiled at all in a '--api=3 no-deprecated' configuration. 14 */ 15 #define OPENSSL_SUPPRESS_DEPRECATED 16 17 #include "apps.h" 18 19 #ifndef OPENSSL_NO_ENGINE 20 21 # include <stdarg.h> 22 # include <string.h> 23 # include <openssl/engine.h> 24 # include <openssl/store.h> 25 26 /* 27 * Support for legacy private engine keys via the 'org.openssl.engine:' scheme 28 * 29 * org.openssl.engine:{engineid}:{keyid} 30 * 31 * Note: we ONLY support ENGINE_load_private_key() and ENGINE_load_public_key() 32 * Note 2: This scheme has a precedent in code in PKIX-SSH. for exactly 33 * this sort of purpose. 34 */ 35 36 /* Local definition of OSSL_STORE_LOADER_CTX */ 37 struct ossl_store_loader_ctx_st { 38 ENGINE *e; /* Structural reference */ 39 char *keyid; 40 int expected; 41 int loaded; /* 0 = key not loaded yet, 1 = key loaded */ 42 }; 43 44 static OSSL_STORE_LOADER_CTX *OSSL_STORE_LOADER_CTX_new(ENGINE *e, char *keyid) 45 { 46 OSSL_STORE_LOADER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); 47 48 if (ctx != NULL) { 49 ctx->e = e; 50 ctx->keyid = keyid; 51 } 52 return ctx; 53 } 54 55 static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx) 56 { 57 if (ctx != NULL) { 58 ENGINE_free(ctx->e); 59 OPENSSL_free(ctx->keyid); 60 OPENSSL_free(ctx); 61 } 62 } 63 64 static OSSL_STORE_LOADER_CTX *engine_open(const OSSL_STORE_LOADER *loader, 65 const char *uri, 66 const UI_METHOD *ui_method, 67 void *ui_data) 68 { 69 const char *p = uri, *q; 70 ENGINE *e = NULL; 71 char *keyid = NULL; 72 OSSL_STORE_LOADER_CTX *ctx = NULL; 73 74 if (OPENSSL_strncasecmp(p, ENGINE_SCHEME_COLON, sizeof(ENGINE_SCHEME_COLON) - 1) 75 != 0) 76 return NULL; 77 p += sizeof(ENGINE_SCHEME_COLON) - 1; 78 79 /* Look for engine ID */ 80 q = strchr(p, ':'); 81 if (q != NULL /* There is both an engine ID and a key ID */ 82 && p[0] != ':' /* The engine ID is at least one character */ 83 && q[1] != '\0') { /* The key ID is at least one character */ 84 char engineid[256]; 85 size_t engineid_l = q - p; 86 87 strncpy(engineid, p, engineid_l); 88 engineid[engineid_l] = '\0'; 89 e = ENGINE_by_id(engineid); 90 91 keyid = OPENSSL_strdup(q + 1); 92 } 93 94 if (e != NULL && keyid != NULL) 95 ctx = OSSL_STORE_LOADER_CTX_new(e, keyid); 96 97 if (ctx == NULL) { 98 OPENSSL_free(keyid); 99 ENGINE_free(e); 100 } 101 102 return ctx; 103 } 104 105 static int engine_expect(OSSL_STORE_LOADER_CTX *ctx, int expected) 106 { 107 if (expected == 0 108 || expected == OSSL_STORE_INFO_PUBKEY 109 || expected == OSSL_STORE_INFO_PKEY) { 110 ctx->expected = expected; 111 return 1; 112 } 113 return 0; 114 } 115 116 static OSSL_STORE_INFO *engine_load(OSSL_STORE_LOADER_CTX *ctx, 117 const UI_METHOD *ui_method, void *ui_data) 118 { 119 EVP_PKEY *pkey = NULL, *pubkey = NULL; 120 OSSL_STORE_INFO *info = NULL; 121 122 if (ctx->loaded == 0) { 123 if (ENGINE_init(ctx->e)) { 124 if (ctx->expected == 0 125 || ctx->expected == OSSL_STORE_INFO_PKEY) 126 pkey = 127 ENGINE_load_private_key(ctx->e, ctx->keyid, 128 (UI_METHOD *)ui_method, ui_data); 129 if ((pkey == NULL && ctx->expected == 0) 130 || ctx->expected == OSSL_STORE_INFO_PUBKEY) 131 pubkey = 132 ENGINE_load_public_key(ctx->e, ctx->keyid, 133 (UI_METHOD *)ui_method, ui_data); 134 ENGINE_finish(ctx->e); 135 } 136 } 137 138 ctx->loaded = 1; 139 140 if (pubkey != NULL) 141 info = OSSL_STORE_INFO_new_PUBKEY(pubkey); 142 else if (pkey != NULL) 143 info = OSSL_STORE_INFO_new_PKEY(pkey); 144 if (info == NULL) { 145 EVP_PKEY_free(pkey); 146 EVP_PKEY_free(pubkey); 147 } 148 return info; 149 } 150 151 static int engine_eof(OSSL_STORE_LOADER_CTX *ctx) 152 { 153 return ctx->loaded != 0; 154 } 155 156 static int engine_error(OSSL_STORE_LOADER_CTX *ctx) 157 { 158 return 0; 159 } 160 161 static int engine_close(OSSL_STORE_LOADER_CTX *ctx) 162 { 163 OSSL_STORE_LOADER_CTX_free(ctx); 164 return 1; 165 } 166 167 int setup_engine_loader(void) 168 { 169 OSSL_STORE_LOADER *loader = NULL; 170 171 if ((loader = OSSL_STORE_LOADER_new(NULL, ENGINE_SCHEME)) == NULL 172 || !OSSL_STORE_LOADER_set_open(loader, engine_open) 173 || !OSSL_STORE_LOADER_set_expect(loader, engine_expect) 174 || !OSSL_STORE_LOADER_set_load(loader, engine_load) 175 || !OSSL_STORE_LOADER_set_eof(loader, engine_eof) 176 || !OSSL_STORE_LOADER_set_error(loader, engine_error) 177 || !OSSL_STORE_LOADER_set_close(loader, engine_close) 178 || !OSSL_STORE_register_loader(loader)) { 179 OSSL_STORE_LOADER_free(loader); 180 loader = NULL; 181 } 182 183 return loader != NULL; 184 } 185 186 void destroy_engine_loader(void) 187 { 188 OSSL_STORE_LOADER *loader = OSSL_STORE_unregister_loader(ENGINE_SCHEME); 189 OSSL_STORE_LOADER_free(loader); 190 } 191 192 #else /* !OPENSSL_NO_ENGINE */ 193 194 int setup_engine_loader(void) 195 { 196 return 0; 197 } 198 199 void destroy_engine_loader(void) 200 { 201 } 202 203 #endif 204