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