xref: /freebsd/crypto/openssl/apps/lib/engine_loader.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
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