Coverage Report

Created: 2024-02-11 06:38

/src/openssl/crypto/property/property_parse.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved.
3
 * Copyright (c) 2019, Oracle and/or its affiliates.  All rights reserved.
4
 *
5
 * Licensed under the Apache License 2.0 (the "License").  You may not use
6
 * this file except in compliance with the License.  You can obtain a copy
7
 * in the file LICENSE in the source distribution or at
8
 * https://www.openssl.org/source/license.html
9
 */
10
11
#include <string.h>
12
#include <stdio.h>
13
#include <stdarg.h>
14
#include <openssl/err.h>
15
#include "internal/propertyerr.h"
16
#include "internal/property.h"
17
#include "crypto/ctype.h"
18
#include "internal/nelem.h"
19
#include "property_local.h"
20
#include "internal/e_os.h"
21
22
DEFINE_STACK_OF(OSSL_PROPERTY_DEFINITION)
23
24
static const char *skip_space(const char *s)
25
49.8k
{
26
49.8k
    while (ossl_isspace(*s))
27
0
        s++;
28
49.8k
    return s;
29
49.8k
}
30
31
static int match_ch(const char *t[], char m)
32
24.6k
{
33
24.6k
    const char *s = *t;
34
35
24.6k
    if (*s == m) {
36
21.3k
        *t = skip_space(s + 1);
37
21.3k
        return 1;
38
21.3k
    }
39
3.25k
    return 0;
40
24.6k
}
41
42
0
#define MATCH(s, m) match(s, m, sizeof(m) - 1)
43
44
static int match(const char *t[], const char m[], size_t m_len)
45
0
{
46
0
    const char *s = *t;
47
48
0
    if (OPENSSL_strncasecmp(s, m, m_len) == 0) {
49
0
        *t = skip_space(s + m_len);
50
0
        return 1;
51
0
    }
52
0
    return 0;
53
0
}
54
55
static int parse_name(OSSL_LIB_CTX *ctx, const char *t[], int create,
56
                      OSSL_PROPERTY_IDX *idx)
57
12.3k
{
58
12.3k
    char name[100];
59
12.3k
    int err = 0;
60
12.3k
    size_t i = 0;
61
12.3k
    const char *s = *t;
62
12.3k
    int user_name = 0;
63
64
12.3k
    for (;;) {
65
12.3k
        if (!ossl_isalpha(*s)) {
66
0
            ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER,
67
0
                           "HERE-->%s", *t);
68
0
            return 0;
69
0
        }
70
80.4k
        do {
71
80.4k
            if (i < sizeof(name) - 1)
72
80.4k
                name[i++] = ossl_tolower(*s);
73
0
            else
74
0
                err = 1;
75
80.4k
        } while (*++s == '_' || ossl_isalnum(*s));
76
12.3k
        if (*s != '.')
77
12.3k
            break;
78
0
        user_name = 1;
79
0
        if (i < sizeof(name) - 1)
80
0
            name[i++] = *s;
81
0
        else
82
0
            err = 1;
83
0
        s++;
84
0
    }
85
12.3k
    name[i] = '\0';
86
12.3k
    if (err) {
87
0
        ERR_raise_data(ERR_LIB_PROP, PROP_R_NAME_TOO_LONG, "HERE-->%s", *t);
88
0
        return 0;
89
0
    }
90
12.3k
    *t = skip_space(s);
91
12.3k
    *idx = ossl_property_name(ctx, name, user_name && create);
92
12.3k
    return 1;
93
12.3k
}
94
95
static int parse_number(const char *t[], OSSL_PROPERTY_DEFINITION *res)
96
0
{
97
0
    const char *s = *t;
98
0
    int64_t v = 0;
99
100
0
    do {
101
0
        if (!ossl_isdigit(*s)) {
102
0
            ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT,
103
0
                           "HERE-->%s", *t);
104
0
            return 0;
105
0
        }
106
        /* overflow check */
107
0
        if (v > ((INT64_MAX - (*s - '0')) / 10)) {
108
0
            ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
109
0
                           "Property %s overflows", *t);
110
0
            return 0;
111
0
        }
112
0
        v = v * 10 + (*s++ - '0');
113
0
    } while (ossl_isdigit(*s));
114
0
    if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
