eee76abc2c03f5012f95753970eb3414f9be58b3
[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(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
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(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
221 static 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
254 static 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
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(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
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(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
431 skip_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
444 err:
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 */
451 int 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  */
460 int 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
518 void 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  */
527 OSSL_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
562 int ossl_property_parse_init(OPENSSL_CTX *ctx)
563 {
564     static const char *const predefined_names[] = {
565         "provider",     /* Name of provider (default, legacy, fips) */
566         "version",      /* Version number of this provider */
567         "fips",         /* FIPS validated or FIPS supporting algorithm */
568         "format",       /* output format for serializers */
569         "type",         /* output type for serializers */
570     };
571     size_t i;
572
573     for (i = 0; i < OSSL_NELEM(predefined_names); i++)
574         if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
575             goto err;
576
577     /* Pre-populate the two Boolean values */
578     if ((ossl_property_true = ossl_property_value(ctx, "yes", 1)) == 0
579         || (ossl_property_false = ossl_property_value(ctx, "no", 1)) == 0)
580         goto err;
581
582     return 1;
583 err:
584     return 0;
585 }