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
);
95 ERR_add_error_data(2, "HERE-->", *t
);
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 PROPerr(PROP_F_PARSE_NAME
, PROP_R_NAME_TOO_LONG
);
116 ERR_add_error_data(2, "HERE-->", *t
);
120 *idx
= ossl_property_name(ctx
, name
, user_name
&& create
);
124 static int parse_number(const char *t
[], PROPERTY_DEFINITION
*res
)
129 if (!ossl_isdigit(*s
))
132 v
= v
* 10 + (*s
++ - '0');
133 } while (ossl_isdigit(*s
));
134 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
135 PROPerr(PROP_F_PARSE_NUMBER
, PROP_R_NOT_A_DECIMAL_DIGIT
);
136 ERR_add_error_data(2, "HERE-->", *t
);
140 res
->type
= PROPERTY_TYPE_NUMBER
;
145 static int parse_hex(const char *t
[], PROPERTY_DEFINITION
*res
)
150 if (!ossl_isxdigit(*s
))
154 if (ossl_isdigit(*s
))
157 v
+= ossl_tolower(*s
) - 'a';
158 } while (ossl_isxdigit(*++s
));
159 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
160 PROPerr(PROP_F_PARSE_HEX
, PROP_R_NOT_AN_HEXADECIMAL_DIGIT
);
161 ERR_add_error_data(2, "HERE-->", *t
);
165 res
->type
= PROPERTY_TYPE_NUMBER
;
170 static int parse_oct(const char *t
[], PROPERTY_DEFINITION
*res
)
175 if (*s
== '9' || *s
== '8' || !ossl_isdigit(*s
))
178 v
= (v
<< 3) + (*s
- '0');
179 } while (ossl_isdigit(*++s
) && *s
!= '9' && *s
!= '8');
180 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
181 PROPerr(PROP_F_PARSE_OCT
, PROP_R_NOT_AN_OCTAL_DIGIT
);
182 ERR_add_error_data(2, "HERE-->", *t
);
186 res
->type
= PROPERTY_TYPE_NUMBER
;
191 static int parse_string(OPENSSL_CTX
*ctx
, const char *t
[], char delim
,
192 PROPERTY_DEFINITION
*res
, const int create
)
199 while (*s
!= '\0' && *s
!= delim
) {
200 if (i
< sizeof(v
) - 1)
207 char buf
[2] = { 0, 0 };
209 PROPerr(PROP_F_PARSE_STRING
,
210 PROP_R_NO_MATCHING_STRING_DELIMETER
);
212 ERR_add_error_data(3, "HERE-->", buf
, *t
);
217 PROPerr(PROP_F_PARSE_STRING
, PROP_R_STRING_TOO_LONG
);
218 ERR_add_error_data(2, "HERE-->", *t
);
220 res
->v
.str_val
= ossl_property_value(ctx
, v
, create
);
222 *t
= skip_space(s
+ 1);
223 res
->type
= PROPERTY_TYPE_STRING
;
227 static int parse_unquoted(OPENSSL_CTX
*ctx
, const char *t
[],
228 PROPERTY_DEFINITION
*res
, const int create
)
235 if (*s
== '\0' || *s
== ',')
237 while (ossl_isprint(*s
) && !ossl_isspace(*s
) && *s
!= ',') {
238 if (i
< sizeof(v
) - 1)
239 v
[i
++] = ossl_tolower(*s
);
244 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
245 PROPerr(PROP_F_PARSE_UNQUOTED
, PROP_R_NOT_AN_ASCII_CHARACTER
);
246 ERR_add_error_data(2, "HERE-->", s
);
251 PROPerr(PROP_F_PARSE_UNQUOTED
, PROP_R_STRING_TOO_LONG
);
252 ERR_add_error_data(2, "HERE-->", *t
);
254 res
->v
.str_val
= ossl_property_value(ctx
, v
, create
);
257 res
->type
= PROPERTY_TYPE_STRING
;
261 static int parse_value(OPENSSL_CTX
*ctx
, const char *t
[],
262 PROPERTY_DEFINITION
*res
, int create
)
267 if (*s
== '"' || *s
== '\'') {
269 r
= parse_string(ctx
, &s
, s
[-1], res
, create
);
270 } else if (*s
== '+') {
272 r
= parse_number(&s
, res
);
273 } else if (*s
== '-') {
275 r
= parse_number(&s
, res
);
276 res
->v
.int_val
= -res
->v
.int_val
;
277 } else if (*s
== '0' && s
[1] == 'x') {
279 r
= parse_hex(&s
, res
);
280 } else if (*s
== '0' && ossl_isdigit(s
[1])) {
282 r
= parse_oct(&s
, res
);
283 } else if (ossl_isdigit(*s
)) {
284 return parse_number(t
, res
);
285 } else if (ossl_isalpha(*s
))
286 return parse_unquoted(ctx
, t
, res
, create
);
292 static int pd_compare(const PROPERTY_DEFINITION
*const *p1
,
293 const PROPERTY_DEFINITION
*const *p2
)
295 const PROPERTY_DEFINITION
*pd1
= *p1
;
296 const PROPERTY_DEFINITION
*pd2
= *p2
;
298 if (pd1
->name_idx
< pd2
->name_idx
)
300 if (pd1
->name_idx
> pd2
->name_idx
)
305 static void pd_free(PROPERTY_DEFINITION
*pd
)
311 * Convert a stack of property definitions and queries into a fixed array.
312 * The items are sorted for efficient query. The stack is not freed.
314 static OSSL_PROPERTY_LIST
*stack_to_property_list(STACK_OF(PROPERTY_DEFINITION
)
317 const int n
= sk_PROPERTY_DEFINITION_num(sk
);
318 OSSL_PROPERTY_LIST
*r
;
321 r
= OPENSSL_malloc(sizeof(*r
)
322 + (n
<= 0 ? 0 : n
- 1) * sizeof(r
->properties
[0]));
324 sk_PROPERTY_DEFINITION_sort(sk
);
327 for (i
= 0; i
< n
; i
++) {
328 r
->properties
[i
] = *sk_PROPERTY_DEFINITION_value(sk
, i
);
329 r
->has_optional
|= r
->properties
[i
].optional
;
336 OSSL_PROPERTY_LIST
*ossl_parse_property(OPENSSL_CTX
*ctx
, const char *defn
)
338 PROPERTY_DEFINITION
*prop
= NULL
;
339 OSSL_PROPERTY_LIST
*res
= NULL
;
340 STACK_OF(PROPERTY_DEFINITION
) *sk
;
341 const char *s
= defn
;
344 if (s
== NULL
|| (sk
= sk_PROPERTY_DEFINITION_new(&pd_compare
)) == NULL
)
350 const char *start
= s
;
352 prop
= OPENSSL_malloc(sizeof(*prop
));
355 memset(&prop
->v
, 0, sizeof(prop
->v
));
357 if (!parse_name(ctx
, &s
, 1, &prop
->name_idx
))
359 prop
->oper
= PROPERTY_OPER_EQ
;
360 if (prop
->name_idx
== 0) {
361 PROPerr(PROP_F_OSSL_PARSE_PROPERTY
, PROP_R_PARSE_FAILED
);
362 ERR_add_error_data(2, "Unknown name HERE-->", start
);
365 if (match_ch(&s
, '=')) {
366 if (!parse_value(ctx
, &s
, prop
, 1)) {
367 PROPerr(PROP_F_OSSL_PARSE_PROPERTY
, PROP_R_NO_VALUE
);
368 ERR_add_error_data(2, "HERE-->", start
);
372 /* A name alone means a true Boolean */
373 prop
->type
= PROPERTY_TYPE_STRING
;
374 prop
->v
.str_val
= ossl_property_true
;
377 if (!sk_PROPERTY_DEFINITION_push(sk
, prop
))
380 done
= !match_ch(&s
, ',');
383 PROPerr(PROP_F_OSSL_PARSE_PROPERTY
, PROP_R_TRAILING_CHARACTERS
);
384 ERR_add_error_data(2, "HERE-->", s
);
387 res
= stack_to_property_list(sk
);
391 sk_PROPERTY_DEFINITION_pop_free(sk
, &pd_free
);
395 OSSL_PROPERTY_LIST
*ossl_parse_query(OPENSSL_CTX
*ctx
, const char *s
)
397 STACK_OF(PROPERTY_DEFINITION
) *sk
;
398 OSSL_PROPERTY_LIST
*res
= NULL
;
399 PROPERTY_DEFINITION
*prop
= NULL
;
402 if (s
== NULL
|| (sk
= sk_PROPERTY_DEFINITION_new(&pd_compare
)) == NULL
)
408 prop
= OPENSSL_malloc(sizeof(*prop
));
411 memset(&prop
->v
, 0, sizeof(prop
->v
));
413 if (match_ch(&s
, '-')) {
414 prop
->oper
= PROPERTY_OVERRIDE
;
416 if (!parse_name(ctx
, &s
, 0, &prop
->name_idx
))
420 prop
->optional
= match_ch(&s
, '?');
421 if (!parse_name(ctx
, &s
, 0, &prop
->name_idx
))
424 if (match_ch(&s
, '=')) {
425 prop
->oper
= PROPERTY_OPER_EQ
;
426 } else if (MATCH(&s
, "!=")) {
427 prop
->oper
= PROPERTY_OPER_NE
;
429 /* A name alone is a Boolean comparison for true */
430 prop
->oper
= PROPERTY_OPER_EQ
;
431 prop
->type
= PROPERTY_TYPE_STRING
;
432 prop
->v
.str_val
= ossl_property_true
;
435 if (!parse_value(ctx
, &s
, prop
, 0))
436 prop
->type
= PROPERTY_TYPE_VALUE_UNDEFINED
;
439 if (!sk_PROPERTY_DEFINITION_push(sk
, prop
))
442 done
= !match_ch(&s
, ',');
445 PROPerr(PROP_F_OSSL_PARSE_QUERY
, PROP_R_TRAILING_CHARACTERS
);
446 ERR_add_error_data(2, "HERE-->", s
);
449 res
= stack_to_property_list(sk
);
453 sk_PROPERTY_DEFINITION_pop_free(sk
, &pd_free
);
457 /* Does a property query have any optional clauses */
458 int ossl_property_has_optional(const OSSL_PROPERTY_LIST
*query
)
460 return query
->has_optional
? 1 : 0;
464 * Compare a query against a definition.
465 * Return the number of clauses matched or -1 if a mandatory clause is false.
467 int ossl_property_match_count(const OSSL_PROPERTY_LIST
*query
,
468 const OSSL_PROPERTY_LIST
*defn
)
470 const PROPERTY_DEFINITION
*const q
= query
->properties
;
471 const PROPERTY_DEFINITION
*const d
= defn
->properties
;
472 int i
= 0, j
= 0, matches
= 0;
475 while (i
< query
->n
) {
476 if ((oper
= q
[i
].oper
) == PROPERTY_OVERRIDE
) {
481 if (q
[i
].name_idx
> d
[j
].name_idx
) { /* skip defn, not in query */
485 if (q
[i
].name_idx
== d
[j
].name_idx
) { /* both in defn and query */
486 const int eq
= q
[i
].type
== d
[j
].type
487 && memcmp(&q
[i
].v
, &d
[j
].v
, sizeof(q
[i
].v
)) == 0;
489 if ((eq
&& oper
== PROPERTY_OPER_EQ
)
490 || (!eq
&& oper
== PROPERTY_OPER_NE
))
492 else if (!q
[i
].optional
)
501 * Handle the cases of a missing value and a query with no corresponding
502 * definition. The former fails for any comparision except inequality,
503 * the latter is treated as a comparison against the Boolean false.
505 if (q
[i
].type
== PROPERTY_TYPE_VALUE_UNDEFINED
) {
506 if (oper
== PROPERTY_OPER_NE
)
508 else if (!q
[i
].optional
)
510 } else if (q
[i
].type
!= PROPERTY_TYPE_STRING
511 || (oper
== PROPERTY_OPER_EQ
512 && q
[i
].v
.str_val
!= ossl_property_false
)
513 || (oper
== PROPERTY_OPER_NE
514 && q
[i
].v
.str_val
== ossl_property_false
)) {
525 void ossl_property_free(OSSL_PROPERTY_LIST
*p
)
531 * Merge two property lists.
532 * If there is a common name, the one from the first list is used.
534 OSSL_PROPERTY_LIST
*ossl_property_merge(const OSSL_PROPERTY_LIST
*a
,
535 const OSSL_PROPERTY_LIST
*b
)
537 const PROPERTY_DEFINITION
*const ap
= a
->properties
;
538 const PROPERTY_DEFINITION
*const bp
= b
->properties
;
539 const PROPERTY_DEFINITION
*copy
;
540 OSSL_PROPERTY_LIST
*r
;
542 const int t
= a
->n
+ b
->n
;
544 r
= OPENSSL_malloc(sizeof(*r
)
545 + (t
== 0 ? 0 : t
- 1) * sizeof(r
->properties
[0]));
549 for (i
= j
= n
= 0; i
< a
->n
|| j
< b
->n
; n
++) {
552 } else if (j
>= b
->n
) {
554 } else if (ap
[i
].name_idx
<= bp
[j
].name_idx
) {
555 if (ap
[i
].name_idx
== bp
[j
].name_idx
)
561 memcpy(r
->properties
+ n
, copy
, sizeof(r
->properties
[0]));
565 r
= OPENSSL_realloc(r
, sizeof(*r
) + (n
- 1) * sizeof(r
->properties
[0]));
569 int ossl_property_parse_init(OPENSSL_CTX
*ctx
)
571 static const char *const predefined_names
[] = {
572 "default", /* Being provided by the default built-in provider */
573 "legacy", /* Provided by the legacy provider */
574 "provider", /* Name of provider (default, fips) */
575 "version", /* Version number of this provider */
576 "fips", /* FIPS supporting provider */
577 "engine", /* An old style engine masquerading as a provider */
581 for (i
= 0; i
< OSSL_NELEM(predefined_names
); i
++)
582 if (ossl_property_name(ctx
, predefined_names
[i
], 1) == 0)
585 /* Pre-populate the two Boolean values */
586 if ((ossl_property_true
= ossl_property_value(ctx
, "yes", 1)) == 0
587 || (ossl_property_false
= ossl_property_value(ctx
, "no", 1)) == 0)