115
0
        ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT,
116
0
                       "HERE-->%s", *t);
117
0
        return 0;
118
0
    }
119
0
    *t = skip_space(s);
120
0
    res->type = OSSL_PROPERTY_TYPE_NUMBER;
121
0
    res->v.int_val = v;
122
0
    return 1;
123
0
}
124
125
static int parse_hex(const char *t[], OSSL_PROPERTY_DEFINITION *res)
126
0
{
127
0
    const char *s = *t;
128
0
    int64_t v = 0;
129
0
    int sval;
130
131
0
    do {
132
0
        if (ossl_isdigit(*s)) {
133
0
            sval = *s - '0';
134
0
        } else if (ossl_isxdigit(*s)) {
135
0
            sval = ossl_tolower(*s) - 'a' + 10;
136
0
        } else {
137
0
            ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT,
138
0
                           "%s", *t);
139
0
            return 0;
140
0
        }
141
142
0
        if (v > ((INT64_MAX - sval) / 16)) {
143
0
            ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
144
0
                           "Property %s overflows", *t);
145
0
            return 0;
146
0
        }
147
148
0
        v <<= 4;
149
0
        v += sval;
150
0
    } while (ossl_isxdigit(*++s));
151
0
    if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
152
0
        ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT,
153
0
                       "HERE-->%s", *t);
154
0
        return 0;
155
0
    }
156
0
    *t = skip_space(s);
157
0
    res->type = OSSL_PROPERTY_TYPE_NUMBER;
158
0
    res->v.int_val = v;
159
0
    return 1;
160
0
}
161
162
static int parse_oct(const char *t[], OSSL_PROPERTY_DEFINITION *res)
163
0
{
164
0
    const char *s = *t;
165
0
    int64_t v = 0;
166
167
0
    do {
168
0
        if (*s == '9' || *s == '8' || !ossl_isdigit(*s)) {
169
0
            ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT,
170
0
                           "HERE-->%s", *t);
171
0
            return 0;
172
0
        }
173
0
        if (v > ((INT64_MAX - (*s - '0')) / 8)) {
174
0
            ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
175
0
                           "Property %s overflows", *t);
176
0
            return 0;
177
0
        }
178
179
0
        v = (v << 3) + (*s - '0');
180
0
    } while (ossl_isdigit(*++s) && *s != '9' && *s != '8');
181
0
    if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
182
0
        ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT,
183
0
                       "HERE-->%s", *t);
184
0
        return 0;
185
0
    }
186
0
    *t = skip_space(s);
187
0
    res->type = OSSL_PROPERTY_TYPE_NUMBER;
188
0
    res->v.int_val = v;
189
0
    return 1;
190
0
}
191
192
static int parse_string(OSSL_LIB_CTX *ctx, const char *t[], char delim,
193
                        OSSL_PROPERTY_DEFINITION *res, const int create)
194
0
{
195
0
    char v[1000];
196
0
    const char *s = *t;
197
0
    size_t i = 0;
198
0
    int err = 0;
199
200
0
    while (*s != '\0' && *s != delim) {
201
0
        if (i < sizeof(v) - 1)
202
0
            v[i++] = *s;
203
0
        else
204
0
            err = 1;
205
0
        s++;
206
0
    }
207
0
    if (*s == '\0') {
208
0
        ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER,
209
0
                       "HERE-->%c%s", delim, *t);
210
0
        return 0;
211
0
    }
212
0
    v[i] = '\0';
213
0
    if (err) {
214
0
        ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
215
0
    } else {
216
0
        res->v.str_val = ossl_property_value(ctx, v, create);
217
0
    }
218
0
    *t = skip_space(s + 1);
219
0
    res->type = OSSL_PROPERTY_TYPE_STRING;
220
0
    return !err;
221
0
}
222
223
static int parse_unquoted(OSSL_LIB_CTX *ctx, const char *t[],
224
                          OSSL_PROPERTY_DEFINITION *res, const int create)
225
12.2k
{
226
12.2k
    char v[1000];
227
12.2k
    const char *s = *t;
228
12.2k
    size_t i = 0;
229
12.2k
    int err = 0;
230
231
12.2k
    if (*s == '\0' || *s == ',')
232
0
        return 0;
233
91.3k
    while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') {
234
79.0k
        if (i < sizeof(v) - 1)
235
79.0k
            v[i++] = ossl_tolower(*s);
236
0
        else
237
0
            err = 1;
238
79.0k
        s++;
239
79.0k
    }
