]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/property/property_parse.c
Update copyright year
[thirdparty/openssl.git] / crypto / property / property_parse.c
CommitLineData
1bdbdaff 1/*
3c2bdd7d 2 * Copyright 2019-2021 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"
25f2138b 17#include "crypto/ctype.h"
1bdbdaff 18#include "internal/nelem.h"
706457b7 19#include "property_local.h"
1bdbdaff
P
20#include "e_os.h"
21
22typedef enum {
23 PROPERTY_TYPE_STRING, PROPERTY_TYPE_NUMBER,
24 PROPERTY_TYPE_VALUE_UNDEFINED
25} PROPERTY_TYPE;
26
27typedef enum {
28 PROPERTY_OPER_EQ, PROPERTY_OPER_NE, PROPERTY_OVERRIDE
29} PROPERTY_OPER;
30
31typedef struct {
32 OSSL_PROPERTY_IDX name_idx;
33 PROPERTY_TYPE type;
34 PROPERTY_OPER oper;
da89ac0b 35 unsigned int optional : 1;
1bdbdaff
P
36 union {
37 int64_t int_val; /* Signed integer */
38 OSSL_PROPERTY_IDX str_val; /* String */
39 } v;
40} PROPERTY_DEFINITION;
41
42struct ossl_property_list_st {
43 int n;
da89ac0b 44 unsigned int has_optional : 1;
1bdbdaff
P
45 PROPERTY_DEFINITION properties[1];
46};
47
48static OSSL_PROPERTY_IDX ossl_property_true, ossl_property_false;
49
50DEFINE_STACK_OF(PROPERTY_DEFINITION)
51
52static const char *skip_space(const char *s)
53{
54 while (ossl_isspace(*s))
55 s++;
56 return s;
57}
58
59static int match_ch(const char *t[], char m)
60{
61 const char *s = *t;
62
63 if (*s == m) {
64 *t = skip_space(s + 1);
65 return 1;
66 }
67 return 0;
68}
69
70#define MATCH(s, m) match(s, m, sizeof(m) - 1)
71
72static int match(const char *t[], const char m[], size_t m_len)
73{
74 const char *s = *t;
75
76 if (strncasecmp(s, m, m_len) == 0) {
77 *t = skip_space(s + m_len);
78 return 1;
79 }
80 return 0;
81}
82
b4250010 83static int parse_name(OSSL_LIB_CTX *ctx, const char *t[], int create,
1aedc35f 84 OSSL_PROPERTY_IDX *idx)
1bdbdaff
P
85{
86 char name[100];
87 int err = 0;
88 size_t i = 0;
89 const char *s = *t;
90 int user_name = 0;
91
92 for (;;) {
93 if (!ossl_isalpha(*s)) {
49c64346
RL
94 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER,
95 "HERE-->%s", *t);
1bdbdaff
P
96 return 0;
97 }
98 do {
99 if (i < sizeof(name) - 1)
100 name[i++] = ossl_tolower(*s);
101 else
102 err = 1;
103 } while (*++s == '_' || ossl_isalnum(*s));
104 if (*s != '.')
105 break;
106 user_name = 1;
107 if (i < sizeof(name) - 1)
108 name[i++] = *s;
109 else
110 err = 1;
111 s++;
112 }
113 name[i] = '\0';
4cdb302f 114 if (err) {
49c64346 115 ERR_raise_data(ERR_LIB_PROP, PROP_R_NAME_TOO_LONG, "HERE-->%s", *t);
4cdb302f 116 return 0;
1bdbdaff 117 }
4cdb302f
RL
118 *t = skip_space(s);
119 *idx = ossl_property_name(ctx, name, user_name && create);
120 return 1;
1bdbdaff
P
121}
122
123static int parse_number(const char *t[], PROPERTY_DEFINITION *res)
124{
125 const char *s = *t;
126 int64_t v = 0;
127
128 if (!ossl_isdigit(*s))
129 return 0;
130 do {
131 v = v * 10 + (*s++ - '0');
132 } while (ossl_isdigit(*s));
133 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
49c64346
RL
134 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT,
135 "HERE-->%s", *t);
1bdbdaff
P
136 return 0;
137 }
138 *t = skip_space(s);
139 res->type = PROPERTY_TYPE_NUMBER;
140 res->v.int_val = v;
141 return 1;
142}
143
144static int parse_hex(const char *t[], PROPERTY_DEFINITION *res)
145{
146 const char *s = *t;
147 int64_t v = 0;
148
149 if (!ossl_isxdigit(*s))
150 return 0;
151 do {
152 v <<= 4;
153 if (ossl_isdigit(*s))
154 v += *s - '0';
155 else
156 v += ossl_tolower(*s) - 'a';
157 } while (ossl_isxdigit(*++s));
158 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
49c64346
RL
159 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT,
160 "HERE-->%s", *t);
1bdbdaff
P
161 return 0;
162 }
163 *t = skip_space(s);
164 res->type = PROPERTY_TYPE_NUMBER;
165 res->v.int_val = v;
166 return 1;
167}
168
169static int parse_oct(const char *t[], PROPERTY_DEFINITION *res)
170{
171 const char *s = *t;
172 int64_t v = 0;
173
174 if (*s == '9' || *s == '8' || !ossl_isdigit(*s))
175 return 0;
176 do {
177 v = (v << 3) + (*s - '0');
178 } while (ossl_isdigit(*++s) && *s != '9' && *s != '8');
179 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
49c64346
RL
180 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT,
181 "HERE-->%s", *t);
1bdbdaff
P
182 return 0;
183 }
184 *t = skip_space(s);
185 res->type = PROPERTY_TYPE_NUMBER;
186 res->v.int_val = v;
187 return 1;
188}
189
b4250010 190static int parse_string(OSSL_LIB_CTX *ctx, const char *t[], char delim,
1aedc35f 191 PROPERTY_DEFINITION *res, const int create)
1bdbdaff
P
192{
193 char v[1000];
194 const char *s = *t;
195 size_t i = 0;
196 int err = 0;
197
198 while (*s != '\0' && *s != delim) {
199 if (i < sizeof(v) - 1)
200 v[i++] = *s;
201 else
202 err = 1;
203 s++;
204 }
205 if (*s == '\0') {
79c44b4e 206 ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER,
49c64346 207 "HERE-->%c%s", delim, *t);
1bdbdaff
P
208 return 0;
209 }
210 v[i] = '\0';
4cdb302f 211 if (err) {
49c64346 212 ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
4cdb302f 213 } else {
1aedc35f 214 res->v.str_val = ossl_property_value(ctx, v, create);
4cdb302f
RL
215 }
216 *t = skip_space(s + 1);
1bdbdaff
P
217 res->type = PROPERTY_TYPE_STRING;
218 return !err;
219}
220
b4250010 221static int parse_unquoted(OSSL_LIB_CTX *ctx, const char *t[],
1aedc35f 222 PROPERTY_DEFINITION *res, const int create)
1bdbdaff
P
223{
224 char v[1000];
225 const char *s = *t;
226 size_t i = 0;
227 int err = 0;
228
229 if (*s == '\0' || *s == ',')
230 return 0;
231 while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') {
232 if (i < sizeof(v) - 1)
233 v[i++] = ossl_tolower(*s);
234 else
235 err = 1;
236 s++;
237 }
238 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
49c64346
RL
239 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER,
240 "HERE-->%s", s);
1bdbdaff
P
241 return 0;
242 }
243 v[i] = 0;
4cdb302f 244 if (err) {
49c64346 245 ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
4cdb302f 246 } else {
1aedc35f 247 res->v.str_val = ossl_property_value(ctx, v, create);
4cdb302f
RL
248 }
249 *t = skip_space(s);
1bdbdaff
P
250 res->type = PROPERTY_TYPE_STRING;
251 return !err;
252}
253
b4250010 254static int parse_value(OSSL_LIB_CTX *ctx, const char *t[],
1aedc35f 255 PROPERTY_DEFINITION *res, int create)
1bdbdaff
P
256{
257 const char *s = *t;
258 int r = 0;
259
260 if (*s == '"' || *s == '\'') {
261 s++;
1aedc35f 262 r = parse_string(ctx, &s, s[-1], res, create);
1bdbdaff
P
263 } else if (*s == '+') {
264 s++;
265 r = parse_number(&s, res);
266 } else if (*s == '-') {
267 s++;
268 r = parse_number(&s, res);
269 res->v.int_val = -res->v.int_val;
270 } else if (*s == '0' && s[1] == 'x') {
271 s += 2;
272 r = parse_hex(&s, res);
273 } else if (*s == '0' && ossl_isdigit(s[1])) {
274 s++;
275 r = parse_oct(&s, res);
276 } else if (ossl_isdigit(*s)) {
277 return parse_number(t, res);
278 } else if (ossl_isalpha(*s))
1aedc35f 279 return parse_unquoted(ctx, t, res, create);
1bdbdaff
P
280 if (r)
281 *t = s;
282 return r;
283}
284
285static int pd_compare(const PROPERTY_DEFINITION *const *p1,
286 const PROPERTY_DEFINITION *const *p2)
287{
288 const PROPERTY_DEFINITION *pd1 = *p1;
289 const PROPERTY_DEFINITION *pd2 = *p2;
290
291 if (pd1->name_idx < pd2->name_idx)
292 return -1;
293 if (pd1->name_idx > pd2->name_idx)
294 return 1;
295 return 0;
296}
297
298static void pd_free(PROPERTY_DEFINITION *pd)
299{
300 OPENSSL_free(pd);
301}
302
303/*
304 * Convert a stack of property definitions and queries into a fixed array.
305 * The items are sorted for efficient query. The stack is not freed.
306 */
307static OSSL_PROPERTY_LIST *stack_to_property_list(STACK_OF(PROPERTY_DEFINITION)
308 *sk)
309{
310 const int n = sk_PROPERTY_DEFINITION_num(sk);
311 OSSL_PROPERTY_LIST *r;
312 int i;
313
314 r = OPENSSL_malloc(sizeof(*r)
71d1b229 315 + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0]));
1bdbdaff
P
316 if (r != NULL) {
317 sk_PROPERTY_DEFINITION_sort(sk);
318
da89ac0b
P
319 r->has_optional = 0;
320 for (i = 0; i < n; i++) {
1bdbdaff 321 r->properties[i] = *sk_PROPERTY_DEFINITION_value(sk, i);
da89ac0b
P
322 r->has_optional |= r->properties[i].optional;
323 }
1bdbdaff
P
324 r->n = n;
325 }
326 return r;
327}
328
b4250010 329OSSL_PROPERTY_LIST *ossl_parse_property(OSSL_LIB_CTX *ctx, const char *defn)
1bdbdaff
P
330{
331 PROPERTY_DEFINITION *prop = NULL;
332 OSSL_PROPERTY_LIST *res = NULL;
333 STACK_OF(PROPERTY_DEFINITION) *sk;
334 const char *s = defn;
335 int done;
336
337 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
338 return NULL;
339
340 s = skip_space(s);
341 done = *s == '\0';
342 while (!done) {
4cdb302f
RL
343 const char *start = s;
344
1bdbdaff
P
345 prop = OPENSSL_malloc(sizeof(*prop));
346 if (prop == NULL)
347 goto err;
348 memset(&prop->v, 0, sizeof(prop->v));
da89ac0b 349 prop->optional = 0;
1aedc35f 350 if (!parse_name(ctx, &s, 1, &prop->name_idx))
1bdbdaff
P
351 goto err;
352 prop->oper = PROPERTY_OPER_EQ;
353 if (prop->name_idx == 0) {
49c64346
RL
354 ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
355 "Unknown name HERE-->%s", start);
1bdbdaff
P
356 goto err;
357 }
358 if (match_ch(&s, '=')) {
1aedc35f 359 if (!parse_value(ctx, &s, prop, 1)) {
49c64346
RL
360 ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_VALUE,
361 "HERE-->%s", start);
1bdbdaff
P
362 goto err;
363 }
364 } else {
365 /* A name alone means a true Boolean */
366 prop->type = PROPERTY_TYPE_STRING;
367 prop->v.str_val = ossl_property_true;
368 }
369
370 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
371 goto err;
372 prop = NULL;
373 done = !match_ch(&s, ',');
374 }
375 if (*s != '\0') {
49c64346
RL
376 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
377 "HERE-->%s", s);
1bdbdaff
P
378 goto err;
379 }
380 res = stack_to_property_list(sk);
381
382err:
383 OPENSSL_free(prop);
384 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
385 return res;
386}
387
1e08f3ba
P
388OSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s,
389 int create_values)
1bdbdaff
P
390{
391 STACK_OF(PROPERTY_DEFINITION) *sk;
392 OSSL_PROPERTY_LIST *res = NULL;
393 PROPERTY_DEFINITION *prop = NULL;
394 int done;
395
396 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
397 return NULL;
398
399 s = skip_space(s);
400 done = *s == '\0';
401 while (!done) {
402 prop = OPENSSL_malloc(sizeof(*prop));
403 if (prop == NULL)
404 goto err;
405 memset(&prop->v, 0, sizeof(prop->v));
406
407 if (match_ch(&s, '-')) {
408 prop->oper = PROPERTY_OVERRIDE;
da89ac0b 409 prop->optional = 0;
1aedc35f 410 if (!parse_name(ctx, &s, 0, &prop->name_idx))
1bdbdaff
P
411 goto err;
412 goto skip_value;
413 }
da89ac0b 414 prop->optional = match_ch(&s, '?');
1aedc35f 415 if (!parse_name(ctx, &s, 0, &prop->name_idx))
1bdbdaff
P
416 goto err;
417
418 if (match_ch(&s, '=')) {
419 prop->oper = PROPERTY_OPER_EQ;
420 } else if (MATCH(&s, "!=")) {
421 prop->oper = PROPERTY_OPER_NE;
422 } else {
423 /* A name alone is a Boolean comparison for true */
424 prop->oper = PROPERTY_OPER_EQ;
425 prop->type = PROPERTY_TYPE_STRING;
426 prop->v.str_val = ossl_property_true;
427 goto skip_value;
428 }
1e08f3ba 429 if (!parse_value(ctx, &s, prop, create_values))
1bdbdaff
P
430 prop->type = PROPERTY_TYPE_VALUE_UNDEFINED;
431
432skip_value:
433 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
434 goto err;
435 prop = NULL;
436 done = !match_ch(&s, ',');
437 }
438 if (*s != '\0') {
49c64346
RL
439 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
440 "HERE-->%s", s);
1bdbdaff
P
441 goto err;
442 }
443 res = stack_to_property_list(sk);
444
445err:
446 OPENSSL_free(prop);
447 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
448 return res;
449}
450
da89ac0b
P
451/* Does a property query have any optional clauses */
452int ossl_property_has_optional(const OSSL_PROPERTY_LIST *query)
453{
454 return query->has_optional ? 1 : 0;
455}
456
b4250010 457int ossl_property_is_enabled(OSSL_LIB_CTX *ctx, const char *property_name,
e0624f0d
SL
458 const OSSL_PROPERTY_LIST *prop_list)
459{
460 int i;
461 OSSL_PROPERTY_IDX name_id;
462 const PROPERTY_DEFINITION *prop = NULL;
463
464 if (prop_list == NULL)
465 return 0;
466
467 if (!parse_name(ctx, &property_name, 0, &name_id))
468 return 0;
469
470 prop = prop_list->properties;
471 for (i = 0; i < prop_list->n; ++i) {
472 if (prop[i].name_idx == name_id) {
473 /* Do a separate check for override as it does not set type */
474 if (prop[i].optional || prop[i].oper == PROPERTY_OVERRIDE)
475 return 0;
476 return (prop[i].type == PROPERTY_TYPE_STRING
477 && ((prop[i].oper == PROPERTY_OPER_EQ
478 && prop[i].v.str_val == ossl_property_true)
479 || (prop[i].oper == PROPERTY_OPER_NE
480 && prop[i].v.str_val != ossl_property_true)));
481 }
482 }
483 return 0;
484}
485
da89ac0b
P
486/*
487 * Compare a query against a definition.
488 * Return the number of clauses matched or -1 if a mandatory clause is false.
489 */
490int ossl_property_match_count(const OSSL_PROPERTY_LIST *query,
491 const OSSL_PROPERTY_LIST *defn)
1bdbdaff
P
492{
493 const PROPERTY_DEFINITION *const q = query->properties;
494 const PROPERTY_DEFINITION *const d = defn->properties;
da89ac0b 495 int i = 0, j = 0, matches = 0;
1bdbdaff
P
496 PROPERTY_OPER oper;
497
498 while (i < query->n) {
499 if ((oper = q[i].oper) == PROPERTY_OVERRIDE) {
500 i++;
501 continue;
502 }
503 if (j < defn->n) {
504 if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */
505 j++;
506 continue;
507 }
508 if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */
509 const int eq = q[i].type == d[j].type
510 && memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0;
511
da89ac0b
P
512 if ((eq && oper == PROPERTY_OPER_EQ)
513 || (!eq && oper == PROPERTY_OPER_NE))
514 matches++;
515 else if (!q[i].optional)
516 return -1;
1bdbdaff
P
517 i++;
518 j++;
519 continue;
520 }
521 }
522
523 /*
524 * Handle the cases of a missing value and a query with no corresponding
79c44b4e 525 * definition. The former fails for any comparison except inequality,
1bdbdaff
P
526 * the latter is treated as a comparison against the Boolean false.
527 */
528 if (q[i].type == PROPERTY_TYPE_VALUE_UNDEFINED) {
da89ac0b
P
529 if (oper == PROPERTY_OPER_NE)
530 matches++;
531 else if (!q[i].optional)
532 return -1;
1bdbdaff
P
533 } else if (q[i].type != PROPERTY_TYPE_STRING
534 || (oper == PROPERTY_OPER_EQ
535 && q[i].v.str_val != ossl_property_false)
536 || (oper == PROPERTY_OPER_NE
537 && q[i].v.str_val == ossl_property_false)) {
da89ac0b
P
538 if (!q[i].optional)
539 return -1;
540 } else {
541 matches++;
1bdbdaff
P
542 }
543 i++;
544 }
da89ac0b 545 return matches;
1bdbdaff
P
546}
547
548void ossl_property_free(OSSL_PROPERTY_LIST *p)
549{
550 OPENSSL_free(p);
551}
552
553/*
554 * Merge two property lists.
555 * If there is a common name, the one from the first list is used.
556 */
557OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
558 const OSSL_PROPERTY_LIST *b)
559{
560 const PROPERTY_DEFINITION *const ap = a->properties;
561 const PROPERTY_DEFINITION *const bp = b->properties;
562 const PROPERTY_DEFINITION *copy;
563 OSSL_PROPERTY_LIST *r;
564 int i, j, n;
565 const int t = a->n + b->n;
566
567 r = OPENSSL_malloc(sizeof(*r)
568 + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
569 if (r == NULL)
570 return NULL;
571
e3d6dc59 572 r->has_optional = 0;
1bdbdaff
P
573 for (i = j = n = 0; i < a->n || j < b->n; n++) {
574 if (i >= a->n) {
575 copy = &bp[j++];
576 } else if (j >= b->n) {
577 copy = &ap[i++];
578 } else if (ap[i].name_idx <= bp[j].name_idx) {
579 if (ap[i].name_idx == bp[j].name_idx)
580 j++;
581 copy = &ap[i++];
582 } else {
583 copy = &bp[j++];
584 }
585 memcpy(r->properties + n, copy, sizeof(r->properties[0]));
e3d6dc59 586 r->has_optional |= copy->optional;
1bdbdaff
P
587 }
588 r->n = n;
589 if (n != t)
590 r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
591 return r;
592}
593
b4250010 594int ossl_property_parse_init(OSSL_LIB_CTX *ctx)
1bdbdaff
P
595{
596 static const char *const predefined_names[] = {
745fc918 597 "provider", /* Name of provider (default, legacy, fips) */
1bdbdaff 598 "version", /* Version number of this provider */
745fc918 599 "fips", /* FIPS validated or FIPS supporting algorithm */
5a6d6fe6
RL
600 "output", /* Output type for encoders */
601 "input", /* Input type for decoders */
602 "structure", /* Structure name for encoders and decoders */
1bdbdaff
P
603 };
604 size_t i;
605
606 for (i = 0; i < OSSL_NELEM(predefined_names); i++)
1aedc35f 607 if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
1bdbdaff
P
608 goto err;
609
610 /* Pre-populate the two Boolean values */
1aedc35f
MC
611 if ((ossl_property_true = ossl_property_value(ctx, "yes", 1)) == 0
612 || (ossl_property_false = ossl_property_value(ctx, "no", 1)) == 0)
1bdbdaff
P
613 goto err;
614
615 return 1;
616err:
617 return 0;
618}