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