240
12.2k
    if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
241
0
        ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER,
242
0
                       "HERE-->%s", s);
243
0
        return 0;
244
0
    }
245
12.2k
    v[i] = 0;
246
12.2k
    if (err)
247
0
        ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
248
12.2k
    else if ((res->v.str_val = ossl_property_value(ctx, v, create)) == 0)
249
0
        err = 1;
250
12.2k
    *t = skip_space(s);
251
12.2k
    res->type = OSSL_PROPERTY_TYPE_STRING;
252
12.2k
    return !err;
253
12.2k
}
254
255
static int parse_value(OSSL_LIB_CTX *ctx, const char *t[],
256
                       OSSL_PROPERTY_DEFINITION *res, int create)
257
12.2k
{
258
12.2k
    const char *s = *t;
259
12.2k
    int r = 0;
260
261
12.2k
    if (*s == '"' || *s == '\'') {
262
0
        s++;
263
0
        r = parse_string(ctx, &s, s[-1], res, create);
264
12.2k
    } else if (*s == '+') {
265
0
        s++;
266
0
        r = parse_number(&s, res);
267
12.2k
    } else if (*s == '-') {
268
0
        s++;
269
0
        r = parse_number(&s, res);
270
0
        res->v.int_val = -res->v.int_val;
271
12.2k
    } else if (*s == '0' && s[1] == 'x') {
272
0
        s += 2;
273
0
        r = parse_hex(&s, res);
274
12.2k
    } else if (*s == '0' && ossl_isdigit(s[1])) {
275
0
        s++;
276
0
        r = parse_oct(&s, res);
277
12.2k
    } else if (ossl_isdigit(*s)) {
278
0
        return parse_number(t, res);
279
12.2k
    } else if (ossl_isalpha(*s))
280
12.2k
        return parse_unquoted(ctx, t, res, create);
281
0
    if (r)
282
0
        *t = s;
283
0
    return r;
284
12.2k
}
285
286
static int pd_compare(const OSSL_PROPERTY_DEFINITION *const *p1,
287
                      const OSSL_PROPERTY_DEFINITION *const *p2)
288
11.7k
{
289
11.7k
    const OSSL_PROPERTY_DEFINITION *pd1 = *p1;
290
11.7k
    const OSSL_PROPERTY_DEFINITION *pd2 = *p2;
291
292
11.7k
    if (pd1->name_idx < pd2->name_idx)
293
11.7k
        return -1;
294
0
    if (pd1->name_idx > pd2->name_idx)
295
0
        return 1;
296
0
    return 0;
297
0
}
298
299
static void pd_free(OSSL_PROPERTY_DEFINITION *pd)
300
12.3k
{
301
12.3k
    OPENSSL_free(pd);
302
12.3k
}
303
304
/*
305
 * Convert a stack of property definitions and queries into a fixed array.
306
 * The items are sorted for efficient query.  The stack is not freed.
307
 * This function also checks for duplicated names and returns an error if
308
 * any exist.
309
 */
310
static OSSL_PROPERTY_LIST *
311
stack_to_property_list(OSSL_LIB_CTX *ctx,
312
                       STACK_OF(OSSL_PROPERTY_DEFINITION) *sk)
313
3.90k
{
314
3.90k
    const int n = sk_OSSL_PROPERTY_DEFINITION_num(sk);
315
3.90k
    OSSL_PROPERTY_LIST *r;
316
3.90k
    OSSL_PROPERTY_IDX prev_name_idx = 0;
317
3.90k
    int i;
318
319
3.90k
    r = OPENSSL_malloc(sizeof(*r)
320
3.90k
                       + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0]));
