]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/property/property_parse.c
Properties for implementation selection.
[thirdparty/openssl.git] / crypto / property / property_parse.c
1 /*
2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
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"
17 #include "internal/ctype.h"
18 #include "internal/nelem.h"
19 #include "property_lcl.h"
20 #include "e_os.h"
21
22 typedef enum {
23 PROPERTY_TYPE_STRING, PROPERTY_TYPE_NUMBER,
24 PROPERTY_TYPE_VALUE_UNDEFINED
25 } PROPERTY_TYPE;
26
27 typedef enum {
28 PROPERTY_OPER_EQ, PROPERTY_OPER_NE, PROPERTY_OVERRIDE
29 } PROPERTY_OPER;
30
31 typedef struct {
32 OSSL_PROPERTY_IDX name_idx;
33 PROPERTY_TYPE type;
34 PROPERTY_OPER oper;
35 union {
36 int64_t int_val; /* Signed integer */
37 OSSL_PROPERTY_IDX str_val; /* String */
38 } v;
39 } PROPERTY_DEFINITION;
40
41 struct ossl_property_list_st {
42 int n;
43 PROPERTY_DEFINITION properties[1];
44 };
45
46 static OSSL_PROPERTY_IDX ossl_property_true, ossl_property_false;
47
48 DEFINE_STACK_OF(PROPERTY_DEFINITION)
49
50 static const char *skip_space(const char *s)
51 {
52 while (ossl_isspace(*s))
53 s++;
54 return s;
55 }
56
57 static int match_ch(const char *t[], char m)
58 {
59 const char *s = *t;
60
61 if (*s == m) {
62 *t = skip_space(s + 1);
63 return 1;
64 }
65 return 0;
66 }
67
68 #define MATCH(s, m) match(s, m, sizeof(m) - 1)
69
70 static int match(const char *t[], const char m[], size_t m_len)
71 {
72 const char *s = *t;
73
74 if (strncasecmp(s, m, m_len) == 0) {
75 *t = skip_space(s + m_len);
76 return 1;
77 }
78 return 0;
79 }
80
81 static int parse_name(const char *t[], int create, OSSL_PROPERTY_IDX *idx)
82 {
83 char name[100];
84 int err = 0;
85 size_t i = 0;
86 const char *s = *t;
87 int user_name = 0;
88
89 for (;;) {
90 if (!ossl_isalpha(*s)) {
91 PROPerr(PROP_F_PARSE_NAME, PROP_R_NOT_AN_IDENTIFIER);
92 return 0;
93 }
94 do {
95 if (i < sizeof(name) - 1)
96 name[i++] = ossl_tolower(*s);
97 else
98 err = 1;
99 } while (*++s == '_' || ossl_isalnum(*s));
100 if (*s != '.')
101 break;
102 user_name = 1;
103 if (i < sizeof(name) - 1)
104 name[i++] = *s;
105 else
106 err = 1;
107 s++;
108 }
109 name[i] = '\0';
110 *t = skip_space(s);
111 if (!err) {
112 *idx = ossl_property_name(name, user_name && create);
113 return 1;
114 }
115 PROPerr(PROP_F_PARSE_NAME, PROP_R_NAME_TOO_LONG);
116 return 0;
117 }
118
119 static int parse_number(const char *t[], PROPERTY_DEFINITION *res)
120 {
121 const char *s = *t;
122 int64_t v = 0;
123
124 if (!ossl_isdigit(*s))
125 return 0;
126 do {
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);
131 return 0;
132 }
133 *t = skip_space(s);
134 res->type = PROPERTY_TYPE_NUMBER;
135 res->v.int_val = v;
136 return 1;
137 }
138
139 static int parse_hex(const char *t[], PROPERTY_DEFINITION *res)
140 {
141 const char *s = *t;
142 int64_t v = 0;
143
144 if (!ossl_isxdigit(*s))
145 return 0;
146 do {
147 v <<= 4;
148 if (ossl_isdigit(*s))
149 v += *s - '0';
150 else
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);
155 return 0;
156 }
157 *t = skip_space(s);
158 res->type = PROPERTY_TYPE_NUMBER;
159 res->v.int_val = v;
160 return 1;
161 }
162
163 static int parse_oct(const char *t[], PROPERTY_DEFINITION *res)
164 {
165 const char *s = *t;
166 int64_t v = 0;
167
168 if (*s == '9' || *s == '8' || !ossl_isdigit(*s))
169 return 0;
170 do {
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);
175 return 0;
176 }
177 *t = skip_space(s);
178 res->type = PROPERTY_TYPE_NUMBER;
179 res->v.int_val = v;
180 return 1;
181 }
182
183 static int parse_string(const char *t[], char delim, PROPERTY_DEFINITION *res,
184 const int create)
185 {
186 char v[1000];
187 const char *s = *t;
188 size_t i = 0;
189 int err = 0;
190
191 while (*s != '\0' && *s != delim) {
192 if (i < sizeof(v) - 1)
193 v[i++] = *s;
194 else
195 err = 1;
196 s++;
197 }
198 if (*s == '\0') {
199 PROPerr(PROP_F_PARSE_STRING,
200 PROP_R_NO_MATCHING_STRING_DELIMETER);
201 return 0;
202 }
203 v[i] = '\0';
204 *t = skip_space(s + 1);
205 if (err)
206 PROPerr(PROP_F_PARSE_STRING, PROP_R_STRING_TOO_LONG);
207 else
208 res->v.str_val = ossl_property_value(v, create);
209 res->type = PROPERTY_TYPE_STRING;
210 return !err;
211 }
212
213 static int parse_unquoted(const char *t[], PROPERTY_DEFINITION *res,
214 const int create)
215 {
216 char v[1000];
217 const char *s = *t;
218 size_t i = 0;
219 int err = 0;
220
221 if (*s == '\0' || *s == ',')
222 return 0;
223 while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') {
224 if (i < sizeof(v) - 1)
225 v[i++] = ossl_tolower(*s);
226 else
227 err = 1;
228 s++;
229 }
230 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
231 PROPerr(PROP_F_PARSE_UNQUOTED, PROP_R_NOT_AN_ASCII_CHARACTER);
232 return 0;
233 }
234 v[i] = 0;
235 *t = skip_space(s);
236 if (err)
237 PROPerr(PROP_F_PARSE_UNQUOTED, PROP_R_STRING_TOO_LONG);
238 else
239 res->v.str_val = ossl_property_value(v, create);
240 res->type = PROPERTY_TYPE_STRING;
241 return !err;
242 }
243
244 static int parse_value(const char *t[], PROPERTY_DEFINITION *res, int create)
245 {
246 const char *s = *t;
247 int r = 0;
248
249 if (*s == '"' || *s == '\'') {
250 s++;
251 r = parse_string(&s, s[-1], res, create);
252 } else if (*s == '+') {
253 s++;
254 r = parse_number(&s, res);
255 } else if (*s == '-') {
256 s++;
257 r = parse_number(&s, res);
258 res->v.int_val = -res->v.int_val;
259 } else if (*s == '0' && s[1] == 'x') {
260 s += 2;
261 r = parse_hex(&s, res);
262 } else if (*s == '0' && ossl_isdigit(s[1])) {
263 s++;
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);
269 if (r)
270 *t = s;
271 return r;
272 }
273
274 static int pd_compare(const PROPERTY_DEFINITION *const *p1,
275 const PROPERTY_DEFINITION *const *p2)
276 {
277 const PROPERTY_DEFINITION *pd1 = *p1;
278 const PROPERTY_DEFINITION *pd2 = *p2;
279
280 if (pd1->name_idx < pd2->name_idx)
281 return -1;
282 if (pd1->name_idx > pd2->name_idx)
283 return 1;
284 return 0;
285 }
286
287 static void pd_free(PROPERTY_DEFINITION *pd)
288 {
289 OPENSSL_free(pd);
290 }
291
292 /*
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.
295 */
296 static OSSL_PROPERTY_LIST *stack_to_property_list(STACK_OF(PROPERTY_DEFINITION)
297 *sk)
298 {
299 const int n = sk_PROPERTY_DEFINITION_num(sk);
300 OSSL_PROPERTY_LIST *r;
301 int i;
302
303 r = OPENSSL_malloc(sizeof(*r)
304 + (n == 0 ? 0 : n - 1) * sizeof(r->properties[0]));
305 if (r != NULL) {
306 sk_PROPERTY_DEFINITION_sort(sk);
307
308 for (i = 0; i < n; i++)
309 r->properties[i] = *sk_PROPERTY_DEFINITION_value(sk, i);
310 r->n = n;
311 }
312 return r;
313 }
314
315 OSSL_PROPERTY_LIST *ossl_parse_property(const char *defn)
316 {
317 PROPERTY_DEFINITION *prop = NULL;
318 OSSL_PROPERTY_LIST *res = NULL;
319 STACK_OF(PROPERTY_DEFINITION) *sk;
320 const char *s = defn;
321 int done;
322
323 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
324 return NULL;
325
326 s = skip_space(s);
327 done = *s == '\0';
328 while (!done) {
329 prop = OPENSSL_malloc(sizeof(*prop));
330 if (prop == NULL)
331 goto err;
332 memset(&prop->v, 0, sizeof(prop->v));
333 if (!parse_name(&s, 1, &prop->name_idx))
334 goto err;
335 prop->oper = PROPERTY_OPER_EQ;
336 if (prop->name_idx == 0) {
337 PROPerr(PROP_F_OSSL_PARSE_PROPERTY, PROP_R_PARSE_FAILED);
338 goto err;
339 }
340 if (match_ch(&s, '=')) {
341 if (!parse_value(&s, prop, 1)) {
342 PROPerr(PROP_F_OSSL_PARSE_PROPERTY, PROP_R_NO_VALUE);
343 goto err;
344 }
345 } else {
346 /* A name alone means a true Boolean */
347 prop->type = PROPERTY_TYPE_STRING;
348 prop->v.str_val = ossl_property_true;
349 }
350
351 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
352 goto err;
353 prop = NULL;
354 done = !match_ch(&s, ',');
355 }
356 if (*s != '\0') {
357 PROPerr(PROP_F_OSSL_PARSE_PROPERTY, PROP_R_TRAILING_CHARACTERS);
358 goto err;
359 }
360 res = stack_to_property_list(sk);
361
362 err:
363 OPENSSL_free(prop);
364 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
365 return res;
366 }
367
368 OSSL_PROPERTY_LIST *ossl_parse_query(const char *s)
369 {
370 STACK_OF(PROPERTY_DEFINITION) *sk;
371 OSSL_PROPERTY_LIST *res = NULL;
372 PROPERTY_DEFINITION *prop = NULL;
373 int done;
374
375 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
376 return NULL;
377
378 s = skip_space(s);
379 done = *s == '\0';
380 while (!done) {
381 prop = OPENSSL_malloc(sizeof(*prop));
382 if (prop == NULL)
383 goto err;
384 memset(&prop->v, 0, sizeof(prop->v));
385
386 if (match_ch(&s, '-')) {
387 prop->oper = PROPERTY_OVERRIDE;
388 if (!parse_name(&s, 0, &prop->name_idx))
389 goto err;
390 goto skip_value;
391 }
392 if (!parse_name(&s, 0, &prop->name_idx))
393 goto err;
394
395 if (match_ch(&s, '=')) {
396 prop->oper = PROPERTY_OPER_EQ;
397 } else if (MATCH(&s, "!=")) {
398 prop->oper = PROPERTY_OPER_NE;
399 } else {
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;
404 goto skip_value;
405 }
406 if (!parse_value(&s, prop, 0))
407 prop->type = PROPERTY_TYPE_VALUE_UNDEFINED;
408
409 skip_value:
410 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
411 goto err;
412 prop = NULL;
413 done = !match_ch(&s, ',');
414 }
415 if (*s != '\0') {
416 PROPerr(PROP_F_OSSL_PARSE_QUERY, PROP_R_TRAILING_CHARACTERS);
417 goto err;
418 }
419 res = stack_to_property_list(sk);
420
421 err:
422 OPENSSL_free(prop);
423 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
424 return res;
425 }
426
427 int ossl_property_match(const OSSL_PROPERTY_LIST *query,
428 const OSSL_PROPERTY_LIST *defn)
429 {
430 const PROPERTY_DEFINITION *const q = query->properties;
431 const PROPERTY_DEFINITION *const d = defn->properties;
432 int i = 0, j = 0;
433 PROPERTY_OPER oper;
434
435 while (i < query->n) {
436 if ((oper = q[i].oper) == PROPERTY_OVERRIDE) {
437 i++;
438 continue;
439 }
440 if (j < defn->n) {
441 if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */
442 j++;
443 continue;
444 }
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;
448
449 if ((eq && oper != PROPERTY_OPER_EQ)
450 || (!eq && oper != PROPERTY_OPER_NE))
451 return 0;
452 i++;
453 j++;
454 continue;
455 }
456 }
457
458 /*
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.
462 */
463 if (q[i].type == PROPERTY_TYPE_VALUE_UNDEFINED) {
464 if (oper != PROPERTY_OPER_NE)
465 return 0;
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)) {
471 return 0;
472 }
473 i++;
474 }
475 return 1;
476 }
477
478 void ossl_property_free(OSSL_PROPERTY_LIST *p)
479 {
480 OPENSSL_free(p);
481 }
482
483 /*
484 * Merge two property lists.
485 * If there is a common name, the one from the first list is used.
486 */
487 OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
488 const OSSL_PROPERTY_LIST *b)
489 {
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;
494 int i, j, n;
495 const int t = a->n + b->n;
496
497 r = OPENSSL_malloc(sizeof(*r)
498 + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
499 if (r == NULL)
500 return NULL;
501
502 for (i = j = n = 0; i < a->n || j < b->n; n++) {
503 if (i >= a->n) {
504 copy = &bp[j++];
505 } else if (j >= b->n) {
506 copy = &ap[i++];
507 } else if (ap[i].name_idx <= bp[j].name_idx) {
508 if (ap[i].name_idx == bp[j].name_idx)
509 j++;
510 copy = &ap[i++];
511 } else {
512 copy = &bp[j++];
513 }
514 memcpy(r->properties + n, copy, sizeof(r->properties[0]));
515 }
516 r->n = n;
517 if (n != t)
518 r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
519 return r;
520 }
521
522 int ossl_property_parse_init(void)
523 {
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 */
530 };
531 size_t i;
532
533 for (i = 0; i < OSSL_NELEM(predefined_names); i++)
534 if (ossl_property_name(predefined_names[i], 1) == 0)
535 goto err;
536
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)
540 goto err;
541
542 return 1;
543 err:
544 return 0;
545 }