property: default queries create the property values.
[openssl.git] / crypto / property / property_parse.c
1 /*
2  * Copyright 2019-2020 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
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     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
42 struct ossl_property_list_st {
43     int n;
44     unsigned int has_optional : 1;
45     PROPERTY_DEFINITION properties[1];
46 };
47
48 static OSSL_PROPERTY_IDX ossl_property_true, ossl_property_false;
49
50 DEFINE_STACK_OF(PROPERTY_DEFINITION)
51
52 static const char *skip_space(const char *s)
53 {
54     while (ossl_isspace(*s))
55         s++;
56     return s;
57 }
58
59 static 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
72 static 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
83 static int parse_name(OSSL_LIB_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
123 static 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
144 static 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
169 static 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
190 static int parse_string(OSSL_LIB_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
221 static int parse_unquoted(OSSL_LIB_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
254 static int parse_value(OSSL_LIB_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
285 static 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
298 static 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  */
307 static 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
329 OSSL_PROPERTY_LIST *ossl_parse_property(OSSL_LIB_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
382 err:
383     OPENSSL_free(prop);
384     sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
385     return res;
386 }
387
388 OSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s,
389                                      int create_values)
390 {
391     STACK_OF(PROPERTY_DEFINITION) *sk;
392     OSSL_PROPERTY_LIST *res = NULL;
393     PROPERTY_DEFINITION *prop = NULL;
394     int done;
395
396     if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
397         return NULL;
398
399     s = skip_space(s);
400     done = *s == '\0';
401     while (!done) {
402         prop = OPENSSL_malloc(sizeof(*prop));
403         if (prop == NULL)
404             goto err;
405         memset(&prop->v, 0, sizeof(prop->v));
406
407         if (match_ch(&s, '-')) {
408             prop->oper = PROPERTY_OVERRIDE;
409             prop->optional = 0;
410             if (!parse_name(ctx, &s, 0, &prop->name_idx))
411                 goto err;
412             goto skip_value;
413         }
414         prop->optional = match_ch(&s, '?');
415         if (!parse_name(ctx, &s, 0, &prop->name_idx))
416             goto err;
417
418         if (match_ch(&s, '=')) {
419             prop->oper = PROPERTY_OPER_EQ;
420         } else if (MATCH(&s, "!=")) {
421             prop->oper = PROPERTY_OPER_NE;
422         } else {
423             /* A name alone is a Boolean comparison for true */
424             prop->oper = PROPERTY_OPER_EQ;
425             prop->type = PROPERTY_TYPE_STRING;
426             prop->v.str_val = ossl_property_true;
427             goto skip_value;
428         }
429         if (!parse_value(ctx, &s, prop, create_values))
430             prop->type = PROPERTY_TYPE_VALUE_UNDEFINED;
431
432 skip_value:
433         if (!sk_PROPERTY_DEFINITION_push(sk, prop))
434             goto err;
435         prop = NULL;
436         done = !match_ch(&s, ',');
437     }
438     if (*s != '\0') {
439         ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
440                        "HERE-->%s", s);
441         goto err;
442     }
443     res = stack_to_property_list(sk);
444
445 err:
446     OPENSSL_free(prop);
447     sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
448     return res;
449 }
450
451 /* Does a property query have any optional clauses */
452 int ossl_property_has_optional(const OSSL_PROPERTY_LIST *query)
453 {
454     return query->has_optional ? 1 : 0;
455 }
456
457 int ossl_property_is_enabled(OSSL_LIB_CTX *ctx,  const char *property_name,
458                              const OSSL_PROPERTY_LIST *prop_list)
459 {
460     int i;
461     OSSL_PROPERTY_IDX name_id;
462     const PROPERTY_DEFINITION *prop = NULL;
463
464     if (prop_list == NULL)
465         return 0;
466
467     if (!parse_name(ctx, &property_name, 0, &name_id))
468         return 0;
469
470     prop = prop_list->properties;
471     for (i = 0; i < prop_list->n; ++i) {
472         if (prop[i].name_idx == name_id) {
473             /* Do a separate check for override as it does not set type */
474             if (prop[i].optional || prop[i].oper == PROPERTY_OVERRIDE)
475                 return 0;
476             return (prop[i].type == PROPERTY_TYPE_STRING
477                     && ((prop[i].oper == PROPERTY_OPER_EQ
478                              && prop[i].v.str_val == ossl_property_true)
479                          || (prop[i].oper == PROPERTY_OPER_NE
480                              && prop[i].v.str_val != ossl_property_true)));
481         }
482     }
483     return 0;
484 }
485
486 /*
487  * Compare a query against a definition.
488  * Return the number of clauses matched or -1 if a mandatory clause is false.
489  */
490 int ossl_property_match_count(const OSSL_PROPERTY_LIST *query,
491                               const OSSL_PROPERTY_LIST *defn)
492 {
493     const PROPERTY_DEFINITION *const q = query->properties;
494     const PROPERTY_DEFINITION *const d = defn->properties;
495     int i = 0, j = 0, matches = 0;
496     PROPERTY_OPER oper;
497
498     while (i < query->n) {
499         if ((oper = q[i].oper) == PROPERTY_OVERRIDE) {
500             i++;
501             continue;
502         }
503         if (j < defn->n) {
504             if (q[i].name_idx > d[j].name_idx) {  /* skip defn, not in query */
505                 j++;
506                 continue;
507             }
508             if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */
509                 const int eq = q[i].type == d[j].type
510                                && memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0;
511
512                 if ((eq && oper == PROPERTY_OPER_EQ)
513                     || (!eq && oper == PROPERTY_OPER_NE))
514                     matches++;
515                 else if (!q[i].optional)
516                     return -1;
517                 i++;
518                 j++;
519                 continue;
520             }
521         }
522
523         /*
524          * Handle the cases of a missing value and a query with no corresponding
525          * definition.  The former fails for any comparison except inequality,
526          * the latter is treated as a comparison against the Boolean false.
527          */
528         if (q[i].type == PROPERTY_TYPE_VALUE_UNDEFINED) {
529             if (oper == PROPERTY_OPER_NE)
530                 matches++;
531             else if (!q[i].optional)
532                 return -1;
533         } else if (q[i].type != PROPERTY_TYPE_STRING
534                    || (oper == PROPERTY_OPER_EQ
535                        && q[i].v.str_val != ossl_property_false)
536                    || (oper == PROPERTY_OPER_NE
537                        && q[i].v.str_val == ossl_property_false)) {
538             if (!q[i].optional)
539                 return -1;
540         } else {
541             matches++;
542         }
543         i++;
544     }
545     return matches;
546 }
547
548 void ossl_property_free(OSSL_PROPERTY_LIST *p)
549 {
550     OPENSSL_free(p);
551 }
552
553 /*
554  * Merge two property lists.
555  * If there is a common name, the one from the first list is used.
556  */
557 OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
558                                         const OSSL_PROPERTY_LIST *b)
559 {
560     const PROPERTY_DEFINITION *const ap = a->properties;
561     const PROPERTY_DEFINITION *const bp = b->properties;
562     const PROPERTY_DEFINITION *copy;
563     OSSL_PROPERTY_LIST *r;
564     int i, j, n;
565     const int t = a->n + b->n;
566
567     r = OPENSSL_malloc(sizeof(*r)
568                        + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
569     if (r == NULL)
570         return NULL;
571
572     r->has_optional = 0;
573     for (i = j = n = 0; i < a->n || j < b->n; n++) {
574         if (i >= a->n) {
575             copy = &bp[j++];
576         } else if (j >= b->n) {
577             copy = &ap[i++];
578         } else if (ap[i].name_idx <= bp[j].name_idx) {
579             if (ap[i].name_idx == bp[j].name_idx)
580                 j++;
581             copy = &ap[i++];
582         } else {
583             copy = &bp[j++];
584         }
585         memcpy(r->properties + n, copy, sizeof(r->properties[0]));
586         r->has_optional |= copy->optional;
587     }
588     r->n = n;
589     if (n != t)
590         r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
591     return r;
592 }
593
594 int ossl_property_parse_init(OSSL_LIB_CTX *ctx)
595 {
596     static const char *const predefined_names[] = {
597         "provider",     /* Name of provider (default, legacy, fips) */
598         "version",      /* Version number of this provider */
599         "fips",         /* FIPS validated or FIPS supporting algorithm */
600         "output",       /* Output type for encoders */
601         "input",        /* Input type for decoders */
602         "structure",    /* Structure name for encoders and decoders */
603     };
604     size_t i;
605
606     for (i = 0; i < OSSL_NELEM(predefined_names); i++)
607         if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
608             goto err;
609
610     /* Pre-populate the two Boolean values */
611     if ((ossl_property_true = ossl_property_value(ctx, "yes", 1)) == 0
612         || (ossl_property_false = ossl_property_value(ctx, "no", 1)) == 0)
613         goto err;
614
615     return 1;
616 err:
617     return 0;
618 }