321
3.90k
    if (r != NULL) {
322
3.90k
        sk_OSSL_PROPERTY_DEFINITION_sort(sk);
323
324
3.90k
        r->has_optional = 0;
325
16.2k
        for (i = 0; i < n; i++) {
326
12.3k
            r->properties[i] = *sk_OSSL_PROPERTY_DEFINITION_value(sk, i);
327
12.3k
            r->has_optional |= r->properties[i].optional;
328
329
            /* Check for duplicated names */
330
12.3k
            if (i > 0 && r->properties[i].name_idx == prev_name_idx) {
331
0
                OPENSSL_free(r);
332
0
                ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
333
0
                               "Duplicated name `%s'",
334
0
                               ossl_property_name_str(ctx, prev_name_idx));
335
0
                return NULL;
336
0
            }
337
12.3k
            prev_name_idx = r->properties[i].name_idx;
338
12.3k
        }
339
3.90k
        r->num_properties = n;
340
3.90k
    }
341
3.90k
    return r;
342
3.90k
}
343
344
OSSL_PROPERTY_LIST *ossl_parse_property(OSSL_LIB_CTX *ctx, const char *defn)
345
3.23k
{
346
3.23k
    OSSL_PROPERTY_DEFINITION *prop = NULL;
347
3.23k
    OSSL_PROPERTY_LIST *res = NULL;
348
3.23k
    STACK_OF(OSSL_PROPERTY_DEFINITION) *sk;
349
3.23k
    const char *s = defn;
350
3.23k
    int done;
351
352
3.23k
    if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
353
0
        return NULL;
354
355
3.23k
    s = skip_space(s);
356
3.23k
    done = *s == '\0';
357
15.5k
    while (!done) {
358
12.2k
        const char *start = s;
359
360
12.2k
        prop = OPENSSL_malloc(sizeof(*prop));
361
12.2k
        if (prop == NULL)
362
0
            goto err;
363
12.2k
        memset(&prop->v, 0, sizeof(prop->v));
364
12.2k
        prop->optional = 0;
365
12.2k
        if (!parse_name(ctx, &s, 1, &prop->name_idx))
366
0
            goto err;
367
12.2k
        prop->oper = OSSL_PROPERTY_OPER_EQ;
368
12.2k
        if (prop->name_idx == 0) {
369
0
            ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
370
0
                           "Unknown name HERE-->%s", start);
371
0
            goto err;
372
0
        }
373
12.2k
        if (match_ch(&s, '=')) {
374
12.2k
            if (!parse_value(ctx, &s, prop, 1)) {
375
0
                ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_VALUE,
376
0
                               "HERE-->%s", start);
377
0
                goto err;
378
0
            }
379
12.2k
        } else {
380
            /* A name alone means a true Boolean */
381
0
            prop->type = OSSL_PROPERTY_TYPE_STRING;
382
0
            prop->v.str_val = OSSL_PROPERTY_TRUE;
383
0
        }
384
385
12.2k
        if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop))
386
0
            goto err;
387
12.2k
        prop = NULL;
388
12.2k
        done = !match_ch(&s, ',');
389
12.2k
    }
390
3.23k
    if (*s != '\0') {
391
0
        ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
392
0
                       "HERE-->%s", s);
393
0
        goto err;
394
0
    }
395
3.23k
    res = stack_to_property_list(ctx, sk);
396
397
3.23k
err:
398
3.23k
    OPENSSL_free(prop);
399
3.23k
    sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
400
3.23k
    return res;
401
3.23k
}
402
403
OSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s,
404
                                     int create_values)
405
671
{
406
671
    STACK_OF(OSSL_PROPERTY_DEFINITION) *sk;
407
671
    OSSL_PROPERTY_LIST *res = NULL;
408
671
    OSSL_PROPERTY_DEFINITION *prop = NULL;
409
671
    int done;
410
411
671
    if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
412
0
        return NULL;
413
414
671
    s = skip_space(s);
415
671
    done = *s == '\0';
416
694
    while (!done) {
417
23
        prop = OPENSSL_malloc(sizeof(*prop));
418
23
        if (prop == NULL)
419
0
            goto err;
420
23
        memset(&prop->v, 0, sizeof(prop->v));
421
422
23
        if (match_ch(&s, '-')) {
423
23
            prop->oper = OSSL_PROPERTY_OVERRIDE;
424
23
            prop->optional = 0;
425
23
            if (!parse_name(ctx, &s, 1, &prop->name_idx))
426
0
                goto err;
427
23
            goto skip_value;
428
23
        }
429
0
        prop->optional = match_ch(&s, '?');
430
0
        if (!parse_name(ctx, &s, 1, &prop->name_idx))
431
0
            goto err;
432
433
0
        if (match_ch(&s, '=')) {
434
0
            prop->oper = OSSL_PROPERTY_OPER_EQ;
435
0
        } else if (MATCH(&s, "!=")) {
436
0
            prop->oper = OSSL_PROPERTY_OPER_NE;
437
0
        } else {
438
            /* A name alone is a Boolean comparison for true */
439
0
            prop->oper = OSSL_PROPERTY_OPER_EQ;
440
0
            prop->type = OSSL_PROPERTY_TYPE_STRING;
441
0
            prop->v.str_val = OSSL_PROPERTY_TRUE;
442
0
            goto skip_value;
443
0
        }
444
0
        if (!parse_value(ctx, &s, prop, create_values))
445
0
            prop->type = OSSL_PROPERTY_TYPE_VALUE_UNDEFINED;
446
447
23
skip_value:
448
23
        if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop))
