]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/property/property_parse.c
Optional property query support.
[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 unsigned int optional : 1;
36 union {
37 int64_t int_val; /* Signed integer */
38 OSSL_PROPERTY_IDX str_val; /* String */
39 } v;
40 } PROPERTY_DEFINITION;
41
42 struct ossl_property_list_st {
43 int n;
44 unsigned int has_optional : 1;
45 PROPERTY_DEFINITION properties[1];
46 };
47
48 static OSSL_PROPERTY_IDX ossl_property_true, ossl_property_false;
49
50 DEFINE_STACK_OF(PROPERTY_DEFINITION)
51
52 static const char *skip_space(const char *s)
53 {
54 while (ossl_isspace(*s))
55 s++;
56 return s;
57 }
58
59 static int match_ch(const char *t[], char m)
60 {
61 const char *s = *t;
62
63 if (*s == m) {
64 *t = skip_space(s + 1);
65 return 1;
66 }
67 return 0;
68 }
69
70 #define MATCH(s, m) match(s, m, sizeof(m) - 1)
71
72 static int match(const char *t[], const char m[], size_t m_len)
73 {
74 const char *s = *t;
75
76 if (strncasecmp(s, m, m_len) == 0) {
77 *t = skip_space(s + m_len);
78 return 1;
79 }
80 return 0;
81 }
82
83 static int parse_name(OPENSSL_CTX *ctx, const char *t[], int create,
84 OSSL_PROPERTY_IDX *idx)
85 {
86 char name[100];
87 int err = 0;
88 size_t i = 0;
89 const char *s = *t;
90 int user_name = 0;
91
92 for (;;) {
93 if (!ossl_isalpha(*s)) {
94 PROPerr(PROP_F_PARSE_NAME, PROP_R_NOT_AN_IDENTIFIER);
95 return 0;
96 }
97 do {
98 if (i < sizeof(name) - 1)
99 name[i++] = ossl_tolower(*s);
100 else
101 err = 1;
102 } while (*++s == '_' || ossl_isalnum(*s));
103 if (*s != '.')
104 break;
105 user_name = 1;
106 if (i < sizeof(name) - 1)
107 name[i++] = *s;
108 else
109 err = 1;
110 s++;
111 }
112 name[i] = '\0';
113 *t = skip_space(s);
114 if (!err) {
115 *idx = ossl_property_name(ctx, name, user_name && create);
116 return 1;
117 }
118 PROPerr(PROP_F_PARSE_NAME, PROP_R_NAME_TOO_LONG);
119 return 0;
120 }
121
122 static int parse_number(const char *t[], PROPERTY_DEFINITION *res)
123 {
124 const char *s = *t;
125 int64_t v = 0;
126
127 if (!ossl_isdigit(*s))
128 return 0;
129 do {
130 v = v * 10 + (*s++ - '0');
131 } while (ossl_isdigit(*s));
132 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
133 PROPerr(PROP_F_PARSE_NUMBER, PROP_R_NOT_A_DECIMAL_DIGIT);
134 return 0;
135 }
136 *t = skip_space(s);
137 res->type = PROPERTY_TYPE_NUMBER;
138 res->v.int_val = v;
139 return 1;
140 }
141
142 static int parse_hex(const char *t[], PROPERTY_DEFINITION *res)
143 {
144 const char *s = *t;
145 int64_t v = 0;
146
147 if (!ossl_isxdigit(*s))
148 return 0;
149 do {
150 v <<= 4;
151 if (ossl_isdigit(*s))
152 v += *s - '0';
153 else
154 v += ossl_tolower(*s) - 'a';
155 } while (ossl_isxdigit(*++s));
156 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
157 PROPerr(PROP_F_PARSE_HEX, PROP_R_NOT_AN_HEXADECIMAL_DIGIT);
158 return 0;
159 }
160 *t = skip_space(s);
161 res->type = PROPERTY_TYPE_NUMBER;
162 res->v.int_val = v;
163 return 1;
164 }
165
166 static int parse_oct(const char *t[], PROPERTY_DEFINITION *res)
167 {
168 const char *s = *t;
169 int64_t v = 0;
170
171 if (*s == '9' || *s == '8' || !ossl_isdigit(*s))
172 return 0;
173 do {
174 v = (v << 3) + (*s - '0');
175 } while (ossl_isdigit(*++s) && *s != '9' && *s != '8');
176 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
177 PROPerr(PROP_F_PARSE_OCT, PROP_R_NOT_AN_OCTAL_DIGIT);
178 return 0;
179 }
180 *t = skip_space(s);
181 res->type = PROPERTY_TYPE_NUMBER;
182 res->v.int_val = v;
183 return 1;
184 }
185
186 static int parse_string(OPENSSL_CTX *ctx, const char *t[], char delim,
187 PROPERTY_DEFINITION *res, const int create)
188 {
189 char v[1000];
190 const char *s = *t;
191 size_t i = 0;
192 int err = 0;
193
194 while (*s != '\0' && *s != delim) {
195 if (i < sizeof(v) - 1)
196 v[i++] = *s;
197 else
198 err = 1;
199 s++;
200 }
201 if (*s == '\0') {
202 PROPerr(PROP_F_PARSE_STRING,
203 PROP_R_NO_MATCHING_STRING_DELIMETER);
204 return 0;
205 }
206 v[i] = '\0';
207 *t = skip_space(s + 1);
208 if (err)
209 PROPerr(PROP_F_PARSE_STRING, PROP_R_STRING_TOO_LONG);
210 else
211 res->v.str_val = ossl_property_value(ctx, v, create);
212 res->type = PROPERTY_TYPE_STRING;
213 return !err;
214 }
215
216 static int parse_unquoted(OPENSSL_CTX *ctx, const char *t[],
217 PROPERTY_DEFINITION *res, const int create)
218 {
219 char v[1000];
220 const char *s = *t;
221 size_t i = 0;
222 int err = 0;
223
224 if (*s == '\0' || *s == ',')
225 return 0;
226 while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') {
227 if (i < sizeof(v) - 1)
228 v[i++] = ossl_tolower(*s);
229 else
230 err = 1;
231 s++;
232 }
233 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
234 PROPerr(PROP_F_PARSE_UNQUOTED, PROP_R_NOT_AN_ASCII_CHARACTER);
235 return 0;
236 }
237 v[i] = 0;
238 *t = skip_space(s);
239 if (err)
240 PROPerr(PROP_F_PARSE_UNQUOTED, PROP_R_STRING_TOO_LONG);
241 else
242 res->v.str_val = ossl_property_value(ctx, v, create);
243 res->type = PROPERTY_TYPE_STRING;
244 return !err;
245 }
246
247 static int parse_value(OPENSSL_CTX *ctx, const char *t[],
248 PROPERTY_DEFINITION *res, int create)
249 {
250 const char *s = *t;
251 int r = 0;
252
253 if (*s == '"' || *s == '\'') {
254 s++;
255 r = parse_string(ctx, &s, s[-1], res, create);
256 } else if (*s == '+') {
257 s++;
258 r = parse_number(&s, res);
259 } else if (*s == '-') {
260 s++;
261 r = parse_number(&s, res);
262 res->v.int_val = -res->v.int_val;
263 } else if (*s == '0' && s[1] == 'x') {
264 s += 2;
265 r = parse_hex(&s, res);
266 } else if (*s == '0' && ossl_isdigit(s[1])) {
267 s++;
268 r = parse_oct(&s, res);
269 } else if (ossl_isdigit(*s)) {
270 return parse_number(t, res);
271 } else if (ossl_isalpha(*s))
272 return parse_unquoted(ctx, t, res, create);
273 if (r)
274 *t = s;
275 return r;
276 }
277
278 static int pd_compare(const PROPERTY_DEFINITION *const *p1,
279 const PROPERTY_DEFINITION *const *p2)
280 {
281 const PROPERTY_DEFINITION *pd1 = *p1;
282 const PROPERTY_DEFINITION *pd2 = *p2;
283
284 if (pd1->name_idx < pd2->name_idx)
285 return -1;
286 if (pd1->name_idx > pd2->name_idx)
287 return 1;
288 return 0;
289 }
290
291 static void pd_free(PROPERTY_DEFINITION *pd)
292 {
293 OPENSSL_free(pd);
294 }
295
296 /*
297 * Convert a stack of property definitions and queries into a fixed array.
298 * The items are sorted for efficient query. The stack is not freed.
299 */
300 static OSSL_PROPERTY_LIST *stack_to_property_list(STACK_OF(PROPERTY_DEFINITION)
301 *sk)
302 {
303 const int n = sk_PROPERTY_DEFINITION_num(sk);
304 OSSL_PROPERTY_LIST *r;
305 int i;
306
307 r = OPENSSL_malloc(sizeof(*r)
308 + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0]));
309 if (r != NULL) {
310 sk_PROPERTY_DEFINITION_sort(sk);
311
312 r->has_optional = 0;
313 for (i = 0; i < n; i++) {
314 r->properties[i] = *sk_PROPERTY_DEFINITION_value(sk, i);
315 r->has_optional |= r->properties[i].optional;
316 }
317 r->n = n;
318 }
319 return r;
320 }
321
322 OSSL_PROPERTY_LIST *ossl_parse_property(OPENSSL_CTX *ctx, const char *defn)
323 {
324 PROPERTY_DEFINITION *prop = NULL;
325 OSSL_PROPERTY_LIST *res = NULL;
326 STACK_OF(PROPERTY_DEFINITION) *sk;
327 const char *s = defn;
328 int done;
329
330 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
331 return NULL;
332
333 s = skip_space(s);
334 done = *s == '\0';
335 while (!done) {
336 prop = OPENSSL_malloc(sizeof(*prop));
337 if (prop == NULL)
338 goto err;
339 memset(&prop->v, 0, sizeof(prop->v));
340 prop->optional = 0;
341 if (!parse_name(ctx, &s, 1, &prop->name_idx))
342 goto err;
343 prop->oper = PROPERTY_OPER_EQ;
344 if (prop->name_idx == 0) {
345 PROPerr(PROP_F_OSSL_PARSE_PROPERTY, PROP_R_PARSE_FAILED);
346 goto err;
347 }
348 if (match_ch(&s, '=')) {
349 if (!parse_value(ctx, &s, prop, 1)) {
350 PROPerr(PROP_F_OSSL_PARSE_PROPERTY, PROP_R_NO_VALUE);
351 goto err;
352 }
353 } else {
354 /* A name alone means a true Boolean */
355 prop->type = PROPERTY_TYPE_STRING;
356 prop->v.str_val = ossl_property_true;
357 }
358
359 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
360 goto err;
361 prop = NULL;
362 done = !match_ch(&s, ',');
363 }
364 if (*s != '\0') {
365 PROPerr(PROP_F_OSSL_PARSE_PROPERTY, PROP_R_TRAILING_CHARACTERS);
366 goto err;
367 }
368 res = stack_to_property_list(sk);
369
370 err:
371 OPENSSL_free(prop);
372 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
373 return res;
374 }
375
376 OSSL_PROPERTY_LIST *ossl_parse_query(OPENSSL_CTX *ctx, const char *s)
377 {
378 STACK_OF(PROPERTY_DEFINITION) *sk;
379 OSSL_PROPERTY_LIST *res = NULL;
380 PROPERTY_DEFINITION *prop = NULL;
381 int done;
382
383 if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
384 return NULL;
385
386 s = skip_space(s);
387 done = *s == '\0';
388 while (!done) {
389 prop = OPENSSL_malloc(sizeof(*prop));
390 if (prop == NULL)
391 goto err;
392 memset(&prop->v, 0, sizeof(prop->v));
393
394 if (match_ch(&s, '-')) {
395 prop->oper = PROPERTY_OVERRIDE;
396 prop->optional = 0;
397 if (!parse_name(ctx, &s, 0, &prop->name_idx))
398 goto err;
399 goto skip_value;
400 }
401 prop->optional = match_ch(&s, '?');
402 if (!parse_name(ctx, &s, 0, &prop->name_idx))
403 goto err;
404
405 if (match_ch(&s, '=')) {
406 prop->oper = PROPERTY_OPER_EQ;
407 } else if (MATCH(&s, "!=")) {
408 prop->oper = PROPERTY_OPER_NE;
409 } else {
410 /* A name alone is a Boolean comparison for true */
411 prop->oper = PROPERTY_OPER_EQ;
412 prop->type = PROPERTY_TYPE_STRING;
413 prop->v.str_val = ossl_property_true;
414 goto skip_value;
415 }
416 if (!parse_value(ctx, &s, prop, 0))
417 prop->type = PROPERTY_TYPE_VALUE_UNDEFINED;
418
419 skip_value:
420 if (!sk_PROPERTY_DEFINITION_push(sk, prop))
421 goto err;
422 prop = NULL;
423 done = !match_ch(&s, ',');
424 }
425 if (*s != '\0') {
426 PROPerr(PROP_F_OSSL_PARSE_QUERY, PROP_R_TRAILING_CHARACTERS);
427 goto err;
428 }
429 res = stack_to_property_list(sk);
430
431 err:
432 OPENSSL_free(prop);
433 sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
434 return res;
435 }
436
437 /* Does a property query have any optional clauses */
438 int ossl_property_has_optional(const OSSL_PROPERTY_LIST *query)
439 {
440 return query->has_optional ? 1 : 0;
441 }
442
443 /*
444 * Compare a query against a definition.
445 * Return the number of clauses matched or -1 if a mandatory clause is false.
446 */
447 int ossl_property_match_count(const OSSL_PROPERTY_LIST *query,
448 const OSSL_PROPERTY_LIST *defn)
449 {
450 const PROPERTY_DEFINITION *const q = query->properties;
451 const PROPERTY_DEFINITION *const d = defn->properties;
452 int i = 0, j = 0, matches = 0;
453 PROPERTY_OPER oper;
454
455 while (i < query->n) {
456 if ((oper = q[i].oper) == PROPERTY_OVERRIDE) {
457 i++;
458 continue;
459 }
460 if (j < defn->n) {
461 if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */
462 j++;
463 continue;
464 }
465 if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */
466 const int eq = q[i].type == d[j].type
467 && memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0;
468
469 if ((eq && oper == PROPERTY_OPER_EQ)
470 || (!eq && oper == PROPERTY_OPER_NE))
471 matches++;
472 else if (!q[i].optional)
473 return -1;
474 i++;
475 j++;
476 continue;
477 }
478 }
479
480 /*
481 * Handle the cases of a missing value and a query with no corresponding
482 * definition. The former fails for any comparision except inequality,
483 * the latter is treated as a comparison against the Boolean false.
484 */
485 if (q[i].type == PROPERTY_TYPE_VALUE_UNDEFINED) {
486 if (oper == PROPERTY_OPER_NE)
487 matches++;
488 else if (!q[i].optional)
489 return -1;
490 } else if (q[i].type != PROPERTY_TYPE_STRING
491 || (oper == PROPERTY_OPER_EQ
492 && q[i].v.str_val != ossl_property_false)
493 || (oper == PROPERTY_OPER_NE
494 && q[i].v.str_val == ossl_property_false)) {
495 if (!q[i].optional)
496 return -1;
497 } else {
498 matches++;
499 }
500 i++;
501 }
502 return matches;
503 }
504
505 void ossl_property_free(OSSL_PROPERTY_LIST *p)
506 {
507 OPENSSL_free(p);
508 }
509
510 /*
511 * Merge two property lists.
512 * If there is a common name, the one from the first list is used.
513 */
514 OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
515 const OSSL_PROPERTY_LIST *b)
516 {
517 const PROPERTY_DEFINITION *const ap = a->properties;
518 const PROPERTY_DEFINITION *const bp = b->properties;
519 const PROPERTY_DEFINITION *copy;
520 OSSL_PROPERTY_LIST *r;
521 int i, j, n;
522 const int t = a->n + b->n;
523
524 r = OPENSSL_malloc(sizeof(*r)
525 + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
526 if (r == NULL)
527 return NULL;
528
529 for (i = j = n = 0; i < a->n || j < b->n; n++) {
530 if (i >= a->n) {
531 copy = &bp[j++];
532 } else if (j >= b->n) {
533 copy = &ap[i++];
534 } else if (ap[i].name_idx <= bp[j].name_idx) {
535 if (ap[i].name_idx == bp[j].name_idx)
536 j++;
537 copy = &ap[i++];
538 } else {
539 copy = &bp[j++];
540 }
541 memcpy(r->properties + n, copy, sizeof(r->properties[0]));
542 }
543 r->n = n;
544 if (n != t)
545 r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
546 return r;
547 }
548
549 int ossl_property_parse_init(OPENSSL_CTX *ctx)
550 {
551 static const char *const predefined_names[] = {
552 "default", /* Being provided by the default built-in provider */
553 "legacy", /* Provided by the legacy provider */
554 "provider", /* Name of provider (default, fips) */
555 "version", /* Version number of this provider */
556 "fips", /* FIPS supporting provider */
557 "engine", /* An old style engine masquerading as a provider */
558 };
559 size_t i;
560
561 for (i = 0; i < OSSL_NELEM(predefined_names); i++)
562 if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
563 goto err;
564
565 /* Pre-populate the two Boolean values */
566 if ((ossl_property_true = ossl_property_value(ctx, "yes", 1)) == 0
567 || (ossl_property_false = ossl_property_value(ctx, "no", 1)) == 0)
568 goto err;
569
570 return 1;
571 err:
572 return 0;
573 }