Instead of global data store it in an OPENSSL_CTX
[oweals/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(OPENSSL_CTX *ctx, const char *t[], int create,
82                       OSSL_PROPERTY_IDX *idx)
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) {
113         *idx = ossl_property_name(ctx, name, user_name && create);
114         return 1;
115     }
116     PROPerr(PROP_F_PARSE_NAME, PROP_R_NAME_TOO_LONG);
117     return 0;
118 }
119
120 static 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
140 static 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
164 static 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
184 static int parse_string(OPENSSL_CTX *ctx, const char *t[], char delim,
185                         PROPERTY_DEFINITION *res, const int create)
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
209         res->v.str_val = ossl_property_value(ctx, v, create);
210     res->type = PROPERTY_TYPE_STRING;
211     return !err;
212 }
213
214 static int parse_unquoted(OPENSSL_CTX *ctx, const char *t[],
215                           PROPERTY_DEFINITION *res, const int create)
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
240         res->v.str_val = ossl_property_value(ctx, v, create);
241     res->type = PROPERTY_TYPE_STRING;
242     return !err;
243 }
244
245 static int parse_value(OPENSSL_CTX *ctx, const char *t[],
246                        PROPERTY_DEFINITION *res, int create)
247 {
248     const char *s = *t;
249     int r = 0;
250
251     if (*s == '"' || *s == '\'') {
252         s++;
253         r = parse_string(ctx, &s, s[-1], res, create);
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))
270         return parse_unquoted(ctx, t, res, create);
271     if (r)
272         *t = s;
273     return r;
274 }
275
276 static 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
289 static 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  */
298 static 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)
306                        + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0]));
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
317 OSSL_PROPERTY_LIST *ossl_parse_property(OPENSSL_CTX *ctx, const char *defn)
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));
335         if (!parse_name(ctx, &s, 1, &prop->name_idx))
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, '=')) {
343             if (!parse_value(ctx, &s, prop, 1)) {
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
364 err:
365     OPENSSL_free(prop);
366     sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
367     return res;
368 }
369
370 OSSL_PROPERTY_LIST *ossl_parse_query(OPENSSL_CTX *ctx, const char *s)
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;
390             if (!parse_name(ctx, &s, 0, &prop->name_idx))
391                 goto err;
392             goto skip_value;
393         }
394         if (!parse_name(ctx, &s, 0, &prop->name_idx))
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         }
408         if (!parse_value(ctx, &s, prop, 0))
409             prop->type = PROPERTY_TYPE_VALUE_UNDEFINED;
410
411 skip_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
423 err:
424     OPENSSL_free(prop);
425     sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
426     return res;
427 }
428
429 int 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
480 void 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  */
489 OSSL_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
524 int ossl_property_parse_init(OPENSSL_CTX *ctx)
525 {
526     static const char *const predefined_names[] = {
527         "default",      /* Being provided by the default built-in provider */
528         "legacy",       /* Provided by the legacy provider */
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++)
537         if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
538             goto err;
539
540     /* Pre-populate the two Boolean values */
541     if ((ossl_property_true = ossl_property_value(ctx, "yes", 1)) == 0
542         || (ossl_property_false = ossl_property_value(ctx, "no", 1)) == 0)
543         goto err;
544
545     return 1;
546 err:
547     return 0;
548 }