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
;
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(OPENSSL_CTX
*ctx
, const char *t
[], int create
,
84 OSSL_PROPERTY_IDX
*idx
)
93 if (!ossl_isalpha(*s
)) {
94 PROPerr(PROP_F_PARSE_NAME
, PROP_R_NOT_AN_IDENTIFIER
);
98 if (i
< sizeof(name
) - 1)
99 name
[i
++] = ossl_tolower(*s
);
102 } while (*++s
== '_' || ossl_isalnum(*s
));
106 if (i
< sizeof(name
) - 1)
115 *idx
= ossl_property_name(ctx
, name
, user_name
&& create
);
118 PROPerr(PROP_F_PARSE_NAME
, PROP_R_NAME_TOO_LONG
);
122 static int parse_number(const char *t
[], PROPERTY_DEFINITION
*res
)
127 if (!ossl_isdigit(*s
))
130 v
= v
* 10 + (*s
++ - '0');
131 } while (ossl_isdigit(*s
));
132 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
133 PROPerr(PROP_F_PARSE_NUMBER
, PROP_R_NOT_A_DECIMAL_DIGIT
);
137 res
->type
= PROPERTY_TYPE_NUMBER
;
142 static int parse_hex(const char *t
[], PROPERTY_DEFINITION
*res
)
147 if (!ossl_isxdigit(*s
))
151 if (ossl_isdigit(*s
))
154 v
+= ossl_tolower(*s
) - 'a';
155 } while (ossl_isxdigit(*++s
));
156 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
157 PROPerr(PROP_F_PARSE_HEX
, PROP_R_NOT_AN_HEXADECIMAL_DIGIT
);
161 res
->type
= PROPERTY_TYPE_NUMBER
;
166 static int parse_oct(const char *t
[], PROPERTY_DEFINITION
*res
)
171 if (*s
== '9' || *s
== '8' || !ossl_isdigit(*s
))
174 v
= (v
<< 3) + (*s
- '0');
175 } while (ossl_isdigit(*++s
) && *s
!= '9' && *s
!= '8');
176 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
177 PROPerr(PROP_F_PARSE_OCT
, PROP_R_NOT_AN_OCTAL_DIGIT
);
181 res
->type
= PROPERTY_TYPE_NUMBER
;
186 static int parse_string(OPENSSL_CTX
*ctx
, const char *t
[], char delim
,
187 PROPERTY_DEFINITION
*res
, const int create
)
194 while (*s
!= '\0' && *s
!= delim
) {
195 if (i
< sizeof(v
) - 1)
202 PROPerr(PROP_F_PARSE_STRING
,
203 PROP_R_NO_MATCHING_STRING_DELIMETER
);
207 *t
= skip_space(s
+ 1);
209 PROPerr(PROP_F_PARSE_STRING
, PROP_R_STRING_TOO_LONG
);
211 res
->v
.str_val
= ossl_property_value(ctx
, v
, create
);
212 res
->type
= PROPERTY_TYPE_STRING
;
216 static int parse_unquoted(OPENSSL_CTX
*ctx
, const char *t
[],
217 PROPERTY_DEFINITION
*res
, const int create
)
224 if (*s
== '\0' || *s
== ',')
226 while (ossl_isprint(*s
) && !ossl_isspace(*s
) && *s
!= ',') {
227 if (i
< sizeof(v
) - 1)
228 v
[i
++] = ossl_tolower(*s
);
233 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
234 PROPerr(PROP_F_PARSE_UNQUOTED
, PROP_R_NOT_AN_ASCII_CHARACTER
);
240 PROPerr(PROP_F_PARSE_UNQUOTED
, PROP_R_STRING_TOO_LONG
);
242 res
->v
.str_val
= ossl_property_value(ctx
, v
, create
);
243 res
->type
= PROPERTY_TYPE_STRING
;
247 static int parse_value(OPENSSL_CTX
*ctx
, const char *t
[],
248 PROPERTY_DEFINITION
*res
, int create
)
253 if (*s
== '"' || *s
== '\'') {
255 r
= parse_string(ctx
, &s
, s
[-1], res
, create
);
256 } else if (*s
== '+') {
258 r
= parse_number(&s
, res
);
259 } else if (*s
== '-') {
261 r
= parse_number(&s
, res
);
262 res
->v
.int_val
= -res
->v
.int_val
;
263 } else if (*s
== '0' && s
[1] == 'x') {
265 r
= parse_hex(&s
, res
);
266 } else if (*s
== '0' && ossl_isdigit(s
[1])) {
268 r
= parse_oct(&s
, res
);
269 } else if (ossl_isdigit(*s
)) {
270 return parse_number(t
, res
);
271 } else if (ossl_isalpha(*s
))
272 return parse_unquoted(ctx
, t
, res
, create
);
278 static int pd_compare(const PROPERTY_DEFINITION
*const *p1
,
279 const PROPERTY_DEFINITION
*const *p2
)
281 const PROPERTY_DEFINITION
*pd1
= *p1
;
282 const PROPERTY_DEFINITION
*pd2
= *p2
;
284 if (pd1
->name_idx
< pd2
->name_idx
)
286 if (pd1
->name_idx
> pd2
->name_idx
)
291 static void pd_free(PROPERTY_DEFINITION
*pd
)
297 * Convert a stack of property definitions and queries into a fixed array.
298 * The items are sorted for efficient query. The stack is not freed.
300 static OSSL_PROPERTY_LIST
*stack_to_property_list(STACK_OF(PROPERTY_DEFINITION
)
303 const int n
= sk_PROPERTY_DEFINITION_num(sk
);
304 OSSL_PROPERTY_LIST
*r
;
307 r
= OPENSSL_malloc(sizeof(*r
)
308 + (n
<= 0 ? 0 : n
- 1) * sizeof(r
->properties
[0]));
310 sk_PROPERTY_DEFINITION_sort(sk
);
313 for (i
= 0; i
< n
; i
++) {
314 r
->properties
[i
] = *sk_PROPERTY_DEFINITION_value(sk
, i
);
315 r
->has_optional
|= r
->properties
[i
].optional
;
322 OSSL_PROPERTY_LIST
*ossl_parse_property(OPENSSL_CTX
*ctx
, const char *defn
)
324 PROPERTY_DEFINITION
*prop
= NULL
;
325 OSSL_PROPERTY_LIST
*res
= NULL
;
326 STACK_OF(PROPERTY_DEFINITION
) *sk
;
327 const char *s
= defn
;
330 if (s
== NULL
|| (sk
= sk_PROPERTY_DEFINITION_new(&pd_compare
)) == NULL
)
336 prop
= OPENSSL_malloc(sizeof(*prop
));
339 memset(&prop
->v
, 0, sizeof(prop
->v
));
341 if (!parse_name(ctx
, &s
, 1, &prop
->name_idx
))
343 prop
->oper
= PROPERTY_OPER_EQ
;
344 if (prop
->name_idx
== 0) {
345 PROPerr(PROP_F_OSSL_PARSE_PROPERTY
, PROP_R_PARSE_FAILED
);
348 if (match_ch(&s
, '=')) {
349 if (!parse_value(ctx
, &s
, prop
, 1)) {
350 PROPerr(PROP_F_OSSL_PARSE_PROPERTY
, PROP_R_NO_VALUE
);
354 /* A name alone means a true Boolean */
355 prop
->type
= PROPERTY_TYPE_STRING
;
356 prop
->v
.str_val
= ossl_property_true
;
359 if (!sk_PROPERTY_DEFINITION_push(sk
, prop
))
362 done
= !match_ch(&s
, ',');
365 PROPerr(PROP_F_OSSL_PARSE_PROPERTY
, PROP_R_TRAILING_CHARACTERS
);
368 res
= stack_to_property_list(sk
);
372 sk_PROPERTY_DEFINITION_pop_free(sk
, &pd_free
);
376 OSSL_PROPERTY_LIST
*ossl_parse_query(OPENSSL_CTX
*ctx
, const char *s
)
378 STACK_OF(PROPERTY_DEFINITION
) *sk
;
379 OSSL_PROPERTY_LIST
*res
= NULL
;
380 PROPERTY_DEFINITION
*prop
= NULL
;
383 if (s
== NULL
|| (sk
= sk_PROPERTY_DEFINITION_new(&pd_compare
)) == NULL
)
389 prop
= OPENSSL_malloc(sizeof(*prop
));
392 memset(&prop
->v
, 0, sizeof(prop
->v
));
394 if (match_ch(&s
, '-')) {
395 prop
->oper
= PROPERTY_OVERRIDE
;
397 if (!parse_name(ctx
, &s
, 0, &prop
->name_idx
))
401 prop
->optional
= match_ch(&s
, '?');
402 if (!parse_name(ctx
, &s
, 0, &prop
->name_idx
))
405 if (match_ch(&s
, '=')) {
406 prop
->oper
= PROPERTY_OPER_EQ
;
407 } else if (MATCH(&s
, "!=")) {
408 prop
->oper
= PROPERTY_OPER_NE
;
410 /* A name alone is a Boolean comparison for true */
411 prop
->oper
= PROPERTY_OPER_EQ
;
412 prop
->type
= PROPERTY_TYPE_STRING
;
413 prop
->v
.str_val
= ossl_property_true
;
416 if (!parse_value(ctx
, &s
, prop
, 0))
417 prop
->type
= PROPERTY_TYPE_VALUE_UNDEFINED
;
420 if (!sk_PROPERTY_DEFINITION_push(sk
, prop
))
423 done
= !match_ch(&s
, ',');
426 PROPerr(PROP_F_OSSL_PARSE_QUERY
, PROP_R_TRAILING_CHARACTERS
);
429 res
= stack_to_property_list(sk
);
433 sk_PROPERTY_DEFINITION_pop_free(sk
, &pd_free
);
437 /* Does a property query have any optional clauses */
438 int ossl_property_has_optional(const OSSL_PROPERTY_LIST
*query
)
440 return query
->has_optional
? 1 : 0;
444 * Compare a query against a definition.
445 * Return the number of clauses matched or -1 if a mandatory clause is false.
447 int ossl_property_match_count(const OSSL_PROPERTY_LIST
*query
,
448 const OSSL_PROPERTY_LIST
*defn
)
450 const PROPERTY_DEFINITION
*const q
= query
->properties
;
451 const PROPERTY_DEFINITION
*const d
= defn
->properties
;
452 int i
= 0, j
= 0, matches
= 0;
455 while (i
< query
->n
) {
456 if ((oper
= q
[i
].oper
) == PROPERTY_OVERRIDE
) {
461 if (q
[i
].name_idx
> d
[j
].name_idx
) { /* skip defn, not in query */
465 if (q
[i
].name_idx
== d
[j
].name_idx
) { /* both in defn and query */
466 const int eq
= q
[i
].type
== d
[j
].type
467 && memcmp(&q
[i
].v
, &d
[j
].v
, sizeof(q
[i
].v
)) == 0;
469 if ((eq
&& oper
== PROPERTY_OPER_EQ
)
470 || (!eq
&& oper
== PROPERTY_OPER_NE
))
472 else if (!q
[i
].optional
)
481 * Handle the cases of a missing value and a query with no corresponding
482 * definition. The former fails for any comparision except inequality,
483 * the latter is treated as a comparison against the Boolean false.
485 if (q
[i
].type
== PROPERTY_TYPE_VALUE_UNDEFINED
) {
486 if (oper
== PROPERTY_OPER_NE
)
488 else if (!q
[i
].optional
)
490 } else if (q
[i
].type
!= PROPERTY_TYPE_STRING
491 || (oper
== PROPERTY_OPER_EQ
492 && q
[i
].v
.str_val
!= ossl_property_false
)
493 || (oper
== PROPERTY_OPER_NE
494 && q
[i
].v
.str_val
== ossl_property_false
)) {
505 void ossl_property_free(OSSL_PROPERTY_LIST
*p
)
511 * Merge two property lists.
512 * If there is a common name, the one from the first list is used.
514 OSSL_PROPERTY_LIST
*ossl_property_merge(const OSSL_PROPERTY_LIST
*a
,
515 const OSSL_PROPERTY_LIST
*b
)
517 const PROPERTY_DEFINITION
*const ap
= a
->properties
;
518 const PROPERTY_DEFINITION
*const bp
= b
->properties
;
519 const PROPERTY_DEFINITION
*copy
;
520 OSSL_PROPERTY_LIST
*r
;
522 const int t
= a
->n
+ b
->n
;
524 r
= OPENSSL_malloc(sizeof(*r
)
525 + (t
== 0 ? 0 : t
- 1) * sizeof(r
->properties
[0]));
529 for (i
= j
= n
= 0; i
< a
->n
|| j
< b
->n
; n
++) {
532 } else if (j
>= b
->n
) {
534 } else if (ap
[i
].name_idx
<= bp
[j
].name_idx
) {
535 if (ap
[i
].name_idx
== bp
[j
].name_idx
)
541 memcpy(r
->properties
+ n
, copy
, sizeof(r
->properties
[0]));
545 r
= OPENSSL_realloc(r
, sizeof(*r
) + (n
- 1) * sizeof(r
->properties
[0]));
549 int ossl_property_parse_init(OPENSSL_CTX
*ctx
)
551 static const char *const predefined_names
[] = {
552 "default", /* Being provided by the default built-in provider */
553 "legacy", /* Provided by the legacy provider */
554 "provider", /* Name of provider (default, fips) */
555 "version", /* Version number of this provider */
556 "fips", /* FIPS supporting provider */
557 "engine", /* An old style engine masquerading as a provider */
561 for (i
= 0; i
< OSSL_NELEM(predefined_names
); i
++)
562 if (ossl_property_name(ctx
, predefined_names
[i
], 1) == 0)
565 /* Pre-populate the two Boolean values */
566 if ((ossl_property_true
= ossl_property_value(ctx
, "yes", 1)) == 0
567 || (ossl_property_false
= ossl_property_value(ctx
, "no", 1)) == 0)