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