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)