2 * Copyright 2019-2021 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"
22 OSSL_PROPERTY_IDX ossl_property_true, ossl_property_false;
24 DEFINE_STACK_OF(OSSL_PROPERTY_DEFINITION)
26 static const char *skip_space(const char *s)
28 while (ossl_isspace(*s))
33 static int match_ch(const char *t[], char m)
38 *t = skip_space(s + 1);
44 #define MATCH(s, m) match(s, m, sizeof(m) - 1)
46 static int match(const char *t[], const char m[], size_t m_len)
50 if (strncasecmp(s, m, m_len) == 0) {
51 *t = skip_space(s + m_len);
57 static int parse_name(OSSL_LIB_CTX *ctx, const char *t[], int create,
58 OSSL_PROPERTY_IDX *idx)
67 if (!ossl_isalpha(*s)) {
68 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER,
73 if (i < sizeof(name) - 1)
74 name[i++] = ossl_tolower(*s);
77 } while (*++s == '_' || ossl_isalnum(*s));
81 if (i < sizeof(name) - 1)
89 ERR_raise_data(ERR_LIB_PROP, PROP_R_NAME_TOO_LONG, "HERE-->%s", *t);
93 *idx = ossl_property_name(ctx, name, user_name && create);
97 static int parse_number(const char *t[], OSSL_PROPERTY_DEFINITION *res)
102 if (!ossl_isdigit(*s))
105 v = v * 10 + (*s++ - '0');
106 } while (ossl_isdigit(*s));
107 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
108 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT,
113 res->type = OSSL_PROPERTY_TYPE_NUMBER;
118 static int parse_hex(const char *t[], OSSL_PROPERTY_DEFINITION *res)
123 if (!ossl_isxdigit(*s))
127 if (ossl_isdigit(*s))
130 v += ossl_tolower(*s) - 'a';
131 } while (ossl_isxdigit(*++s));
132 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
133 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT,
138 res->type = OSSL_PROPERTY_TYPE_NUMBER;
143 static int parse_oct(const char *t[], OSSL_PROPERTY_DEFINITION *res)
148 if (*s == '9' || *s == '8' || !ossl_isdigit(*s))
151 v = (v << 3) + (*s - '0');
152 } while (ossl_isdigit(*++s) && *s != '9' && *s != '8');
153 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
154 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT,
159 res->type = OSSL_PROPERTY_TYPE_NUMBER;
164 static int parse_string(OSSL_LIB_CTX *ctx, const char *t[], char delim,
165 OSSL_PROPERTY_DEFINITION *res, const int create)
172 while (*s != '\0' && *s != delim) {
173 if (i < sizeof(v) - 1)
180 ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER,
181 "HERE-->%c%s", delim, *t);
186 ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
188 res->v.str_val = ossl_property_value(ctx, v, create);
190 *t = skip_space(s + 1);
191 res->type = OSSL_PROPERTY_TYPE_STRING;
195 static int parse_unquoted(OSSL_LIB_CTX *ctx, const char *t[],
196 OSSL_PROPERTY_DEFINITION *res, const int create)
203 if (*s == '\0' || *s == ',')
205 while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') {
206 if (i < sizeof(v) - 1)
207 v[i++] = ossl_tolower(*s);
212 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
213 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER,
219 ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
221 res->v.str_val = ossl_property_value(ctx, v, create);
224 res->type = OSSL_PROPERTY_TYPE_STRING;
228 static int parse_value(OSSL_LIB_CTX *ctx, const char *t[],
229 OSSL_PROPERTY_DEFINITION *res, int create)
234 if (*s == '"' || *s == '\'') {
236 r = parse_string(ctx, &s, s[-1], res, create);
237 } else if (*s == '+') {
239 r = parse_number(&s, res);
240 } else if (*s == '-') {
242 r = parse_number(&s, res);
243 res->v.int_val = -res->v.int_val;
244 } else if (*s == '0' && s[1] == 'x') {
246 r = parse_hex(&s, res);
247 } else if (*s == '0' && ossl_isdigit(s[1])) {
249 r = parse_oct(&s, res);
250 } else if (ossl_isdigit(*s)) {
251 return parse_number(t, res);
252 } else if (ossl_isalpha(*s))
253 return parse_unquoted(ctx, t, res, create);
259 static int pd_compare(const OSSL_PROPERTY_DEFINITION *const *p1,
260 const OSSL_PROPERTY_DEFINITION *const *p2)
262 const OSSL_PROPERTY_DEFINITION *pd1 = *p1;
263 const OSSL_PROPERTY_DEFINITION *pd2 = *p2;
265 if (pd1->name_idx < pd2->name_idx)
267 if (pd1->name_idx > pd2->name_idx)
272 static void pd_free(OSSL_PROPERTY_DEFINITION *pd)
278 * Convert a stack of property definitions and queries into a fixed array.
279 * The items are sorted for efficient query. The stack is not freed.
281 static OSSL_PROPERTY_LIST *
282 stack_to_property_list(STACK_OF(OSSL_PROPERTY_DEFINITION) *sk)
284 const int n = sk_OSSL_PROPERTY_DEFINITION_num(sk);
285 OSSL_PROPERTY_LIST *r;
288 r = OPENSSL_malloc(sizeof(*r)
289 + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0]));
291 sk_OSSL_PROPERTY_DEFINITION_sort(sk);
294 for (i = 0; i < n; i++) {
295 r->properties[i] = *sk_OSSL_PROPERTY_DEFINITION_value(sk, i);
296 r->has_optional |= r->properties[i].optional;
298 r->num_properties = n;
303 OSSL_PROPERTY_LIST *ossl_parse_property(OSSL_LIB_CTX *ctx, const char *defn)
305 OSSL_PROPERTY_DEFINITION *prop = NULL;
306 OSSL_PROPERTY_LIST *res = NULL;
307 STACK_OF(OSSL_PROPERTY_DEFINITION) *sk;
308 const char *s = defn;
311 if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
317 const char *start = s;
319 prop = OPENSSL_malloc(sizeof(*prop));
322 memset(&prop->v, 0, sizeof(prop->v));
324 if (!parse_name(ctx, &s, 1, &prop->name_idx))
326 prop->oper = OSSL_PROPERTY_OPER_EQ;
327 if (prop->name_idx == 0) {
328 ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
329 "Unknown name HERE-->%s", start);
332 if (match_ch(&s, '=')) {
333 if (!parse_value(ctx, &s, prop, 1)) {
334 ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_VALUE,
339 /* A name alone means a true Boolean */
340 prop->type = OSSL_PROPERTY_TYPE_STRING;
341 prop->v.str_val = ossl_property_true;
344 if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop))
347 done = !match_ch(&s, ',');
350 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
354 res = stack_to_property_list(sk);
358 sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
362 OSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s,
365 STACK_OF(OSSL_PROPERTY_DEFINITION) *sk;
366 OSSL_PROPERTY_LIST *res = NULL;
367 OSSL_PROPERTY_DEFINITION *prop = NULL;
370 if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
376 prop = OPENSSL_malloc(sizeof(*prop));
379 memset(&prop->v, 0, sizeof(prop->v));
381 if (match_ch(&s, '-')) {
382 prop->oper = OSSL_PROPERTY_OVERRIDE;
384 if (!parse_name(ctx, &s, 1, &prop->name_idx))
388 prop->optional = match_ch(&s, '?');
389 if (!parse_name(ctx, &s, 1, &prop->name_idx))
392 if (match_ch(&s, '=')) {
393 prop->oper = OSSL_PROPERTY_OPER_EQ;
394 } else if (MATCH(&s, "!=")) {
395 prop->oper = OSSL_PROPERTY_OPER_NE;
397 /* A name alone is a Boolean comparison for true */
398 prop->oper = OSSL_PROPERTY_OPER_EQ;
399 prop->type = OSSL_PROPERTY_TYPE_STRING;
400 prop->v.str_val = ossl_property_true;
403 if (!parse_value(ctx, &s, prop, create_values))
404 prop->type = OSSL_PROPERTY_TYPE_VALUE_UNDEFINED;
407 if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop))
410 done = !match_ch(&s, ',');
413 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
417 res = stack_to_property_list(sk);
421 sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
426 * Compare a query against a definition.
427 * Return the number of clauses matched or -1 if a mandatory clause is false.
429 int ossl_property_match_count(const OSSL_PROPERTY_LIST *query,
430 const OSSL_PROPERTY_LIST *defn)
432 const OSSL_PROPERTY_DEFINITION *const q = query->properties;
433 const OSSL_PROPERTY_DEFINITION *const d = defn->properties;
434 int i = 0, j = 0, matches = 0;
435 OSSL_PROPERTY_OPER oper;
437 while (i < query->num_properties) {
438 if ((oper = q[i].oper) == OSSL_PROPERTY_OVERRIDE) {
442 if (j < defn->num_properties) {
443 if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */
447 if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */
448 const int eq = q[i].type == d[j].type
449 && memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0;
451 if ((eq && oper == OSSL_PROPERTY_OPER_EQ)
452 || (!eq && oper == OSSL_PROPERTY_OPER_NE))
454 else if (!q[i].optional)
463 * Handle the cases of a missing value and a query with no corresponding
464 * definition. The former fails for any comparison except inequality,
465 * the latter is treated as a comparison against the Boolean false.
467 if (q[i].type == OSSL_PROPERTY_TYPE_VALUE_UNDEFINED) {
468 if (oper == OSSL_PROPERTY_OPER_NE)
470 else if (!q[i].optional)
472 } else if (q[i].type != OSSL_PROPERTY_TYPE_STRING
473 || (oper == OSSL_PROPERTY_OPER_EQ
474 && q[i].v.str_val != ossl_property_false)
475 || (oper == OSSL_PROPERTY_OPER_NE
476 && q[i].v.str_val == ossl_property_false)) {
487 void ossl_property_free(OSSL_PROPERTY_LIST *p)
493 * Merge two property lists.
494 * If there is a common name, the one from the first list is used.
496 OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
497 const OSSL_PROPERTY_LIST *b)
499 const OSSL_PROPERTY_DEFINITION *const ap = a->properties;
500 const OSSL_PROPERTY_DEFINITION *const bp = b->properties;
501 const OSSL_PROPERTY_DEFINITION *copy;
502 OSSL_PROPERTY_LIST *r;
504 const int t = a->num_properties + b->num_properties;
506 r = OPENSSL_malloc(sizeof(*r)
507 + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
512 for (i = j = n = 0; i < a->num_properties || j < b->num_properties; n++) {
513 if (i >= a->num_properties) {
515 } else if (j >= b->num_properties) {
517 } else if (ap[i].name_idx <= bp[j].name_idx) {
518 if (ap[i].name_idx == bp[j].name_idx)
524 memcpy(r->properties + n, copy, sizeof(r->properties[0]));
525 r->has_optional |= copy->optional;
527 r->num_properties = n;
529 r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
533 int ossl_property_parse_init(OSSL_LIB_CTX *ctx)
535 static const char *const predefined_names[] = {
536 "provider", /* Name of provider (default, legacy, fips) */
537 "version", /* Version number of this provider */
538 "fips", /* FIPS validated or FIPS supporting algorithm */
539 "output", /* Output type for encoders */
540 "input", /* Input type for decoders */
541 "structure", /* Structure name for encoders and decoders */
545 for (i = 0; i < OSSL_NELEM(predefined_names); i++)
546 if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
549 /* Pre-populate the two Boolean values */
550 if ((ossl_property_true = ossl_property_value(ctx, "yes", 1)) == 0
551 || (ossl_property_false = ossl_property_value(ctx, "no", 1)) == 0)
559 static void put_char(char ch, char **buf, size_t *remain, size_t *needed)
574 static void put_str(const char *str, char **buf, size_t *remain, size_t *needed)
578 len = olen = strlen(str);
584 if(*remain < len + 1)
588 strncpy(*buf, str, len);
593 if(len < olen && *remain == 1) {
600 static void put_num(int64_t val, char **buf, size_t *remain, size_t *needed)
602 int64_t tmpval = val;
609 for (; tmpval > 9; len++, tmpval /= 10);
616 BIO_snprintf(*buf, *remain, "%lld", (long long int)val);
626 size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx,
627 const OSSL_PROPERTY_LIST *list, char *buf,
631 const OSSL_PROPERTY_DEFINITION *prop = NULL;
640 if (list->num_properties != 0)
641 prop = &list->properties[list->num_properties - 1];
642 for (i = 0; i < list->num_properties; i++, prop--) {
643 /* Skip invalid names */
644 if (prop->name_idx == 0)
648 put_char(',', &buf, &bufsize, &needed);
651 put_char('?', &buf, &bufsize, &needed);
652 else if (prop->oper == OSSL_PROPERTY_OVERRIDE)
653 put_char('-', &buf, &bufsize, &needed);
655 val = ossl_property_name_str(ctx, prop->name_idx);
658 put_str(val, &buf, &bufsize, &needed);
660 switch (prop->oper) {
661 case OSSL_PROPERTY_OPER_NE:
662 put_char('!', &buf, &bufsize, &needed);
664 case OSSL_PROPERTY_OPER_EQ:
665 put_char('=', &buf, &bufsize, &needed);
667 switch (prop->type) {
668 case OSSL_PROPERTY_TYPE_STRING:
669 val = ossl_property_value_str(ctx, prop->v.str_val);
672 put_str(val, &buf, &bufsize, &needed);
675 case OSSL_PROPERTY_TYPE_NUMBER:
676 put_num(prop->v.int_val, &buf, &bufsize, &needed);
689 put_char('\0', &buf, &bufsize, &needed);