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