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