xref: /openssl/apps/lib/engine_loader.c (revision 23b795d3)
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 =
126                     ENGINE_load_private_key(ctx->e, ctx->keyid,
127                                             (UI_METHOD *)ui_method, ui_data);
128             if ((pkey == NULL && ctx->expected == 0)
129                 || ctx->expected == OSSL_STORE_INFO_PUBKEY)
130                 pubkey =
131                     ENGINE_load_public_key(ctx->e, ctx->keyid,
132                                            (UI_METHOD *)ui_method, ui_data);
133             ENGINE_finish(ctx->e);
134         }
135     }
136 
137     ctx->loaded = 1;
138 
139     if (pubkey != NULL)
140         info = OSSL_STORE_INFO_new_PUBKEY(pubkey);
141     else if (pkey != NULL)
142         info = OSSL_STORE_INFO_new_PKEY(pkey);
143     if (info == NULL) {
144         EVP_PKEY_free(pkey);
145         EVP_PKEY_free(pubkey);
146     }
147     return info;
148 }
149 
engine_eof(OSSL_STORE_LOADER_CTX * ctx)150 static int engine_eof(OSSL_STORE_LOADER_CTX *ctx)
151 {
152     return ctx->loaded != 0;
153 }
154 
engine_error(OSSL_STORE_LOADER_CTX * ctx)155 static int engine_error(OSSL_STORE_LOADER_CTX *ctx)
156 {
157     return 0;
158 }
159 
engine_close(OSSL_STORE_LOADER_CTX * ctx)160 static int engine_close(OSSL_STORE_LOADER_CTX *ctx)
161 {
162     OSSL_STORE_LOADER_CTX_free(ctx);
163     return 1;
164 }
165 
setup_engine_loader(void)166 int setup_engine_loader(void)
167 {
168     OSSL_STORE_LOADER *loader = NULL;
169 
170     if ((loader = OSSL_STORE_LOADER_new(NULL, ENGINE_SCHEME)) == NULL
171         || !OSSL_STORE_LOADER_set_open(loader, engine_open)
172         || !OSSL_STORE_LOADER_set_expect(loader, engine_expect)
173         || !OSSL_STORE_LOADER_set_load(loader, engine_load)
174         || !OSSL_STORE_LOADER_set_eof(loader, engine_eof)
175         || !OSSL_STORE_LOADER_set_error(loader, engine_error)
176         || !OSSL_STORE_LOADER_set_close(loader, engine_close)
177         || !OSSL_STORE_register_loader(loader)) {
178         OSSL_STORE_LOADER_free(loader);
179         loader = NULL;
180     }
181 
182     return loader != NULL;
183 }
184 
destroy_engine_loader(void)185 void destroy_engine_loader(void)
186 {
187     OSSL_STORE_LOADER *loader = OSSL_STORE_unregister_loader(ENGINE_SCHEME);
188     OSSL_STORE_LOADER_free(loader);
189 }
190 
191 #else  /* !OPENSSL_NO_ENGINE */
192 
setup_engine_loader(void)193 int setup_engine_loader(void)
194 {
195     return 0;
196 }
197 
destroy_engine_loader(void)198 void destroy_engine_loader(void)
199 {
200 }
201 
202 #endif
203