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