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