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/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 
187     if (ctx->dctx != NULL)
188         return 1;
189 
190     ctx->dctx = OSSL_DECODER_CTX_new();
191     if (ctx->dctx == NULL) {
192         ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
193         return 0;
194     }
195 
196     if (!OSSL_DECODER_CTX_set_input_type(ctx->dctx, "DER")) {
197         ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
198         goto err;
199     }
200 
201     if (!OSSL_DECODER_CTX_set_input_structure(ctx->dctx, "Certificate")) {
202         ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
203         goto err;
204     }
205 
206     for (to_algo = ossl_any_to_obj_algorithm;
207          to_algo->algorithm_names != NULL;
208          to_algo++) {
209         OSSL_DECODER *to_obj = NULL;
210         OSSL_DECODER_INSTANCE *to_obj_inst = NULL;
211 
212         /*
213          * Create the internal last resort decoder implementation
214          * together with a "decoder instance".
215          * The decoder doesn't need any identification or to be
216          * attached to any provider, since it's only used locally.
217          */
218         to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL);
219         if (to_obj != NULL)
220             to_obj_inst = ossl_decoder_instance_new(to_obj, ctx->provctx);
221 
222         OSSL_DECODER_free(to_obj);
223         if (to_obj_inst == NULL)
224             goto err;
225 
226         if (!ossl_decoder_ctx_add_decoder_inst(ctx->dctx,
227                                                to_obj_inst)) {
228             ossl_decoder_instance_free(to_obj_inst);
229             ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
230             goto err;
231         }
232     }
233 
234     if (!OSSL_DECODER_CTX_add_extra(ctx->dctx, libctx, ctx->propq)) {
235         ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
236         goto err;
237     }
238 
239     if (!OSSL_DECODER_CTX_set_construct(ctx->dctx, load_construct)) {
240         ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
241         goto err;
242     }
243 
244     if (!OSSL_DECODER_CTX_set_cleanup(ctx->dctx, load_cleanup)) {
245         ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
246         goto err;
247     }
248 
249     return 1;
250 
251 err:
252     OSSL_DECODER_CTX_free(ctx->dctx);
253     ctx->dctx = NULL;
254     return 0;
255 }
256 
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)257 static int winstore_load_using(struct winstore_ctx_st *ctx,
258                                OSSL_CALLBACK *object_cb, void *object_cbarg,
259                                OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg,
260                                const void *der, size_t der_len)
261 {
262     struct load_data_st data;
263     const unsigned char *der_ = der;
264     size_t der_len_ = der_len;
265 
266     if (setup_decoder(ctx) == 0)
267         return 0;
268 
269     data.object_cb      = object_cb;
270     data.object_cbarg   = object_cbarg;
271 
272     OSSL_DECODER_CTX_set_construct_data(ctx->dctx, &data);
273     OSSL_DECODER_CTX_set_passphrase_cb(ctx->dctx, pw_cb, pw_cbarg);
274 
275     if (OSSL_DECODER_from_data(ctx->dctx, &der_, &der_len_) == 0)
276         return 0;
277 
278     return 1;
279 }
280 
winstore_load(void * loaderctx,OSSL_CALLBACK * object_cb,void * object_cbarg,OSSL_PASSPHRASE_CALLBACK * pw_cb,void * pw_cbarg)281 static int winstore_load(void *loaderctx,
282                          OSSL_CALLBACK *object_cb, void *object_cbarg,
283                          OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
284 {
285     int ret = 0;
286     struct winstore_ctx_st *ctx = loaderctx;
287 
288     if (ctx->state != STATE_READ)
289         return 0;
290 
291     ret = winstore_load_using(ctx, object_cb, object_cbarg, pw_cb, pw_cbarg,
292                               ctx->win_ctx->pbCertEncoded,
293                               ctx->win_ctx->cbCertEncoded);
294 
295     if (ret == 1)
296         winstore_win_advance(ctx);
297 
298     return ret;
299 }
300 
winstore_eof(void * loaderctx)301 static int winstore_eof(void *loaderctx)
302 {
303     struct winstore_ctx_st *ctx = loaderctx;
304 
305     return ctx->state != STATE_READ;
306 }
307 
winstore_close(void * loaderctx)308 static int winstore_close(void *loaderctx)
309 {
310     struct winstore_ctx_st *ctx = loaderctx;
311 
312     winstore_win_reset(ctx);
313     CertCloseStore(ctx->win_store, 0);
314     OSSL_DECODER_CTX_free(ctx->dctx);
315     OPENSSL_free(ctx->propq);
316     OPENSSL_free(ctx->subject);
317     OPENSSL_free(ctx);
318     return 1;
319 }
320 
321 const OSSL_DISPATCH ossl_winstore_store_functions[] = {
322     { OSSL_FUNC_STORE_OPEN, (void (*)(void))winstore_open },
323     { OSSL_FUNC_STORE_ATTACH, (void (*)(void))winstore_attach },
324     { OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS, (void (*)(void))winstore_settable_ctx_params },
325     { OSSL_FUNC_STORE_SET_CTX_PARAMS, (void (*)(void))winstore_set_ctx_params },
326     { OSSL_FUNC_STORE_LOAD, (void (*)(void))winstore_load },
327     { OSSL_FUNC_STORE_EOF, (void (*)(void))winstore_eof },
328     { OSSL_FUNC_STORE_CLOSE, (void (*)(void))winstore_close },
329     OSSL_DISPATCH_END,
330 };
331