449
0
            goto err;
450
23
        prop = NULL;
451
23
        done = !match_ch(&s, ',');
452
23
    }
453
671
    if (*s != '\0') {
454
0
        ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
455
0
                       "HERE-->%s", s);
456
0
        goto err;
457
0
    }
458
671
    res = stack_to_property_list(ctx, sk);
459
460
671
err:
461
671
    OPENSSL_free(prop);
462
671
    sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
463
671
    return res;
464
671
}
465
466
/*
467
 * Compare a query against a definition.
468
 * Return the number of clauses matched or -1 if a mandatory clause is false.
469
 */
470
int ossl_property_match_count(const OSSL_PROPERTY_LIST *query,
471
                              const OSSL_PROPERTY_LIST *defn)
472
671
{
473
671
    const OSSL_PROPERTY_DEFINITION *const q = query->properties;
474
671
    const OSSL_PROPERTY_DEFINITION *const d = defn->properties;
475
671
    int i = 0, j = 0, matches = 0;
476
671
    OSSL_PROPERTY_OPER oper;
477
478
694
    while (i < query->num_properties) {
479
23
        if ((oper = q[i].oper) == OSSL_PROPERTY_OVERRIDE) {
480
23
            i++;
481
23
            continue;
482
23
        }
483
0
        if (j < defn->num_properties) {
484
0
            if (q[i].name_idx > d[j].name_idx) {  /* skip defn, not in query */
485
0
                j++;
486
0
                continue;
487
0
            }
488
0
            if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */
489
0
                const int eq = q[i].type == d[j].type
490
0
                               && memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0;
491
492
0
                if ((eq && oper == OSSL_PROPERTY_OPER_EQ)
493
0
                    || (!eq && oper == OSSL_PROPERTY_OPER_NE))
494
0
                    matches++;
495
0
                else if (!q[i].optional)
496
0
                    return -1;
497
0
                i++;
498
0
                j++;
499
0
                continue;
500
0
            }
501
0
        }
502
503
        /*
504
         * Handle the cases of a missing value and a query with no corresponding
505
         * definition.  The former fails for any comparison except inequality,
506
         * the latter is treated as a comparison against the Boolean false.
507
         */
508
0
        if (q[i].type == OSSL_PROPERTY_TYPE_VALUE_UNDEFINED) {
509
0
            if (oper == OSSL_PROPERTY_OPER_NE)
510
0
                matches++;
511
0
            else if (!q[i].optional)
512
0
                return -1;
513
0
        } else if (q[i].type != OSSL_PROPERTY_TYPE_STRING
514
0
                   || (oper == OSSL_PROPERTY_OPER_EQ
515
0
                       && q[i].v.str_val != OSSL_PROPERTY_FALSE)
516
0
                   || (oper == OSSL_PROPERTY_OPER_NE
517
0
                       && q[i].v.str_val == OSSL_PROPERTY_FALSE)) {
518
0
            if (!q[i].optional)
519
0
                return -1;
520
0
        } else {
521
0
            matches++;
522
0
        }
523
0
        i++;
524
0
    }
525
671
    return matches;
526
671
}
527
528
void ossl_property_free(OSSL_PROPERTY_LIST *p)
529
3.99k
{
530
3.99k
    OPENSSL_free(p);
531
3.99k
}
532
533
/*
534
 * Merge two property lists.
535
 * If there is a common name, the one from the first list is used.
536
 */
