1 /*
2 * Copyright 2022-2025 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 #include <openssl/store.h>
10 #include <openssl/core_dispatch.h>
11 #include <openssl/core_names.h>
12 #include <openssl/core_object.h>
13 #include <openssl/bio.h>
14 #include <openssl/err.h>
15 #include <openssl/params.h>
16 #include <openssl/decoder.h>
17 #include <openssl/proverr.h>
18 #include <openssl/store.h> /* The OSSL_STORE_INFO type numbers */
19 #include "internal/cryptlib.h"
20 #include "internal/o_dir.h"
21 #include "crypto/decoder.h"
22 #include "crypto/ctype.h" /* ossl_isdigit() */
23 #include "prov/implementations.h"
24 #include "prov/providercommon.h"
25 #include "prov/bio.h"
26 #include "file_store_local.h"
27 #ifdef __CYGWIN__
28 # include <windows.h>
29 #endif
30 #include <wincrypt.h>
31
32 enum {
33 STATE_IDLE,
34 STATE_READ,
35 STATE_EOF,
36 };
37
38 struct winstore_ctx_st {
39 void *provctx;
40 char *propq;
41 unsigned char *subject;
42 size_t subject_len;
43
44 HCERTSTORE win_store;
45 const CERT_CONTEXT *win_ctx;
46 int state;
47
48 OSSL_DECODER_CTX *dctx;
49 };
50
winstore_win_reset(struct winstore_ctx_st * ctx)51 static void winstore_win_reset(struct winstore_ctx_st *ctx)
52 {
53 if (ctx->win_ctx != NULL) {
54 CertFreeCertificateContext(ctx->win_ctx);
55 ctx->win_ctx = NULL;
56 }
57
58 ctx->state = STATE_IDLE;
59 }
60
winstore_win_advance(struct winstore_ctx_st * ctx)61 static void winstore_win_advance(struct winstore_ctx_st *ctx)
62 {
63 CERT_NAME_BLOB name = {0};
64
65 if (ctx->state == STATE_EOF)
66 return;
67
68 name.cbData = ctx->subject_len;
69 name.pbData = ctx->subject;
70
71 ctx->win_ctx = (name.cbData == 0 ? NULL :
72 CertFindCertificateInStore(ctx->win_store,
73 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
74 0, CERT_FIND_SUBJECT_NAME,
75 &name, ctx->win_ctx));
76
77 ctx->state = (ctx->win_ctx == NULL) ? STATE_EOF : STATE_READ;
78 }
79
winstore_open(void * provctx,const char * uri)80 static void *winstore_open(void *provctx, const char *uri)
81 {
82 struct winstore_ctx_st *ctx = NULL;
83
84 if (!HAS_CASE_PREFIX(uri, "org.openssl.winstore:"))
85 return NULL;
86
87 ctx = OPENSSL_zalloc(sizeof(*ctx));
88 if (ctx == NULL)
89 return NULL;
90
91 ctx->provctx = provctx;
92 ctx->win_store = CertOpenSystemStoreW(0, L"ROOT");
93 if (ctx->win_store == NULL) {
94 OPENSSL_free(ctx);
95 return NULL;
96 }
97
98 winstore_win_reset(ctx);
99 return ctx;
100 }
101
winstore_attach(void * provctx,OSSL_CORE_BIO * cin)102 static void *winstore_attach(void *provctx, OSSL_CORE_BIO *cin)
103 {
104 return NULL; /* not supported */
105 }
106
winstore_settable_ctx_params(void * loaderctx,const OSSL_PARAM params[])107 static const OSSL_PARAM *winstore_settable_ctx_params(void *loaderctx, const OSSL_PARAM params[])
108 {
109 static const OSSL_PARAM known_settable_ctx_params[] = {
110 OSSL_PARAM_octet_string(OSSL_STORE_PARAM_SUBJECT, NULL, 0),
111 OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_PROPERTIES, NULL, 0),
112 OSSL_PARAM_END
113 };
114 return known_settable_ctx_params;
115 }
116
winstore_set_ctx_params(void * loaderctx,const OSSL_PARAM params[])117 static int winstore_set_ctx_params(void *loaderctx, const OSSL_PARAM params[])
118 {
119 struct winstore_ctx_st *ctx = loaderctx;
120 const OSSL_PARAM *p;
121 int do_reset = 0;
122
123 if (ossl_param_is_empty(params))
124 return 1;
125
126 p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_PROPERTIES);
127 if (p != NULL) {
128 do_reset = 1;
129 OPENSSL_free(ctx->propq);
130 ctx->propq = NULL;
131 if (!OSSL_PARAM_get_utf8_string(p, &ctx->propq, 0))
132 return 0;
133 }
134
135 p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SUBJECT);
136 if (p != NULL) {
137 const unsigned char *der = NULL;
138 size_t der_len = 0;
139
140 if (!OSSL_PARAM_get_octet_string_ptr(p, (const void **)&der, &der_len))
141 return 0;
142
143 do_reset = 1;
144
145 OPENSSL_free(ctx->subject);
146
147 ctx->subject = OPENSSL_malloc(der_len);
148 if (ctx->subject == NULL) {
149 ctx->subject_len = 0;
150 return 0;
151 }
152
153 ctx->subject_len = der_len;
154 memcpy(ctx->subject, der, der_len);
155 }
156
157 if (do_reset) {
158 winstore_win_reset(ctx);
159 winstore_win_advance(ctx);
160 }
161
162 return 1;
163 }
164
165 struct load_data_st {
166 OSSL_CALLBACK *object_cb;
167 void *object_cbarg;
168 };
169
load_construct(OSSL_DECODER_INSTANCE * decoder_inst,const OSSL_PARAM * params,void * construct_data)170 static int load_construct(OSSL_DECODER_INSTANCE *decoder_inst,
171 const OSSL_PARAM *params, void *construct_data)
172 {
173 struct load_data_st *data = construct_data;
174 return data->object_cb(params, data->object_cbarg);
175 }
176
load_cleanup(void * construct_data)177 static void load_cleanup(void *construct_data)
178 {
179 /* No-op. */
180 }
181
setup_decoder(struct winstore_ctx_st * ctx)182 static int setup_decoder(struct winstore_ctx_st *ctx)
183 {
184 OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(ctx->provctx);
185 const OSSL_ALGORITHM *to_algo = NULL;
186 const char *input_structure = NULL;
187
188 if (ctx->dctx != NULL)
189 return 1;
190
191 ctx->dctx = OSSL_DECODER_CTX_new();
192 if (ctx->dctx == NULL) {
193 ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
194 return 0;
195 }
196
197 if (!OSSL_DECODER_CTX_set_input_type(ctx->dctx, "DER")) {
198 ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
199 goto err;
200 }
201
202 input_structure = "Certificate";
203 if (!OSSL_DECODER_CTX_set_input_structure(ctx->dctx, input_structure)) {
204 ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
205 goto err;
206 }
207
208 for (to_algo = ossl_any_to_obj_algorithm;
209 to_algo->algorithm_names != NULL;
210 to_algo++) {
211 OSSL_DECODER *to_obj = NULL;
212 OSSL_DECODER_INSTANCE *to_obj_inst = NULL;
213 const char *input_type;
214
215 /*
216 * Create the internal last resort decoder implementation
217 * together with a "decoder instance".
218 * The decoder doesn't need any identification or to be
219 * attached to any provider, since it's only used locally.
220 */
221 to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL);
222 if (to_obj != NULL)
223 to_obj_inst = ossl_decoder_instance_new_forprov(to_obj, ctx->provctx,
224 input_structure);
225
226 OSSL_DECODER_free(to_obj);
227 if (to_obj_inst == NULL)
228 goto err;
229
230 /*
231 * The input type has to be DER
232 */
233 input_type = OSSL_DECODER_INSTANCE_get_input_type(to_obj_inst);
234 if (OPENSSL_strcasecmp(input_type, "DER") != 0) {
235 ossl_decoder_instance_free(to_obj_inst);
236 continue;
237 }
238
239 if (!ossl_decoder_ctx_add_decoder_inst(ctx->dctx,
240 to_obj_inst)) {
241 ossl_decoder_instance_free(to_obj_inst);
242 ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
243 goto err;
244 }
245 }
246
247 if (!OSSL_DECODER_CTX_add_extra(ctx->dctx, libctx, ctx->propq)) {
248 ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
249 goto err;
250 }
251
252 if (!OSSL_DECODER_CTX_set_construct(ctx->dctx, load_construct)) {
253 ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
254 goto err;
255 }
256
257 if (!OSSL_DECODER_CTX_set_cleanup(ctx->dctx, load_cleanup)) {
258 ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
259 goto err;
260 }
261
262 return 1;
263
264 err:
265 OSSL_DECODER_CTX_free(ctx->dctx);
266 ctx->dctx = NULL;
267 return 0;
268 }
269
winstore_load_using(struct winstore_ctx_st * ctx,OSSL_CALLBACK * object_cb,void * object_cbarg,OSSL_PASSPHRASE_CALLBACK * pw_cb,void * pw_cbarg,const void * der,size_t der_len)270 static int winstore_load_using(struct winstore_ctx_st *ctx,
271 OSSL_CALLBACK *object_cb, void *object_cbarg,
272 OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg,
273 const void *der, size_t der_len)
274 {
275 struct load_data_st data;
276 const unsigned char *der_ = der;
277 size_t der_len_ = der_len;
278
279 if (setup_decoder(ctx) == 0)
280 return 0;
281
282 data.object_cb = object_cb;
283 data.object_cbarg = object_cbarg;
284
285 OSSL_DECODER_CTX_set_construct_data(ctx->dctx, &data);
286 OSSL_DECODER_CTX_set_passphrase_cb(ctx->dctx, pw_cb, pw_cbarg);
287
288 if (OSSL_DECODER_from_data(ctx->dctx, &der_, &der_len_) == 0)
289 return 0;
290
291 return 1;
292 }
293
winstore_load(void * loaderctx,OSSL_CALLBACK * object_cb,void * object_cbarg,OSSL_PASSPHRASE_CALLBACK * pw_cb,void * pw_cbarg)294 static int winstore_load(void *loaderctx,
295 OSSL_CALLBACK *object_cb, void *object_cbarg,
296 OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
297 {
298 int ret = 0;
299 struct winstore_ctx_st *ctx = loaderctx;
300
301 if (ctx->state != STATE_READ)
302 return 0;
303
304 ret = winstore_load_using(ctx, object_cb, object_cbarg, pw_cb, pw_cbarg,
305 ctx->win_ctx->pbCertEncoded,
306 ctx->win_ctx->cbCertEncoded);
307
308 if (ret == 1)
309 winstore_win_advance(ctx);
310
311 return ret;
312 }
313
winstore_eof(void * loaderctx)314 static int winstore_eof(void *loaderctx)
315 {
316 struct winstore_ctx_st *ctx = loaderctx;
317
318 return ctx->state != STATE_READ;
319 }
320
winstore_close(void * loaderctx)321 static int winstore_close(void *loaderctx)
322 {
323 struct winstore_ctx_st *ctx = loaderctx;
324
325 winstore_win_reset(ctx);
326 CertCloseStore(ctx->win_store, 0);
327 OSSL_DECODER_CTX_free(ctx->dctx);
328 OPENSSL_free(ctx->propq);
329 OPENSSL_free(ctx->subject);
330 OPENSSL_free(ctx);
331 return 1;
332 }
333
334 const OSSL_DISPATCH ossl_winstore_store_functions[] = {
335 { OSSL_FUNC_STORE_OPEN, (void (*)(void))winstore_open },
336 { OSSL_FUNC_STORE_ATTACH, (void (*)(void))winstore_attach },
337 { OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS, (void (*)(void))winstore_settable_ctx_params },
338 { OSSL_FUNC_STORE_SET_CTX_PARAMS, (void (*)(void))winstore_set_ctx_params },
339 { OSSL_FUNC_STORE_LOAD, (void (*)(void))winstore_load },
340 { OSSL_FUNC_STORE_EOF, (void (*)(void))winstore_eof },
341 { OSSL_FUNC_STORE_CLOSE, (void (*)(void))winstore_close },
342 OSSL_DISPATCH_END,
343 };
344