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
OSSL_STORE_LOADER_CTX_new(ENGINE * e,char * keyid)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
OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX * ctx)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
engine_open(const OSSL_STORE_LOADER * loader,const char * uri,const UI_METHOD * ui_method,void * ui_data)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 (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
engine_expect(OSSL_STORE_LOADER_CTX * ctx,int expected)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
engine_load(OSSL_STORE_LOADER_CTX * ctx,const UI_METHOD * ui_method,void * ui_data)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
engine_eof(OSSL_STORE_LOADER_CTX * ctx)151 static int engine_eof(OSSL_STORE_LOADER_CTX *ctx)
152 {
153 return ctx->loaded != 0;
154 }
155
engine_error(OSSL_STORE_LOADER_CTX * ctx)156 static int engine_error(OSSL_STORE_LOADER_CTX *ctx)
157 {
158 return 0;
159 }
160
engine_close(OSSL_STORE_LOADER_CTX * ctx)161 static int engine_close(OSSL_STORE_LOADER_CTX *ctx)
162 {
163 OSSL_STORE_LOADER_CTX_free(ctx);
164 return 1;
165 }
166
setup_engine_loader(void)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
destroy_engine_loader(void)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
setup_engine_loader(void)194 int setup_engine_loader(void)
195 {
196 return 0;
197 }
198
destroy_engine_loader(void)199 void destroy_engine_loader(void)
200 {
201 }
202
203 #endif
204