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