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
|
---|