Coverage Report

Created: 2025-11-16 06:40

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