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