537
OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
538
                                        const OSSL_PROPERTY_LIST *b)
539
0
{
540
0
    const OSSL_PROPERTY_DEFINITION *const ap = a->properties;
541
0
    const OSSL_PROPERTY_DEFINITION *const bp = b->properties;
542
0
    const OSSL_PROPERTY_DEFINITION *copy;
543
0
    OSSL_PROPERTY_LIST *r;
544
0
    int i, j, n;
545
0
    const int t = a->num_properties + b->num_properties;
546
547
0
    r = OPENSSL_malloc(sizeof(*r)
548
0
                       + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
549
0
    if (r == NULL)
550
0
        return NULL;
551
552
0
    r->has_optional = 0;
553
0
    for (i = j = n = 0; i < a->num_properties || j < b->num_properties; n++) {
554
0
        if (i >= a->num_properties) {
555
0
            copy = &bp[j++];
556
0
        } else if (j >= b->num_properties) {
557
0
            copy = &ap[i++];
558
0
        } else if (ap[i].name_idx <= bp[j].name_idx) {
559
0
            if (ap[i].name_idx == bp[j].name_idx)
560
0
                j++;
561
0
            copy = &ap[i++];
562
0
        } else {
563
0
            copy = &bp[j++];
564
0
        }
565
0
        memcpy(r->properties + n, copy, sizeof(r->properties[0]));
566
0
        r->has_optional |= copy->optional;
567
0
    }
568
0
    r->num_properties = n;
569
0
    if (n != t)
570
0
        r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
571
0
    return r;
572
0
}
573
574
int ossl_property_parse_init(OSSL_LIB_CTX *ctx)
575
157
{
576
157
    static const char *const predefined_names[] = {
577
157
        "provider",     /* Name of provider (default, legacy, fips) */
578
157
        "version",      /* Version number of this provider */
579
157
        "fips",         /* FIPS validated or FIPS supporting algorithm */
580
157
        "output",       /* Output type for encoders */
581
157
        "input",        /* Input type for decoders */
582
157
        "structure",    /* Structure name for encoders and decoders */
583
157
    };
584
157
    size_t i;
585
586
1.09k
    for (i = 0; i < OSSL_NELEM(predefined_names); i++)
587
942
        if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
588
0
            goto err;
589
590
    /*
591
     * Pre-populate the two Boolean values. We must do them before any other
592
     * values and in this order so that we get the same index as the global
593
     * OSSL_PROPERTY_TRUE and OSSL_PROPERTY_FALSE values
594
     */
595
157
    if ((ossl_property_value(ctx, "yes", 1) != OSSL_PROPERTY_TRUE)
596
157
        || (ossl_property_value(ctx, "no", 1) != OSSL_PROPERTY_FALSE))
597
0
        goto err;
598
599
157
    return 1;
600
0
err:
601
0
    return 0;
602
157
}
603
604
static void put_char(char ch, char **buf, size_t *remain, size_t *needed)
605
0
{
606
0
    if (*remain == 0) {
607
0
        ++*needed;
608
0
        return;
609
0
    }
610
0
    if (*remain == 1)
611
0
        **buf = '\0';
612
0
    else
613
0
        **buf = ch;
614
0
    ++*buf;
615
0
    ++*needed;
616
0
    --*remain;
617
0
}
618
619
static void put_str(const char *str, char **buf, size_t *remain, size_t *needed)
620
0
{
621
0
    size_t olen, len, i;
622
0
    char quote = '\0';
623
0
    int quotes;
624
625
0
    len = olen = strlen(str);
626
0
    *needed += len;
627
628
    /*
629
     * Check to see if we need quotes or not.
630
     * Characters that are legal in a PropertyName don't need quoting.
631
     * We simply assume all others require quotes.
632
     */
633
0
    for (i = 0; i < len; i++)
634
0
        if (!ossl_isalnum(str[i]) && str[i] != '.' && str[i] != '_') {
635
            /* Default to single quotes ... */
636
0
            if (quote == '\0')
637
0
                quote = '\'';
638
            /* ... but use double quotes if a single is present */
639
0
            if (str[i] == '\'')
640
0
                quote = '"';
641
0
        }
642
643
0
    quotes = quote != '\0';
644
0
    if (*remain == 0) {
645
0
        *needed += 2 * quotes;
646
0
        return;
647
0
    }
648
649
0
    if (quotes)
650
0
        put_char(quote, buf, remain, needed);
651
652
0
    if (*remain < len + 1 + quotes)
653
0
        len = *remain - 1;
654
655
0
    if (len > 0) {
656
0
        memcpy(*buf, str, len);
657
0
        *buf += len;
658
0
        *remain -= len;
659
0
    }
660
661
0
    if (quotes)
662
0
        put_char(quote, buf, remain, needed);
663
664
0
    if (len < olen && *remain == 1) {
665
0
        **buf = '\0';
666
0
        ++*buf;
667
0
        --*remain;
668
0
    }
669
0
}
670
671
static void put_num(int64_t val, char **buf, size_t *remain, size_t *needed)
672
0
{
673
0
    int64_t tmpval = val;
674
0
    size_t len = 1;
675
676
0
    if (tmpval < 0) {
677
0
        len++;
678
0
        tmpval = -tmpval;
679
0
    }
680
0
    for (; tmpval > 9; len++, tmpval /= 10);
681
682
0
    *needed += len;
683
684
0
    if (*remain == 0)
685
0
        return;
686
687
0
    BIO_snprintf(*buf, *remain, "%lld", (long long int)val);
688
0
    if (*remain < len) {
689
0
        *buf += *remain;
690
0
        *remain = 0;
691
0
    } else {
692
0
        *buf += len;
693
0
        *remain -= len;
694
0
    }
695
0
}
696
697
size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx,
698
                                    const OSSL_PROPERTY_LIST *list, char *buf,
699
                                    size_t bufsize)
