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
)
390 STACK_OF(PROPERTY_DEFINITION
) *sk
;
391 OSSL_PROPERTY_LIST
*res
= NULL
;
392 PROPERTY_DEFINITION
*prop
= NULL
;
395 if (s
== NULL
|| (sk
= sk_PROPERTY_DEFINITION_new(&pd_compare
)) == NULL
)
401 prop
= OPENSSL_malloc(sizeof(*prop
));
404 memset(&prop
->v
, 0, sizeof(prop
->v
));
406 if (match_ch(&s
, '-')) {
407 prop
->oper
= PROPERTY_OVERRIDE
;
409 if (!parse_name(ctx
, &s
, 0, &prop
->name_idx
))
413 prop
->optional
= match_ch(&s
, '?');
414 if (!parse_name(ctx
, &s
, 0, &prop
->name_idx
))
417 if (match_ch(&s
, '=')) {
418 prop
->oper
= PROPERTY_OPER_EQ
;
419 } else if (MATCH(&s
, "!=")) {
420 prop
->oper
= PROPERTY_OPER_NE
;
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
;
428 if (!parse_value(ctx
, &s
, prop
, 0))
429 prop
->type
= PROPERTY_TYPE_VALUE_UNDEFINED
;
432 if (!sk_PROPERTY_DEFINITION_push(sk
, prop
))
435 done
= !match_ch(&s
, ',');
438 ERR_raise_data(ERR_LIB_PROP
, PROP_R_TRAILING_CHARACTERS
,
442 res
= stack_to_property_list(sk
);
446 sk_PROPERTY_DEFINITION_pop_free(sk
, &pd_free
);
450 /* Does a property query have any optional clauses */
451 int ossl_property_has_optional(const OSSL_PROPERTY_LIST
*query
)
453 return query
->has_optional
? 1 : 0;
456 int ossl_property_is_enabled(OSSL_LIB_CTX
*ctx
, const char *property_name
,
457 const OSSL_PROPERTY_LIST
*prop_list
)
460 OSSL_PROPERTY_IDX name_id
;
461 const PROPERTY_DEFINITION
*prop
= NULL
;
463 if (prop_list
== NULL
)
466 if (!parse_name(ctx
, &property_name
, 0, &name_id
))
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
)
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
)));
486 * Compare a query against a definition.
487 * Return the number of clauses matched or -1 if a mandatory clause is false.
489 int ossl_property_match_count(const OSSL_PROPERTY_LIST
*query
,
490 const OSSL_PROPERTY_LIST
*defn
)
492 const PROPERTY_DEFINITION
*const q
= query
->properties
;
493 const PROPERTY_DEFINITION
*const d
= defn
->properties
;
494 int i
= 0, j
= 0, matches
= 0;
497 while (i
< query
->n
) {
498 if ((oper
= q
[i
].oper
) == PROPERTY_OVERRIDE
) {
503 if (q
[i
].name_idx
> d
[j
].name_idx
) { /* skip defn, not in query */
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;
511 if ((eq
&& oper
== PROPERTY_OPER_EQ
)
512 || (!eq
&& oper
== PROPERTY_OPER_NE
))
514 else if (!q
[i
].optional
)
523 * Handle the cases of a missing value and a query with no corresponding
524 * definition. The former fails for any comparison except inequality,
525 * the latter is treated as a comparison against the Boolean false.
527 if (q
[i
].type
== PROPERTY_TYPE_VALUE_UNDEFINED
) {
528 if (oper
== PROPERTY_OPER_NE
)
530 else if (!q
[i
].optional
)
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
)) {
547 void ossl_property_free(OSSL_PROPERTY_LIST
*p
)
553 * Merge two property lists.
554 * If there is a common name, the one from the first list is used.
556 OSSL_PROPERTY_LIST
*ossl_property_merge(const OSSL_PROPERTY_LIST
*a
,
557 const OSSL_PROPERTY_LIST
*b
)
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
;
564 const int t
= a
->n
+ b
->n
;
566 r
= OPENSSL_malloc(sizeof(*r
)
567 + (t
== 0 ? 0 : t
- 1) * sizeof(r
->properties
[0]));
572 for (i
= j
= n
= 0; i
< a
->n
|| j
< b
->n
; n
++) {
575 } else if (j
>= b
->n
) {
577 } else if (ap
[i
].name_idx
<= bp
[j
].name_idx
) {
578 if (ap
[i
].name_idx
== bp
[j
].name_idx
)
584 memcpy(r
->properties
+ n
, copy
, sizeof(r
->properties
[0]));
585 r
->has_optional
|= copy
->optional
;
589 r
= OPENSSL_realloc(r
, sizeof(*r
) + (n
- 1) * sizeof(r
->properties
[0]));
593 int ossl_property_parse_init(OSSL_LIB_CTX
*ctx
)
595 static const char *const predefined_names
[] = {
596 "provider", /* Name of provider (default, legacy, fips) */
597 "version", /* Version number of this provider */
598 "fips", /* FIPS validated or FIPS supporting algorithm */
599 "output", /* Output type for encoders */
600 "input", /* Input type for decoders */
601 "structure", /* Structure name for encoders and decoders */
605 for (i
= 0; i
< OSSL_NELEM(predefined_names
); i
++)
606 if (ossl_property_name(ctx
, predefined_names
[i
], 1) == 0)
609 /* Pre-populate the two Boolean values */
610 if ((ossl_property_true
= ossl_property_value(ctx
, "yes", 1)) == 0
611 || (ossl_property_false
= ossl_property_value(ctx
, "no", 1)) == 0)