2 * Copyright 2019 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 "internal/ctype.h"
18 #include "internal/nelem.h"
19 #include "property_lcl.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;
36 int64_t int_val; /* Signed integer */
37 OSSL_PROPERTY_IDX str_val; /* String */
39 } PROPERTY_DEFINITION;
41 struct ossl_property_list_st {
43 PROPERTY_DEFINITION properties[1];
46 static OSSL_PROPERTY_IDX ossl_property_true, ossl_property_false;
48 DEFINE_STACK_OF(PROPERTY_DEFINITION)
50 static const char *skip_space(const char *s)
52 while (ossl_isspace(*s))
57 static int match_ch(const char *t[], char m)
62 *t = skip_space(s + 1);
68 #define MATCH(s, m) match(s, m, sizeof(m) - 1)
70 static int match(const char *t[], const char m[], size_t m_len)
74 if (strncasecmp(s, m, m_len) == 0) {
75 *t = skip_space(s + m_len);
81 static int parse_name(const char *t[], int create, OSSL_PROPERTY_IDX *idx)
90 if (!ossl_isalpha(*s)) {
91 PROPerr(PROP_F_PARSE_NAME, PROP_R_NOT_AN_IDENTIFIER);
95 if (i < sizeof(name) - 1)
96 name[i++] = ossl_tolower(*s);
99 } while (*++s == '_' || ossl_isalnum(*s));
103 if (i < sizeof(name) - 1)
112 *idx = ossl_property_name(name, user_name && create);
115 PROPerr(PROP_F_PARSE_NAME, PROP_R_NAME_TOO_LONG);
119 static int parse_number(const char *t[], PROPERTY_DEFINITION *res)
124 if (!ossl_isdigit(*s))
127 v = v * 10 + (*s++ - '0');
128 } while (ossl_isdigit(*s));
129 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
130 PROPerr(PROP_F_PARSE_NUMBER, PROP_R_NOT_A_DECIMAL_DIGIT);
134 res->type = PROPERTY_TYPE_NUMBER;
139 static int parse_hex(const char *t[], PROPERTY_DEFINITION *res)
144 if (!ossl_isxdigit(*s))
148 if (ossl_isdigit(*s))
151 v += ossl_tolower(*s) - 'a';
152 } while (ossl_isxdigit(*++s));
153 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
154 PROPerr(PROP_F_PARSE_HEX, PROP_R_NOT_AN_HEXADECIMAL_DIGIT);
158 res->type = PROPERTY_TYPE_NUMBER;
163 static int parse_oct(const char *t[], PROPERTY_DEFINITION *res)
168 if (*s == '9' || *s == '8' || !ossl_isdigit(*s))
171 v = (v << 3) + (*s - '0');
172 } while (ossl_isdigit(*++s) && *s != '9' && *s != '8');
173 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
174 PROPerr(PROP_F_PARSE_OCT, PROP_R_NOT_AN_OCTAL_DIGIT);
178 res->type = PROPERTY_TYPE_NUMBER;
183 static int parse_string(const char *t[], char delim, PROPERTY_DEFINITION *res,
191 while (*s != '\0' && *s != delim) {
192 if (i < sizeof(v) - 1)
199 PROPerr(PROP_F_PARSE_STRING,
200 PROP_R_NO_MATCHING_STRING_DELIMETER);
204 *t = skip_space(s + 1);
206 PROPerr(PROP_F_PARSE_STRING, PROP_R_STRING_TOO_LONG);
208 res->v.str_val = ossl_property_value(v, create);
209 res->type = PROPERTY_TYPE_STRING;
213 static int parse_unquoted(const char *t[], PROPERTY_DEFINITION *res,
221 if (*s == '\0' || *s == ',')
223 while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') {
224 if (i < sizeof(v) - 1)
225 v[i++] = ossl_tolower(*s);
230 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
231 PROPerr(PROP_F_PARSE_UNQUOTED, PROP_R_NOT_AN_ASCII_CHARACTER);
237 PROPerr(PROP_F_PARSE_UNQUOTED, PROP_R_STRING_TOO_LONG);
239 res->v.str_val = ossl_property_value(v, create);
240 res->type = PROPERTY_TYPE_STRING;
244 static int parse_value(const char *t[], PROPERTY_DEFINITION *res, int create)
249 if (*s == '"' || *s == '\'') {
251 r = parse_string(&s, s[-1], res, create);
252 } else if (*s == '+') {
254 r = parse_number(&s, res);
255 } else if (*s == '-') {
257 r = parse_number(&s, res);
258 res->v.int_val = -res->v.int_val;
259 } else if (*s == '0' && s[1] == 'x') {
261 r = parse_hex(&s, res);
262 } else if (*s == '0' && ossl_isdigit(s[1])) {
264 r = parse_oct(&s, res);
265 } else if (ossl_isdigit(*s)) {
266 return parse_number(t, res);
267 } else if (ossl_isalpha(*s))
268 return parse_unquoted(t, res, create);
274 static int pd_compare(const PROPERTY_DEFINITION *const *p1,
275 const PROPERTY_DEFINITION *const *p2)
277 const PROPERTY_DEFINITION *pd1 = *p1;
278 const PROPERTY_DEFINITION *pd2 = *p2;
280 if (pd1->name_idx < pd2->name_idx)
282 if (pd1->name_idx > pd2->name_idx)
287 static void pd_free(PROPERTY_DEFINITION *pd)
293 * Convert a stack of property definitions and queries into a fixed array.
294 * The items are sorted for efficient query. The stack is not freed.
296 static OSSL_PROPERTY_LIST *stack_to_property_list(STACK_OF(PROPERTY_DEFINITION)
299 const int n = sk_PROPERTY_DEFINITION_num(sk);
300 OSSL_PROPERTY_LIST *r;
303 r = OPENSSL_malloc(sizeof(*r)
304 + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0]));
306 sk_PROPERTY_DEFINITION_sort(sk);
308 for (i = 0; i < n; i++)
309 r->properties[i] = *sk_PROPERTY_DEFINITION_value(sk, i);
315 OSSL_PROPERTY_LIST *ossl_parse_property(const char *defn)
317 PROPERTY_DEFINITION *prop = NULL;
318 OSSL_PROPERTY_LIST *res = NULL;
319 STACK_OF(PROPERTY_DEFINITION) *sk;
320 const char *s = defn;
323 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
329 prop = OPENSSL_malloc(sizeof(*prop));
332 memset(&prop->v, 0, sizeof(prop->v));
333 if (!parse_name(&s, 1, &prop->name_idx))
335 prop->oper = PROPERTY_OPER_EQ;
336 if (prop->name_idx == 0) {
337 PROPerr(PROP_F_OSSL_PARSE_PROPERTY, PROP_R_PARSE_FAILED);
340 if (match_ch(&s, '=')) {
341 if (!parse_value(&s, prop, 1)) {
342 PROPerr(PROP_F_OSSL_PARSE_PROPERTY, PROP_R_NO_VALUE);
346 /* A name alone means a true Boolean */
347 prop->type = PROPERTY_TYPE_STRING;
348 prop->v.str_val = ossl_property_true;
351 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
354 done = !match_ch(&s, ',');
357 PROPerr(PROP_F_OSSL_PARSE_PROPERTY, PROP_R_TRAILING_CHARACTERS);
360 res = stack_to_property_list(sk);
364 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
368 OSSL_PROPERTY_LIST *ossl_parse_query(const char *s)
370 STACK_OF(PROPERTY_DEFINITION) *sk;
371 OSSL_PROPERTY_LIST *res = NULL;
372 PROPERTY_DEFINITION *prop = NULL;
375 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
381 prop = OPENSSL_malloc(sizeof(*prop));
384 memset(&prop->v, 0, sizeof(prop->v));
386 if (match_ch(&s, '-')) {
387 prop->oper = PROPERTY_OVERRIDE;
388 if (!parse_name(&s, 0, &prop->name_idx))
392 if (!parse_name(&s, 0, &prop->name_idx))
395 if (match_ch(&s, '=')) {
396 prop->oper = PROPERTY_OPER_EQ;
397 } else if (MATCH(&s, "!=")) {
398 prop->oper = PROPERTY_OPER_NE;
400 /* A name alone is a Boolean comparison for true */
401 prop->oper = PROPERTY_OPER_EQ;
402 prop->type = PROPERTY_TYPE_STRING;
403 prop->v.str_val = ossl_property_true;
406 if (!parse_value(&s, prop, 0))
407 prop->type = PROPERTY_TYPE_VALUE_UNDEFINED;
410 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
413 done = !match_ch(&s, ',');
416 PROPerr(PROP_F_OSSL_PARSE_QUERY, PROP_R_TRAILING_CHARACTERS);
419 res = stack_to_property_list(sk);
423 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
427 int ossl_property_match(const OSSL_PROPERTY_LIST *query,
428 const OSSL_PROPERTY_LIST *defn)
430 const PROPERTY_DEFINITION *const q = query->properties;
431 const PROPERTY_DEFINITION *const d = defn->properties;
435 while (i < query->n) {
436 if ((oper = q[i].oper) == PROPERTY_OVERRIDE) {
441 if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */
445 if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */
446 const int eq = q[i].type == d[j].type
447 && memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0;
449 if ((eq && oper != PROPERTY_OPER_EQ)
450 || (!eq && oper != PROPERTY_OPER_NE))
459 * Handle the cases of a missing value and a query with no corresponding
460 * definition. The former fails for any comparision except inequality,
461 * the latter is treated as a comparison against the Boolean false.
463 if (q[i].type == PROPERTY_TYPE_VALUE_UNDEFINED) {
464 if (oper != PROPERTY_OPER_NE)
466 } else if (q[i].type != PROPERTY_TYPE_STRING
467 || (oper == PROPERTY_OPER_EQ
468 && q[i].v.str_val != ossl_property_false)
469 || (oper == PROPERTY_OPER_NE
470 && q[i].v.str_val == ossl_property_false)) {
478 void ossl_property_free(OSSL_PROPERTY_LIST *p)
484 * Merge two property lists.
485 * If there is a common name, the one from the first list is used.
487 OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
488 const OSSL_PROPERTY_LIST *b)
490 const PROPERTY_DEFINITION *const ap = a->properties;
491 const PROPERTY_DEFINITION *const bp = b->properties;
492 const PROPERTY_DEFINITION *copy;
493 OSSL_PROPERTY_LIST *r;
495 const int t = a->n + b->n;
497 r = OPENSSL_malloc(sizeof(*r)
498 + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
502 for (i = j = n = 0; i < a->n || j < b->n; n++) {
505 } else if (j >= b->n) {
507 } else if (ap[i].name_idx <= bp[j].name_idx) {
508 if (ap[i].name_idx == bp[j].name_idx)
514 memcpy(r->properties + n, copy, sizeof(r->properties[0]));
518 r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
522 int ossl_property_parse_init(void)
524 static const char *const predefined_names[] = {
525 "default", /* Being provided by the default built-in provider */
526 "provider", /* Name of provider (default, fips) */
527 "version", /* Version number of this provider */
528 "fips", /* FIPS supporting provider */
529 "engine", /* An old style engine masquerading as a provider */
533 for (i = 0; i < OSSL_NELEM(predefined_names); i++)
534 if (ossl_property_name(predefined_names[i], 1) == 0)
537 /* Pre-populate the two Boolean values */
538 if ((ossl_property_true = ossl_property_value("yes", 1)) == 0
539 || (ossl_property_false = ossl_property_value("no", 1)) == 0)