]>
Commit | Line | Data |
---|---|---|
1bdbdaff | 1 | /* |
b6461792 | 2 | * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. |
1bdbdaff P |
3 | * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. |
4 | * | |
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 | |
9 | */ | |
10 | ||
11 | #include <string.h> | |
12 | #include <stdio.h> | |
13 | #include <stdarg.h> | |
14 | #include <openssl/err.h> | |
15 | #include "internal/propertyerr.h" | |
16 | #include "internal/property.h" | |
c3e8d678 | 17 | #include "internal/numbers.h" |
25f2138b | 18 | #include "crypto/ctype.h" |
1bdbdaff | 19 | #include "internal/nelem.h" |
706457b7 | 20 | #include "property_local.h" |
d5f9166b | 21 | #include "internal/e_os.h" |
1bdbdaff | 22 | |
6ec3b2cf | 23 | DEFINE_STACK_OF(OSSL_PROPERTY_DEFINITION) |
1bdbdaff P |
24 | |
25 | static const char *skip_space(const char *s) | |
26 | { | |
27 | while (ossl_isspace(*s)) | |
28 | s++; | |
29 | return s; | |
30 | } | |
31 | ||
32 | static int match_ch(const char *t[], char m) | |
33 | { | |
34 | const char *s = *t; | |
35 | ||
36 | if (*s == m) { | |
37 | *t = skip_space(s + 1); | |
38 | return 1; | |
39 | } | |
40 | return 0; | |
41 | } | |
42 | ||
43 | #define MATCH(s, m) match(s, m, sizeof(m) - 1) | |
44 | ||
45 | static int match(const char *t[], const char m[], size_t m_len) | |
46 | { | |
47 | const char *s = *t; | |
48 | ||
fba140c7 | 49 | if (OPENSSL_strncasecmp(s, m, m_len) == 0) { |
1bdbdaff P |
50 | *t = skip_space(s + m_len); |
51 | return 1; | |
52 | } | |
53 | return 0; | |
54 | } | |
55 | ||
b4250010 | 56 | static int parse_name(OSSL_LIB_CTX *ctx, const char *t[], int create, |
1aedc35f | 57 | OSSL_PROPERTY_IDX *idx) |
1bdbdaff P |
58 | { |
59 | char name[100]; | |
60 | int err = 0; | |
61 | size_t i = 0; | |
62 | const char *s = *t; | |
63 | int user_name = 0; | |
64 | ||
65 | for (;;) { | |
66 | if (!ossl_isalpha(*s)) { | |
49c64346 RL |
67 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER, |
68 | "HERE-->%s", *t); | |
1bdbdaff P |
69 | return 0; |
70 | } | |
71 | do { | |
72 | if (i < sizeof(name) - 1) | |
73 | name[i++] = ossl_tolower(*s); | |
74 | else | |
75 | err = 1; | |
76 | } while (*++s == '_' || ossl_isalnum(*s)); | |
77 | if (*s != '.') | |
78 | break; | |
79 | user_name = 1; | |
80 | if (i < sizeof(name) - 1) | |
81 | name[i++] = *s; | |
82 | else | |
83 | err = 1; | |
84 | s++; | |
85 | } | |
86 | name[i] = '\0'; | |
4cdb302f | 87 | if (err) { |
49c64346 | 88 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NAME_TOO_LONG, "HERE-->%s", *t); |
4cdb302f | 89 | return 0; |
1bdbdaff | 90 | } |
4cdb302f RL |
91 | *t = skip_space(s); |
92 | *idx = ossl_property_name(ctx, name, user_name && create); | |
93 | return 1; | |
1bdbdaff P |
94 | } |
95 | ||
6ec3b2cf | 96 | static int parse_number(const char *t[], OSSL_PROPERTY_DEFINITION *res) |
1bdbdaff P |
97 | { |
98 | const char *s = *t; | |
99 | int64_t v = 0; | |
100 | ||
1bdbdaff | 101 | do { |
986c48c4 NH |
102 | if (!ossl_isdigit(*s)) { |
103 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT, | |
104 | "HERE-->%s", *t); | |
105 | return 0; | |
106 | } | |
107 | /* overflow check */ | |
108 | if (v > ((INT64_MAX - (*s - '0')) / 10)) { | |
109 | ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED, | |
110 | "Property %s overflows", *t); | |
111 | return 0; | |
112 | } | |
1bdbdaff P |
113 | v = v * 10 + (*s++ - '0'); |
114 | } while (ossl_isdigit(*s)); | |
115 | if (!ossl_isspace(*s) && *s != '\0' && *s != ',') { | |
49c64346 RL |
116 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT, |
117 | "HERE-->%s", *t); | |
1bdbdaff P |
118 | return 0; |
119 | } | |
120 | *t = skip_space(s); | |
6ec3b2cf | 121 | res->type = OSSL_PROPERTY_TYPE_NUMBER; |
1bdbdaff P |
122 | res->v.int_val = v; |
123 | return 1; | |
124 | } | |
125 | ||
6ec3b2cf | 126 | static int parse_hex(const char *t[], OSSL_PROPERTY_DEFINITION *res) |
1bdbdaff P |
127 | { |
128 | const char *s = *t; | |
129 | int64_t v = 0; | |
986c48c4 | 130 | int sval; |
1bdbdaff | 131 | |
1bdbdaff | 132 | do { |
986c48c4 NH |
133 | if (ossl_isdigit(*s)) { |
134 | sval = *s - '0'; | |
135 | } else if (ossl_isxdigit(*s)) { | |
136 | sval = ossl_tolower(*s) - 'a' + 10; | |
137 | } else { | |
138 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT, | |
139 | "%s", *t); | |
140 | return 0; | |
141 | } | |
142 | ||
143 | if (v > ((INT64_MAX - sval) / 16)) { | |
144 | ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED, | |
145 | "Property %s overflows", *t); | |
146 | return 0; | |
147 | } | |
148 | ||
1bdbdaff | 149 | v <<= 4; |
986c48c4 | 150 | v += sval; |
1bdbdaff P |
151 | } while (ossl_isxdigit(*++s)); |
152 | if (!ossl_isspace(*s) && *s != '\0' && *s != ',') { | |
49c64346 RL |
153 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT, |
154 | "HERE-->%s", *t); | |
1bdbdaff P |
155 | return 0; |
156 | } | |
157 | *t = skip_space(s); | |
6ec3b2cf | 158 | res->type = OSSL_PROPERTY_TYPE_NUMBER; |
1bdbdaff P |
159 | res->v.int_val = v; |
160 | return 1; | |
161 | } | |
162 | ||
6ec3b2cf | 163 | static int parse_oct(const char *t[], OSSL_PROPERTY_DEFINITION *res) |
1bdbdaff P |
164 | { |
165 | const char *s = *t; | |
166 | int64_t v = 0; | |
167 | ||
1bdbdaff | 168 | do { |
986c48c4 NH |
169 | if (*s == '9' || *s == '8' || !ossl_isdigit(*s)) { |
170 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT, | |
171 | "HERE-->%s", *t); | |
172 | return 0; | |
173 | } | |
174 | if (v > ((INT64_MAX - (*s - '0')) / 8)) { | |
175 | ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED, | |
176 | "Property %s overflows", *t); | |
177 | return 0; | |
178 | } | |
179 | ||
1bdbdaff P |
180 | v = (v << 3) + (*s - '0'); |
181 | } while (ossl_isdigit(*++s) && *s != '9' && *s != '8'); | |
182 | if (!ossl_isspace(*s) && *s != '\0' && *s != ',') { | |
49c64346 RL |
183 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT, |
184 | "HERE-->%s", *t); | |
1bdbdaff P |
185 | return 0; |
186 | } | |
187 | *t = skip_space(s); | |
6ec3b2cf | 188 | res->type = OSSL_PROPERTY_TYPE_NUMBER; |
1bdbdaff P |
189 | res->v.int_val = v; |
190 | return 1; | |
191 | } | |
192 | ||
b4250010 | 193 | static int parse_string(OSSL_LIB_CTX *ctx, const char *t[], char delim, |
6ec3b2cf | 194 | OSSL_PROPERTY_DEFINITION *res, const int create) |
1bdbdaff P |
195 | { |
196 | char v[1000]; | |
197 | const char *s = *t; | |
198 | size_t i = 0; | |
199 | int err = 0; | |
200 | ||
201 | while (*s != '\0' && *s != delim) { | |
202 | if (i < sizeof(v) - 1) | |
203 | v[i++] = *s; | |
204 | else | |
205 | err = 1; | |
206 | s++; | |
207 | } | |
208 | if (*s == '\0') { | |
79c44b4e | 209 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER, |
49c64346 | 210 | "HERE-->%c%s", delim, *t); |
1bdbdaff P |
211 | return 0; |
212 | } | |
213 | v[i] = '\0'; | |
4cdb302f | 214 | if (err) { |
49c64346 | 215 | ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t); |
4cdb302f | 216 | } else { |
1aedc35f | 217 | res->v.str_val = ossl_property_value(ctx, v, create); |
4cdb302f RL |
218 | } |
219 | *t = skip_space(s + 1); | |
6ec3b2cf | 220 | res->type = OSSL_PROPERTY_TYPE_STRING; |
1bdbdaff P |
221 | return !err; |
222 | } | |
223 | ||
b4250010 | 224 | static int parse_unquoted(OSSL_LIB_CTX *ctx, const char *t[], |
6ec3b2cf | 225 | OSSL_PROPERTY_DEFINITION *res, const int create) |
1bdbdaff P |
226 | { |
227 | char v[1000]; | |
228 | const char *s = *t; | |
229 | size_t i = 0; | |
230 | int err = 0; | |
231 | ||
232 | if (*s == '\0' || *s == ',') | |
233 | return 0; | |
234 | while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') { | |
235 | if (i < sizeof(v) - 1) | |
236 | v[i++] = ossl_tolower(*s); | |
237 | else | |
238 | err = 1; | |
239 | s++; | |
240 | } | |
241 | if (!ossl_isspace(*s) && *s != '\0' && *s != ',') { | |
49c64346 RL |
242 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER, |
243 | "HERE-->%s", s); | |
1bdbdaff P |
244 | return 0; |
245 | } | |
246 | v[i] = 0; | |
f91568eb | 247 | if (err) |
49c64346 | 248 | ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t); |
f91568eb TM |
249 | else if ((res->v.str_val = ossl_property_value(ctx, v, create)) == 0) |
250 | err = 1; | |
4cdb302f | 251 | *t = skip_space(s); |
6ec3b2cf | 252 | res->type = OSSL_PROPERTY_TYPE_STRING; |
1bdbdaff P |
253 | return !err; |
254 | } | |
255 | ||
b4250010 | 256 | static int parse_value(OSSL_LIB_CTX *ctx, const char *t[], |
6ec3b2cf | 257 | OSSL_PROPERTY_DEFINITION *res, int create) |
1bdbdaff P |
258 | { |
259 | const char *s = *t; | |
260 | int r = 0; | |
261 | ||
262 | if (*s == '"' || *s == '\'') { | |
263 | s++; | |
1aedc35f | 264 | r = parse_string(ctx, &s, s[-1], res, create); |
1bdbdaff P |
265 | } else if (*s == '+') { |
266 | s++; | |
267 | r = parse_number(&s, res); | |
268 | } else if (*s == '-') { | |
269 | s++; | |
270 | r = parse_number(&s, res); | |
271 | res->v.int_val = -res->v.int_val; | |
272 | } else if (*s == '0' && s[1] == 'x') { | |
273 | s += 2; | |
274 | r = parse_hex(&s, res); | |
275 | } else if (*s == '0' && ossl_isdigit(s[1])) { | |
276 | s++; | |
277 | r = parse_oct(&s, res); | |
278 | } else if (ossl_isdigit(*s)) { | |
279 | return parse_number(t, res); | |
280 | } else if (ossl_isalpha(*s)) | |
1aedc35f | 281 | return parse_unquoted(ctx, t, res, create); |
1bdbdaff P |
282 | if (r) |
283 | *t = s; | |
284 | return r; | |
285 | } | |
286 | ||
6ec3b2cf RL |
287 | static int pd_compare(const OSSL_PROPERTY_DEFINITION *const *p1, |
288 | const OSSL_PROPERTY_DEFINITION *const *p2) | |
1bdbdaff | 289 | { |
6ec3b2cf RL |
290 | const OSSL_PROPERTY_DEFINITION *pd1 = *p1; |
291 | const OSSL_PROPERTY_DEFINITION *pd2 = *p2; | |
1bdbdaff P |
292 | |
293 | if (pd1->name_idx < pd2->name_idx) | |
294 | return -1; | |
295 | if (pd1->name_idx > pd2->name_idx) | |
296 | return 1; | |
297 | return 0; | |
298 | } | |
299 | ||
6ec3b2cf | 300 | static void pd_free(OSSL_PROPERTY_DEFINITION *pd) |
1bdbdaff P |
301 | { |
302 | OPENSSL_free(pd); | |
303 | } | |
304 | ||
305 | /* | |
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. | |
8e61832e P |
308 | * This function also checks for duplicated names and returns an error if |
309 | * any exist. | |
1bdbdaff | 310 | */ |
6ec3b2cf | 311 | static OSSL_PROPERTY_LIST * |
8e61832e P |
312 | stack_to_property_list(OSSL_LIB_CTX *ctx, |
313 | STACK_OF(OSSL_PROPERTY_DEFINITION) *sk) | |
1bdbdaff | 314 | { |
6ec3b2cf | 315 | const int n = sk_OSSL_PROPERTY_DEFINITION_num(sk); |
1bdbdaff | 316 | OSSL_PROPERTY_LIST *r; |
8e61832e | 317 | OSSL_PROPERTY_IDX prev_name_idx = 0; |
1bdbdaff P |
318 | int i; |
319 | ||
320 | r = OPENSSL_malloc(sizeof(*r) | |
71d1b229 | 321 | + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0])); |
1bdbdaff | 322 | if (r != NULL) { |
6ec3b2cf | 323 | sk_OSSL_PROPERTY_DEFINITION_sort(sk); |
1bdbdaff | 324 | |
da89ac0b P |
325 | r->has_optional = 0; |
326 | for (i = 0; i < n; i++) { | |
6ec3b2cf | 327 | r->properties[i] = *sk_OSSL_PROPERTY_DEFINITION_value(sk, i); |
da89ac0b | 328 | r->has_optional |= r->properties[i].optional; |
8e61832e P |
329 | |
330 | /* Check for duplicated names */ | |
331 | if (i > 0 && r->properties[i].name_idx == prev_name_idx) { | |
332 | OPENSSL_free(r); | |
333 | ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED, | |
334 | "Duplicated name `%s'", | |
335 | ossl_property_name_str(ctx, prev_name_idx)); | |
336 | return NULL; | |
337 | } | |
338 | prev_name_idx = r->properties[i].name_idx; | |
da89ac0b | 339 | } |
fa95fc1e | 340 | r->num_properties = n; |
1bdbdaff P |
341 | } |
342 | return r; | |
343 | } | |
344 | ||
b4250010 | 345 | OSSL_PROPERTY_LIST *ossl_parse_property(OSSL_LIB_CTX *ctx, const char *defn) |
1bdbdaff | 346 | { |
6ec3b2cf | 347 | OSSL_PROPERTY_DEFINITION *prop = NULL; |
1bdbdaff | 348 | OSSL_PROPERTY_LIST *res = NULL; |
6ec3b2cf | 349 | STACK_OF(OSSL_PROPERTY_DEFINITION) *sk; |
1bdbdaff P |
350 | const char *s = defn; |
351 | int done; | |
352 | ||
6ec3b2cf | 353 | if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL) |
1bdbdaff P |
354 | return NULL; |
355 | ||
356 | s = skip_space(s); | |
357 | done = *s == '\0'; | |
358 | while (!done) { | |
4cdb302f RL |
359 | const char *start = s; |
360 | ||
1bdbdaff P |
361 | prop = OPENSSL_malloc(sizeof(*prop)); |
362 | if (prop == NULL) | |
363 | goto err; | |
364 | memset(&prop->v, 0, sizeof(prop->v)); | |
da89ac0b | 365 | prop->optional = 0; |
1aedc35f | 366 | if (!parse_name(ctx, &s, 1, &prop->name_idx)) |
1bdbdaff | 367 | goto err; |
6ec3b2cf | 368 | prop->oper = OSSL_PROPERTY_OPER_EQ; |
1bdbdaff | 369 | if (prop->name_idx == 0) { |
49c64346 RL |
370 | ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED, |
371 | "Unknown name HERE-->%s", start); | |
1bdbdaff P |
372 | goto err; |
373 | } | |
374 | if (match_ch(&s, '=')) { | |
1aedc35f | 375 | if (!parse_value(ctx, &s, prop, 1)) { |
49c64346 RL |
376 | ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_VALUE, |
377 | "HERE-->%s", start); | |
1bdbdaff P |
378 | goto err; |
379 | } | |
380 | } else { | |
381 | /* A name alone means a true Boolean */ | |
6ec3b2cf | 382 | prop->type = OSSL_PROPERTY_TYPE_STRING; |
6de9214a | 383 | prop->v.str_val = OSSL_PROPERTY_TRUE; |
1bdbdaff P |
384 | } |
385 | ||
6ec3b2cf | 386 | if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop)) |
1bdbdaff P |
387 | goto err; |
388 | prop = NULL; | |
389 | done = !match_ch(&s, ','); | |
390 | } | |
391 | if (*s != '\0') { | |
49c64346 RL |
392 | ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS, |
393 | "HERE-->%s", s); | |
1bdbdaff P |
394 | goto err; |
395 | } | |
8e61832e | 396 | res = stack_to_property_list(ctx, sk); |
1bdbdaff P |
397 | |
398 | err: | |
399 | OPENSSL_free(prop); | |
6ec3b2cf | 400 | sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free); |
1bdbdaff P |
401 | return res; |
402 | } | |
403 | ||
1e08f3ba P |
404 | OSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s, |
405 | int create_values) | |
1bdbdaff | 406 | { |
6ec3b2cf | 407 | STACK_OF(OSSL_PROPERTY_DEFINITION) *sk; |
1bdbdaff | 408 | OSSL_PROPERTY_LIST *res = NULL; |
6ec3b2cf | 409 | OSSL_PROPERTY_DEFINITION *prop = NULL; |
1bdbdaff P |
410 | int done; |
411 | ||
6ec3b2cf | 412 | if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL) |
1bdbdaff P |
413 | return NULL; |
414 | ||
415 | s = skip_space(s); | |
416 | done = *s == '\0'; | |
417 | while (!done) { | |
418 | prop = OPENSSL_malloc(sizeof(*prop)); | |
419 | if (prop == NULL) | |
420 | goto err; | |
421 | memset(&prop->v, 0, sizeof(prop->v)); | |
422 | ||
423 | if (match_ch(&s, '-')) { | |
6ec3b2cf | 424 | prop->oper = OSSL_PROPERTY_OVERRIDE; |
da89ac0b | 425 | prop->optional = 0; |
1f12bf71 | 426 | if (!parse_name(ctx, &s, 1, &prop->name_idx)) |
1bdbdaff P |
427 | goto err; |
428 | goto skip_value; | |
429 | } | |
da89ac0b | 430 | prop->optional = match_ch(&s, '?'); |
1f12bf71 | 431 | if (!parse_name(ctx, &s, 1, &prop->name_idx)) |
1bdbdaff P |
432 | goto err; |
433 | ||
434 | if (match_ch(&s, '=')) { | |
6ec3b2cf | 435 | prop->oper = OSSL_PROPERTY_OPER_EQ; |
1bdbdaff | 436 | } else if (MATCH(&s, "!=")) { |
6ec3b2cf | 437 | prop->oper = OSSL_PROPERTY_OPER_NE; |
1bdbdaff P |
438 | } else { |
439 | /* A name alone is a Boolean comparison for true */ | |
6ec3b2cf RL |
440 | prop->oper = OSSL_PROPERTY_OPER_EQ; |
441 | prop->type = OSSL_PROPERTY_TYPE_STRING; | |
6de9214a | 442 | prop->v.str_val = OSSL_PROPERTY_TRUE; |
1bdbdaff P |
443 | goto skip_value; |
444 | } | |
1e08f3ba | 445 | if (!parse_value(ctx, &s, prop, create_values)) |
6ec3b2cf | 446 | prop->type = OSSL_PROPERTY_TYPE_VALUE_UNDEFINED; |
1bdbdaff P |
447 | |
448 | skip_value: | |
6ec3b2cf | 449 | if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop)) |
1bdbdaff P |
450 | goto err; |
451 | prop = NULL; | |
452 | done = !match_ch(&s, ','); | |
453 | } | |
454 | if (*s != '\0') { | |
49c64346 RL |
455 | ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS, |
456 | "HERE-->%s", s); | |
1bdbdaff P |
457 | goto err; |
458 | } | |
8e61832e | 459 | res = stack_to_property_list(ctx, sk); |
1bdbdaff P |
460 | |
461 | err: | |
462 | OPENSSL_free(prop); | |
6ec3b2cf | 463 | sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free); |
1bdbdaff P |
464 | return res; |
465 | } | |
466 | ||
da89ac0b P |
467 | /* |
468 | * Compare a query against a definition. | |
469 | * Return the number of clauses matched or -1 if a mandatory clause is false. | |
470 | */ | |
471 | int ossl_property_match_count(const OSSL_PROPERTY_LIST *query, | |
472 | const OSSL_PROPERTY_LIST *defn) | |
1bdbdaff | 473 | { |
6ec3b2cf RL |
474 | const OSSL_PROPERTY_DEFINITION *const q = query->properties; |
475 | const OSSL_PROPERTY_DEFINITION *const d = defn->properties; | |
da89ac0b | 476 | int i = 0, j = 0, matches = 0; |
6ec3b2cf | 477 | OSSL_PROPERTY_OPER oper; |
1bdbdaff | 478 | |
fa95fc1e | 479 | while (i < query->num_properties) { |
6ec3b2cf | 480 | if ((oper = q[i].oper) == OSSL_PROPERTY_OVERRIDE) { |
1bdbdaff P |
481 | i++; |
482 | continue; | |
483 | } | |
fa95fc1e | 484 | if (j < defn->num_properties) { |
1bdbdaff P |
485 | if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */ |
486 | j++; | |
487 | continue; | |
488 | } | |
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; | |
492 | ||
6ec3b2cf RL |
493 | if ((eq && oper == OSSL_PROPERTY_OPER_EQ) |
494 | || (!eq && oper == OSSL_PROPERTY_OPER_NE)) | |
da89ac0b P |
495 | matches++; |
496 | else if (!q[i].optional) | |
497 | return -1; | |
1bdbdaff P |
498 | i++; |
499 | j++; | |
500 | continue; | |
501 | } | |
502 | } | |
503 | ||
504 | /* | |
505 | * Handle the cases of a missing value and a query with no corresponding | |
79c44b4e | 506 | * definition. The former fails for any comparison except inequality, |
1bdbdaff P |
507 | * the latter is treated as a comparison against the Boolean false. |
508 | */ | |
6ec3b2cf RL |
509 | if (q[i].type == OSSL_PROPERTY_TYPE_VALUE_UNDEFINED) { |
510 | if (oper == OSSL_PROPERTY_OPER_NE) | |
da89ac0b P |
511 | matches++; |
512 | else if (!q[i].optional) | |
513 | return -1; | |
6ec3b2cf RL |
514 | } else if (q[i].type != OSSL_PROPERTY_TYPE_STRING |
515 | || (oper == OSSL_PROPERTY_OPER_EQ | |
6de9214a | 516 | && q[i].v.str_val != OSSL_PROPERTY_FALSE) |
6ec3b2cf | 517 | || (oper == OSSL_PROPERTY_OPER_NE |
6de9214a | 518 | && q[i].v.str_val == OSSL_PROPERTY_FALSE)) { |
da89ac0b P |
519 | if (!q[i].optional) |
520 | return -1; | |
521 | } else { | |
522 | matches++; | |
1bdbdaff P |
523 | } |
524 | i++; | |
525 | } | |
da89ac0b | 526 | return matches; |
1bdbdaff P |
527 | } |
528 | ||
529 | void ossl_property_free(OSSL_PROPERTY_LIST *p) | |
530 | { | |
531 | OPENSSL_free(p); | |
532 | } | |
533 | ||
534 | /* | |
535 | * Merge two property lists. | |
536 | * If there is a common name, the one from the first list is used. | |
537 | */ | |
538 | OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a, | |
539 | const OSSL_PROPERTY_LIST *b) | |
540 | { | |
6ec3b2cf RL |
541 | const OSSL_PROPERTY_DEFINITION *const ap = a->properties; |
542 | const OSSL_PROPERTY_DEFINITION *const bp = b->properties; | |
543 | const OSSL_PROPERTY_DEFINITION *copy; | |
1bdbdaff P |
544 | OSSL_PROPERTY_LIST *r; |
545 | int i, j, n; | |
fa95fc1e | 546 | const int t = a->num_properties + b->num_properties; |
1bdbdaff P |
547 | |
548 | r = OPENSSL_malloc(sizeof(*r) | |
549 | + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0])); | |
550 | if (r == NULL) | |
551 | return NULL; | |
552 | ||
e3d6dc59 | 553 | r->has_optional = 0; |
fa95fc1e P |
554 | for (i = j = n = 0; i < a->num_properties || j < b->num_properties; n++) { |
555 | if (i >= a->num_properties) { | |
1bdbdaff | 556 | copy = &bp[j++]; |
fa95fc1e | 557 | } else if (j >= b->num_properties) { |
1bdbdaff P |
558 | copy = &ap[i++]; |
559 | } else if (ap[i].name_idx <= bp[j].name_idx) { | |
560 | if (ap[i].name_idx == bp[j].name_idx) | |
561 | j++; | |
562 | copy = &ap[i++]; | |
563 | } else { | |
564 | copy = &bp[j++]; | |
565 | } | |
566 | memcpy(r->properties + n, copy, sizeof(r->properties[0])); | |
e3d6dc59 | 567 | r->has_optional |= copy->optional; |
1bdbdaff | 568 | } |
fa95fc1e | 569 | r->num_properties = n; |
1bdbdaff P |
570 | if (n != t) |
571 | r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0])); | |
572 | return r; | |
573 | } | |
574 | ||
b4250010 | 575 | int ossl_property_parse_init(OSSL_LIB_CTX *ctx) |
1bdbdaff P |
576 | { |
577 | static const char *const predefined_names[] = { | |
745fc918 | 578 | "provider", /* Name of provider (default, legacy, fips) */ |
1bdbdaff | 579 | "version", /* Version number of this provider */ |
745fc918 | 580 | "fips", /* FIPS validated or FIPS supporting algorithm */ |
5a6d6fe6 RL |
581 | "output", /* Output type for encoders */ |
582 | "input", /* Input type for decoders */ | |
583 | "structure", /* Structure name for encoders and decoders */ | |
1bdbdaff P |
584 | }; |
585 | size_t i; | |
586 | ||
587 | for (i = 0; i < OSSL_NELEM(predefined_names); i++) | |
1aedc35f | 588 | if (ossl_property_name(ctx, predefined_names[i], 1) == 0) |
1bdbdaff P |
589 | goto err; |
590 | ||
6de9214a MC |
591 | /* |
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 | |
595 | */ | |
596 | if ((ossl_property_value(ctx, "yes", 1) != OSSL_PROPERTY_TRUE) | |
597 | || (ossl_property_value(ctx, "no", 1) != OSSL_PROPERTY_FALSE)) | |
1bdbdaff P |
598 | goto err; |
599 | ||
600 | return 1; | |
601 | err: | |
602 | return 0; | |
603 | } | |
e2ed740e MC |
604 | |
605 | static void put_char(char ch, char **buf, size_t *remain, size_t *needed) | |
606 | { | |
607 | if (*remain == 0) { | |
608 | ++*needed; | |
609 | return; | |
610 | } | |
1287dabd | 611 | if (*remain == 1) |
e2ed740e MC |
612 | **buf = '\0'; |
613 | else | |
614 | **buf = ch; | |
615 | ++*buf; | |
616 | ++*needed; | |
617 | --*remain; | |
618 | } | |
619 | ||
620 | static void put_str(const char *str, char **buf, size_t *remain, size_t *needed) | |
621 | { | |
fb20e66c P |
622 | size_t olen, len, i; |
623 | char quote = '\0'; | |
624 | int quotes; | |
e2ed740e MC |
625 | |
626 | len = olen = strlen(str); | |
627 | *needed += len; | |
628 | ||
fb20e66c P |
629 | /* |
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. | |
633 | */ | |
634 | for (i = 0; i < len; i++) | |
635 | if (!ossl_isalnum(str[i]) && str[i] != '.' && str[i] != '_') { | |
636 | /* Default to single quotes ... */ | |
637 | if (quote == '\0') | |
638 | quote = '\''; | |
639 | /* ... but use double quotes if a single is present */ | |
640 | if (str[i] == '\'') | |
641 | quote = '"'; | |
642 | } | |
643 | ||
644 | quotes = quote != '\0'; | |
645 | if (*remain == 0) { | |
646 | *needed += 2 * quotes; | |
e2ed740e | 647 | return; |
fb20e66c | 648 | } |
e2ed740e | 649 | |
fb20e66c P |
650 | if (quotes) |
651 | put_char(quote, buf, remain, needed); | |
652 | ||
653 | if (*remain < len + 1 + quotes) | |
e2ed740e MC |
654 | len = *remain - 1; |
655 | ||
1287dabd | 656 | if (len > 0) { |
5ad3e76c | 657 | memcpy(*buf, str, len); |
e2ed740e MC |
658 | *buf += len; |
659 | *remain -= len; | |
660 | } | |
661 | ||
fb20e66c P |
662 | if (quotes) |
663 | put_char(quote, buf, remain, needed); | |
664 | ||
1287dabd | 665 | if (len < olen && *remain == 1) { |
e2ed740e MC |
666 | **buf = '\0'; |
667 | ++*buf; | |
668 | --*remain; | |
669 | } | |
670 | } | |
671 | ||
862497a9 | 672 | static void put_num(int64_t val, char **buf, size_t *remain, size_t *needed) |
e2ed740e | 673 | { |
862497a9 | 674 | int64_t tmpval = val; |
e2ed740e MC |
675 | size_t len = 1; |
676 | ||
862497a9 P |
677 | if (tmpval < 0) { |
678 | len++; | |
679 | tmpval = -tmpval; | |
680 | } | |
e2ed740e MC |
681 | for (; tmpval > 9; len++, tmpval /= 10); |
682 | ||
683 | *needed += len; | |
684 | ||
685 | if (*remain == 0) | |
686 | return; | |
687 | ||
862497a9 | 688 | BIO_snprintf(*buf, *remain, "%lld", (long long int)val); |
e2ed740e MC |
689 | if (*remain < len) { |
690 | *buf += *remain; | |
691 | *remain = 0; | |
692 | } else { | |
693 | *buf += len; | |
694 | *remain -= len; | |
695 | } | |
696 | } | |
697 | ||
698 | size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx, | |
699 | const OSSL_PROPERTY_LIST *list, char *buf, | |
700 | size_t bufsize) | |
701 | { | |
702 | int i; | |
6ec3b2cf | 703 | const OSSL_PROPERTY_DEFINITION *prop = NULL; |
e2ed740e MC |
704 | size_t needed = 0; |
705 | const char *val; | |
706 | ||
707 | if (list == NULL) { | |
708 | if (bufsize > 0) | |
709 | *buf = '\0'; | |
710 | return 1; | |
711 | } | |
fa95fc1e P |
712 | if (list->num_properties != 0) |
713 | prop = &list->properties[list->num_properties - 1]; | |
714 | for (i = 0; i < list->num_properties; i++, prop--) { | |
e2ed740e MC |
715 | /* Skip invalid names */ |
716 | if (prop->name_idx == 0) | |
717 | continue; | |
718 | ||
719 | if (needed > 0) | |
720 | put_char(',', &buf, &bufsize, &needed); | |
721 | ||
722 | if (prop->optional) | |
723 | put_char('?', &buf, &bufsize, &needed); | |
6ec3b2cf | 724 | else if (prop->oper == OSSL_PROPERTY_OVERRIDE) |
e2ed740e MC |
725 | put_char('-', &buf, &bufsize, &needed); |
726 | ||
727 | val = ossl_property_name_str(ctx, prop->name_idx); | |
728 | if (val == NULL) | |
729 | return 0; | |
730 | put_str(val, &buf, &bufsize, &needed); | |
731 | ||
732 | switch (prop->oper) { | |
6ec3b2cf | 733 | case OSSL_PROPERTY_OPER_NE: |
e2ed740e MC |
734 | put_char('!', &buf, &bufsize, &needed); |
735 | /* fall through */ | |
6ec3b2cf | 736 | case OSSL_PROPERTY_OPER_EQ: |
e2ed740e MC |
737 | put_char('=', &buf, &bufsize, &needed); |
738 | /* put value */ | |
739 | switch (prop->type) { | |
6ec3b2cf | 740 | case OSSL_PROPERTY_TYPE_STRING: |
e2ed740e MC |
741 | val = ossl_property_value_str(ctx, prop->v.str_val); |
742 | if (val == NULL) | |
743 | return 0; | |
744 | put_str(val, &buf, &bufsize, &needed); | |
745 | break; | |
746 | ||
6ec3b2cf | 747 | case OSSL_PROPERTY_TYPE_NUMBER: |
e2ed740e MC |
748 | put_num(prop->v.int_val, &buf, &bufsize, &needed); |
749 | break; | |
750 | ||
751 | default: | |
752 | return 0; | |
753 | } | |
754 | break; | |
755 | default: | |
756 | /* do nothing */ | |
757 | break; | |
758 | } | |
759 | } | |
760 | ||
761 | put_char('\0', &buf, &bufsize, &needed); | |
762 | return needed; | |
763 | } |