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