2 * Copyright 2019-2024 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/numbers.h"
18 #include "crypto/ctype.h"
19 #include "internal/nelem.h"
20 #include "property_local.h"
21 #include "internal/e_os.h"
23 DEFINE_STACK_OF(OSSL_PROPERTY_DEFINITION
)
25 static const char *skip_space(const char *s
)
27 while (ossl_isspace(*s
))
32 static int match_ch(const char *t
[], char m
)
37 *t
= skip_space(s
+ 1);
43 #define MATCH(s, m) match(s, m, sizeof(m) - 1)
45 static int match(const char *t
[], const char m
[], size_t m_len
)
49 if (OPENSSL_strncasecmp(s
, m
, m_len
) == 0) {
50 *t
= skip_space(s
+ m_len
);
56 static int parse_name(OSSL_LIB_CTX
*ctx
, const char *t
[], int create
,
57 OSSL_PROPERTY_IDX
*idx
)
66 if (!ossl_isalpha(*s
)) {
67 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NOT_AN_IDENTIFIER
,
72 if (i
< sizeof(name
) - 1)
73 name
[i
++] = ossl_tolower(*s
);
76 } while (*++s
== '_' || ossl_isalnum(*s
));
80 if (i
< sizeof(name
) - 1)
88 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NAME_TOO_LONG
, "HERE-->%s", *t
);
92 *idx
= ossl_property_name(ctx
, name
, user_name
&& create
);
96 static int parse_number(const char *t
[], OSSL_PROPERTY_DEFINITION
*res
)
102 if (!ossl_isdigit(*s
)) {
103 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NOT_A_DECIMAL_DIGIT
,
108 if (v
> ((INT64_MAX
- (*s
- '0')) / 10)) {
109 ERR_raise_data(ERR_LIB_PROP
, PROP_R_PARSE_FAILED
,
110 "Property %s overflows", *t
);
113 v
= v
* 10 + (*s
++ - '0');
114 } while (ossl_isdigit(*s
));
115 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
116 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NOT_A_DECIMAL_DIGIT
,
121 res
->type
= OSSL_PROPERTY_TYPE_NUMBER
;
126 static int parse_hex(const char *t
[], OSSL_PROPERTY_DEFINITION
*res
)
133 if (ossl_isdigit(*s
)) {
135 } else if (ossl_isxdigit(*s
)) {
136 sval
= ossl_tolower(*s
) - 'a' + 10;
138 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NOT_AN_HEXADECIMAL_DIGIT
,
143 if (v
> ((INT64_MAX
- sval
) / 16)) {
144 ERR_raise_data(ERR_LIB_PROP
, PROP_R_PARSE_FAILED
,
145 "Property %s overflows", *t
);
151 } while (ossl_isxdigit(*++s
));
152 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
153 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NOT_AN_HEXADECIMAL_DIGIT
,
158 res
->type
= OSSL_PROPERTY_TYPE_NUMBER
;
163 static int parse_oct(const char *t
[], OSSL_PROPERTY_DEFINITION
*res
)
169 if (*s
== '9' || *s
== '8' || !ossl_isdigit(*s
)) {
170 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NOT_AN_OCTAL_DIGIT
,
174 if (v
> ((INT64_MAX
- (*s
- '0')) / 8)) {
175 ERR_raise_data(ERR_LIB_PROP
, PROP_R_PARSE_FAILED
,
176 "Property %s overflows", *t
);
180 v
= (v
<< 3) + (*s
- '0');
181 } while (ossl_isdigit(*++s
) && *s
!= '9' && *s
!= '8');
182 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
183 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NOT_AN_OCTAL_DIGIT
,
188 res
->type
= OSSL_PROPERTY_TYPE_NUMBER
;
193 static int parse_string(OSSL_LIB_CTX
*ctx
, const char *t
[], char delim
,
194 OSSL_PROPERTY_DEFINITION
*res
, const int create
)
201 while (*s
!= '\0' && *s
!= delim
) {
202 if (i
< sizeof(v
) - 1)
209 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NO_MATCHING_STRING_DELIMITER
,
210 "HERE-->%c%s", delim
, *t
);
215 ERR_raise_data(ERR_LIB_PROP
, PROP_R_STRING_TOO_LONG
, "HERE-->%s", *t
);
217 res
->v
.str_val
= ossl_property_value(ctx
, v
, create
);
219 *t
= skip_space(s
+ 1);
220 res
->type
= OSSL_PROPERTY_TYPE_STRING
;
224 static int parse_unquoted(OSSL_LIB_CTX
*ctx
, const char *t
[],
225 OSSL_PROPERTY_DEFINITION
*res
, const int create
)
232 if (*s
== '\0' || *s
== ',')
234 while (ossl_isprint(*s
) && !ossl_isspace(*s
) && *s
!= ',') {
235 if (i
< sizeof(v
) - 1)
236 v
[i
++] = ossl_tolower(*s
);
241 if (!ossl_isspace(*s
) && *s
!= '\0' && *s
!= ',') {
242 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NOT_AN_ASCII_CHARACTER
,
248 ERR_raise_data(ERR_LIB_PROP
, PROP_R_STRING_TOO_LONG
, "HERE-->%s", *t
);
249 else if ((res
->v
.str_val
= ossl_property_value(ctx
, v
, create
)) == 0)
252 res
->type
= OSSL_PROPERTY_TYPE_STRING
;
256 static int parse_value(OSSL_LIB_CTX
*ctx
, const char *t
[],
257 OSSL_PROPERTY_DEFINITION
*res
, int create
)
262 if (*s
== '"' || *s
== '\'') {
264 r
= parse_string(ctx
, &s
, s
[-1], res
, create
);
265 } else if (*s
== '+') {
267 r
= parse_number(&s
, res
);
268 } else if (*s
== '-') {
270 r
= parse_number(&s
, res
);
271 res
->v
.int_val
= -res
->v
.int_val
;
272 } else if (*s
== '0' && s
[1] == 'x') {
274 r
= parse_hex(&s
, res
);
275 } else if (*s
== '0' && ossl_isdigit(s
[1])) {
277 r
= parse_oct(&s
, res
);
278 } else if (ossl_isdigit(*s
)) {
279 return parse_number(t
, res
);
280 } else if (ossl_isalpha(*s
))
281 return parse_unquoted(ctx
, t
, res
, create
);
287 static int pd_compare(const OSSL_PROPERTY_DEFINITION
*const *p1
,
288 const OSSL_PROPERTY_DEFINITION
*const *p2
)
290 const OSSL_PROPERTY_DEFINITION
*pd1
= *p1
;
291 const OSSL_PROPERTY_DEFINITION
*pd2
= *p2
;
293 if (pd1
->name_idx
< pd2
->name_idx
)
295 if (pd1
->name_idx
> pd2
->name_idx
)
300 static void pd_free(OSSL_PROPERTY_DEFINITION
*pd
)
306 * Convert a stack of property definitions and queries into a fixed array.
307 * The items are sorted for efficient query. The stack is not freed.
308 * This function also checks for duplicated names and returns an error if
311 static OSSL_PROPERTY_LIST
*
312 stack_to_property_list(OSSL_LIB_CTX
*ctx
,
313 STACK_OF(OSSL_PROPERTY_DEFINITION
) *sk
)
315 const int n
= sk_OSSL_PROPERTY_DEFINITION_num(sk
);
316 OSSL_PROPERTY_LIST
*r
;
317 OSSL_PROPERTY_IDX prev_name_idx
= 0;
320 r
= OPENSSL_malloc(sizeof(*r
)
321 + (n
<= 0 ? 0 : n
- 1) * sizeof(r
->properties
[0]));
323 sk_OSSL_PROPERTY_DEFINITION_sort(sk
);
326 for (i
= 0; i
< n
; i
++) {
327 r
->properties
[i
] = *sk_OSSL_PROPERTY_DEFINITION_value(sk
, i
);
328 r
->has_optional
|= r
->properties
[i
].optional
;
330 /* Check for duplicated names */
331 if (i
> 0 && r
->properties
[i
].name_idx
== prev_name_idx
) {
333 ERR_raise_data(ERR_LIB_PROP
, PROP_R_PARSE_FAILED
,
334 "Duplicated name `%s'",
335 ossl_property_name_str(ctx
, prev_name_idx
));
338 prev_name_idx
= r
->properties
[i
].name_idx
;
340 r
->num_properties
= n
;
345 OSSL_PROPERTY_LIST
*ossl_parse_property(OSSL_LIB_CTX
*ctx
, const char *defn
)
347 OSSL_PROPERTY_DEFINITION
*prop
= NULL
;
348 OSSL_PROPERTY_LIST
*res
= NULL
;
349 STACK_OF(OSSL_PROPERTY_DEFINITION
) *sk
;
350 const char *s
= defn
;
353 if (s
== NULL
|| (sk
= sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare
)) == NULL
)
359 const char *start
= s
;
361 prop
= OPENSSL_malloc(sizeof(*prop
));
364 memset(&prop
->v
, 0, sizeof(prop
->v
));
366 if (!parse_name(ctx
, &s
, 1, &prop
->name_idx
))
368 prop
->oper
= OSSL_PROPERTY_OPER_EQ
;
369 if (prop
->name_idx
== 0) {
370 ERR_raise_data(ERR_LIB_PROP
, PROP_R_PARSE_FAILED
,
371 "Unknown name HERE-->%s", start
);
374 if (match_ch(&s
, '=')) {
375 if (!parse_value(ctx
, &s
, prop
, 1)) {
376 ERR_raise_data(ERR_LIB_PROP
, PROP_R_NO_VALUE
,
381 /* A name alone means a true Boolean */
382 prop
->type
= OSSL_PROPERTY_TYPE_STRING
;
383 prop
->v
.str_val
= OSSL_PROPERTY_TRUE
;
386 if (!sk_OSSL_PROPERTY_DEFINITION_push(sk
, prop
))
389 done
= !match_ch(&s
, ',');
392 ERR_raise_data(ERR_LIB_PROP
, PROP_R_TRAILING_CHARACTERS
,
396 res
= stack_to_property_list(ctx
, sk
);
400 sk_OSSL_PROPERTY_DEFINITION_pop_free(sk
, &pd_free
);
404 OSSL_PROPERTY_LIST
*ossl_parse_query(OSSL_LIB_CTX
*ctx
, const char *s
,
407 STACK_OF(OSSL_PROPERTY_DEFINITION
) *sk
;
408 OSSL_PROPERTY_LIST
*res
= NULL
;
409 OSSL_PROPERTY_DEFINITION
*prop
= NULL
;
412 if (s
== NULL
|| (sk
= sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare
)) == NULL
)
418 prop
= OPENSSL_malloc(sizeof(*prop
));
421 memset(&prop
->v
, 0, sizeof(prop
->v
));
423 if (match_ch(&s
, '-')) {
424 prop
->oper
= OSSL_PROPERTY_OVERRIDE
;
426 if (!parse_name(ctx
, &s
, 1, &prop
->name_idx
))
430 prop
->optional
= match_ch(&s
, '?');
431 if (!parse_name(ctx
, &s
, 1, &prop
->name_idx
))
434 if (match_ch(&s
, '=')) {
435 prop
->oper
= OSSL_PROPERTY_OPER_EQ
;
436 } else if (MATCH(&s
, "!=")) {
437 prop
->oper
= OSSL_PROPERTY_OPER_NE
;
439 /* A name alone is a Boolean comparison for true */
440 prop
->oper
= OSSL_PROPERTY_OPER_EQ
;
441 prop
->type
= OSSL_PROPERTY_TYPE_STRING
;
442 prop
->v
.str_val
= OSSL_PROPERTY_TRUE
;
445 if (!parse_value(ctx
, &s
, prop
, create_values
))
446 prop
->type
= OSSL_PROPERTY_TYPE_VALUE_UNDEFINED
;
449 if (!sk_OSSL_PROPERTY_DEFINITION_push(sk
, prop
))
452 done
= !match_ch(&s
, ',');
455 ERR_raise_data(ERR_LIB_PROP
, PROP_R_TRAILING_CHARACTERS
,
459 res
= stack_to_property_list(ctx
, sk
);
463 sk_OSSL_PROPERTY_DEFINITION_pop_free(sk
, &pd_free
);
468 * Compare a query against a definition.
469 * Return the number of clauses matched or -1 if a mandatory clause is false.
471 int ossl_property_match_count(const OSSL_PROPERTY_LIST
*query
,
472 const OSSL_PROPERTY_LIST
*defn
)
474 const OSSL_PROPERTY_DEFINITION
*const q
= query
->properties
;
475 const OSSL_PROPERTY_DEFINITION
*const d
= defn
->properties
;
476 int i
= 0, j
= 0, matches
= 0;
477 OSSL_PROPERTY_OPER oper
;
479 while (i
< query
->num_properties
) {
480 if ((oper
= q
[i
].oper
) == OSSL_PROPERTY_OVERRIDE
) {
484 if (j
< defn
->num_properties
) {
485 if (q
[i
].name_idx
> d
[j
].name_idx
) { /* skip defn, not in query */
489 if (q
[i
].name_idx
== d
[j
].name_idx
) { /* both in defn and query */
490 const int eq
= q
[i
].type
== d
[j
].type
491 && memcmp(&q
[i
].v
, &d
[j
].v
, sizeof(q
[i
].v
)) == 0;
493 if ((eq
&& oper
== OSSL_PROPERTY_OPER_EQ
)
494 || (!eq
&& oper
== OSSL_PROPERTY_OPER_NE
))
496 else if (!q
[i
].optional
)
505 * Handle the cases of a missing value and a query with no corresponding
506 * definition. The former fails for any comparison except inequality,
507 * the latter is treated as a comparison against the Boolean false.
509 if (q
[i
].type
== OSSL_PROPERTY_TYPE_VALUE_UNDEFINED
) {
510 if (oper
== OSSL_PROPERTY_OPER_NE
)
512 else if (!q
[i
].optional
)
514 } else if (q
[i
].type
!= OSSL_PROPERTY_TYPE_STRING
515 || (oper
== OSSL_PROPERTY_OPER_EQ
516 && q
[i
].v
.str_val
!= OSSL_PROPERTY_FALSE
)
517 || (oper
== OSSL_PROPERTY_OPER_NE
518 && q
[i
].v
.str_val
== OSSL_PROPERTY_FALSE
)) {
529 void ossl_property_free(OSSL_PROPERTY_LIST
*p
)
535 * Merge two property lists.
536 * If there is a common name, the one from the first list is used.
538 OSSL_PROPERTY_LIST
*ossl_property_merge(const OSSL_PROPERTY_LIST
*a
,
539 const OSSL_PROPERTY_LIST
*b
)
541 const OSSL_PROPERTY_DEFINITION
*const ap
= a
->properties
;
542 const OSSL_PROPERTY_DEFINITION
*const bp
= b
->properties
;
543 const OSSL_PROPERTY_DEFINITION
*copy
;
544 OSSL_PROPERTY_LIST
*r
;
546 const int t
= a
->num_properties
+ b
->num_properties
;
548 r
= OPENSSL_malloc(sizeof(*r
)
549 + (t
== 0 ? 0 : t
- 1) * sizeof(r
->properties
[0]));
554 for (i
= j
= n
= 0; i
< a
->num_properties
|| j
< b
->num_properties
; n
++) {
555 if (i
>= a
->num_properties
) {
557 } else if (j
>= b
->num_properties
) {
559 } else if (ap
[i
].name_idx
<= bp
[j
].name_idx
) {
560 if (ap
[i
].name_idx
== bp
[j
].name_idx
)
566 memcpy(r
->properties
+ n
, copy
, sizeof(r
->properties
[0]));
567 r
->has_optional
|= copy
->optional
;
569 r
->num_properties
= n
;
571 r
= OPENSSL_realloc(r
, sizeof(*r
) + (n
- 1) * sizeof(r
->properties
[0]));
575 int ossl_property_parse_init(OSSL_LIB_CTX
*ctx
)
577 static const char *const predefined_names
[] = {
578 "provider", /* Name of provider (default, legacy, fips) */
579 "version", /* Version number of this provider */
580 "fips", /* FIPS validated or FIPS supporting algorithm */
581 "output", /* Output type for encoders */
582 "input", /* Input type for decoders */
583 "structure", /* Structure name for encoders and decoders */
587 for (i
= 0; i
< OSSL_NELEM(predefined_names
); i
++)
588 if (ossl_property_name(ctx
, predefined_names
[i
], 1) == 0)
592 * Pre-populate the two Boolean values. We must do them before any other
593 * values and in this order so that we get the same index as the global
594 * OSSL_PROPERTY_TRUE and OSSL_PROPERTY_FALSE values
596 if ((ossl_property_value(ctx
, "yes", 1) != OSSL_PROPERTY_TRUE
)
597 || (ossl_property_value(ctx
, "no", 1) != OSSL_PROPERTY_FALSE
))
605 static void put_char(char ch
, char **buf
, size_t *remain
, size_t *needed
)
620 static void put_str(const char *str
, char **buf
, size_t *remain
, size_t *needed
)
626 len
= olen
= strlen(str
);
630 * Check to see if we need quotes or not.
631 * Characters that are legal in a PropertyName don't need quoting.
632 * We simply assume all others require quotes.
634 for (i
= 0; i
< len
; i
++)
635 if (!ossl_isalnum(str
[i
]) && str
[i
] != '.' && str
[i
] != '_') {
636 /* Default to single quotes ... */
639 /* ... but use double quotes if a single is present */
644 quotes
= quote
!= '\0';
646 *needed
+= 2 * quotes
;
651 put_char(quote
, buf
, remain
, needed
);
653 if (*remain
< len
+ 1 + quotes
)
657 memcpy(*buf
, str
, len
);
663 put_char(quote
, buf
, remain
, needed
);
665 if (len
< olen
&& *remain
== 1) {
672 static void put_num(int64_t val
, char **buf
, size_t *remain
, size_t *needed
)
674 int64_t tmpval
= val
;
681 for (; tmpval
> 9; len
++, tmpval
/= 10);
688 BIO_snprintf(*buf
, *remain
, "%lld", (long long int)val
);
698 size_t ossl_property_list_to_string(OSSL_LIB_CTX
*ctx
,
699 const OSSL_PROPERTY_LIST
*list
, char *buf
,
703 const OSSL_PROPERTY_DEFINITION
*prop
= NULL
;
712 if (list
->num_properties
!= 0)
713 prop
= &list
->properties
[list
->num_properties
- 1];
714 for (i
= 0; i
< list
->num_properties
; i
++, prop
--) {
715 /* Skip invalid names */
716 if (prop
->name_idx
== 0)
720 put_char(',', &buf
, &bufsize
, &needed
);
723 put_char('?', &buf
, &bufsize
, &needed
);
724 else if (prop
->oper
== OSSL_PROPERTY_OVERRIDE
)
725 put_char('-', &buf
, &bufsize
, &needed
);
727 val
= ossl_property_name_str(ctx
, prop
->name_idx
);
730 put_str(val
, &buf
, &bufsize
, &needed
);
732 switch (prop
->oper
) {
733 case OSSL_PROPERTY_OPER_NE
:
734 put_char('!', &buf
, &bufsize
, &needed
);
736 case OSSL_PROPERTY_OPER_EQ
:
737 put_char('=', &buf
, &bufsize
, &needed
);
739 switch (prop
->type
) {
740 case OSSL_PROPERTY_TYPE_STRING
:
741 val
= ossl_property_value_str(ctx
, prop
->v
.str_val
);
744 put_str(val
, &buf
, &bufsize
, &needed
);
747 case OSSL_PROPERTY_TYPE_NUMBER
:
748 put_num(prop
->v
.int_val
, &buf
, &bufsize
, &needed
);
761 put_char('\0', &buf
, &bufsize
, &needed
);