]>
Commit | Line | Data |
---|---|---|
71a5516d | 1 | /* |
4eefdbda | 2 | * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. |
71a5516d RL |
3 | * |
4 | * Licensed under the OpenSSL license (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 | ||
07016a8a | 10 | #include "e_os.h" |
71a5516d RL |
11 | #include <stdlib.h> |
12 | #include <string.h> | |
71a5516d RL |
13 | #include <openssl/crypto.h> |
14 | #include <openssl/err.h> | |
15 | #include <openssl/store.h> | |
16 | #include "internal/thread_once.h" | |
4c17819c | 17 | #include "internal/store_int.h" |
71a5516d RL |
18 | #include "store_locl.h" |
19 | ||
20 | struct ossl_store_ctx_st { | |
21 | const OSSL_STORE_LOADER *loader; | |
22 | OSSL_STORE_LOADER_CTX *loader_ctx; | |
23 | const UI_METHOD *ui_method; | |
24 | void *ui_data; | |
25 | OSSL_STORE_post_process_info_fn post_process; | |
26 | void *post_process_data; | |
4eefdbda RL |
27 | |
28 | /* 0 before the first STORE_load(), 1 otherwise */ | |
29 | int loading; | |
71a5516d RL |
30 | }; |
31 | ||
32 | OSSL_STORE_CTX *OSSL_STORE_open(const char *uri, const UI_METHOD *ui_method, | |
33 | void *ui_data, | |
34 | OSSL_STORE_post_process_info_fn post_process, | |
35 | void *post_process_data) | |
36 | { | |
ae9c39d8 | 37 | const OSSL_STORE_LOADER *loader = NULL; |
71a5516d RL |
38 | OSSL_STORE_LOADER_CTX *loader_ctx = NULL; |
39 | OSSL_STORE_CTX *ctx = NULL; | |
ae9c39d8 RL |
40 | char scheme_copy[256], *p, *schemes[2]; |
41 | size_t schemes_n = 0; | |
42 | size_t i; | |
43 | ||
44 | /* | |
45 | * Put the file scheme first. If the uri does represent an existing file, | |
46 | * possible device name and all, then it should be loaded. Only a failed | |
47 | * attempt at loading a local file should have us try something else. | |
48 | */ | |
49 | schemes[schemes_n++] = "file"; | |
71a5516d | 50 | |
ae9c39d8 RL |
51 | /* |
52 | * Now, check if we have something that looks like a scheme, and add it | |
53 | * as a second scheme. However, also check if there's an authority start | |
54 | * (://), because that will invalidate the previous file scheme. Also, | |
55 | * check that this isn't actually the file scheme, as there's no point | |
56 | * going through that one twice! | |
57 | */ | |
71a5516d RL |
58 | OPENSSL_strlcpy(scheme_copy, uri, sizeof(scheme_copy)); |
59 | if ((p = strchr(scheme_copy, ':')) != NULL) { | |
ae9c39d8 RL |
60 | *p++ = '\0'; |
61 | if (strcasecmp(scheme_copy, "file") != 0) { | |
62 | if (strncmp(p, "//", 2) == 0) | |
63 | schemes_n--; /* Invalidate the file scheme */ | |
64 | schemes[schemes_n++] = scheme_copy; | |
65 | } | |
71a5516d RL |
66 | } |
67 | ||
140dab3d RL |
68 | ERR_set_mark(); |
69 | ||
ae9c39d8 RL |
70 | /* Try each scheme until we find one that could open the URI */ |
71 | for (i = 0; loader_ctx == NULL && i < schemes_n; i++) { | |
72 | if ((loader = ossl_store_get0_loader_int(schemes[i])) != NULL) | |
73 | loader_ctx = loader->open(loader, uri, ui_method, ui_data); | |
74 | } | |
75 | if (loader_ctx == NULL) | |
140dab3d | 76 | goto err; |
ae9c39d8 | 77 | |
71a5516d RL |
78 | if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) { |
79 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_OPEN, ERR_R_MALLOC_FAILURE); | |
140dab3d | 80 | goto err; |
71a5516d RL |
81 | } |
82 | ||
83 | ctx->loader = loader; | |
84 | ctx->loader_ctx = loader_ctx; | |
71a5516d RL |
85 | ctx->ui_method = ui_method; |
86 | ctx->ui_data = ui_data; | |
87 | ctx->post_process = post_process; | |
88 | ctx->post_process_data = post_process_data; | |
89 | ||
140dab3d RL |
90 | /* |
91 | * If the attempt to open with the 'file' scheme loader failed and the | |
92 | * other scheme loader succeeded, the failure to open with the 'file' | |
93 | * scheme loader leaves an error on the error stack. Let's remove it. | |
94 | */ | |
95 | ERR_pop_to_mark(); | |
96 | ||
97 | return ctx; | |
98 | ||
99 | err: | |
100 | ERR_clear_last_mark(); | |
71a5516d RL |
101 | if (loader_ctx != NULL) { |
102 | /* | |
103 | * We ignore a returned error because we will return NULL anyway in | |
104 | * this case, so if something goes wrong when closing, that'll simply | |
105 | * just add another entry on the error stack. | |
106 | */ | |
107 | (void)loader->close(loader_ctx); | |
108 | } | |
140dab3d | 109 | return NULL; |
71a5516d RL |
110 | } |
111 | ||
112 | int OSSL_STORE_ctrl(OSSL_STORE_CTX *ctx, int cmd, ...) | |
113 | { | |
114 | va_list args; | |
4fd39122 | 115 | int ret; |
71a5516d RL |
116 | |
117 | va_start(args, cmd); | |
4fd39122 | 118 | ret = OSSL_STORE_vctrl(ctx, cmd, args); |
71a5516d RL |
119 | va_end(args); |
120 | ||
121 | return ret; | |
122 | } | |
123 | ||
4fd39122 RL |
124 | int OSSL_STORE_vctrl(OSSL_STORE_CTX *ctx, int cmd, va_list args) |
125 | { | |
126 | if (ctx->loader->ctrl != NULL) | |
127 | return ctx->loader->ctrl(ctx->loader_ctx, cmd, args); | |
128 | return 0; | |
129 | } | |
130 | ||
71a5516d RL |
131 | OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx) |
132 | { | |
133 | OSSL_STORE_INFO *v = NULL; | |
134 | ||
4eefdbda | 135 | ctx->loading = 1; |
71a5516d | 136 | again: |
6e2f49b3 RL |
137 | if (OSSL_STORE_eof(ctx)) |
138 | return NULL; | |
139 | ||
71a5516d RL |
140 | v = ctx->loader->load(ctx->loader_ctx, ctx->ui_method, ctx->ui_data); |
141 | ||
142 | if (ctx->post_process != NULL && v != NULL) { | |
143 | v = ctx->post_process(v, ctx->post_process_data); | |
144 | ||
145 | /* | |
146 | * By returning NULL, the callback decides that this object should | |
147 | * be ignored. | |
148 | */ | |
149 | if (v == NULL) | |
150 | goto again; | |
151 | } | |
152 | ||
153 | return v; | |
154 | } | |
155 | ||
156 | int OSSL_STORE_error(OSSL_STORE_CTX *ctx) | |
157 | { | |
158 | return ctx->loader->error(ctx->loader_ctx); | |
159 | } | |
160 | ||
161 | int OSSL_STORE_eof(OSSL_STORE_CTX *ctx) | |
162 | { | |
163 | return ctx->loader->eof(ctx->loader_ctx); | |
164 | } | |
165 | ||
166 | int OSSL_STORE_close(OSSL_STORE_CTX *ctx) | |
167 | { | |
168 | int loader_ret = ctx->loader->close(ctx->loader_ctx); | |
169 | ||
170 | OPENSSL_free(ctx); | |
171 | return loader_ret; | |
172 | } | |
173 | ||
174 | /* | |
175 | * Functions to generate OSSL_STORE_INFOs, one function for each type we | |
baa77e07 | 176 | * support having in them as well as a generic constructor. |
71a5516d RL |
177 | * |
178 | * In all cases, ownership of the object is transfered to the OSSL_STORE_INFO | |
179 | * and will therefore be freed when the OSSL_STORE_INFO is freed. | |
180 | */ | |
181 | static OSSL_STORE_INFO *store_info_new(int type, void *data) | |
182 | { | |
183 | OSSL_STORE_INFO *info = OPENSSL_zalloc(sizeof(*info)); | |
184 | ||
185 | if (info == NULL) | |
186 | return NULL; | |
187 | ||
188 | info->type = type; | |
189 | info->_.data = data; | |
190 | return info; | |
191 | } | |
192 | ||
193 | OSSL_STORE_INFO *OSSL_STORE_INFO_new_NAME(char *name) | |
194 | { | |
195 | OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_NAME, NULL); | |
196 | ||
197 | if (info == NULL) { | |
198 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_NAME, | |
199 | ERR_R_MALLOC_FAILURE); | |
200 | return NULL; | |
201 | } | |
202 | ||
203 | info->_.name.name = name; | |
204 | info->_.name.desc = NULL; | |
205 | ||
206 | return info; | |
207 | } | |
208 | ||
209 | int OSSL_STORE_INFO_set0_NAME_description(OSSL_STORE_INFO *info, char *desc) | |
210 | { | |
211 | if (info->type != OSSL_STORE_INFO_NAME) { | |
212 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_SET0_NAME_DESCRIPTION, | |
213 | ERR_R_PASSED_INVALID_ARGUMENT); | |
214 | return 0; | |
215 | } | |
216 | ||
217 | info->_.name.desc = desc; | |
218 | ||
219 | return 1; | |
220 | } | |
221 | OSSL_STORE_INFO *OSSL_STORE_INFO_new_PARAMS(EVP_PKEY *params) | |
222 | { | |
223 | OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_PARAMS, params); | |
224 | ||
225 | if (info == NULL) | |
226 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_PARAMS, | |
227 | ERR_R_MALLOC_FAILURE); | |
228 | return info; | |
229 | } | |
230 | ||
231 | OSSL_STORE_INFO *OSSL_STORE_INFO_new_PKEY(EVP_PKEY *pkey) | |
232 | { | |
233 | OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_PKEY, pkey); | |
234 | ||
235 | if (info == NULL) | |
236 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_PKEY, | |
237 | ERR_R_MALLOC_FAILURE); | |
238 | return info; | |
239 | } | |
240 | ||
241 | OSSL_STORE_INFO *OSSL_STORE_INFO_new_CERT(X509 *x509) | |
242 | { | |
243 | OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_CERT, x509); | |
244 | ||
245 | if (info == NULL) | |
246 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_CERT, | |
247 | ERR_R_MALLOC_FAILURE); | |
248 | return info; | |
249 | } | |
250 | ||
251 | OSSL_STORE_INFO *OSSL_STORE_INFO_new_CRL(X509_CRL *crl) | |
252 | { | |
253 | OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_CRL, crl); | |
254 | ||
255 | if (info == NULL) | |
256 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_CRL, | |
257 | ERR_R_MALLOC_FAILURE); | |
258 | return info; | |
259 | } | |
260 | ||
261 | /* | |
262 | * Functions to try to extract data from a OSSL_STORE_INFO. | |
263 | */ | |
264 | int OSSL_STORE_INFO_get_type(const OSSL_STORE_INFO *info) | |
265 | { | |
266 | return info->type; | |
267 | } | |
268 | ||
269 | const char *OSSL_STORE_INFO_get0_NAME(const OSSL_STORE_INFO *info) | |
270 | { | |
271 | if (info->type == OSSL_STORE_INFO_NAME) | |
272 | return info->_.name.name; | |
273 | return NULL; | |
274 | } | |
275 | ||
276 | char *OSSL_STORE_INFO_get1_NAME(const OSSL_STORE_INFO *info) | |
277 | { | |
278 | if (info->type == OSSL_STORE_INFO_NAME) { | |
279 | char *ret = OPENSSL_strdup(info->_.name.name); | |
280 | ||
281 | if (ret == NULL) | |
282 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME, | |
283 | ERR_R_MALLOC_FAILURE); | |
284 | return ret; | |
285 | } | |
286 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME, | |
287 | OSSL_STORE_R_NOT_A_NAME); | |
288 | return NULL; | |
289 | } | |
290 | ||
291 | const char *OSSL_STORE_INFO_get0_NAME_description(const OSSL_STORE_INFO *info) | |
292 | { | |
293 | if (info->type == OSSL_STORE_INFO_NAME) | |
294 | return info->_.name.desc; | |
295 | return NULL; | |
296 | } | |
297 | ||
298 | char *OSSL_STORE_INFO_get1_NAME_description(const OSSL_STORE_INFO *info) | |
299 | { | |
300 | if (info->type == OSSL_STORE_INFO_NAME) { | |
301 | char *ret = OPENSSL_strdup(info->_.name.desc | |
302 | ? info->_.name.desc : ""); | |
303 | ||
304 | if (ret == NULL) | |
305 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME_DESCRIPTION, | |
306 | ERR_R_MALLOC_FAILURE); | |
307 | return ret; | |
308 | } | |
309 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME_DESCRIPTION, | |
310 | OSSL_STORE_R_NOT_A_NAME); | |
311 | return NULL; | |
312 | } | |
313 | ||
314 | EVP_PKEY *OSSL_STORE_INFO_get0_PARAMS(const OSSL_STORE_INFO *info) | |
315 | { | |
316 | if (info->type == OSSL_STORE_INFO_PARAMS) | |
317 | return info->_.params; | |
318 | return NULL; | |
319 | } | |
320 | ||
321 | EVP_PKEY *OSSL_STORE_INFO_get1_PARAMS(const OSSL_STORE_INFO *info) | |
322 | { | |
323 | if (info->type == OSSL_STORE_INFO_PARAMS) { | |
324 | EVP_PKEY_up_ref(info->_.params); | |
325 | return info->_.params; | |
326 | } | |
327 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_PARAMS, | |
328 | OSSL_STORE_R_NOT_PARAMETERS); | |
329 | return NULL; | |
330 | } | |
331 | ||
332 | EVP_PKEY *OSSL_STORE_INFO_get0_PKEY(const OSSL_STORE_INFO *info) | |
333 | { | |
334 | if (info->type == OSSL_STORE_INFO_PKEY) | |
335 | return info->_.pkey; | |
336 | return NULL; | |
337 | } | |
338 | ||
339 | EVP_PKEY *OSSL_STORE_INFO_get1_PKEY(const OSSL_STORE_INFO *info) | |
340 | { | |
341 | if (info->type == OSSL_STORE_INFO_PKEY) { | |
342 | EVP_PKEY_up_ref(info->_.pkey); | |
343 | return info->_.pkey; | |
344 | } | |
345 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_PKEY, | |
346 | OSSL_STORE_R_NOT_A_KEY); | |
347 | return NULL; | |
348 | } | |
349 | ||
350 | X509 *OSSL_STORE_INFO_get0_CERT(const OSSL_STORE_INFO *info) | |
351 | { | |
352 | if (info->type == OSSL_STORE_INFO_CERT) | |
353 | return info->_.x509; | |
354 | return NULL; | |
355 | } | |
356 | ||
357 | X509 *OSSL_STORE_INFO_get1_CERT(const OSSL_STORE_INFO *info) | |
358 | { | |
359 | if (info->type == OSSL_STORE_INFO_CERT) { | |
360 | X509_up_ref(info->_.x509); | |
361 | return info->_.x509; | |
362 | } | |
363 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT, | |
364 | OSSL_STORE_R_NOT_A_CERTIFICATE); | |
365 | return NULL; | |
366 | } | |
367 | ||
368 | X509_CRL *OSSL_STORE_INFO_get0_CRL(const OSSL_STORE_INFO *info) | |
369 | { | |
370 | if (info->type == OSSL_STORE_INFO_CRL) | |
371 | return info->_.crl; | |
372 | return NULL; | |
373 | } | |
374 | ||
375 | X509_CRL *OSSL_STORE_INFO_get1_CRL(const OSSL_STORE_INFO *info) | |
376 | { | |
377 | if (info->type == OSSL_STORE_INFO_CRL) { | |
378 | X509_CRL_up_ref(info->_.crl); | |
379 | return info->_.crl; | |
380 | } | |
381 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_CRL, | |
382 | OSSL_STORE_R_NOT_A_CRL); | |
383 | return NULL; | |
384 | } | |
385 | ||
386 | /* | |
387 | * Free the OSSL_STORE_INFO | |
388 | */ | |
389 | void OSSL_STORE_INFO_free(OSSL_STORE_INFO *info) | |
390 | { | |
391 | if (info != NULL) { | |
392 | switch (info->type) { | |
50ecedda RL |
393 | case OSSL_STORE_INFO_EMBEDDED: |
394 | BUF_MEM_free(info->_.embedded.blob); | |
395 | OPENSSL_free(info->_.embedded.pem_name); | |
396 | break; | |
71a5516d RL |
397 | case OSSL_STORE_INFO_NAME: |
398 | OPENSSL_free(info->_.name.name); | |
399 | OPENSSL_free(info->_.name.desc); | |
400 | break; | |
401 | case OSSL_STORE_INFO_PARAMS: | |
402 | EVP_PKEY_free(info->_.params); | |
403 | break; | |
404 | case OSSL_STORE_INFO_PKEY: | |
405 | EVP_PKEY_free(info->_.pkey); | |
406 | break; | |
407 | case OSSL_STORE_INFO_CERT: | |
408 | X509_free(info->_.x509); | |
409 | break; | |
410 | case OSSL_STORE_INFO_CRL: | |
411 | X509_CRL_free(info->_.crl); | |
412 | break; | |
413 | } | |
414 | OPENSSL_free(info); | |
415 | } | |
416 | } | |
417 | ||
50ecedda RL |
418 | /* Internal functions */ |
419 | OSSL_STORE_INFO *ossl_store_info_new_EMBEDDED(const char *new_pem_name, | |
420 | BUF_MEM *embedded) | |
421 | { | |
422 | OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_EMBEDDED, NULL); | |
423 | ||
424 | if (info == NULL) { | |
425 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_EMBEDDED, | |
426 | ERR_R_MALLOC_FAILURE); | |
427 | return NULL; | |
428 | } | |
429 | ||
430 | info->_.embedded.blob = embedded; | |
431 | info->_.embedded.pem_name = | |
432 | new_pem_name == NULL ? NULL : OPENSSL_strdup(new_pem_name); | |
433 | ||
434 | if (new_pem_name != NULL && info->_.embedded.pem_name == NULL) { | |
435 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_EMBEDDED, | |
436 | ERR_R_MALLOC_FAILURE); | |
437 | OSSL_STORE_INFO_free(info); | |
438 | info = NULL; | |
439 | } | |
440 | ||
441 | return info; | |
442 | } | |
443 | ||
444 | BUF_MEM *ossl_store_info_get0_EMBEDDED_buffer(OSSL_STORE_INFO *info) | |
445 | { | |
446 | if (info->type == OSSL_STORE_INFO_EMBEDDED) | |
447 | return info->_.embedded.blob; | |
448 | return NULL; | |
449 | } | |
450 | ||
451 | char *ossl_store_info_get0_EMBEDDED_pem_name(OSSL_STORE_INFO *info) | |
452 | { | |
453 | if (info->type == OSSL_STORE_INFO_EMBEDDED) | |
454 | return info->_.embedded.pem_name; | |
455 | return NULL; | |
456 | } | |
4c17819c RL |
457 | |
458 | OSSL_STORE_CTX *ossl_store_attach_pem_bio(BIO *bp, const UI_METHOD *ui_method, | |
459 | void *ui_data) | |
460 | { | |
461 | OSSL_STORE_CTX *ctx = NULL; | |
462 | const OSSL_STORE_LOADER *loader = NULL; | |
463 | OSSL_STORE_LOADER_CTX *loader_ctx = NULL; | |
464 | ||
465 | if ((loader = ossl_store_get0_loader_int("file")) == NULL | |
466 | || ((loader_ctx = ossl_store_file_attach_pem_bio_int(bp)) == NULL)) | |
467 | goto done; | |
468 | if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) { | |
469 | OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_ATTACH_PEM_BIO, | |
470 | ERR_R_MALLOC_FAILURE); | |
471 | goto done; | |
472 | } | |
473 | ||
474 | ctx->loader = loader; | |
475 | ctx->loader_ctx = loader_ctx; | |
476 | loader_ctx = NULL; | |
477 | ctx->ui_method = ui_method; | |
478 | ctx->ui_data = ui_data; | |
479 | ctx->post_process = NULL; | |
480 | ctx->post_process_data = NULL; | |
481 | ||
482 | done: | |
483 | if (loader_ctx != NULL) | |
484 | /* | |
485 | * We ignore a returned error because we will return NULL anyway in | |
486 | * this case, so if something goes wrong when closing, that'll simply | |
487 | * just add another entry on the error stack. | |
488 | */ | |
489 | (void)loader->close(loader_ctx); | |
490 | return ctx; | |
491 | } | |
492 | ||
493 | int ossl_store_detach_pem_bio(OSSL_STORE_CTX *ctx) | |
494 | { | |
495 | int loader_ret = ossl_store_file_detach_pem_bio_int(ctx->loader_ctx); | |
496 | ||
497 | OPENSSL_free(ctx); | |
498 | return loader_ret; | |
499 | } |