]>
Commit | Line | Data |
---|---|---|
9c6da42d | 1 | /* |
fecb3aae | 2 | * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. |
9c6da42d | 3 | * |
5c0d0c86 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
9c6da42d RL |
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 | ||
16feca71 RL |
10 | /* THIS ENGINE IS FOR TESTING PURPOSES ONLY. */ |
11 | ||
5fc0992f DDO |
12 | /* This file has quite some overlap with providers/implementations/storemgmt/file_store.c */ |
13 | ||
e4468e6d P |
14 | /* We need to use some engine deprecated APIs */ |
15 | #define OPENSSL_SUPPRESS_DEPRECATED | |
16 | ||
fba140c7 | 17 | #include "internal/e_os.h" /* for stat */ |
9c6da42d | 18 | #include <string.h> |
970f467a | 19 | #include <sys/stat.h> |
93d2f9fa | 20 | #include <ctype.h> |
970f467a | 21 | #include <assert.h> |
9c6da42d RL |
22 | |
23 | #include <openssl/bio.h> | |
24 | #include <openssl/dsa.h> /* For d2i_DSAPrivateKey */ | |
25 | #include <openssl/err.h> | |
26 | #include <openssl/evp.h> | |
27 | #include <openssl/pem.h> | |
28 | #include <openssl/pkcs12.h> /* For the PKCS8 stuff o.O */ | |
29 | #include <openssl/rsa.h> /* For d2i_RSAPrivateKey */ | |
30 | #include <openssl/safestack.h> | |
31 | #include <openssl/store.h> | |
32 | #include <openssl/ui.h> | |
16feca71 | 33 | #include <openssl/engine.h> |
9c6da42d | 34 | #include <openssl/x509.h> /* For the PKCS8 stuff o.O */ |
16feca71 | 35 | #include "internal/asn1.h" /* For asn1_d2i_read_bio */ |
970f467a RL |
36 | #include "internal/o_dir.h" |
37 | #include "internal/cryptlib.h" | |
bf991b25 | 38 | #include "crypto/ctype.h" /* For ossl_isdigit */ |
0934cf48 | 39 | #include "crypto/pem.h" /* For PVK and "blob" PEM headers */ |
16feca71 RL |
40 | |
41 | #include "e_loader_attic_err.c" | |
9c6da42d | 42 | |
16feca71 | 43 | DEFINE_STACK_OF(OSSL_STORE_INFO) |
852c2ed2 | 44 | |
f20aa69e AP |
45 | #ifndef S_ISDIR |
46 | # define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) | |
47 | #endif | |
48 | ||
479af767 | 49 | /*- |
9c6da42d | 50 | * Password prompting |
479af767 | 51 | * ------------------ |
9c6da42d RL |
52 | */ |
53 | ||
54 | static char *file_get_pass(const UI_METHOD *ui_method, char *pass, | |
bac4bffb RL |
55 | size_t maxsize, const char *desc, const char *info, |
56 | void *data) | |
9c6da42d RL |
57 | { |
58 | UI *ui = UI_new(); | |
59 | char *prompt = NULL; | |
60 | ||
61 | if (ui == NULL) { | |
e077455e | 62 | ATTICerr(0, ERR_R_UI_LIB); |
9c6da42d RL |
63 | return NULL; |
64 | } | |
65 | ||
66 | if (ui_method != NULL) | |
67 | UI_set_method(ui, ui_method); | |
68 | UI_add_user_data(ui, data); | |
69 | ||
bac4bffb | 70 | if ((prompt = UI_construct_prompt(ui, desc, info)) == NULL) { |
e077455e | 71 | ATTICerr(0, ERR_R_UI_LIB); |
9c6da42d | 72 | pass = NULL; |
5755c11f PH |
73 | } else if (UI_add_input_string(ui, prompt, UI_INPUT_FLAG_DEFAULT_PWD, |
74 | pass, 0, maxsize - 1) <= 0) { | |
16feca71 | 75 | ATTICerr(0, ERR_R_UI_LIB); |
9c6da42d RL |
76 | pass = NULL; |
77 | } else { | |
78 | switch (UI_process(ui)) { | |
79 | case -2: | |
16feca71 | 80 | ATTICerr(0, ATTIC_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED); |
9c6da42d RL |
81 | pass = NULL; |
82 | break; | |
83 | case -1: | |
16feca71 | 84 | ATTICerr(0, ERR_R_UI_LIB); |
9c6da42d RL |
85 | pass = NULL; |
86 | break; | |
87 | default: | |
88 | break; | |
89 | } | |
90 | } | |
91 | ||
92 | OPENSSL_free(prompt); | |
93 | UI_free(ui); | |
94 | return pass; | |
95 | } | |
96 | ||
97 | struct pem_pass_data { | |
98 | const UI_METHOD *ui_method; | |
99 | void *data; | |
bac4bffb | 100 | const char *prompt_desc; |
9c6da42d RL |
101 | const char *prompt_info; |
102 | }; | |
479af767 | 103 | |
9c6da42d | 104 | static int file_fill_pem_pass_data(struct pem_pass_data *pass_data, |
bac4bffb | 105 | const char *desc, const char *info, |
9c6da42d RL |
106 | const UI_METHOD *ui_method, void *ui_data) |
107 | { | |
108 | if (pass_data == NULL) | |
109 | return 0; | |
110 | pass_data->ui_method = ui_method; | |
111 | pass_data->data = ui_data; | |
bac4bffb RL |
112 | pass_data->prompt_desc = desc; |
113 | pass_data->prompt_info = info; | |
9c6da42d RL |
114 | return 1; |
115 | } | |
479af767 RL |
116 | |
117 | /* This is used anywhere a pem_password_cb is needed */ | |
9c6da42d RL |
118 | static int file_get_pem_pass(char *buf, int num, int w, void *data) |
119 | { | |
120 | struct pem_pass_data *pass_data = data; | |
121 | char *pass = file_get_pass(pass_data->ui_method, buf, num, | |
bac4bffb RL |
122 | pass_data->prompt_desc, pass_data->prompt_info, |
123 | pass_data->data); | |
9c6da42d RL |
124 | |
125 | return pass == NULL ? 0 : strlen(pass); | |
126 | } | |
127 | ||
16feca71 RL |
128 | /* |
129 | * Check if |str| ends with |suffix| preceded by a space, and if it does, | |
130 | * return the index of that space. If there is no such suffix in |str|, | |
131 | * return -1. | |
132 | * For |str| == "FOO BAR" and |suffix| == "BAR", the returned value is 3. | |
133 | */ | |
134 | static int check_suffix(const char *str, const char *suffix) | |
135 | { | |
136 | int str_len = strlen(str); | |
137 | int suffix_len = strlen(suffix) + 1; | |
138 | const char *p = NULL; | |
139 | ||
140 | if (suffix_len >= str_len) | |
141 | return -1; | |
142 | p = str + str_len - suffix_len; | |
143 | if (*p != ' ' | |
144 | || strcmp(p + 1, suffix) != 0) | |
145 | return -1; | |
146 | return p - str; | |
147 | } | |
148 | ||
149 | /* | |
150 | * EMBEDDED is a special type of OSSL_STORE_INFO, specially for the file | |
151 | * handlers, so we define it internally. This uses the possibility to | |
152 | * create an OSSL_STORE_INFO with a generic data pointer and arbitrary | |
153 | * type number. | |
154 | * | |
155 | * This is used by a FILE_HANDLER's try_decode function to signal that it | |
156 | * has decoded the incoming blob into a new blob, and that the attempted | |
157 | * decoding should be immediately restarted with the new blob, using the | |
158 | * new PEM name. | |
159 | */ | |
160 | /* Negative numbers are never used for public OSSL_STORE_INFO types */ | |
161 | #define STORE_INFO_EMBEDDED -1 | |
162 | ||
163 | /* This is the embedded data */ | |
164 | struct embedded_st { | |
165 | BUF_MEM *blob; | |
166 | char *pem_name; | |
167 | }; | |
168 | ||
169 | /* Helper functions */ | |
170 | static struct embedded_st *get0_EMBEDDED(OSSL_STORE_INFO *info) | |
171 | { | |
172 | return OSSL_STORE_INFO_get0_data(STORE_INFO_EMBEDDED, info); | |
173 | } | |
174 | ||
175 | static void store_info_free(OSSL_STORE_INFO *info) | |
176 | { | |
177 | struct embedded_st *data; | |
178 | ||
179 | if (info != NULL && (data = get0_EMBEDDED(info)) != NULL) { | |
180 | BUF_MEM_free(data->blob); | |
181 | OPENSSL_free(data->pem_name); | |
182 | OPENSSL_free(data); | |
183 | } | |
184 | OSSL_STORE_INFO_free(info); | |
185 | } | |
186 | ||
187 | static OSSL_STORE_INFO *new_EMBEDDED(const char *new_pem_name, | |
188 | BUF_MEM *embedded) | |
189 | { | |
190 | OSSL_STORE_INFO *info = NULL; | |
191 | struct embedded_st *data = NULL; | |
192 | ||
e077455e RL |
193 | if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL) |
194 | return NULL; | |
195 | if ((info = OSSL_STORE_INFO_new(STORE_INFO_EMBEDDED, data)) == NULL) { | |
196 | ATTICerr(0, ERR_R_OSSL_STORE_LIB); | |
16feca71 RL |
197 | OPENSSL_free(data); |
198 | return NULL; | |
199 | } | |
200 | ||
b1423d04 | 201 | data->blob = embedded; |
16feca71 RL |
202 | data->pem_name = |
203 | new_pem_name == NULL ? NULL : OPENSSL_strdup(new_pem_name); | |
204 | ||
205 | if (new_pem_name != NULL && data->pem_name == NULL) { | |
16feca71 RL |
206 | store_info_free(info); |
207 | info = NULL; | |
208 | } | |
16feca71 RL |
209 | |
210 | return info; | |
211 | } | |
212 | ||
479af767 RL |
213 | /*- |
214 | * The file scheme decoders | |
215 | * ------------------------ | |
216 | * | |
217 | * Each possible data type has its own decoder, which either operates | |
218 | * through a given PEM name, or attempts to decode to see if the blob | |
219 | * it's given is decodable for its data type. The assumption is that | |
220 | * only the correct data type will match the content. | |
9c6da42d RL |
221 | */ |
222 | ||
223 | /*- | |
224 | * The try_decode function is called to check if the blob of data can | |
225 | * be used by this handler, and if it can, decodes it into a supported | |
9929c817 | 226 | * OpenSSL type and returns an OSSL_STORE_INFO with the decoded data. |
9c6da42d RL |
227 | * Input: |
228 | * pem_name: If this blob comes from a PEM file, this holds | |
229 | * the PEM name. If it comes from another type of | |
230 | * file, this is NULL. | |
231 | * pem_header: If this blob comes from a PEM file, this holds | |
232 | * the PEM headers. If it comes from another type of | |
233 | * file, this is NULL. | |
234 | * blob: The blob of data to match with what this handler | |
235 | * can use. | |
236 | * len: The length of the blob. | |
e61ec2d9 RL |
237 | * handler_ctx: For a handler marked repeatable, this pointer can |
238 | * be used to create a context for the handler. IT IS | |
239 | * THE HANDLER'S RESPONSIBILITY TO CREATE AND DESTROY | |
240 | * THIS CONTEXT APPROPRIATELY, i.e. create on first call | |
241 | * and destroy when about to return NULL. | |
6fc1d33c RL |
242 | * matchcount: A pointer to an int to count matches for this data. |
243 | * Usually becomes 0 (no match) or 1 (match!), but may | |
244 | * be higher in the (unlikely) event that the data matches | |
245 | * more than one possibility. The int will always be | |
246 | * zero when the function is called. | |
9c6da42d RL |
247 | * ui_method: Application UI method for getting a password, pin |
248 | * or any other interactive data. | |
249 | * ui_data: Application data to be passed to ui_method when | |
250 | * it's called. | |
8755b085 MC |
251 | * libctx: The library context to be used if applicable |
252 | * propq: The property query string for any algorithm fetches | |
9c6da42d | 253 | * Output: |
9929c817 | 254 | * an OSSL_STORE_INFO |
9c6da42d RL |
255 | */ |
256 | typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name, | |
257 | const char *pem_header, | |
258 | const unsigned char *blob, | |
e61ec2d9 | 259 | size_t len, void **handler_ctx, |
6fc1d33c | 260 | int *matchcount, |
9c6da42d | 261 | const UI_METHOD *ui_method, |
bac4bffb | 262 | void *ui_data, const char *uri, |
b4250010 | 263 | OSSL_LIB_CTX *libctx, |
8755b085 | 264 | const char *propq); |
e61ec2d9 RL |
265 | /* |
266 | * The eof function should return 1 if there's no more data to be found | |
267 | * with the handler_ctx, otherwise 0. This is only used when the handler is | |
268 | * marked repeatable. | |
269 | */ | |
270 | typedef int (*file_eof_fn)(void *handler_ctx); | |
271 | /* | |
272 | * The destroy_ctx function is used to destroy the handler_ctx that was | |
c2969ff6 | 273 | * initiated by a repeatable try_decode function. This is only used when |
e61ec2d9 RL |
274 | * the handler is marked repeatable. |
275 | */ | |
276 | typedef void (*file_destroy_ctx_fn)(void **handler_ctx); | |
9c6da42d RL |
277 | |
278 | typedef struct file_handler_st { | |
279 | const char *name; | |
280 | file_try_decode_fn try_decode; | |
e61ec2d9 RL |
281 | file_eof_fn eof; |
282 | file_destroy_ctx_fn destroy_ctx; | |
283 | ||
284 | /* flags */ | |
285 | int repeatable; | |
9c6da42d RL |
286 | } FILE_HANDLER; |
287 | ||
479af767 RL |
288 | /* |
289 | * PKCS#12 decoder. It operates by decoding all of the blob content, | |
290 | * extracting all the interesting data from it and storing them internally, | |
291 | * then serving them one piece at a time. | |
292 | */ | |
a09003ea RL |
293 | static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name, |
294 | const char *pem_header, | |
295 | const unsigned char *blob, | |
296 | size_t len, void **pctx, | |
6fc1d33c | 297 | int *matchcount, |
a09003ea | 298 | const UI_METHOD *ui_method, |
bac4bffb | 299 | void *ui_data, const char *uri, |
b4250010 | 300 | OSSL_LIB_CTX *libctx, |
8755b085 | 301 | const char *propq) |
a09003ea RL |
302 | { |
303 | OSSL_STORE_INFO *store_info = NULL; | |
304 | STACK_OF(OSSL_STORE_INFO) *ctx = *pctx; | |
305 | ||
306 | if (ctx == NULL) { | |
307 | /* Initial parsing */ | |
308 | PKCS12 *p12; | |
a09003ea RL |
309 | |
310 | if (pem_name != NULL) | |
311 | /* No match, there is no PEM PKCS12 tag */ | |
312 | return NULL; | |
313 | ||
314 | if ((p12 = d2i_PKCS12(NULL, &blob, len)) != NULL) { | |
315 | char *pass = NULL; | |
316 | char tpass[PEM_BUFSIZE]; | |
317 | EVP_PKEY *pkey = NULL; | |
318 | X509 *cert = NULL; | |
319 | STACK_OF(X509) *chain = NULL; | |
320 | ||
6fc1d33c RL |
321 | *matchcount = 1; |
322 | ||
61dd4168 DDO |
323 | if (!PKCS12_mac_present(p12) |
324 | || PKCS12_verify_mac(p12, "", 0) | |
a09003ea RL |
325 | || PKCS12_verify_mac(p12, NULL, 0)) { |
326 | pass = ""; | |
327 | } else { | |
328 | if ((pass = file_get_pass(ui_method, tpass, PEM_BUFSIZE, | |
3a6df6bd | 329 | "PKCS12 import", uri, |
a09003ea | 330 | ui_data)) == NULL) { |
16feca71 | 331 | ATTICerr(0, ATTIC_R_PASSPHRASE_CALLBACK_ERROR); |
a09003ea RL |
332 | goto p12_end; |
333 | } | |
334 | if (!PKCS12_verify_mac(p12, pass, strlen(pass))) { | |
16feca71 | 335 | ATTICerr(0, ATTIC_R_ERROR_VERIFYING_PKCS12_MAC); |
a09003ea RL |
336 | goto p12_end; |
337 | } | |
338 | } | |
339 | ||
340 | if (PKCS12_parse(p12, pass, &pkey, &cert, &chain)) { | |
7747a49f AP |
341 | OSSL_STORE_INFO *osi_pkey = NULL; |
342 | OSSL_STORE_INFO *osi_cert = NULL; | |
343 | OSSL_STORE_INFO *osi_ca = NULL; | |
c29ba6a9 DDO |
344 | int ok = 1; |
345 | ||
346 | if ((ctx = sk_OSSL_STORE_INFO_new_null()) != NULL) { | |
347 | if (pkey != NULL) { | |
348 | if ((osi_pkey = OSSL_STORE_INFO_new_PKEY(pkey)) != NULL | |
349 | /* clearing pkey here avoids case distinctions */ | |
350 | && (pkey = NULL) == NULL | |
351 | && sk_OSSL_STORE_INFO_push(ctx, osi_pkey) != 0) | |
352 | osi_pkey = NULL; | |
353 | else | |
354 | ok = 0; | |
355 | } | |
356 | if (ok && cert != NULL) { | |
357 | if ((osi_cert = OSSL_STORE_INFO_new_CERT(cert)) != NULL | |
358 | /* clearing cert here avoids case distinctions */ | |
359 | && (cert = NULL) == NULL | |
360 | && sk_OSSL_STORE_INFO_push(ctx, osi_cert) != 0) | |
361 | osi_cert = NULL; | |
362 | else | |
363 | ok = 0; | |
364 | } | |
365 | while (ok && sk_X509_num(chain) > 0) { | |
a09003ea RL |
366 | X509 *ca = sk_X509_value(chain, 0); |
367 | ||
c29ba6a9 DDO |
368 | if ((osi_ca = OSSL_STORE_INFO_new_CERT(ca)) != NULL |
369 | && sk_X509_shift(chain) != NULL | |
370 | && sk_OSSL_STORE_INFO_push(ctx, osi_ca) != 0) | |
371 | osi_ca = NULL; | |
372 | else | |
a09003ea | 373 | ok = 0; |
a09003ea RL |
374 | } |
375 | } | |
c29ba6a9 DDO |
376 | EVP_PKEY_free(pkey); |
377 | X509_free(cert); | |
79b2a2f2 | 378 | OSSL_STACK_OF_X509_free(chain); |
16feca71 RL |
379 | store_info_free(osi_pkey); |
380 | store_info_free(osi_cert); | |
381 | store_info_free(osi_ca); | |
a09003ea | 382 | if (!ok) { |
16feca71 | 383 | sk_OSSL_STORE_INFO_pop_free(ctx, store_info_free); |
a09003ea RL |
384 | ctx = NULL; |
385 | } | |
386 | *pctx = ctx; | |
387 | } | |
388 | } | |
389 | p12_end: | |
390 | PKCS12_free(p12); | |
c29ba6a9 | 391 | if (ctx == NULL) |
a09003ea RL |
392 | return NULL; |
393 | } | |
394 | ||
c29ba6a9 DDO |
395 | *matchcount = 1; |
396 | store_info = sk_OSSL_STORE_INFO_shift(ctx); | |
a09003ea RL |
397 | return store_info; |
398 | } | |
479af767 | 399 | |
a09003ea RL |
400 | static int eof_PKCS12(void *ctx_) |
401 | { | |
402 | STACK_OF(OSSL_STORE_INFO) *ctx = ctx_; | |
403 | ||
404 | return ctx == NULL || sk_OSSL_STORE_INFO_num(ctx) == 0; | |
405 | } | |
479af767 | 406 | |
a09003ea RL |
407 | static void destroy_ctx_PKCS12(void **pctx) |
408 | { | |
409 | STACK_OF(OSSL_STORE_INFO) *ctx = *pctx; | |
410 | ||
16feca71 | 411 | sk_OSSL_STORE_INFO_pop_free(ctx, store_info_free); |
a09003ea RL |
412 | *pctx = NULL; |
413 | } | |
479af767 | 414 | |
a09003ea RL |
415 | static FILE_HANDLER PKCS12_handler = { |
416 | "PKCS12", | |
417 | try_decode_PKCS12, | |
418 | eof_PKCS12, | |
419 | destroy_ctx_PKCS12, | |
9f5ff440 | 420 | 1 /* repeatable */ |
a09003ea RL |
421 | }; |
422 | ||
479af767 RL |
423 | /* |
424 | * Encrypted PKCS#8 decoder. It operates by just decrypting the given blob | |
425 | * into a new blob, which is returned as an EMBEDDED STORE_INFO. The whole | |
426 | * decoding process will then start over with the new blob. | |
427 | */ | |
7ad2ef36 RL |
428 | static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name, |
429 | const char *pem_header, | |
430 | const unsigned char *blob, | |
431 | size_t len, void **pctx, | |
6fc1d33c | 432 | int *matchcount, |
7ad2ef36 | 433 | const UI_METHOD *ui_method, |
8755b085 | 434 | void *ui_data, |
bac4bffb | 435 | const char *uri, |
b4250010 | 436 | OSSL_LIB_CTX *libctx, |
8755b085 | 437 | const char *propq) |
7ad2ef36 RL |
438 | { |
439 | X509_SIG *p8 = NULL; | |
440 | char kbuf[PEM_BUFSIZE]; | |
441 | char *pass = NULL; | |
442 | const X509_ALGOR *dalg = NULL; | |
443 | const ASN1_OCTET_STRING *doct = NULL; | |
444 | OSSL_STORE_INFO *store_info = NULL; | |
445 | BUF_MEM *mem = NULL; | |
446 | unsigned char *new_data = NULL; | |
447 | int new_data_len; | |
448 | ||
6fc1d33c RL |
449 | if (pem_name != NULL) { |
450 | if (strcmp(pem_name, PEM_STRING_PKCS8) != 0) | |
451 | return NULL; | |
452 | *matchcount = 1; | |
453 | } | |
7ad2ef36 RL |
454 | |
455 | if ((p8 = d2i_X509_SIG(NULL, &blob, len)) == NULL) | |
456 | return NULL; | |
457 | ||
6fc1d33c RL |
458 | *matchcount = 1; |
459 | ||
7ad2ef36 | 460 | if ((mem = BUF_MEM_new()) == NULL) { |
e077455e | 461 | ATTICerr(0, ERR_R_BUF_LIB); |
7ad2ef36 RL |
462 | goto nop8; |
463 | } | |
464 | ||
465 | if ((pass = file_get_pass(ui_method, kbuf, PEM_BUFSIZE, | |
bac4bffb RL |
466 | "PKCS8 decrypt pass phrase", uri, |
467 | ui_data)) == NULL) { | |
16feca71 | 468 | ATTICerr(0, ATTIC_R_BAD_PASSWORD_READ); |
7ad2ef36 RL |
469 | goto nop8; |
470 | } | |
471 | ||
472 | X509_SIG_get0(p8, &dalg, &doct); | |
473 | if (!PKCS12_pbe_crypt(dalg, pass, strlen(pass), doct->data, doct->length, | |
474 | &new_data, &new_data_len, 0)) | |
475 | goto nop8; | |
476 | ||
477 | mem->data = (char *)new_data; | |
478 | mem->max = mem->length = (size_t)new_data_len; | |
479 | X509_SIG_free(p8); | |
efe8d69d | 480 | p8 = NULL; |
7ad2ef36 | 481 | |
16feca71 | 482 | store_info = new_EMBEDDED(PEM_STRING_PKCS8INF, mem); |
7ad2ef36 | 483 | if (store_info == NULL) { |
e077455e | 484 | ATTICerr(0, ERR_R_OSSL_STORE_LIB); |
7ad2ef36 RL |
485 | goto nop8; |
486 | } | |
487 | ||
488 | return store_info; | |
489 | nop8: | |
490 | X509_SIG_free(p8); | |
491 | BUF_MEM_free(mem); | |
492 | return NULL; | |
493 | } | |
479af767 | 494 | |
7ad2ef36 RL |
495 | static FILE_HANDLER PKCS8Encrypted_handler = { |
496 | "PKCS8Encrypted", | |
497 | try_decode_PKCS8Encrypted | |
498 | }; | |
499 | ||
479af767 RL |
500 | /* |
501 | * Private key decoder. Decodes all sorts of private keys, both PKCS#8 | |
502 | * encoded ones and old style PEM ones (with the key type is encoded into | |
503 | * the PEM name). | |
504 | */ | |
9c6da42d RL |
505 | static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name, |
506 | const char *pem_header, | |
507 | const unsigned char *blob, | |
e61ec2d9 | 508 | size_t len, void **pctx, |
6fc1d33c | 509 | int *matchcount, |
9c6da42d | 510 | const UI_METHOD *ui_method, |
bac4bffb | 511 | void *ui_data, const char *uri, |
b4250010 | 512 | OSSL_LIB_CTX *libctx, |
8755b085 | 513 | const char *propq) |
9c6da42d RL |
514 | { |
515 | OSSL_STORE_INFO *store_info = NULL; | |
516 | EVP_PKEY *pkey = NULL; | |
517 | const EVP_PKEY_ASN1_METHOD *ameth = NULL; | |
518 | ||
519 | if (pem_name != NULL) { | |
7ad2ef36 RL |
520 | if (strcmp(pem_name, PEM_STRING_PKCS8INF) == 0) { |
521 | PKCS8_PRIV_KEY_INFO *p8inf = | |
522 | d2i_PKCS8_PRIV_KEY_INFO(NULL, &blob, len); | |
523 | ||
6fc1d33c | 524 | *matchcount = 1; |
7ad2ef36 | 525 | if (p8inf != NULL) |
d8652be0 | 526 | pkey = EVP_PKCS82PKEY_ex(p8inf, libctx, propq); |
7ad2ef36 RL |
527 | PKCS8_PRIV_KEY_INFO_free(p8inf); |
528 | } else { | |
529 | int slen; | |
16feca71 | 530 | int pkey_id; |
7ad2ef36 | 531 | |
16feca71 | 532 | if ((slen = check_suffix(pem_name, "PRIVATE KEY")) > 0 |
7ad2ef36 | 533 | && (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name, |
16feca71 RL |
534 | slen)) != NULL |
535 | && EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, | |
536 | ameth)) { | |
6fc1d33c | 537 | *matchcount = 1; |
16feca71 | 538 | pkey = d2i_PrivateKey_ex(pkey_id, NULL, &blob, len, |
8755b085 | 539 | libctx, propq); |
6fc1d33c | 540 | } |
7ad2ef36 | 541 | } |
9c6da42d RL |
542 | } else { |
543 | int i; | |
b84439b0 RL |
544 | #ifndef OPENSSL_NO_ENGINE |
545 | ENGINE *curengine = ENGINE_get_first(); | |
546 | ||
547 | while (curengine != NULL) { | |
548 | ENGINE_PKEY_ASN1_METHS_PTR asn1meths = | |
549 | ENGINE_get_pkey_asn1_meths(curengine); | |
550 | ||
551 | if (asn1meths != NULL) { | |
552 | const int *nids = NULL; | |
553 | int nids_n = asn1meths(curengine, NULL, &nids, 0); | |
554 | ||
555 | for (i = 0; i < nids_n; i++) { | |
556 | EVP_PKEY_ASN1_METHOD *ameth2 = NULL; | |
557 | EVP_PKEY *tmp_pkey = NULL; | |
558 | const unsigned char *tmp_blob = blob; | |
16feca71 | 559 | int pkey_id, pkey_flags; |
b84439b0 | 560 | |
16feca71 RL |
561 | if (!asn1meths(curengine, &ameth2, NULL, nids[i]) |
562 | || !EVP_PKEY_asn1_get0_info(&pkey_id, NULL, | |
563 | &pkey_flags, NULL, NULL, | |
564 | ameth2) | |
565 | || (pkey_flags & ASN1_PKEY_ALIAS) != 0) | |
b84439b0 RL |
566 | continue; |
567 | ||
9a30f40c | 568 | ERR_set_mark(); /* prevent flooding error queue */ |
16feca71 RL |
569 | tmp_pkey = d2i_PrivateKey_ex(pkey_id, NULL, |
570 | &tmp_blob, len, | |
571 | libctx, propq); | |
b84439b0 RL |
572 | if (tmp_pkey != NULL) { |
573 | if (pkey != NULL) | |
574 | EVP_PKEY_free(tmp_pkey); | |
575 | else | |
576 | pkey = tmp_pkey; | |
577 | (*matchcount)++; | |
578 | } | |
9a30f40c | 579 | ERR_pop_to_mark(); |
b84439b0 RL |
580 | } |
581 | } | |
582 | curengine = ENGINE_get_next(curengine); | |
583 | } | |
584 | #endif | |
9c6da42d RL |
585 | |
586 | for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { | |
6fc1d33c RL |
587 | EVP_PKEY *tmp_pkey = NULL; |
588 | const unsigned char *tmp_blob = blob; | |
16feca71 | 589 | int pkey_id, pkey_flags; |
6fc1d33c | 590 | |
9c6da42d | 591 | ameth = EVP_PKEY_asn1_get0(i); |
16feca71 RL |
592 | if (!EVP_PKEY_asn1_get0_info(&pkey_id, NULL, &pkey_flags, NULL, |
593 | NULL, ameth) | |
594 | || (pkey_flags & ASN1_PKEY_ALIAS) != 0) | |
9c6da42d | 595 | continue; |
6fc1d33c | 596 | |
9a30f40c | 597 | ERR_set_mark(); /* prevent flooding error queue */ |
16feca71 | 598 | tmp_pkey = d2i_PrivateKey_ex(pkey_id, NULL, &tmp_blob, len, |
8755b085 | 599 | libctx, propq); |
6fc1d33c RL |
600 | if (tmp_pkey != NULL) { |
601 | if (pkey != NULL) | |
602 | EVP_PKEY_free(tmp_pkey); | |
603 | else | |
604 | pkey = tmp_pkey; | |
605 | (*matchcount)++; | |
606 | } | |
9a30f40c | 607 | ERR_pop_to_mark(); |
6fc1d33c RL |
608 | } |
609 | ||
610 | if (*matchcount > 1) { | |
611 | EVP_PKEY_free(pkey); | |
612 | pkey = NULL; | |
9c6da42d RL |
613 | } |
614 | } | |
615 | if (pkey == NULL) | |
616 | /* No match */ | |
617 | return NULL; | |
618 | ||
619 | store_info = OSSL_STORE_INFO_new_PKEY(pkey); | |
620 | if (store_info == NULL) | |
621 | EVP_PKEY_free(pkey); | |
622 | ||
623 | return store_info; | |
624 | } | |
479af767 | 625 | |
9c6da42d RL |
626 | static FILE_HANDLER PrivateKey_handler = { |
627 | "PrivateKey", | |
628 | try_decode_PrivateKey | |
629 | }; | |
630 | ||
479af767 | 631 | /* |
c2969ff6 | 632 | * Public key decoder. Only supports SubjectPublicKeyInfo formatted keys. |
479af767 | 633 | */ |
9c6da42d RL |
634 | static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name, |
635 | const char *pem_header, | |
636 | const unsigned char *blob, | |
e61ec2d9 | 637 | size_t len, void **pctx, |
6fc1d33c | 638 | int *matchcount, |
9c6da42d | 639 | const UI_METHOD *ui_method, |
bac4bffb | 640 | void *ui_data, const char *uri, |
b4250010 | 641 | OSSL_LIB_CTX *libctx, |
8755b085 | 642 | const char *propq) |
9c6da42d RL |
643 | { |
644 | OSSL_STORE_INFO *store_info = NULL; | |
645 | EVP_PKEY *pkey = NULL; | |
646 | ||
6fc1d33c RL |
647 | if (pem_name != NULL) { |
648 | if (strcmp(pem_name, PEM_STRING_PUBLIC) != 0) | |
649 | /* No match */ | |
650 | return NULL; | |
651 | *matchcount = 1; | |
652 | } | |
9c6da42d | 653 | |
6fc1d33c RL |
654 | if ((pkey = d2i_PUBKEY(NULL, &blob, len)) != NULL) { |
655 | *matchcount = 1; | |
2274d22d | 656 | store_info = OSSL_STORE_INFO_new_PUBKEY(pkey); |
6fc1d33c | 657 | } |
9c6da42d RL |
658 | |
659 | return store_info; | |
660 | } | |
479af767 | 661 | |
9c6da42d RL |
662 | static FILE_HANDLER PUBKEY_handler = { |
663 | "PUBKEY", | |
664 | try_decode_PUBKEY | |
665 | }; | |
666 | ||
479af767 RL |
667 | /* |
668 | * Key parameter decoder. | |
669 | */ | |
9c6da42d RL |
670 | static OSSL_STORE_INFO *try_decode_params(const char *pem_name, |
671 | const char *pem_header, | |
672 | const unsigned char *blob, | |
e61ec2d9 | 673 | size_t len, void **pctx, |
6fc1d33c | 674 | int *matchcount, |
9c6da42d | 675 | const UI_METHOD *ui_method, |
bac4bffb | 676 | void *ui_data, const char *uri, |
b4250010 | 677 | OSSL_LIB_CTX *libctx, |
8755b085 | 678 | const char *propq) |
9c6da42d RL |
679 | { |
680 | OSSL_STORE_INFO *store_info = NULL; | |
6fc1d33c | 681 | EVP_PKEY *pkey = NULL; |
9c6da42d | 682 | const EVP_PKEY_ASN1_METHOD *ameth = NULL; |
9c6da42d | 683 | |
6fc1d33c | 684 | if (pem_name != NULL) { |
16feca71 RL |
685 | int slen; |
686 | int pkey_id; | |
6fc1d33c | 687 | |
16feca71 RL |
688 | if ((slen = check_suffix(pem_name, "PARAMETERS")) > 0 |
689 | && (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name, slen)) != NULL | |
690 | && EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, | |
691 | ameth)) { | |
692 | *matchcount = 1; | |
693 | pkey = d2i_KeyParams(pkey_id, NULL, &blob, len); | |
11d66064 | 694 | } |
9c6da42d RL |
695 | } else { |
696 | int i; | |
697 | ||
698 | for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { | |
16feca71 | 699 | EVP_PKEY *tmp_pkey = NULL; |
6fc1d33c | 700 | const unsigned char *tmp_blob = blob; |
16feca71 | 701 | int pkey_id, pkey_flags; |
11d66064 | 702 | |
9c6da42d | 703 | ameth = EVP_PKEY_asn1_get0(i); |
16feca71 RL |
704 | if (!EVP_PKEY_asn1_get0_info(&pkey_id, NULL, &pkey_flags, NULL, |
705 | NULL, ameth) | |
706 | || (pkey_flags & ASN1_PKEY_ALIAS) != 0) | |
9c6da42d | 707 | continue; |
11d66064 | 708 | |
9a30f40c DDO |
709 | ERR_set_mark(); /* prevent flooding error queue */ |
710 | ||
16feca71 RL |
711 | tmp_pkey = d2i_KeyParams(pkey_id, NULL, &tmp_blob, len); |
712 | ||
713 | if (tmp_pkey != NULL) { | |
11d66064 RL |
714 | if (pkey != NULL) |
715 | EVP_PKEY_free(tmp_pkey); | |
716 | else | |
717 | pkey = tmp_pkey; | |
6fc1d33c | 718 | (*matchcount)++; |
9c6da42d | 719 | } |
9a30f40c | 720 | ERR_pop_to_mark(); |
9c6da42d | 721 | } |
11d66064 | 722 | |
16feca71 RL |
723 | if (*matchcount > 1) { |
724 | EVP_PKEY_free(pkey); | |
725 | pkey = NULL; | |
11d66064 | 726 | } |
9c6da42d | 727 | } |
16feca71 RL |
728 | if (pkey == NULL) |
729 | /* No match */ | |
730 | return NULL; | |
9c6da42d | 731 | |
16feca71 | 732 | store_info = OSSL_STORE_INFO_new_PARAMS(pkey); |
9c6da42d RL |
733 | if (store_info == NULL) |
734 | EVP_PKEY_free(pkey); | |
735 | ||
736 | return store_info; | |
737 | } | |
479af767 | 738 | |
9c6da42d RL |
739 | static FILE_HANDLER params_handler = { |
740 | "params", | |
741 | try_decode_params | |
742 | }; | |
743 | ||
479af767 RL |
744 | /* |
745 | * X.509 certificate decoder. | |
746 | */ | |
9c6da42d RL |
747 | static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name, |
748 | const char *pem_header, | |
749 | const unsigned char *blob, | |
e61ec2d9 | 750 | size_t len, void **pctx, |
6fc1d33c | 751 | int *matchcount, |
9c6da42d | 752 | const UI_METHOD *ui_method, |
8755b085 | 753 | void *ui_data, |
bac4bffb | 754 | const char *uri, |
b4250010 | 755 | OSSL_LIB_CTX *libctx, |
8755b085 | 756 | const char *propq) |
9c6da42d RL |
757 | { |
758 | OSSL_STORE_INFO *store_info = NULL; | |
759 | X509 *cert = NULL; | |
760 | ||
761 | /* | |
762 | * In most cases, we can try to interpret the serialized data as a trusted | |
763 | * cert (X509 + X509_AUX) and fall back to reading it as a normal cert | |
764 | * (just X509), but if the PEM name specifically declares it as a trusted | |
765 | * cert, then no fallback should be engaged. |ignore_trusted| tells if | |
766 | * the fallback can be used (1) or not (0). | |
767 | */ | |
768 | int ignore_trusted = 1; | |
769 | ||
770 | if (pem_name != NULL) { | |
771 | if (strcmp(pem_name, PEM_STRING_X509_TRUSTED) == 0) | |
772 | ignore_trusted = 0; | |
773 | else if (strcmp(pem_name, PEM_STRING_X509_OLD) != 0 | |
774 | && strcmp(pem_name, PEM_STRING_X509) != 0) | |
775 | /* No match */ | |
776 | return NULL; | |
6fc1d33c | 777 | *matchcount = 1; |
9c6da42d RL |
778 | } |
779 | ||
d8652be0 | 780 | cert = X509_new_ex(libctx, propq); |
6725682d SL |
781 | if (cert == NULL) |
782 | return NULL; | |
783 | ||
784 | if ((d2i_X509_AUX(&cert, &blob, len)) != NULL | |
785 | || (ignore_trusted && (d2i_X509(&cert, &blob, len)) != NULL)) { | |
6fc1d33c | 786 | *matchcount = 1; |
9c6da42d | 787 | store_info = OSSL_STORE_INFO_new_CERT(cert); |
6fc1d33c | 788 | } |
9c6da42d RL |
789 | |
790 | if (store_info == NULL) | |
791 | X509_free(cert); | |
792 | ||
793 | return store_info; | |
794 | } | |
479af767 | 795 | |
9c6da42d RL |
796 | static FILE_HANDLER X509Certificate_handler = { |
797 | "X509Certificate", | |
798 | try_decode_X509Certificate | |
799 | }; | |
800 | ||
479af767 RL |
801 | /* |
802 | * X.509 CRL decoder. | |
803 | */ | |
9c6da42d RL |
804 | static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name, |
805 | const char *pem_header, | |
806 | const unsigned char *blob, | |
e61ec2d9 | 807 | size_t len, void **pctx, |
6fc1d33c | 808 | int *matchcount, |
9c6da42d | 809 | const UI_METHOD *ui_method, |
bac4bffb | 810 | void *ui_data, const char *uri, |
b4250010 | 811 | OSSL_LIB_CTX *libctx, |
8755b085 | 812 | const char *propq) |
9c6da42d RL |
813 | { |
814 | OSSL_STORE_INFO *store_info = NULL; | |
815 | X509_CRL *crl = NULL; | |
816 | ||
6fc1d33c RL |
817 | if (pem_name != NULL) { |
818 | if (strcmp(pem_name, PEM_STRING_X509_CRL) != 0) | |
819 | /* No match */ | |
820 | return NULL; | |
821 | *matchcount = 1; | |
822 | } | |
9c6da42d | 823 | |
6fc1d33c RL |
824 | if ((crl = d2i_X509_CRL(NULL, &blob, len)) != NULL) { |
825 | *matchcount = 1; | |
9c6da42d | 826 | store_info = OSSL_STORE_INFO_new_CRL(crl); |
6fc1d33c | 827 | } |
9c6da42d RL |
828 | |
829 | if (store_info == NULL) | |
830 | X509_CRL_free(crl); | |
831 | ||
832 | return store_info; | |
833 | } | |
479af767 | 834 | |
9c6da42d RL |
835 | static FILE_HANDLER X509CRL_handler = { |
836 | "X509CRL", | |
837 | try_decode_X509CRL | |
838 | }; | |
839 | ||
479af767 RL |
840 | /* |
841 | * To finish it all off, we collect all the handlers. | |
842 | */ | |
9c6da42d | 843 | static const FILE_HANDLER *file_handlers[] = { |
a09003ea | 844 | &PKCS12_handler, |
7ad2ef36 | 845 | &PKCS8Encrypted_handler, |
9c6da42d RL |
846 | &X509Certificate_handler, |
847 | &X509CRL_handler, | |
848 | ¶ms_handler, | |
849 | &PUBKEY_handler, | |
850 | &PrivateKey_handler, | |
851 | }; | |
852 | ||
853 | ||
479af767 | 854 | /*- |
9c6da42d | 855 | * The loader itself |
479af767 | 856 | * ----------------- |
9c6da42d RL |
857 | */ |
858 | ||
859 | struct ossl_store_loader_ctx_st { | |
bac4bffb | 860 | char *uri; /* The URI we currently try to load */ |
970f467a RL |
861 | enum { |
862 | is_raw = 0, | |
863 | is_pem, | |
864 | is_dir | |
865 | } type; | |
9c6da42d | 866 | int errcnt; |
7852f588 | 867 | #define FILE_FLAG_SECMEM (1<<0) |
6ab6ecfd | 868 | #define FILE_FLAG_ATTACHED (1<<1) |
7852f588 | 869 | unsigned int flags; |
970f467a | 870 | union { |
9f5ff440 | 871 | struct { /* Used with is_raw and is_pem */ |
970f467a RL |
872 | BIO *file; |
873 | ||
874 | /* | |
875 | * The following are used when the handler is marked as | |
876 | * repeatable | |
877 | */ | |
878 | const FILE_HANDLER *last_handler; | |
879 | void *last_handler_ctx; | |
880 | } file; | |
9f5ff440 | 881 | struct { /* Used with is_dir */ |
970f467a RL |
882 | OPENSSL_DIR_CTX *ctx; |
883 | int end_reached; | |
970f467a | 884 | |
93d2f9fa RL |
885 | /* |
886 | * When a search expression is given, these are filled in. | |
887 | * |search_name| contains the file basename to look for. | |
888 | * The string is exactly 8 characters long. | |
889 | */ | |
890 | char search_name[9]; | |
891 | ||
970f467a RL |
892 | /* |
893 | * The directory reading utility we have combines opening with | |
894 | * reading the first name. To make sure we can detect the end | |
895 | * at the right time, we read early and cache the name. | |
896 | */ | |
897 | const char *last_entry; | |
898 | int last_errno; | |
899 | } dir; | |
900 | } _; | |
6541d9e2 RL |
901 | |
902 | /* Expected object type. May be unspecified */ | |
903 | int expected_type; | |
16feca71 | 904 | |
b4250010 | 905 | OSSL_LIB_CTX *libctx; |
8755b085 | 906 | char *propq; |
9c6da42d RL |
907 | }; |
908 | ||
970f467a RL |
909 | static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx) |
910 | { | |
bac4bffb RL |
911 | if (ctx == NULL) |
912 | return; | |
913 | ||
6725682d | 914 | OPENSSL_free(ctx->propq); |
bac4bffb RL |
915 | OPENSSL_free(ctx->uri); |
916 | if (ctx->type != is_dir) { | |
970f467a RL |
917 | if (ctx->_.file.last_handler != NULL) { |
918 | ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx); | |
919 | ctx->_.file.last_handler_ctx = NULL; | |
920 | ctx->_.file.last_handler = NULL; | |
921 | } | |
922 | } | |
923 | OPENSSL_free(ctx); | |
924 | } | |
925 | ||
6ab6ecfd RL |
926 | static int file_find_type(OSSL_STORE_LOADER_CTX *ctx) |
927 | { | |
928 | BIO *buff = NULL; | |
929 | char peekbuf[4096] = { 0, }; | |
930 | ||
931 | if ((buff = BIO_new(BIO_f_buffer())) == NULL) | |
932 | return 0; | |
933 | ||
934 | ctx->_.file.file = BIO_push(buff, ctx->_.file.file); | |
935 | if (BIO_buffer_peek(ctx->_.file.file, peekbuf, sizeof(peekbuf) - 1) > 0) { | |
936 | peekbuf[sizeof(peekbuf) - 1] = '\0'; | |
937 | if (strstr(peekbuf, "-----BEGIN ") != NULL) | |
938 | ctx->type = is_pem; | |
939 | } | |
940 | return 1; | |
941 | } | |
942 | ||
d8652be0 | 943 | static OSSL_STORE_LOADER_CTX *file_open_ex |
6725682d | 944 | (const OSSL_STORE_LOADER *loader, const char *uri, |
b4250010 | 945 | OSSL_LIB_CTX *libctx, const char *propq, |
6725682d | 946 | const UI_METHOD *ui_method, void *ui_data) |
9c6da42d | 947 | { |
9c6da42d | 948 | OSSL_STORE_LOADER_CTX *ctx = NULL; |
970f467a | 949 | struct stat st; |
6eaebfaa RL |
950 | struct { |
951 | const char *path; | |
952 | unsigned int check_absolute:1; | |
953 | } path_data[2]; | |
954 | size_t path_data_n = 0, i; | |
747adb6a | 955 | const char *path, *p = uri, *q; |
9c6da42d | 956 | |
ae9c39d8 RL |
957 | /* |
958 | * First step, just take the URI as is. | |
959 | */ | |
6eaebfaa RL |
960 | path_data[path_data_n].check_absolute = 0; |
961 | path_data[path_data_n++].path = uri; | |
ae9c39d8 RL |
962 | |
963 | /* | |
747adb6a | 964 | * Second step, if the URI appears to start with the "file" scheme, |
ae9c39d8 RL |
965 | * extract the path and make that the second path to check. |
966 | * There's a special case if the URI also contains an authority, then | |
967 | * the full URI shouldn't be used as a path anywhere. | |
968 | */ | |
747adb6a DDO |
969 | if (CHECK_AND_SKIP_CASE_PREFIX(p, "file:")) { |
970 | q = p; | |
971 | if (CHECK_AND_SKIP_PREFIX(q, "//")) { | |
6eaebfaa | 972 | path_data_n--; /* Invalidate using the full URI */ |
747adb6a DDO |
973 | if (CHECK_AND_SKIP_CASE_PREFIX(q, "localhost/") |
974 | || CHECK_AND_SKIP_PREFIX(q, "/")) { | |
975 | p = q - 1; | |
ae9c39d8 | 976 | } else { |
16feca71 | 977 | ATTICerr(0, ATTIC_R_URI_AUTHORITY_UNSUPPORTED); |
ae9c39d8 RL |
978 | return NULL; |
979 | } | |
9c6da42d RL |
980 | } |
981 | ||
6eaebfaa RL |
982 | path_data[path_data_n].check_absolute = 1; |
983 | #ifdef _WIN32 | |
747adb6a | 984 | /* Windows "file:" URIs with a drive letter start with a '/' */ |
6eaebfaa | 985 | if (p[0] == '/' && p[2] == ':' && p[3] == '/') { |
16feca71 | 986 | char c = tolower(p[1]); |
11459953 RL |
987 | |
988 | if (c >= 'a' && c <= 'z') { | |
989 | p++; | |
990 | /* We know it's absolute, so no need to check */ | |
991 | path_data[path_data_n].check_absolute = 0; | |
992 | } | |
6eaebfaa RL |
993 | } |
994 | #endif | |
995 | path_data[path_data_n++].path = p; | |
996 | } | |
997 | ||
998 | ||
999 | for (i = 0, path = NULL; path == NULL && i < path_data_n; i++) { | |
9c6da42d RL |
1000 | /* |
1001 | * If the scheme "file" was an explicit part of the URI, the path must | |
1002 | * be absolute. So says RFC 8089 | |
1003 | */ | |
6eaebfaa | 1004 | if (path_data[i].check_absolute && path_data[i].path[0] != '/') { |
16feca71 | 1005 | ATTICerr(0, ATTIC_R_PATH_MUST_BE_ABSOLUTE); |
6eaebfaa | 1006 | ERR_add_error_data(1, path_data[i].path); |
9c6da42d RL |
1007 | return NULL; |
1008 | } | |
1009 | ||
6eaebfaa | 1010 | if (stat(path_data[i].path, &st) < 0) { |
ff988500 RS |
1011 | ERR_raise_data(ERR_LIB_SYS, errno, |
1012 | "calling stat(%s)", | |
1013 | path_data[i].path); | |
ae9c39d8 | 1014 | } else { |
6eaebfaa | 1015 | path = path_data[i].path; |
ae9c39d8 RL |
1016 | } |
1017 | } | |
1018 | if (path == NULL) { | |
970f467a RL |
1019 | return NULL; |
1020 | } | |
1021 | ||
9a30f40c | 1022 | /* Successfully found a working path */ |
ae9c39d8 | 1023 | |
9c6da42d | 1024 | ctx = OPENSSL_zalloc(sizeof(*ctx)); |
e077455e | 1025 | if (ctx == NULL) |
9c6da42d | 1026 | return NULL; |
bac4bffb | 1027 | ctx->uri = OPENSSL_strdup(uri); |
e077455e | 1028 | if (ctx->uri == NULL) |
bac4bffb | 1029 | goto err; |
9c6da42d | 1030 | |
f20aa69e | 1031 | if (S_ISDIR(st.st_mode)) { |
970f467a | 1032 | ctx->type = is_dir; |
970f467a RL |
1033 | ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, path); |
1034 | ctx->_.dir.last_errno = errno; | |
1035 | if (ctx->_.dir.last_entry == NULL) { | |
1036 | if (ctx->_.dir.last_errno != 0) { | |
16feca71 | 1037 | ERR_raise(ERR_LIB_SYS, ctx->_.dir.last_errno); |
970f467a RL |
1038 | goto err; |
1039 | } | |
1040 | ctx->_.dir.end_reached = 1; | |
1041 | } | |
6ab6ecfd RL |
1042 | } else if ((ctx->_.file.file = BIO_new_file(path, "rb")) == NULL |
1043 | || !file_find_type(ctx)) { | |
1044 | BIO_free_all(ctx->_.file.file); | |
1045 | goto err; | |
9c6da42d | 1046 | } |
6725682d SL |
1047 | if (propq != NULL) { |
1048 | ctx->propq = OPENSSL_strdup(propq); | |
e077455e | 1049 | if (ctx->propq == NULL) |
6725682d | 1050 | goto err; |
6725682d SL |
1051 | } |
1052 | ctx->libctx = libctx; | |
9c6da42d RL |
1053 | |
1054 | return ctx; | |
1055 | err: | |
970f467a | 1056 | OSSL_STORE_LOADER_CTX_free(ctx); |
9c6da42d RL |
1057 | return NULL; |
1058 | } | |
1059 | ||
6725682d SL |
1060 | static OSSL_STORE_LOADER_CTX *file_open |
1061 | (const OSSL_STORE_LOADER *loader, const char *uri, | |
1062 | const UI_METHOD *ui_method, void *ui_data) | |
6ab6ecfd | 1063 | { |
d8652be0 | 1064 | return file_open_ex(loader, uri, NULL, NULL, ui_method, ui_data); |
6725682d | 1065 | } |
6ab6ecfd | 1066 | |
6725682d SL |
1067 | static OSSL_STORE_LOADER_CTX *file_attach |
1068 | (const OSSL_STORE_LOADER *loader, BIO *bp, | |
b4250010 | 1069 | OSSL_LIB_CTX *libctx, const char *propq, |
6725682d SL |
1070 | const UI_METHOD *ui_method, void *ui_data) |
1071 | { | |
1072 | OSSL_STORE_LOADER_CTX *ctx = NULL; | |
1073 | ||
16feca71 RL |
1074 | if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL |
1075 | || (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL)) { | |
16feca71 RL |
1076 | OSSL_STORE_LOADER_CTX_free(ctx); |
1077 | return NULL; | |
6725682d | 1078 | } |
6ab6ecfd RL |
1079 | ctx->libctx = libctx; |
1080 | ctx->flags |= FILE_FLAG_ATTACHED; | |
1081 | ctx->_.file.file = bp; | |
1082 | if (!file_find_type(ctx)) { | |
1083 | /* Safety measure */ | |
1084 | ctx->_.file.file = NULL; | |
6725682d | 1085 | goto err; |
6ab6ecfd | 1086 | } |
6ab6ecfd | 1087 | return ctx; |
6725682d SL |
1088 | err: |
1089 | OSSL_STORE_LOADER_CTX_free(ctx); | |
1090 | return NULL; | |
6ab6ecfd RL |
1091 | } |
1092 | ||
7852f588 RL |
1093 | static int file_ctrl(OSSL_STORE_LOADER_CTX *ctx, int cmd, va_list args) |
1094 | { | |
1095 | int ret = 1; | |
1096 | ||
1097 | switch (cmd) { | |
1098 | case OSSL_STORE_C_USE_SECMEM: | |
1099 | { | |
1100 | int on = *(va_arg(args, int *)); | |
1101 | ||
1102 | switch (on) { | |
1103 | case 0: | |
1104 | ctx->flags &= ~FILE_FLAG_SECMEM; | |
1105 | break; | |
1106 | case 1: | |
1107 | ctx->flags |= FILE_FLAG_SECMEM; | |
1108 | break; | |
1109 | default: | |
16feca71 | 1110 | ATTICerr(0, ERR_R_PASSED_INVALID_ARGUMENT); |
7852f588 RL |
1111 | ret = 0; |
1112 | break; | |
1113 | } | |
1114 | } | |
1115 | break; | |
1116 | default: | |
1117 | break; | |
1118 | } | |
1119 | ||
1120 | return ret; | |
1121 | } | |
1122 | ||
6541d9e2 RL |
1123 | static int file_expect(OSSL_STORE_LOADER_CTX *ctx, int expected) |
1124 | { | |
1125 | ctx->expected_type = expected; | |
1126 | return 1; | |
1127 | } | |
1128 | ||
e3c4ad28 RL |
1129 | static int file_find(OSSL_STORE_LOADER_CTX *ctx, |
1130 | const OSSL_STORE_SEARCH *search) | |
93d2f9fa RL |
1131 | { |
1132 | /* | |
1133 | * If ctx == NULL, the library is looking to know if this loader supports | |
1134 | * the given search type. | |
1135 | */ | |
1136 | ||
1137 | if (OSSL_STORE_SEARCH_get_type(search) == OSSL_STORE_SEARCH_BY_NAME) { | |
1138 | unsigned long hash = 0; | |
1139 | ||
1140 | if (ctx == NULL) | |
1141 | return 1; | |
1142 | ||
1143 | if (ctx->type != is_dir) { | |
16feca71 | 1144 | ATTICerr(0, ATTIC_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES); |
93d2f9fa RL |
1145 | return 0; |
1146 | } | |
1147 | ||
bf973d06 DDO |
1148 | hash = X509_NAME_hash_ex(OSSL_STORE_SEARCH_get0_name(search), |
1149 | NULL, NULL, NULL); | |
93d2f9fa RL |
1150 | BIO_snprintf(ctx->_.dir.search_name, sizeof(ctx->_.dir.search_name), |
1151 | "%08lx", hash); | |
1152 | return 1; | |
1153 | } | |
1154 | ||
1155 | if (ctx != NULL) | |
16feca71 | 1156 | ATTICerr(0, ATTIC_R_UNSUPPORTED_SEARCH_TYPE); |
93d2f9fa RL |
1157 | return 0; |
1158 | } | |
1159 | ||
1aabc244 RL |
1160 | static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx, |
1161 | const char *pem_name, | |
1162 | const char *pem_header, | |
1163 | unsigned char *data, size_t len, | |
1164 | const UI_METHOD *ui_method, | |
1165 | void *ui_data, int *matchcount) | |
1166 | { | |
1167 | OSSL_STORE_INFO *result = NULL; | |
1168 | BUF_MEM *new_mem = NULL; | |
1169 | char *new_pem_name = NULL; | |
1170 | int t = 0; | |
1171 | ||
1172 | again: | |
1173 | { | |
1174 | size_t i = 0; | |
1175 | void *handler_ctx = NULL; | |
1176 | const FILE_HANDLER **matching_handlers = | |
1177 | OPENSSL_zalloc(sizeof(*matching_handlers) | |
1178 | * OSSL_NELEM(file_handlers)); | |
1179 | ||
e077455e | 1180 | if (matching_handlers == NULL) |
1aabc244 | 1181 | goto err; |
1aabc244 RL |
1182 | |
1183 | *matchcount = 0; | |
1184 | for (i = 0; i < OSSL_NELEM(file_handlers); i++) { | |
1185 | const FILE_HANDLER *handler = file_handlers[i]; | |
6fc1d33c | 1186 | int try_matchcount = 0; |
1aabc244 | 1187 | void *tmp_handler_ctx = NULL; |
9a30f40c DDO |
1188 | OSSL_STORE_INFO *tmp_result; |
1189 | unsigned long err; | |
1190 | ||
1191 | ERR_set_mark(); | |
1192 | tmp_result = | |
1aabc244 | 1193 | handler->try_decode(pem_name, pem_header, data, len, |
6fc1d33c | 1194 | &tmp_handler_ctx, &try_matchcount, |
bac4bffb RL |
1195 | ui_method, ui_data, ctx->uri, |
1196 | ctx->libctx, ctx->propq); | |
9a30f40c DDO |
1197 | /* avoid flooding error queue with low-level ASN.1 parse errors */ |
1198 | err = ERR_peek_last_error(); | |
1199 | if (ERR_GET_LIB(err) == ERR_LIB_ASN1 | |
1200 | && ERR_GET_REASON(err) == ERR_R_NESTED_ASN1_ERROR) | |
1201 | ERR_pop_to_mark(); | |
1202 | else | |
1203 | ERR_clear_last_mark(); | |
1aabc244 | 1204 | |
6fc1d33c | 1205 | if (try_matchcount > 0) { |
a0fda2cf F |
1206 | |
1207 | matching_handlers[*matchcount] = handler; | |
1aabc244 RL |
1208 | |
1209 | if (handler_ctx) | |
1210 | handler->destroy_ctx(&handler_ctx); | |
1211 | handler_ctx = tmp_handler_ctx; | |
1212 | ||
6fc1d33c | 1213 | if ((*matchcount += try_matchcount) > 1) { |
1aabc244 | 1214 | /* more than one match => ambiguous, kill any result */ |
16feca71 RL |
1215 | store_info_free(result); |
1216 | store_info_free(tmp_result); | |
1aabc244 RL |
1217 | if (handler->destroy_ctx != NULL) |
1218 | handler->destroy_ctx(&handler_ctx); | |
1219 | handler_ctx = NULL; | |
6fc1d33c | 1220 | tmp_result = NULL; |
1aabc244 RL |
1221 | result = NULL; |
1222 | } | |
6fc1d33c RL |
1223 | if (result == NULL) |
1224 | result = tmp_result; | |
09afbec9 DDO |
1225 | if (result == NULL) /* e.g., PKCS#12 file decryption error */ |
1226 | break; | |
1aabc244 RL |
1227 | } |
1228 | } | |
1229 | ||
09afbec9 DDO |
1230 | if (result != NULL |
1231 | && *matchcount == 1 && matching_handlers[0]->repeatable) { | |
6fc1d33c RL |
1232 | ctx->_.file.last_handler = matching_handlers[0]; |
1233 | ctx->_.file.last_handler_ctx = handler_ctx; | |
1aabc244 RL |
1234 | } |
1235 | ||
1236 | OPENSSL_free(matching_handlers); | |
1237 | } | |
1238 | ||
1239 | err: | |
1240 | OPENSSL_free(new_pem_name); | |
1241 | BUF_MEM_free(new_mem); | |
1242 | ||
1243 | if (result != NULL | |
16feca71 RL |
1244 | && (t = OSSL_STORE_INFO_get_type(result)) == STORE_INFO_EMBEDDED) { |
1245 | struct embedded_st *embedded = get0_EMBEDDED(result); | |
1246 | ||
1247 | /* "steal" the embedded data */ | |
1248 | pem_name = new_pem_name = embedded->pem_name; | |
1249 | new_mem = embedded->blob; | |
1aabc244 RL |
1250 | data = (unsigned char *)new_mem->data; |
1251 | len = new_mem->length; | |
16feca71 RL |
1252 | embedded->pem_name = NULL; |
1253 | embedded->blob = NULL; | |
1254 | ||
1255 | store_info_free(result); | |
1aabc244 RL |
1256 | result = NULL; |
1257 | goto again; | |
1258 | } | |
1259 | ||
1aabc244 RL |
1260 | return result; |
1261 | } | |
1262 | ||
1263 | static OSSL_STORE_INFO *file_load_try_repeat(OSSL_STORE_LOADER_CTX *ctx, | |
1264 | const UI_METHOD *ui_method, | |
1265 | void *ui_data) | |
9c6da42d RL |
1266 | { |
1267 | OSSL_STORE_INFO *result = NULL; | |
6fc1d33c | 1268 | int try_matchcount = 0; |
9c6da42d | 1269 | |
970f467a RL |
1270 | if (ctx->_.file.last_handler != NULL) { |
1271 | result = | |
1272 | ctx->_.file.last_handler->try_decode(NULL, NULL, NULL, 0, | |
1273 | &ctx->_.file.last_handler_ctx, | |
6fc1d33c | 1274 | &try_matchcount, |
bac4bffb | 1275 | ui_method, ui_data, ctx->uri, |
8755b085 | 1276 | ctx->libctx, ctx->propq); |
e61ec2d9 | 1277 | |
1aabc244 | 1278 | if (result == NULL) { |
970f467a RL |
1279 | ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx); |
1280 | ctx->_.file.last_handler_ctx = NULL; | |
1281 | ctx->_.file.last_handler = NULL; | |
1aabc244 RL |
1282 | } |
1283 | } | |
1284 | return result; | |
1285 | } | |
e61ec2d9 | 1286 | |
358d446f | 1287 | static void pem_free_flag(void *pem_data, int secure, size_t num) |
7852f588 RL |
1288 | { |
1289 | if (secure) | |
358d446f | 1290 | OPENSSL_secure_clear_free(pem_data, num); |
7852f588 RL |
1291 | else |
1292 | OPENSSL_free(pem_data); | |
1293 | } | |
1aabc244 RL |
1294 | static int file_read_pem(BIO *bp, char **pem_name, char **pem_header, |
1295 | unsigned char **data, long *len, | |
bac4bffb RL |
1296 | const UI_METHOD *ui_method, void *ui_data, |
1297 | const char *uri, int secure) | |
1aabc244 | 1298 | { |
7852f588 RL |
1299 | int i = secure |
1300 | ? PEM_read_bio_ex(bp, pem_name, pem_header, data, len, | |
1301 | PEM_FLAG_SECURE | PEM_FLAG_EAY_COMPATIBLE) | |
1302 | : PEM_read_bio(bp, pem_name, pem_header, data, len); | |
1aabc244 RL |
1303 | |
1304 | if (i <= 0) | |
1305 | return 0; | |
1306 | ||
1307 | /* | |
1308 | * 10 is the number of characters in "Proc-Type:", which | |
1309 | * PEM_get_EVP_CIPHER_INFO() requires to be present. | |
1310 | * If the PEM header has less characters than that, it's | |
1311 | * not worth spending cycles on it. | |
1312 | */ | |
1313 | if (strlen(*pem_header) > 10) { | |
1314 | EVP_CIPHER_INFO cipher; | |
1315 | struct pem_pass_data pass_data; | |
1316 | ||
1317 | if (!PEM_get_EVP_CIPHER_INFO(*pem_header, &cipher) | |
bac4bffb RL |
1318 | || !file_fill_pem_pass_data(&pass_data, "PEM pass phrase", uri, |
1319 | ui_method, ui_data) | |
1aabc244 RL |
1320 | || !PEM_do_header(&cipher, *data, len, file_get_pem_pass, |
1321 | &pass_data)) { | |
1322 | return 0; | |
1323 | } | |
e61ec2d9 | 1324 | } |
1aabc244 RL |
1325 | return 1; |
1326 | } | |
1327 | ||
f55838f3 RL |
1328 | static OSSL_STORE_INFO *file_try_read_msblob(BIO *bp, int *matchcount) |
1329 | { | |
f55838f3 RL |
1330 | OSSL_STORE_INFO *result = NULL; |
1331 | int ispub = -1; | |
1332 | ||
1333 | { | |
1334 | unsigned int magic = 0, bitlen = 0; | |
1335 | int isdss = 0; | |
1336 | unsigned char peekbuf[16] = { 0, }; | |
1337 | const unsigned char *p = peekbuf; | |
1338 | ||
1339 | if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0) | |
1340 | return 0; | |
546b9f6b PH |
1341 | if (ossl_do_blob_header(&p, sizeof(peekbuf), &magic, &bitlen, |
1342 | &isdss, &ispub) <= 0) | |
f55838f3 RL |
1343 | return 0; |
1344 | } | |
1345 | ||
1346 | (*matchcount)++; | |
1347 | ||
1348 | { | |
1349 | EVP_PKEY *tmp = ispub | |
1350 | ? b2i_PublicKey_bio(bp) | |
1351 | : b2i_PrivateKey_bio(bp); | |
1352 | ||
1353 | if (tmp == NULL | |
1354 | || (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) { | |
1355 | EVP_PKEY_free(tmp); | |
1356 | return 0; | |
1357 | } | |
1358 | } | |
1359 | ||
1360 | return result; | |
f55838f3 RL |
1361 | } |
1362 | ||
1363 | static OSSL_STORE_INFO *file_try_read_PVK(BIO *bp, const UI_METHOD *ui_method, | |
1364 | void *ui_data, const char *uri, | |
1365 | int *matchcount) | |
1366 | { | |
f55838f3 RL |
1367 | OSSL_STORE_INFO *result = NULL; |
1368 | ||
1369 | { | |
1370 | unsigned int saltlen = 0, keylen = 0; | |
1371 | unsigned char peekbuf[24] = { 0, }; | |
1372 | const unsigned char *p = peekbuf; | |
1373 | ||
1374 | if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0) | |
1375 | return 0; | |
1376 | if (!ossl_do_PVK_header(&p, sizeof(peekbuf), 0, &saltlen, &keylen)) | |
1377 | return 0; | |
1378 | } | |
1379 | ||
1380 | (*matchcount)++; | |
1381 | ||
1382 | { | |
1383 | EVP_PKEY *tmp = NULL; | |
1384 | struct pem_pass_data pass_data; | |
1385 | ||
1386 | if (!file_fill_pem_pass_data(&pass_data, "PVK pass phrase", uri, | |
1387 | ui_method, ui_data) | |
1388 | || (tmp = b2i_PVK_bio(bp, file_get_pem_pass, &pass_data)) == NULL | |
1389 | || (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) { | |
1390 | EVP_PKEY_free(tmp); | |
1391 | return 0; | |
1392 | } | |
1393 | } | |
1394 | ||
1395 | return result; | |
f55838f3 RL |
1396 | } |
1397 | ||
1aabc244 RL |
1398 | static int file_read_asn1(BIO *bp, unsigned char **data, long *len) |
1399 | { | |
1400 | BUF_MEM *mem = NULL; | |
1401 | ||
1402 | if (asn1_d2i_read_bio(bp, &mem) < 0) | |
1403 | return 0; | |
1404 | ||
1405 | *data = (unsigned char *)mem->data; | |
1406 | *len = (long)mem->length; | |
1407 | OPENSSL_free(mem); | |
1408 | ||
1409 | return 1; | |
1410 | } | |
1411 | ||
970f467a RL |
1412 | static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name, |
1413 | char **data) | |
1414 | { | |
1415 | assert(name != NULL); | |
1416 | assert(data != NULL); | |
1417 | { | |
69d16b70 | 1418 | const char *pathsep = ossl_ends_with_dirsep(ctx->uri) ? "" : "/"; |
bac4bffb | 1419 | long calculated_length = strlen(ctx->uri) + strlen(pathsep) |
970f467a RL |
1420 | + strlen(name) + 1 /* \0 */; |
1421 | ||
1422 | *data = OPENSSL_zalloc(calculated_length); | |
e077455e | 1423 | if (*data == NULL) |
970f467a | 1424 | return 0; |
970f467a | 1425 | |
bac4bffb | 1426 | OPENSSL_strlcat(*data, ctx->uri, calculated_length); |
970f467a RL |
1427 | OPENSSL_strlcat(*data, pathsep, calculated_length); |
1428 | OPENSSL_strlcat(*data, name, calculated_length); | |
1429 | } | |
1430 | return 1; | |
1431 | } | |
1432 | ||
93d2f9fa RL |
1433 | static int file_name_check(OSSL_STORE_LOADER_CTX *ctx, const char *name) |
1434 | { | |
1435 | const char *p = NULL; | |
5fc0992f | 1436 | size_t len = strlen(ctx->_.dir.search_name); |
93d2f9fa RL |
1437 | |
1438 | /* If there are no search criteria, all names are accepted */ | |
1439 | if (ctx->_.dir.search_name[0] == '\0') | |
1440 | return 1; | |
1441 | ||
1442 | /* If the expected type isn't supported, no name is accepted */ | |
1443 | if (ctx->expected_type != 0 | |
1444 | && ctx->expected_type != OSSL_STORE_INFO_CERT | |
1445 | && ctx->expected_type != OSSL_STORE_INFO_CRL) | |
1446 | return 0; | |
1447 | ||
1448 | /* | |
1449 | * First, check the basename | |
1450 | */ | |
fba140c7 DB |
1451 | if (OPENSSL_strncasecmp(name, ctx->_.dir.search_name, len) != 0 |
1452 | || name[len] != '.') | |
93d2f9fa | 1453 | return 0; |
5fc0992f | 1454 | p = &name[len + 1]; |
93d2f9fa RL |
1455 | |
1456 | /* | |
1457 | * Then, if the expected type is a CRL, check that the extension starts | |
1458 | * with 'r' | |
1459 | */ | |
1460 | if (*p == 'r') { | |
1461 | p++; | |
1462 | if (ctx->expected_type != 0 | |
1463 | && ctx->expected_type != OSSL_STORE_INFO_CRL) | |
1464 | return 0; | |
1465 | } else if (ctx->expected_type == OSSL_STORE_INFO_CRL) { | |
1466 | return 0; | |
1467 | } | |
1468 | ||
1469 | /* | |
1470 | * Last, check that the rest of the extension is a decimal number, at | |
1471 | * least one digit long. | |
1472 | */ | |
82298744 | 1473 | if (!isdigit((unsigned char)*p)) |
93d2f9fa | 1474 | return 0; |
82298744 | 1475 | while (isdigit((unsigned char)*p)) |
93d2f9fa RL |
1476 | p++; |
1477 | ||
9f5ff440 | 1478 | #ifdef __VMS |
93d2f9fa RL |
1479 | /* |
1480 | * One extra step here, check for a possible generation number. | |
1481 | */ | |
1482 | if (*p == ';') | |
1483 | for (p++; *p != '\0'; p++) | |
fa339c69 | 1484 | if (!ossl_isdigit(*p)) |
93d2f9fa | 1485 | break; |
9f5ff440 | 1486 | #endif |
93d2f9fa RL |
1487 | |
1488 | /* | |
1489 | * If we've reached the end of the string at this point, we've successfully | |
1490 | * found a fitting file name. | |
1491 | */ | |
1492 | return *p == '\0'; | |
1493 | } | |
1494 | ||
1aabc244 RL |
1495 | static int file_eof(OSSL_STORE_LOADER_CTX *ctx); |
1496 | static int file_error(OSSL_STORE_LOADER_CTX *ctx); | |
1497 | static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx, | |
6725682d SL |
1498 | const UI_METHOD *ui_method, |
1499 | void *ui_data) | |
1aabc244 RL |
1500 | { |
1501 | OSSL_STORE_INFO *result = NULL; | |
1aabc244 | 1502 | |
6fc1d33c | 1503 | ctx->errcnt = 0; |
6fc1d33c | 1504 | |
970f467a RL |
1505 | if (ctx->type == is_dir) { |
1506 | do { | |
1507 | char *newname = NULL; | |
e61ec2d9 | 1508 | |
970f467a RL |
1509 | if (ctx->_.dir.last_entry == NULL) { |
1510 | if (!ctx->_.dir.end_reached) { | |
970f467a | 1511 | assert(ctx->_.dir.last_errno != 0); |
16feca71 | 1512 | ERR_raise(ERR_LIB_SYS, ctx->_.dir.last_errno); |
9c6da42d | 1513 | ctx->errcnt++; |
970f467a RL |
1514 | } |
1515 | return NULL; | |
9c6da42d | 1516 | } |
970f467a RL |
1517 | |
1518 | if (ctx->_.dir.last_entry[0] != '.' | |
93d2f9fa | 1519 | && file_name_check(ctx, ctx->_.dir.last_entry) |
970f467a RL |
1520 | && !file_name_to_uri(ctx, ctx->_.dir.last_entry, &newname)) |
1521 | return NULL; | |
1522 | ||
1523 | /* | |
1524 | * On the first call (with a NULL context), OPENSSL_DIR_read() | |
1525 | * cares about the second argument. On the following calls, it | |
1526 | * only cares that it isn't NULL. Therefore, we can safely give | |
1527 | * it our URI here. | |
1528 | */ | |
bac4bffb | 1529 | ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, ctx->uri); |
970f467a RL |
1530 | ctx->_.dir.last_errno = errno; |
1531 | if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0) | |
1532 | ctx->_.dir.end_reached = 1; | |
1533 | ||
1534 | if (newname != NULL | |
1535 | && (result = OSSL_STORE_INFO_new_NAME(newname)) == NULL) { | |
1536 | OPENSSL_free(newname); | |
16feca71 | 1537 | ATTICerr(0, ERR_R_OSSL_STORE_LIB); |
970f467a | 1538 | return NULL; |
9c6da42d | 1539 | } |
970f467a RL |
1540 | } while (result == NULL && !file_eof(ctx)); |
1541 | } else { | |
1542 | int matchcount = -1; | |
9c6da42d | 1543 | |
6541d9e2 | 1544 | again: |
970f467a RL |
1545 | result = file_load_try_repeat(ctx, ui_method, ui_data); |
1546 | if (result != NULL) | |
1547 | return result; | |
9c6da42d | 1548 | |
6fc1d33c | 1549 | if (file_eof(ctx)) |
970f467a | 1550 | return NULL; |
9c6da42d | 1551 | |
970f467a RL |
1552 | do { |
1553 | char *pem_name = NULL; /* PEM record name */ | |
1554 | char *pem_header = NULL; /* PEM record header */ | |
1555 | unsigned char *data = NULL; /* DER encoded data */ | |
1556 | long len = 0; /* DER encoded data length */ | |
1557 | ||
1558 | matchcount = -1; | |
1559 | if (ctx->type == is_pem) { | |
1560 | if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header, | |
bac4bffb | 1561 | &data, &len, ui_method, ui_data, ctx->uri, |
7852f588 | 1562 | (ctx->flags & FILE_FLAG_SECMEM) != 0)) { |
6fc1d33c RL |
1563 | ctx->errcnt++; |
1564 | goto endloop; | |
970f467a RL |
1565 | } |
1566 | } else { | |
f55838f3 RL |
1567 | if ((result = file_try_read_msblob(ctx->_.file.file, |
1568 | &matchcount)) != NULL | |
1569 | || (result = file_try_read_PVK(ctx->_.file.file, | |
1570 | ui_method, ui_data, ctx->uri, | |
1571 | &matchcount)) != NULL) | |
1572 | goto endloop; | |
1573 | ||
970f467a | 1574 | if (!file_read_asn1(ctx->_.file.file, &data, &len)) { |
6fc1d33c RL |
1575 | ctx->errcnt++; |
1576 | goto endloop; | |
970f467a RL |
1577 | } |
1578 | } | |
1579 | ||
1580 | result = file_load_try_decode(ctx, pem_name, pem_header, data, len, | |
1581 | ui_method, ui_data, &matchcount); | |
1582 | ||
6fc1d33c RL |
1583 | if (result != NULL) |
1584 | goto endloop; | |
1585 | ||
1586 | /* | |
1587 | * If a PEM name matches more than one handler, the handlers are | |
1588 | * badly coded. | |
1589 | */ | |
1590 | if (!ossl_assert(pem_name == NULL || matchcount <= 1)) { | |
1591 | ctx->errcnt++; | |
1592 | goto endloop; | |
1593 | } | |
1594 | ||
1595 | if (matchcount > 1) { | |
16feca71 | 1596 | ATTICerr(0, ATTIC_R_AMBIGUOUS_CONTENT_TYPE); |
6fc1d33c RL |
1597 | } else if (matchcount == 1) { |
1598 | /* | |
1599 | * If there are other errors on the stack, they already show | |
1600 | * what the problem is. | |
1601 | */ | |
1602 | if (ERR_peek_error() == 0) { | |
16feca71 | 1603 | ATTICerr(0, ATTIC_R_UNSUPPORTED_CONTENT_TYPE); |
6fc1d33c RL |
1604 | if (pem_name != NULL) |
1605 | ERR_add_error_data(3, "PEM type is '", pem_name, "'"); | |
1606 | } | |
1607 | } | |
1608 | if (matchcount > 0) | |
1609 | ctx->errcnt++; | |
1610 | ||
1611 | endloop: | |
358d446f BE |
1612 | pem_free_flag(pem_name, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0); |
1613 | pem_free_flag(pem_header, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0); | |
1614 | pem_free_flag(data, (ctx->flags & FILE_FLAG_SECMEM) != 0, len); | |
970f467a RL |
1615 | } while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx)); |
1616 | ||
1617 | /* We bail out on ambiguity */ | |
821278a8 | 1618 | if (matchcount > 1) { |
16feca71 | 1619 | store_info_free(result); |
970f467a | 1620 | return NULL; |
821278a8 | 1621 | } |
6541d9e2 RL |
1622 | |
1623 | if (result != NULL | |
1624 | && ctx->expected_type != 0 | |
1625 | && ctx->expected_type != OSSL_STORE_INFO_get_type(result)) { | |
16feca71 | 1626 | store_info_free(result); |
6541d9e2 RL |
1627 | goto again; |
1628 | } | |
970f467a | 1629 | } |
9c6da42d | 1630 | |
9c6da42d RL |
1631 | return result; |
1632 | } | |
1633 | ||
1634 | static int file_error(OSSL_STORE_LOADER_CTX *ctx) | |
1635 | { | |
1636 | return ctx->errcnt > 0; | |
1637 | } | |
1638 | ||
1639 | static int file_eof(OSSL_STORE_LOADER_CTX *ctx) | |
1640 | { | |
970f467a RL |
1641 | if (ctx->type == is_dir) |
1642 | return ctx->_.dir.end_reached; | |
1643 | ||
1644 | if (ctx->_.file.last_handler != NULL | |
1645 | && !ctx->_.file.last_handler->eof(ctx->_.file.last_handler_ctx)) | |
e61ec2d9 | 1646 | return 0; |
970f467a | 1647 | return BIO_eof(ctx->_.file.file); |
9c6da42d RL |
1648 | } |
1649 | ||
1650 | static int file_close(OSSL_STORE_LOADER_CTX *ctx) | |
1651 | { | |
6ab6ecfd RL |
1652 | if ((ctx->flags & FILE_FLAG_ATTACHED) == 0) { |
1653 | if (ctx->type == is_dir) | |
1654 | OPENSSL_DIR_end(&ctx->_.dir.ctx); | |
1655 | else | |
1656 | BIO_free_all(ctx->_.file.file); | |
970f467a | 1657 | } else { |
6ab6ecfd RL |
1658 | /* |
1659 | * Because file_attach() called file_find_type(), we know that a | |
1660 | * BIO_f_buffer() has been pushed on top of the regular BIO. | |
1661 | */ | |
1662 | BIO *buff = ctx->_.file.file; | |
9c6da42d | 1663 | |
6ab6ecfd RL |
1664 | /* Detach buff */ |
1665 | (void)BIO_pop(ctx->_.file.file); | |
1666 | /* Safety measure */ | |
1667 | ctx->_.file.file = NULL; | |
1668 | ||
1669 | BIO_free(buff); | |
1670 | } | |
4c17819c RL |
1671 | OSSL_STORE_LOADER_CTX_free(ctx); |
1672 | return 1; | |
1673 | } | |
1674 | ||
16feca71 RL |
1675 | /*- |
1676 | * ENGINE management | |
1677 | */ | |
1678 | ||
1679 | static const char *loader_attic_id = "loader_attic"; | |
1680 | static const char *loader_attic_name = "'file:' loader"; | |
1681 | ||
1682 | static OSSL_STORE_LOADER *loader_attic = NULL; | |
1683 | ||
1684 | static int loader_attic_init(ENGINE *e) | |
9c6da42d | 1685 | { |
16feca71 | 1686 | return 1; |
9c6da42d RL |
1687 | } |
1688 | ||
16feca71 RL |
1689 | |
1690 | static int loader_attic_finish(ENGINE *e) | |
9c6da42d | 1691 | { |
16feca71 RL |
1692 | return 1; |
1693 | } | |
9c6da42d | 1694 | |
16feca71 RL |
1695 | |
1696 | static int loader_attic_destroy(ENGINE *e) | |
1697 | { | |
1698 | OSSL_STORE_LOADER *loader = OSSL_STORE_unregister_loader("file"); | |
1699 | ||
1700 | if (loader == NULL) | |
1701 | return 0; | |
1702 | ||
1703 | ERR_unload_ATTIC_strings(); | |
1704 | OSSL_STORE_LOADER_free(loader); | |
1705 | return 1; | |
1706 | } | |
1707 | ||
1708 | static int bind_loader_attic(ENGINE *e) | |
1709 | { | |
1710 | ||
ec4c86d9 | 1711 | /* Ensure the ATTIC error handling is set up on best effort basis */ |
16feca71 RL |
1712 | ERR_load_ATTIC_strings(); |
1713 | ||
1714 | if (/* Create the OSSL_STORE_LOADER */ | |
1715 | (loader_attic = OSSL_STORE_LOADER_new(e, "file")) == NULL | |
746f3674 | 1716 | || !OSSL_STORE_LOADER_set_open_ex(loader_attic, file_open_ex) |
16feca71 RL |
1717 | || !OSSL_STORE_LOADER_set_open(loader_attic, file_open) |
1718 | || !OSSL_STORE_LOADER_set_attach(loader_attic, file_attach) | |
1719 | || !OSSL_STORE_LOADER_set_ctrl(loader_attic, file_ctrl) | |
1720 | || !OSSL_STORE_LOADER_set_expect(loader_attic, file_expect) | |
1721 | || !OSSL_STORE_LOADER_set_find(loader_attic, file_find) | |
1722 | || !OSSL_STORE_LOADER_set_load(loader_attic, file_load) | |
1723 | || !OSSL_STORE_LOADER_set_eof(loader_attic, file_eof) | |
1724 | || !OSSL_STORE_LOADER_set_error(loader_attic, file_error) | |
1725 | || !OSSL_STORE_LOADER_set_close(loader_attic, file_close) | |
1726 | /* Init the engine itself */ | |
1727 | || !ENGINE_set_id(e, loader_attic_id) | |
1728 | || !ENGINE_set_name(e, loader_attic_name) | |
1729 | || !ENGINE_set_destroy_function(e, loader_attic_destroy) | |
1730 | || !ENGINE_set_init_function(e, loader_attic_init) | |
1731 | || !ENGINE_set_finish_function(e, loader_attic_finish) | |
1732 | /* Finally, register the method with libcrypto */ | |
1733 | || !OSSL_STORE_register_loader(loader_attic)) { | |
1734 | OSSL_STORE_LOADER_free(loader_attic); | |
1735 | loader_attic = NULL; | |
1736 | ATTICerr(0, ATTIC_R_INIT_FAILED); | |
1737 | return 0; | |
1738 | } | |
1739 | ||
1740 | return 1; | |
1741 | } | |
1742 | ||
1743 | #ifdef OPENSSL_NO_DYNAMIC_ENGINE | |
1744 | # error "Only allowed as dynamically shared object" | |
1745 | #endif | |
1746 | ||
1747 | static int bind_helper(ENGINE *e, const char *id) | |
1748 | { | |
1749 | if (id && (strcmp(id, loader_attic_id) != 0)) | |
1750 | return 0; | |
1751 | if (!bind_loader_attic(e)) | |
1752 | return 0; | |
1753 | return 1; | |
9c6da42d | 1754 | } |
16feca71 RL |
1755 | |
1756 | IMPLEMENT_DYNAMIC_CHECK_FN() | |
1757 | IMPLEMENT_DYNAMIC_BIND_FN(bind_helper) |