700
0
{
701
0
    int i;
702
0
    const OSSL_PROPERTY_DEFINITION *prop = NULL;
703
0
    size_t needed = 0;
704
0
    const char *val;
705
706
0
    if (list == NULL) {
707
0
        if (bufsize > 0)
708
0
            *buf = '\0';
709
0
        return 1;
710
0
    }
711
0
    if (list->num_properties != 0)
712
0
        prop = &list->properties[list->num_properties - 1];
713
0
    for (i = 0; i < list->num_properties; i++, prop--) {
714
        /* Skip invalid names */
715
0
        if (prop->name_idx == 0)
716
0
            continue;
717
718
0
        if (needed > 0)
719
0
            put_char(',', &buf, &bufsize, &needed);
720
721
0
        if (prop->optional)
722
0
            put_char('?', &buf, &bufsize, &needed);
723
0
        else if (prop->oper == OSSL_PROPERTY_OVERRIDE)
724
0
            put_char('-', &buf, &bufsize, &needed);
725
726
0
        val = ossl_property_name_str(ctx, prop->name_idx);
727
0
        if (val == NULL)
728
0
            return 0;
729
0
        put_str(val, &buf, &bufsize, &needed);
730
731
0
        switch (prop->oper) {
732
0
            case OSSL_PROPERTY_OPER_NE:
733
0
                put_char('!', &buf, &bufsize, &needed);
734
                /* fall through */
735
0
            case OSSL_PROPERTY_OPER_EQ:
736
0
                put_char('=', &buf, &bufsize, &needed);
737
                /* put value */
738
0
                switch (prop->type) {
739
0
                case OSSL_PROPERTY_TYPE_STRING:
740
0
                    val = ossl_property_value_str(ctx, prop->v.str_val);
741
0
                    if (val == NULL)
742
0
                        return 0;
743
0
                    put_str(val, &buf, &bufsize, &needed);
744
0
                    break;
745
746
0
                case OSSL_PROPERTY_TYPE_NUMBER:
747
0
                    put_num(prop->v.int_val, &buf, &bufsize, &needed);
748
0
                    break;
749
750
0
                default:
751
0
                    return 0;
752
0
                }
753
0
                break;
754
0
            default:
755
                /* do nothing */
756
0
                break;
757
0
        }
758
0
    }
759
760
0
    put_char('\0', &buf, &bufsize, &needed);
761
0
    return needed;
762
0
}