2 * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
3 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
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
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"
23 PROPERTY_TYPE_STRING, PROPERTY_TYPE_NUMBER,
24 PROPERTY_TYPE_VALUE_UNDEFINED
28 PROPERTY_OPER_EQ, PROPERTY_OPER_NE, PROPERTY_OVERRIDE
32 OSSL_PROPERTY_IDX name_idx;
35 unsigned int optional : 1;
37 int64_t int_val; /* Signed integer */
38 OSSL_PROPERTY_IDX str_val; /* String */
40 } PROPERTY_DEFINITION;
42 struct ossl_property_list_st {
44 unsigned int has_optional : 1;
45 PROPERTY_DEFINITION properties[1];
48 static OSSL_PROPERTY_IDX ossl_property_true, ossl_property_false;
50 DEFINE_STACK_OF(PROPERTY_DEFINITION)
52 static const char *skip_space(const char *s)
54 while (ossl_isspace(*s))
59 static int match_ch(const char *t[], char m)
64 *t = skip_space(s + 1);
70 #define MATCH(s, m) match(s, m, sizeof(m) - 1)
72 static int match(const char *t[], const char m[], size_t m_len)
76 if (strncasecmp(s, m, m_len) == 0) {
77 *t = skip_space(s + m_len);
83 static int parse_name(OSSL_LIB_CTX *ctx, const char *t[], int create,
84 OSSL_PROPERTY_IDX *idx)
93 if (!ossl_isalpha(*s)) {
94 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER,
99 if (i < sizeof(name) - 1)
100 name[i++] = ossl_tolower(*s);
103 } while (*++s == '_' || ossl_isalnum(*s));
107 if (i < sizeof(name) - 1)
115 ERR_raise_data(ERR_LIB_PROP, PROP_R_NAME_TOO_LONG, "HERE-->%s", *t);
119 *idx = ossl_property_name(ctx, name, user_name && create);
123 static int parse_number(const char *t[], PROPERTY_DEFINITION *res)
128 if (!ossl_isdigit(*s))
131 v = v * 10 + (*s++ - '0');
132 } while (ossl_isdigit(*s));
133 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
134 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT,
139 res->type = PROPERTY_TYPE_NUMBER;
144 static int parse_hex(const char *t[], PROPERTY_DEFINITION *res)
149 if (!ossl_isxdigit(*s))
153 if (ossl_isdigit(*s))
156 v += ossl_tolower(*s) - 'a';
157 } while (ossl_isxdigit(*++s));
158 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
159 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT,
164 res->type = PROPERTY_TYPE_NUMBER;
169 static int parse_oct(const char *t[], PROPERTY_DEFINITION *res)
174 if (*s == '9' || *s == '8' || !ossl_isdigit(*s))
177 v = (v << 3) + (*s - '0');
178 } while (ossl_isdigit(*++s) && *s != '9' && *s != '8');
179 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
180 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT,
185 res->type = PROPERTY_TYPE_NUMBER;
190 static int parse_string(OSSL_LIB_CTX *ctx, const char *t[], char delim,
191 PROPERTY_DEFINITION *res, const int create)
198 while (*s != '\0' && *s != delim) {
199 if (i < sizeof(v) - 1)
206 ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER,
207 "HERE-->%c%s", delim, *t);
212 ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
214 res->v.str_val = ossl_property_value(ctx, v, create);
216 *t = skip_space(s + 1);
217 res->type = PROPERTY_TYPE_STRING;
221 static int parse_unquoted(OSSL_LIB_CTX *ctx, const char *t[],
222 PROPERTY_DEFINITION *res, const int create)
229 if (*s == '\0' || *s == ',')
231 while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') {
232 if (i < sizeof(v) - 1)
233 v[i++] = ossl_tolower(*s);
238 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
239 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER,
245 ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
247 res->v.str_val = ossl_property_value(ctx, v, create);
250 res->type = PROPERTY_TYPE_STRING;
254 static int parse_value(OSSL_LIB_CTX *ctx, const char *t[],
255 PROPERTY_DEFINITION *res, int create)
260 if (*s == '"' || *s == '\'') {
262 r = parse_string(ctx, &s, s[-1], res, create);
263 } else if (*s == '+') {
265 r = parse_number(&s, res);
266 } else if (*s == '-') {
268 r = parse_number(&s, res);
269 res->v.int_val = -res->v.int_val;
270 } else if (*s == '0' && s[1] == 'x') {
272 r = parse_hex(&s, res);
273 } else if (*s == '0' && ossl_isdigit(s[1])) {
275 r = parse_oct(&s, res);
276 } else if (ossl_isdigit(*s)) {
277 return parse_number(t, res);
278 } else if (ossl_isalpha(*s))
279 return parse_unquoted(ctx, t, res, create);
285 static int pd_compare(const PROPERTY_DEFINITION *const *p1,
286 const PROPERTY_DEFINITION *const *p2)
288 const PROPERTY_DEFINITION *pd1 = *p1;
289 const PROPERTY_DEFINITION *pd2 = *p2;
291 if (pd1->name_idx < pd2->name_idx)
293 if (pd1->name_idx > pd2->name_idx)
298 static void pd_free(PROPERTY_DEFINITION *pd)
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.
307 static OSSL_PROPERTY_LIST *stack_to_property_list(STACK_OF(PROPERTY_DEFINITION)
310 const int n = sk_PROPERTY_DEFINITION_num(sk);
311 OSSL_PROPERTY_LIST *r;
314 r = OPENSSL_malloc(sizeof(*r)
315 + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0]));
317 sk_PROPERTY_DEFINITION_sort(sk);
320 for (i = 0; i < n; i++) {
321 r->properties[i] = *sk_PROPERTY_DEFINITION_value(sk, i);
322 r->has_optional |= r->properties[i].optional;
329 OSSL_PROPERTY_LIST *ossl_parse_property(OSSL_LIB_CTX *ctx, const char *defn)
331 PROPERTY_DEFINITION *prop = NULL;
332 OSSL_PROPERTY_LIST *res = NULL;
333 STACK_OF(PROPERTY_DEFINITION) *sk;
334 const char *s = defn;
337 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
343 const char *start = s;
345 prop = OPENSSL_malloc(sizeof(*prop));
348 memset(&prop->v, 0, sizeof(prop->v));
350 if (!parse_name(ctx, &s, 1, &prop->name_idx))
352 prop->oper = PROPERTY_OPER_EQ;
353 if (prop->name_idx == 0) {
354 ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
355 "Unknown name HERE-->%s", start);
358 if (match_ch(&s, '=')) {
359 if (!parse_value(ctx, &s, prop, 1)) {
360 ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_VALUE,
365 /* A name alone means a true Boolean */
366 prop->type = PROPERTY_TYPE_STRING;
367 prop->v.str_val = ossl_property_true;
370 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
373 done = !match_ch(&s, ',');
376 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
380 res = stack_to_property_list(sk);
384 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
388 OSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s,
391 STACK_OF(PROPERTY_DEFINITION) *sk;
392 OSSL_PROPERTY_LIST *res = NULL;
393 PROPERTY_DEFINITION *prop = NULL;
396 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
402 prop = OPENSSL_malloc(sizeof(*prop));
405 memset(&prop->v, 0, sizeof(prop->v));
407 if (match_ch(&s, '-')) {
408 prop->oper = PROPERTY_OVERRIDE;
410 if (!parse_name(ctx, &s, 0, &prop->name_idx))
414 prop->optional = match_ch(&s, '?');
415 if (!parse_name(ctx, &s, 0, &prop->name_idx))
418 if (match_ch(&s, '=')) {
419 prop->oper = PROPERTY_OPER_EQ;
420 } else if (MATCH(&s, "!=")) {
421 prop->oper = PROPERTY_OPER_NE;
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;
429 if (!parse_value(ctx, &s, prop, create_values))
430 prop->type = PROPERTY_TYPE_VALUE_UNDEFINED;
433 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
436 done = !match_ch(&s, ',');
439 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
443 res = stack_to_property_list(sk);
447 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
451 /* Does a property query have any optional clauses */
452 int ossl_property_has_optional(const OSSL_PROPERTY_LIST *query)
454 return query->has_optional ? 1 : 0;
457 int ossl_property_is_enabled(OSSL_LIB_CTX *ctx, const char *property_name,
458 const OSSL_PROPERTY_LIST *prop_list)
461 OSSL_PROPERTY_IDX name_id;
462 const PROPERTY_DEFINITION *prop = NULL;
464 if (prop_list == NULL)
467 if (!parse_name(ctx, &property_name, 0, &name_id))
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)
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)));
487 * Compare a query against a definition.
488 * Return the number of clauses matched or -1 if a mandatory clause is false.
490 int ossl_property_match_count(const OSSL_PROPERTY_LIST *query,
491 const OSSL_PROPERTY_LIST *defn)
493 const PROPERTY_DEFINITION *const q = query->properties;
494 const PROPERTY_DEFINITION *const d = defn->properties;
495 int i = 0, j = 0, matches = 0;
498 while (i < query->n) {
499 if ((oper = q[i].oper) == PROPERTY_OVERRIDE) {
504 if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */
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;
512 if ((eq && oper == PROPERTY_OPER_EQ)
513 || (!eq && oper == PROPERTY_OPER_NE))
515 else if (!q[i].optional)
524 * Handle the cases of a missing value and a query with no corresponding
525 * definition. The former fails for any comparison except inequality,
526 * the latter is treated as a comparison against the Boolean false.
528 if (q[i].type == PROPERTY_TYPE_VALUE_UNDEFINED) {
529 if (oper == PROPERTY_OPER_NE)
531 else if (!q[i].optional)
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)) {
548 void ossl_property_free(OSSL_PROPERTY_LIST *p)
554 * Merge two property lists.
555 * If there is a common name, the one from the first list is used.
557 OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
558 const OSSL_PROPERTY_LIST *b)
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;
565 const int t = a->n + b->n;
567 r = OPENSSL_malloc(sizeof(*r)
568 + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
573 for (i = j = n = 0; i < a->n || j < b->n; n++) {
576 } else if (j >= b->n) {
578 } else if (ap[i].name_idx <= bp[j].name_idx) {
579 if (ap[i].name_idx == bp[j].name_idx)
585 memcpy(r->properties + n, copy, sizeof(r->properties[0]));
586 r->has_optional |= copy->optional;
590 r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
594 int ossl_property_parse_init(OSSL_LIB_CTX *ctx)
596 static const char *const predefined_names[] = {
597 "provider", /* Name of provider (default, legacy, fips) */
598 "version", /* Version number of this provider */
599 "fips", /* FIPS validated or FIPS supporting algorithm */
600 "output", /* Output type for encoders */
601 "input", /* Input type for decoders */
602 "structure", /* Structure name for encoders and decoders */
606 for (i = 0; i < OSSL_NELEM(predefined_names); i++)
607 if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
610 /* Pre-populate the two Boolean values */
611 if ((ossl_property_true = ossl_property_value(ctx, "yes", 1)) == 0
612 || (ossl_property_false = ossl_property_value(ctx, "no", 1)) == 0)