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