xref: /src/crypto/openssl/providers/implementations/storemgmt/winstore_store.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
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