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