]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/property/property_parse.c
Rename OPENSSL_CTX prefix to OSSL_LIB_CTX
[thirdparty/openssl.git] / crypto / property / property_parse.c
CommitLineData
1bdbdaff 1/*
33388b44 2 * Copyright 2019-2020 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
b4250010 388OSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s)
1bdbdaff
P
389{
390 STACK_OF(PROPERTY_DEFINITION) *sk;
391 OSSL_PROPERTY_LIST *res = NULL;
392 PROPERTY_DEFINITION *prop = NULL;
393 int done;
394
395 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
396 return NULL;
397
398 s = skip_space(s);
399 done = *s == '\0';
400 while (!done) {
401 prop = OPENSSL_malloc(sizeof(*prop));
402 if (prop == NULL)
403 goto err;
404 memset(&prop->v, 0, sizeof(prop->v));
405
406 if (match_ch(&s, '-')) {
407 prop->oper = PROPERTY_OVERRIDE;
da89ac0b 408 prop->optional = 0;
1aedc35f 409 if (!parse_name(ctx, &s, 0, &prop->name_idx))
1bdbdaff
P
410 goto err;
411 goto skip_value;
412 }
da89ac0b 413 prop->optional = match_ch(&s, '?');
1aedc35f 414 if (!parse_name(ctx, &s, 0, &prop->name_idx))
1bdbdaff
P
415 goto err;
416
417 if (match_ch(&s, '=')) {
418 prop->oper = PROPERTY_OPER_EQ;
419 } else if (MATCH(&s, "!=")) {
420 prop->oper = PROPERTY_OPER_NE;
421 } else {
422 /* A name alone is a Boolean comparison for true */
423 prop->oper = PROPERTY_OPER_EQ;
424 prop->type = PROPERTY_TYPE_STRING;
425 prop->v.str_val = ossl_property_true;
426 goto skip_value;
427 }
1aedc35f 428 if (!parse_value(ctx, &s, prop, 0))
1bdbdaff
P
429 prop->type = PROPERTY_TYPE_VALUE_UNDEFINED;
430
431skip_value:
432 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
433 goto err;
434 prop = NULL;
435 done = !match_ch(&s, ',');
436 }
437 if (*s != '\0') {
49c64346
RL
438 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
439 "HERE-->%s", s);
1bdbdaff
P
440 goto err;
441 }
442 res = stack_to_property_list(sk);
443
444err:
445 OPENSSL_free(prop);
446 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
447 return res;
448}
449
da89ac0b
P
450/* Does a property query have any optional clauses */
451int ossl_property_has_optional(const OSSL_PROPERTY_LIST *query)
452{
453 return query->has_optional ? 1 : 0;
454}
455
b4250010 456int ossl_property_is_enabled(OSSL_LIB_CTX *ctx, const char *property_name,
e0624f0d
SL
457 const OSSL_PROPERTY_LIST *prop_list)
458{
459 int i;
460 OSSL_PROPERTY_IDX name_id;
461 const PROPERTY_DEFINITION *prop = NULL;
462
463 if (prop_list == NULL)
464 return 0;
465
466 if (!parse_name(ctx, &property_name, 0, &name_id))
467 return 0;
468
469 prop = prop_list->properties;
470 for (i = 0; i < prop_list->n; ++i) {
471 if (prop[i].name_idx == name_id) {
472 /* Do a separate check for override as it does not set type */
473 if (prop[i].optional || prop[i].oper == PROPERTY_OVERRIDE)
474 return 0;
475 return (prop[i].type == PROPERTY_TYPE_STRING
476 && ((prop[i].oper == PROPERTY_OPER_EQ
477 && prop[i].v.str_val == ossl_property_true)
478 || (prop[i].oper == PROPERTY_OPER_NE
479 && prop[i].v.str_val != ossl_property_true)));
480 }
481 }
482 return 0;
483}
484
da89ac0b
P
485/*
486 * Compare a query against a definition.
487 * Return the number of clauses matched or -1 if a mandatory clause is false.
488 */
489int ossl_property_match_count(const OSSL_PROPERTY_LIST *query,
490 const OSSL_PROPERTY_LIST *defn)
1bdbdaff
P
491{
492 const PROPERTY_DEFINITION *const q = query->properties;
493 const PROPERTY_DEFINITION *const d = defn->properties;
da89ac0b 494 int i = 0, j = 0, matches = 0;
1bdbdaff
P
495 PROPERTY_OPER oper;
496
497 while (i < query->n) {
498 if ((oper = q[i].oper) == PROPERTY_OVERRIDE) {
499 i++;
500 continue;
501 }
502 if (j < defn->n) {
503 if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */
504 j++;
505 continue;
506 }
507 if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */
508 const int eq = q[i].type == d[j].type
509 && memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0;
510
da89ac0b
P
511 if ((eq && oper == PROPERTY_OPER_EQ)
512 || (!eq && oper == PROPERTY_OPER_NE))
513 matches++;
514 else if (!q[i].optional)
515 return -1;
1bdbdaff
P
516 i++;
517 j++;
518 continue;
519 }
520 }
521
522 /*
523 * Handle the cases of a missing value and a query with no corresponding
79c44b4e 524 * definition. The former fails for any comparison except inequality,
1bdbdaff
P
525 * the latter is treated as a comparison against the Boolean false.
526 */
527 if (q[i].type == PROPERTY_TYPE_VALUE_UNDEFINED) {
da89ac0b
P
528 if (oper == PROPERTY_OPER_NE)
529 matches++;
530 else if (!q[i].optional)
531 return -1;
1bdbdaff
P
532 } else if (q[i].type != PROPERTY_TYPE_STRING
533 || (oper == PROPERTY_OPER_EQ
534 && q[i].v.str_val != ossl_property_false)
535 || (oper == PROPERTY_OPER_NE
536 && q[i].v.str_val == ossl_property_false)) {
da89ac0b
P
537 if (!q[i].optional)
538 return -1;
539 } else {
540 matches++;
1bdbdaff
P
541 }
542 i++;
543 }
da89ac0b 544 return matches;
1bdbdaff
P
545}
546
547void ossl_property_free(OSSL_PROPERTY_LIST *p)
548{
549 OPENSSL_free(p);
550}
551
552/*
553 * Merge two property lists.
554 * If there is a common name, the one from the first list is used.
555 */
556OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
557 const OSSL_PROPERTY_LIST *b)
558{
559 const PROPERTY_DEFINITION *const ap = a->properties;
560 const PROPERTY_DEFINITION *const bp = b->properties;
561 const PROPERTY_DEFINITION *copy;
562 OSSL_PROPERTY_LIST *r;
563 int i, j, n;
564 const int t = a->n + b->n;
565
566 r = OPENSSL_malloc(sizeof(*r)
567 + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
568 if (r == NULL)
569 return NULL;
570
e3d6dc59 571 r->has_optional = 0;
1bdbdaff
P
572 for (i = j = n = 0; i < a->n || j < b->n; n++) {
573 if (i >= a->n) {
574 copy = &bp[j++];
575 } else if (j >= b->n) {
576 copy = &ap[i++];
577 } else if (ap[i].name_idx <= bp[j].name_idx) {
578 if (ap[i].name_idx == bp[j].name_idx)
579 j++;
580 copy = &ap[i++];
581 } else {
582 copy = &bp[j++];
583 }
584 memcpy(r->properties + n, copy, sizeof(r->properties[0]));
e3d6dc59 585 r->has_optional |= copy->optional;
1bdbdaff
P
586 }
587 r->n = n;
588 if (n != t)
589 r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
590 return r;
591}
592
b4250010 593int ossl_property_parse_init(OSSL_LIB_CTX *ctx)
1bdbdaff
P
594{
595 static const char *const predefined_names[] = {
745fc918 596 "provider", /* Name of provider (default, legacy, fips) */
1bdbdaff 597 "version", /* Version number of this provider */
745fc918 598 "fips", /* FIPS validated or FIPS supporting algorithm */
5a6d6fe6
RL
599 "output", /* Output type for encoders */
600 "input", /* Input type for decoders */
601 "structure", /* Structure name for encoders and decoders */
1bdbdaff
P
602 };
603 size_t i;
604
605 for (i = 0; i < OSSL_NELEM(predefined_names); i++)
1aedc35f 606 if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
1bdbdaff
P
607 goto err;
608
609 /* Pre-populate the two Boolean values */
1aedc35f
MC
610 if ((ossl_property_true = ossl_property_value(ctx, "yes", 1)) == 0
611 || (ossl_property_false = ossl_property_value(ctx, "no", 1)) == 0)
1bdbdaff
P
612 goto err;
613
614 return 1;
615err:
616 return 0;
617}