Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/providers/implementations/storemgmt/file_store.c
34371 views
1
/*
2
* Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved.
3
*
4
* Licensed under the Apache License 2.0 (the "License"). You may not use
5
* this file except in compliance with the License. You can obtain a copy
6
* in the file LICENSE in the source distribution or at
7
* https://www.openssl.org/source/license.html
8
*/
9
10
/* This file has quite some overlap with engines/e_loader_attic.c */
11
12
#include <string.h>
13
#include <sys/stat.h>
14
#include <ctype.h> /* isdigit */
15
#include <assert.h>
16
17
#include <openssl/core_dispatch.h>
18
#include <openssl/core_names.h>
19
#include <openssl/core_object.h>
20
#include <openssl/bio.h>
21
#include <openssl/err.h>
22
#include <openssl/params.h>
23
#include <openssl/decoder.h>
24
#include <openssl/proverr.h>
25
#include <openssl/store.h> /* The OSSL_STORE_INFO type numbers */
26
#include "internal/cryptlib.h"
27
#include "internal/o_dir.h"
28
#include "crypto/decoder.h"
29
#include "crypto/ctype.h" /* ossl_isdigit() */
30
#include "prov/implementations.h"
31
#include "prov/bio.h"
32
#include "prov/providercommon.h"
33
#include "file_store_local.h"
34
35
DEFINE_STACK_OF(OSSL_STORE_INFO)
36
37
#ifdef _WIN32
38
# define stat _stat
39
#endif
40
41
#ifndef S_ISDIR
42
# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR)
43
#endif
44
45
static OSSL_FUNC_store_open_fn file_open;
46
static OSSL_FUNC_store_attach_fn file_attach;
47
static OSSL_FUNC_store_settable_ctx_params_fn file_settable_ctx_params;
48
static OSSL_FUNC_store_set_ctx_params_fn file_set_ctx_params;
49
static OSSL_FUNC_store_load_fn file_load;
50
static OSSL_FUNC_store_eof_fn file_eof;
51
static OSSL_FUNC_store_close_fn file_close;
52
53
/*
54
* This implementation makes full use of OSSL_DECODER, and then some.
55
* It uses its own internal decoder implementation that reads DER and
56
* passes that on to the data callback; this decoder is created with
57
* internal OpenSSL functions, thereby bypassing the need for a surrounding
58
* provider. This is ok, since this is a local decoder, not meant for
59
* public consumption.
60
* Finally, it sets up its own construct and cleanup functions.
61
*
62
* Essentially, that makes this implementation a kind of glorified decoder.
63
*/
64
65
struct file_ctx_st {
66
void *provctx;
67
char *uri; /* The URI we currently try to load */
68
enum {
69
IS_FILE = 0, /* Read file and pass results */
70
IS_DIR /* Pass directory entry names */
71
} type;
72
73
union {
74
/* Used with |IS_FILE| */
75
struct {
76
BIO *file;
77
78
OSSL_DECODER_CTX *decoderctx;
79
char *input_type;
80
char *propq; /* The properties we got as a parameter */
81
} file;
82
83
/* Used with |IS_DIR| */
84
struct {
85
OPENSSL_DIR_CTX *ctx;
86
int end_reached;
87
88
/*
89
* When a search expression is given, these are filled in.
90
* |search_name| contains the file basename to look for.
91
* The string is exactly 8 characters long.
92
*/
93
char search_name[9];
94
95
/*
96
* The directory reading utility we have combines opening with
97
* reading the first name. To make sure we can detect the end
98
* at the right time, we read early and cache the name.
99
*/
100
const char *last_entry;
101
int last_errno;
102
} dir;
103
} _;
104
105
/* Expected object type. May be unspecified */
106
int expected_type;
107
};
108
109
static void free_file_ctx(struct file_ctx_st *ctx)
110
{
111
if (ctx == NULL)
112
return;
113
114
OPENSSL_free(ctx->uri);
115
if (ctx->type != IS_DIR) {
116
OSSL_DECODER_CTX_free(ctx->_.file.decoderctx);
117
OPENSSL_free(ctx->_.file.propq);
118
OPENSSL_free(ctx->_.file.input_type);
119
}
120
OPENSSL_free(ctx);
121
}
122
123
static struct file_ctx_st *new_file_ctx(int type, const char *uri,
124
void *provctx)
125
{
126
struct file_ctx_st *ctx = NULL;
127
128
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL
129
&& (uri == NULL || (ctx->uri = OPENSSL_strdup(uri)) != NULL)) {
130
ctx->type = type;
131
ctx->provctx = provctx;
132
return ctx;
133
}
134
free_file_ctx(ctx);
135
return NULL;
136
}
137
138
static OSSL_DECODER_CONSTRUCT file_load_construct;
139
static OSSL_DECODER_CLEANUP file_load_cleanup;
140
141
/*-
142
* Opening / attaching streams and directories
143
* -------------------------------------------
144
*/
145
146
/*
147
* Function to service both file_open() and file_attach()
148
*
149
*
150
*/
151
static struct file_ctx_st *file_open_stream(BIO *source, const char *uri,
152
void *provctx)
153
{
154
struct file_ctx_st *ctx;
155
156
if ((ctx = new_file_ctx(IS_FILE, uri, provctx)) == NULL) {
157
ERR_raise(ERR_LIB_PROV, ERR_R_PROV_LIB);
158
goto err;
159
}
160
161
ctx->_.file.file = source;
162
163
return ctx;
164
err:
165
free_file_ctx(ctx);
166
return NULL;
167
}
168
169
static void *file_open_dir(const char *path, const char *uri, void *provctx)
170
{
171
struct file_ctx_st *ctx;
172
173
if ((ctx = new_file_ctx(IS_DIR, uri, provctx)) == NULL) {
174
ERR_raise(ERR_LIB_PROV, ERR_R_PROV_LIB);
175
return NULL;
176
}
177
178
ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, path);
179
ctx->_.dir.last_errno = errno;
180
if (ctx->_.dir.last_entry == NULL) {
181
if (ctx->_.dir.last_errno != 0) {
182
ERR_raise_data(ERR_LIB_SYS, ctx->_.dir.last_errno,
183
"Calling OPENSSL_DIR_read(\"%s\")", path);
184
goto err;
185
}
186
ctx->_.dir.end_reached = 1;
187
}
188
return ctx;
189
err:
190
file_close(ctx);
191
return NULL;
192
}
193
194
static void *file_open(void *provctx, const char *uri)
195
{
196
struct file_ctx_st *ctx = NULL;
197
struct stat st;
198
struct {
199
const char *path;
200
unsigned int check_absolute:1;
201
} path_data[2];
202
size_t path_data_n = 0, i;
203
const char *path, *p = uri, *q;
204
BIO *bio;
205
206
ERR_set_mark();
207
208
/*
209
* First step, just take the URI as is.
210
*/
211
path_data[path_data_n].check_absolute = 0;
212
path_data[path_data_n++].path = uri;
213
214
/*
215
* Second step, if the URI appears to start with the "file" scheme,
216
* extract the path and make that the second path to check.
217
* There's a special case if the URI also contains an authority, then
218
* the full URI shouldn't be used as a path anywhere.
219
*/
220
if (CHECK_AND_SKIP_CASE_PREFIX(p, "file:")) {
221
q = p;
222
if (CHECK_AND_SKIP_CASE_PREFIX(q, "//")) {
223
path_data_n--; /* Invalidate using the full URI */
224
if (CHECK_AND_SKIP_CASE_PREFIX(q, "localhost/")
225
|| CHECK_AND_SKIP_CASE_PREFIX(q, "/")) {
226
p = q - 1;
227
} else {
228
ERR_clear_last_mark();
229
ERR_raise(ERR_LIB_PROV, PROV_R_URI_AUTHORITY_UNSUPPORTED);
230
return NULL;
231
}
232
}
233
234
path_data[path_data_n].check_absolute = 1;
235
#ifdef _WIN32
236
/* Windows "file:" URIs with a drive letter start with a '/' */
237
if (p[0] == '/' && p[2] == ':' && p[3] == '/') {
238
char c = tolower((unsigned char)p[1]);
239
240
if (c >= 'a' && c <= 'z') {
241
p++;
242
/* We know it's absolute, so no need to check */
243
path_data[path_data_n].check_absolute = 0;
244
}
245
}
246
#endif
247
path_data[path_data_n++].path = p;
248
}
249
250
251
for (i = 0, path = NULL; path == NULL && i < path_data_n; i++) {
252
/*
253
* If the scheme "file" was an explicit part of the URI, the path must
254
* be absolute. So says RFC 8089
255
*/
256
if (path_data[i].check_absolute && path_data[i].path[0] != '/') {
257
ERR_clear_last_mark();
258
ERR_raise_data(ERR_LIB_PROV, PROV_R_PATH_MUST_BE_ABSOLUTE,
259
"Given path=%s", path_data[i].path);
260
return NULL;
261
}
262
263
if (stat(path_data[i].path, &st) < 0) {
264
ERR_raise_data(ERR_LIB_SYS, errno,
265
"calling stat(%s)",
266
path_data[i].path);
267
} else {
268
path = path_data[i].path;
269
}
270
}
271
if (path == NULL) {
272
ERR_clear_last_mark();
273
return NULL;
274
}
275
276
/* Successfully found a working path, clear possible collected errors */
277
ERR_pop_to_mark();
278
279
if (S_ISDIR(st.st_mode))
280
ctx = file_open_dir(path, uri, provctx);
281
else if ((bio = BIO_new_file(path, "rb")) == NULL
282
|| (ctx = file_open_stream(bio, uri, provctx)) == NULL)
283
BIO_free_all(bio);
284
285
return ctx;
286
}
287
288
void *file_attach(void *provctx, OSSL_CORE_BIO *cin)
289
{
290
struct file_ctx_st *ctx;
291
BIO *new_bio = ossl_bio_new_from_core_bio(provctx, cin);
292
293
if (new_bio == NULL)
294
return NULL;
295
296
ctx = file_open_stream(new_bio, NULL, provctx);
297
if (ctx == NULL)
298
BIO_free(new_bio);
299
return ctx;
300
}
301
302
/*-
303
* Setting parameters
304
* ------------------
305
*/
306
307
static const OSSL_PARAM *file_settable_ctx_params(void *provctx)
308
{
309
static const OSSL_PARAM known_settable_ctx_params[] = {
310
OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_PROPERTIES, NULL, 0),
311
OSSL_PARAM_int(OSSL_STORE_PARAM_EXPECT, NULL),
312
OSSL_PARAM_octet_string(OSSL_STORE_PARAM_SUBJECT, NULL, 0),
313
OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_INPUT_TYPE, NULL, 0),
314
OSSL_PARAM_END
315
};
316
return known_settable_ctx_params;
317
}
318
319
static int file_set_ctx_params(void *loaderctx, const OSSL_PARAM params[])
320
{
321
struct file_ctx_st *ctx = loaderctx;
322
const OSSL_PARAM *p;
323
324
if (ossl_param_is_empty(params))
325
return 1;
326
327
if (ctx->type != IS_DIR) {
328
/* these parameters are ignored for directories */
329
p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_PROPERTIES);
330
if (p != NULL) {
331
OPENSSL_free(ctx->_.file.propq);
332
ctx->_.file.propq = NULL;
333
if (!OSSL_PARAM_get_utf8_string(p, &ctx->_.file.propq, 0))
334
return 0;
335
}
336
p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_INPUT_TYPE);
337
if (p != NULL) {
338
OPENSSL_free(ctx->_.file.input_type);
339
ctx->_.file.input_type = NULL;
340
if (!OSSL_PARAM_get_utf8_string(p, &ctx->_.file.input_type, 0))
341
return 0;
342
}
343
}
344
p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_EXPECT);
345
if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->expected_type))
346
return 0;
347
p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SUBJECT);
348
if (p != NULL) {
349
const unsigned char *der = NULL;
350
size_t der_len = 0;
351
X509_NAME *x509_name;
352
unsigned long hash;
353
int ok;
354
355
if (ctx->type != IS_DIR) {
356
ERR_raise(ERR_LIB_PROV,
357
PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES);
358
return 0;
359
}
360
361
if (!OSSL_PARAM_get_octet_string_ptr(p, (const void **)&der, &der_len)
362
|| (x509_name = d2i_X509_NAME(NULL, &der, der_len)) == NULL)
363
return 0;
364
hash = X509_NAME_hash_ex(x509_name,
365
ossl_prov_ctx_get0_libctx(ctx->provctx), NULL,
366
&ok);
367
BIO_snprintf(ctx->_.dir.search_name, sizeof(ctx->_.dir.search_name),
368
"%08lx", hash);
369
X509_NAME_free(x509_name);
370
if (ok == 0)
371
return 0;
372
}
373
return 1;
374
}
375
376
/*-
377
* Loading an object from a stream
378
* -------------------------------
379
*/
380
381
struct file_load_data_st {
382
OSSL_CALLBACK *object_cb;
383
void *object_cbarg;
384
};
385
386
static int file_load_construct(OSSL_DECODER_INSTANCE *decoder_inst,
387
const OSSL_PARAM *params, void *construct_data)
388
{
389
struct file_load_data_st *data = construct_data;
390
391
/*
392
* At some point, we may find it justifiable to recognise PKCS#12 and
393
* handle it specially here, making |file_load()| return pass its
394
* contents one piece at ta time, like |e_loader_attic.c| does.
395
*
396
* However, that currently means parsing them out, which converts the
397
* DER encoded PKCS#12 into a bunch of EVP_PKEYs and X509s, just to
398
* have to re-encode them into DER to create an object abstraction for
399
* each of them.
400
* It's much simpler (less churn) to pass on the object abstraction we
401
* get to the load_result callback and leave it to that one to do the
402
* work. If that's libcrypto code, we know that it has much better
403
* possibilities to handle the EVP_PKEYs and X509s without the extra
404
* churn.
405
*/
406
407
return data->object_cb(params, data->object_cbarg);
408
}
409
410
void file_load_cleanup(void *construct_data)
411
{
412
/* Nothing to do */
413
}
414
415
static int file_setup_decoders(struct file_ctx_st *ctx)
416
{
417
OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(ctx->provctx);
418
const OSSL_ALGORITHM *to_algo = NULL;
419
const char *input_structure = NULL;
420
int ok = 0;
421
422
/* Setup for this session, so only if not already done */
423
if (ctx->_.file.decoderctx == NULL) {
424
if ((ctx->_.file.decoderctx = OSSL_DECODER_CTX_new()) == NULL) {
425
ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
426
goto err;
427
}
428
429
/* Make sure the input type is set */
430
if (!OSSL_DECODER_CTX_set_input_type(ctx->_.file.decoderctx,
431
ctx->_.file.input_type)) {
432
ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
433
goto err;
434
}
435
436
/*
437
* Where applicable, set the outermost structure name.
438
* The goal is to avoid the STORE object types that are
439
* potentially password protected but aren't interesting
440
* for this load.
441
*/
442
switch (ctx->expected_type) {
443
case OSSL_STORE_INFO_PUBKEY:
444
input_structure = "SubjectPublicKeyInfo";
445
if (!OSSL_DECODER_CTX_set_input_structure(ctx->_.file.decoderctx,
446
input_structure)) {
447
ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
448
goto err;
449
}
450
break;
451
case OSSL_STORE_INFO_PKEY:
452
/*
453
* The user's OSSL_STORE_INFO_PKEY covers PKCS#8, whether encrypted
454
* or not. The decoder will figure out whether decryption is
455
* applicable and fall back as necessary. We just need to indicate
456
* that it is OK to try and encrypt, which may involve a password
457
* prompt, so not done unless the data type is explicit, as we
458
* might then get a password prompt for a key when reading only
459
* certs from a file.
460
*/
461
input_structure = "EncryptedPrivateKeyInfo";
462
if (!OSSL_DECODER_CTX_set_input_structure(ctx->_.file.decoderctx,
463
input_structure)) {
464
ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
465
goto err;
466
}
467
break;
468
case OSSL_STORE_INFO_CERT:
469
input_structure = "Certificate";
470
if (!OSSL_DECODER_CTX_set_input_structure(ctx->_.file.decoderctx,
471
input_structure)) {
472
ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
473
goto err;
474
}
475
break;
476
case OSSL_STORE_INFO_CRL:
477
input_structure = "CertificateList";
478
if (!OSSL_DECODER_CTX_set_input_structure(ctx->_.file.decoderctx,
479
input_structure)) {
480
ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
481
goto err;
482
}
483
break;
484
default:
485
break;
486
}
487
488
for (to_algo = ossl_any_to_obj_algorithm;
489
to_algo->algorithm_names != NULL;
490
to_algo++) {
491
OSSL_DECODER *to_obj = NULL;
492
OSSL_DECODER_INSTANCE *to_obj_inst = NULL;
493
const char *input_type;
494
495
/*
496
* Create the internal last resort decoder implementation
497
* together with a "decoder instance".
498
* The decoder doesn't need any identification or to be
499
* attached to any provider, since it's only used locally.
500
*/
501
to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL);
502
if (to_obj != NULL)
503
to_obj_inst =
504
ossl_decoder_instance_new_forprov(to_obj, ctx->provctx,
505
input_structure);
506
OSSL_DECODER_free(to_obj);
507
if (to_obj_inst == NULL)
508
goto err;
509
/*
510
* The input type has to match unless, the input type is PEM
511
* and the decoder input type is DER, in which case we'll pick
512
* up additional decoders.
513
*/
514
input_type = OSSL_DECODER_INSTANCE_get_input_type(to_obj_inst);
515
if (ctx->_.file.input_type != NULL
516
&& OPENSSL_strcasecmp(input_type, ctx->_.file.input_type) != 0
517
&& (OPENSSL_strcasecmp(ctx->_.file.input_type, "PEM") != 0
518
|| OPENSSL_strcasecmp(input_type, "der") != 0)) {
519
ossl_decoder_instance_free(to_obj_inst);
520
continue;
521
}
522
523
if (!ossl_decoder_ctx_add_decoder_inst(ctx->_.file.decoderctx,
524
to_obj_inst)) {
525
ossl_decoder_instance_free(to_obj_inst);
526
ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
527
goto err;
528
}
529
}
530
/* Add on the usual extra decoders */
531
if (!OSSL_DECODER_CTX_add_extra(ctx->_.file.decoderctx,
532
libctx, ctx->_.file.propq)) {
533
ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
534
goto err;
535
}
536
537
/*
538
* Then install our constructor hooks, which just passes decoded
539
* data to the load callback
540
*/
541
if (!OSSL_DECODER_CTX_set_construct(ctx->_.file.decoderctx,
542
file_load_construct)
543
|| !OSSL_DECODER_CTX_set_cleanup(ctx->_.file.decoderctx,
544
file_load_cleanup)) {
545
ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB);
546
goto err;
547
}
548
}
549
550
ok = 1;
551
err:
552
return ok;
553
}
554
555
static int file_load_file(struct file_ctx_st *ctx,
556
OSSL_CALLBACK *object_cb, void *object_cbarg,
557
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
558
{
559
struct file_load_data_st data;
560
int ret, err;
561
562
/* Setup the decoders (one time shot per session */
563
564
if (!file_setup_decoders(ctx))
565
return 0;
566
567
/* Setup for this object */
568
569
data.object_cb = object_cb;
570
data.object_cbarg = object_cbarg;
571
OSSL_DECODER_CTX_set_construct_data(ctx->_.file.decoderctx, &data);
572
OSSL_DECODER_CTX_set_passphrase_cb(ctx->_.file.decoderctx, pw_cb, pw_cbarg);
573
574
/* Launch */
575
576
ERR_set_mark();
577
ret = OSSL_DECODER_from_bio(ctx->_.file.decoderctx, ctx->_.file.file);
578
if (BIO_eof(ctx->_.file.file)
579
&& ((err = ERR_peek_last_error()) != 0)
580
&& ERR_GET_LIB(err) == ERR_LIB_OSSL_DECODER
581
&& ERR_GET_REASON(err) == ERR_R_UNSUPPORTED)
582
ERR_pop_to_mark();
583
else
584
ERR_clear_last_mark();
585
return ret;
586
}
587
588
/*-
589
* Loading a name object from a directory
590
* --------------------------------------
591
*/
592
593
static char *file_name_to_uri(struct file_ctx_st *ctx, const char *name)
594
{
595
char *data = NULL;
596
597
assert(name != NULL);
598
{
599
const char *pathsep = ossl_ends_with_dirsep(ctx->uri) ? "" : "/";
600
long calculated_length = strlen(ctx->uri) + strlen(pathsep)
601
+ strlen(name) + 1 /* \0 */;
602
603
data = OPENSSL_zalloc(calculated_length);
604
if (data == NULL)
605
return NULL;
606
607
OPENSSL_strlcat(data, ctx->uri, calculated_length);
608
OPENSSL_strlcat(data, pathsep, calculated_length);
609
OPENSSL_strlcat(data, name, calculated_length);
610
}
611
return data;
612
}
613
614
static int file_name_check(struct file_ctx_st *ctx, const char *name)
615
{
616
const char *p = NULL;
617
size_t len = strlen(ctx->_.dir.search_name);
618
619
/* If there are no search criteria, all names are accepted */
620
if (ctx->_.dir.search_name[0] == '\0')
621
return 1;
622
623
/* If the expected type isn't supported, no name is accepted */
624
if (ctx->expected_type != 0
625
&& ctx->expected_type != OSSL_STORE_INFO_CERT
626
&& ctx->expected_type != OSSL_STORE_INFO_CRL)
627
return 0;
628
629
/*
630
* First, check the basename
631
*/
632
if (OPENSSL_strncasecmp(name, ctx->_.dir.search_name, len) != 0
633
|| name[len] != '.')
634
return 0;
635
p = &name[len + 1];
636
637
/*
638
* Then, if the expected type is a CRL, check that the extension starts
639
* with 'r'
640
*/
641
if (*p == 'r') {
642
p++;
643
if (ctx->expected_type != 0
644
&& ctx->expected_type != OSSL_STORE_INFO_CRL)
645
return 0;
646
} else if (ctx->expected_type == OSSL_STORE_INFO_CRL) {
647
return 0;
648
}
649
650
/*
651
* Last, check that the rest of the extension is a decimal number, at
652
* least one digit long.
653
*/
654
if (!isdigit((unsigned char)*p))
655
return 0;
656
while (isdigit((unsigned char)*p))
657
p++;
658
659
#ifdef __VMS
660
/*
661
* One extra step here, check for a possible generation number.
662
*/
663
if (*p == ';')
664
for (p++; *p != '\0'; p++)
665
if (!ossl_isdigit((unsigned char)*p))
666
break;
667
#endif
668
669
/*
670
* If we've reached the end of the string at this point, we've successfully
671
* found a fitting file name.
672
*/
673
return *p == '\0';
674
}
675
676
static int file_load_dir_entry(struct file_ctx_st *ctx,
677
OSSL_CALLBACK *object_cb, void *object_cbarg,
678
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
679
{
680
/* Prepare as much as possible in advance */
681
static const int object_type = OSSL_OBJECT_NAME;
682
OSSL_PARAM object[] = {
683
OSSL_PARAM_int(OSSL_OBJECT_PARAM_TYPE, (int *)&object_type),
684
OSSL_PARAM_utf8_string(OSSL_OBJECT_PARAM_DATA, NULL, 0),
685
OSSL_PARAM_END
686
};
687
char *newname = NULL;
688
int ok;
689
690
/* Loop until we get an error or until we have a suitable name */
691
do {
692
if (ctx->_.dir.last_entry == NULL) {
693
if (!ctx->_.dir.end_reached) {
694
assert(ctx->_.dir.last_errno != 0);
695
ERR_raise(ERR_LIB_SYS, ctx->_.dir.last_errno);
696
}
697
/* file_eof() will tell if EOF was reached */
698
return 0;
699
}
700
701
/* flag acceptable names */
702
if (ctx->_.dir.last_entry[0] != '.'
703
&& file_name_check(ctx, ctx->_.dir.last_entry)) {
704
705
/* If we can't allocate the new name, we fail */
706
if ((newname =
707
file_name_to_uri(ctx, ctx->_.dir.last_entry)) == NULL)
708
return 0;
709
}
710
711
/*
712
* On the first call (with a NULL context), OPENSSL_DIR_read()
713
* cares about the second argument. On the following calls, it
714
* only cares that it isn't NULL. Therefore, we can safely give
715
* it our URI here.
716
*/
717
ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, ctx->uri);
718
ctx->_.dir.last_errno = errno;
719
if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0)
720
ctx->_.dir.end_reached = 1;
721
} while (newname == NULL);
722
723
object[1].data = newname;
724
object[1].data_size = strlen(newname);
725
ok = object_cb(object, object_cbarg);
726
OPENSSL_free(newname);
727
return ok;
728
}
729
730
/*-
731
* Loading, local dispatcher
732
* -------------------------
733
*/
734
735
static int file_load(void *loaderctx,
736
OSSL_CALLBACK *object_cb, void *object_cbarg,
737
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
738
{
739
struct file_ctx_st *ctx = loaderctx;
740
741
switch (ctx->type) {
742
case IS_FILE:
743
return file_load_file(ctx, object_cb, object_cbarg, pw_cb, pw_cbarg);
744
case IS_DIR:
745
return
746
file_load_dir_entry(ctx, object_cb, object_cbarg, pw_cb, pw_cbarg);
747
default:
748
break;
749
}
750
751
/* ctx->type has an unexpected value */
752
assert(0);
753
return 0;
754
}
755
756
/*-
757
* Eof detection and closing
758
* -------------------------
759
*/
760
761
static int file_eof(void *loaderctx)
762
{
763
struct file_ctx_st *ctx = loaderctx;
764
765
switch (ctx->type) {
766
case IS_DIR:
767
return ctx->_.dir.end_reached;
768
case IS_FILE:
769
/*
770
* BIO_pending() checks any filter BIO.
771
* BIO_eof() checks the source BIO.
772
*/
773
return !BIO_pending(ctx->_.file.file)
774
&& BIO_eof(ctx->_.file.file);
775
}
776
777
/* ctx->type has an unexpected value */
778
assert(0);
779
return 1;
780
}
781
782
static int file_close_dir(struct file_ctx_st *ctx)
783
{
784
if (ctx->_.dir.ctx != NULL)
785
OPENSSL_DIR_end(&ctx->_.dir.ctx);
786
free_file_ctx(ctx);
787
return 1;
788
}
789
790
static int file_close_stream(struct file_ctx_st *ctx)
791
{
792
/*
793
* This frees either the provider BIO filter (for file_attach()) OR
794
* the allocated file BIO (for file_open()).
795
*/
796
BIO_free(ctx->_.file.file);
797
ctx->_.file.file = NULL;
798
799
free_file_ctx(ctx);
800
return 1;
801
}
802
803
static int file_close(void *loaderctx)
804
{
805
struct file_ctx_st *ctx = loaderctx;
806
807
switch (ctx->type) {
808
case IS_DIR:
809
return file_close_dir(ctx);
810
case IS_FILE:
811
return file_close_stream(ctx);
812
}
813
814
/* ctx->type has an unexpected value */
815
assert(0);
816
return 1;
817
}
818
819
const OSSL_DISPATCH ossl_file_store_functions[] = {
820
{ OSSL_FUNC_STORE_OPEN, (void (*)(void))file_open },
821
{ OSSL_FUNC_STORE_ATTACH, (void (*)(void))file_attach },
822
{ OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS,
823
(void (*)(void))file_settable_ctx_params },
824
{ OSSL_FUNC_STORE_SET_CTX_PARAMS, (void (*)(void))file_set_ctx_params },
825
{ OSSL_FUNC_STORE_LOAD, (void (*)(void))file_load },
826
{ OSSL_FUNC_STORE_EOF, (void (*)(void))file_eof },
827
{ OSSL_FUNC_STORE_CLOSE, (void (*)(void))file_close },
828
OSSL_DISPATCH_END,
829
};
830
831