VirtualBox

source: vbox/trunk/src/libs/openssl-3.0.7/crypto/property/property_parse.c@ 97371

最後變更 在這個檔案從97371是 95219,由 vboxsync 提交於 3 年 前

libs/openssl: Switched to v3.0.3, bugref:10128

檔案大小: 19.7 KB
 
1/*
2 * Copyright 2019-2022 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
22DEFINE_STACK_OF(OSSL_PROPERTY_DEFINITION)
23
24static const char *skip_space(const char *s)
25{
26 while (ossl_isspace(*s))
27 s++;
28 return s;
29}
30
31static int match_ch(const char *t[], char m)
32{
33 const char *s = *t;
34
35 if (*s == m) {
36 *t = skip_space(s + 1);
37 return 1;
38 }
39 return 0;
40}
41
42#define MATCH(s, m) match(s, m, sizeof(m) - 1)
43
44static int match(const char *t[], const char m[], size_t m_len)
45{
46 const char *s = *t;
47
48 if (OPENSSL_strncasecmp(s, m, m_len) == 0) {
49 *t = skip_space(s + m_len);
50 return 1;
51 }
52 return 0;
53}
54
55static int parse_name(OSSL_LIB_CTX *ctx, const char *t[], int create,
56 OSSL_PROPERTY_IDX *idx)
57{
58 char name[100];
59 int err = 0;
60 size_t i = 0;
61 const char *s = *t;
62 int user_name = 0;
63
64 for (;;) {
65 if (!ossl_isalpha(*s)) {
66 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER,
67 "HERE-->%s", *t);
68 return 0;
69 }
70 do {
71 if (i < sizeof(name) - 1)
72 name[i++] = ossl_tolower(*s);
73 else
74 err = 1;
75 } while (*++s == '_' || ossl_isalnum(*s));
76 if (*s != '.')
77 break;
78 user_name = 1;
79 if (i < sizeof(name) - 1)
80 name[i++] = *s;
81 else
82 err = 1;
83 s++;
84 }
85 name[i] = '\0';
86 if (err) {
87 ERR_raise_data(ERR_LIB_PROP, PROP_R_NAME_TOO_LONG, "HERE-->%s", *t);
88 return 0;
89 }
90 *t = skip_space(s);
91 *idx = ossl_property_name(ctx, name, user_name && create);
92 return 1;
93}
94
95static int parse_number(const char *t[], OSSL_PROPERTY_DEFINITION *res)
96{
97 const char *s = *t;
98 int64_t v = 0;
99
100 if (!ossl_isdigit(*s))
101 return 0;
102 do {
103 v = v * 10 + (*s++ - '0');
104 } while (ossl_isdigit(*s));
105 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
106 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT,
107 "HERE-->%s", *t);
108 return 0;
109 }
110 *t = skip_space(s);
111 res->type = OSSL_PROPERTY_TYPE_NUMBER;
112 res->v.int_val = v;
113 return 1;
114}
115
116static int parse_hex(const char *t[], OSSL_PROPERTY_DEFINITION *res)
117{
118 const char *s = *t;
119 int64_t v = 0;
120
121 if (!ossl_isxdigit(*s))
122 return 0;
123 do {
124 v <<= 4;
125 if (ossl_isdigit(*s))
126 v += *s - '0';
127 else
128 v += ossl_tolower(*s) - 'a';
129 } while (ossl_isxdigit(*++s));
130 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
131 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT,
132 "HERE-->%s", *t);
133 return 0;
134 }
135 *t = skip_space(s);
136 res->type = OSSL_PROPERTY_TYPE_NUMBER;
137 res->v.int_val = v;
138 return 1;
139}
140
141static int parse_oct(const char *t[], OSSL_PROPERTY_DEFINITION *res)
142{
143 const char *s = *t;
144 int64_t v = 0;
145
146 if (*s == '9' || *s == '8' || !ossl_isdigit(*s))
147 return 0;
148 do {
149 v = (v << 3) + (*s - '0');
150 } while (ossl_isdigit(*++s) && *s != '9' && *s != '8');
151 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
152 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT,
153 "HERE-->%s", *t);
154 return 0;
155 }
156 *t = skip_space(s);
157 res->type = OSSL_PROPERTY_TYPE_NUMBER;
158 res->v.int_val = v;
159 return 1;
160}
161
162static int parse_string(OSSL_LIB_CTX *ctx, const char *t[], char delim,
163 OSSL_PROPERTY_DEFINITION *res, const int create)
164{
165 char v[1000];
166 const char *s = *t;
167 size_t i = 0;
168 int err = 0;
169
170 while (*s != '\0' && *s != delim) {
171 if (i < sizeof(v) - 1)
172 v[i++] = *s;
173 else
174 err = 1;
175 s++;
176 }
177 if (*s == '\0') {
178 ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER,
179 "HERE-->%c%s", delim, *t);
180 return 0;
181 }
182 v[i] = '\0';
183 if (err) {
184 ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
185 } else {
186 res->v.str_val = ossl_property_value(ctx, v, create);
187 }
188 *t = skip_space(s + 1);
189 res->type = OSSL_PROPERTY_TYPE_STRING;
190 return !err;
191}
192
193static int parse_unquoted(OSSL_LIB_CTX *ctx, const char *t[],
194 OSSL_PROPERTY_DEFINITION *res, const int create)
195{
196 char v[1000];
197 const char *s = *t;
198 size_t i = 0;
199 int err = 0;
200
201 if (*s == '\0' || *s == ',')
202 return 0;
203 while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') {
204 if (i < sizeof(v) - 1)
205 v[i++] = ossl_tolower(*s);
206 else
207 err = 1;
208 s++;
209 }
210 if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
211 ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER,
212 "HERE-->%s", s);
213 return 0;
214 }
215 v[i] = 0;
216 if (err) {
217 ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
218 } else {
219 res->v.str_val = ossl_property_value(ctx, v, create);
220 }
221 *t = skip_space(s);
222 res->type = OSSL_PROPERTY_TYPE_STRING;
223 return !err;
224}
225
226static int parse_value(OSSL_LIB_CTX *ctx, const char *t[],
227 OSSL_PROPERTY_DEFINITION *res, int create)
228{
229 const char *s = *t;
230 int r = 0;
231
232 if (*s == '"' || *s == '\'') {
233 s++;
234 r = parse_string(ctx, &s, s[-1], res, create);
235 } else if (*s == '+') {
236 s++;
237 r = parse_number(&s, res);
238 } else if (*s == '-') {
239 s++;
240 r = parse_number(&s, res);
241 res->v.int_val = -res->v.int_val;
242 } else if (*s == '0' && s[1] == 'x') {
243 s += 2;
244 r = parse_hex(&s, res);
245 } else if (*s == '0' && ossl_isdigit(s[1])) {
246 s++;
247 r = parse_oct(&s, res);
248 } else if (ossl_isdigit(*s)) {
249 return parse_number(t, res);
250 } else if (ossl_isalpha(*s))
251 return parse_unquoted(ctx, t, res, create);
252 if (r)
253 *t = s;
254 return r;
255}
256
257static int pd_compare(const OSSL_PROPERTY_DEFINITION *const *p1,
258 const OSSL_PROPERTY_DEFINITION *const *p2)
259{
260 const OSSL_PROPERTY_DEFINITION *pd1 = *p1;
261 const OSSL_PROPERTY_DEFINITION *pd2 = *p2;
262
263 if (pd1->name_idx < pd2->name_idx)
264 return -1;
265 if (pd1->name_idx > pd2->name_idx)
266 return 1;
267 return 0;
268}
269
270static void pd_free(OSSL_PROPERTY_DEFINITION *pd)
271{
272 OPENSSL_free(pd);
273}
274
275/*
276 * Convert a stack of property definitions and queries into a fixed array.
277 * The items are sorted for efficient query. The stack is not freed.
278 * This function also checks for duplicated names and returns an error if
279 * any exist.
280 */
281static OSSL_PROPERTY_LIST *
282stack_to_property_list(OSSL_LIB_CTX *ctx,
283 STACK_OF(OSSL_PROPERTY_DEFINITION) *sk)
284{
285 const int n = sk_OSSL_PROPERTY_DEFINITION_num(sk);
286 OSSL_PROPERTY_LIST *r;
287 OSSL_PROPERTY_IDX prev_name_idx = 0;
288 int i;
289
290 r = OPENSSL_malloc(sizeof(*r)
291 + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0]));
292 if (r != NULL) {
293 sk_OSSL_PROPERTY_DEFINITION_sort(sk);
294
295 r->has_optional = 0;
296 for (i = 0; i < n; i++) {
297 r->properties[i] = *sk_OSSL_PROPERTY_DEFINITION_value(sk, i);
298 r->has_optional |= r->properties[i].optional;
299
300 /* Check for duplicated names */
301 if (i > 0 && r->properties[i].name_idx == prev_name_idx) {
302 OPENSSL_free(r);
303 ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
304 "Duplicated name `%s'",
305 ossl_property_name_str(ctx, prev_name_idx));
306 return NULL;
307 }
308 prev_name_idx = r->properties[i].name_idx;
309 }
310 r->num_properties = n;
311 }
312 return r;
313}
314
315OSSL_PROPERTY_LIST *ossl_parse_property(OSSL_LIB_CTX *ctx, const char *defn)
316{
317 OSSL_PROPERTY_DEFINITION *prop = NULL;
318 OSSL_PROPERTY_LIST *res = NULL;
319 STACK_OF(OSSL_PROPERTY_DEFINITION) *sk;
320 const char *s = defn;
321 int done;
322
323 if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
324 return NULL;
325
326 s = skip_space(s);
327 done = *s == '\0';
328 while (!done) {
329 const char *start = s;
330
331 prop = OPENSSL_malloc(sizeof(*prop));
332 if (prop == NULL)
333 goto err;
334 memset(&prop->v, 0, sizeof(prop->v));
335 prop->optional = 0;
336 if (!parse_name(ctx, &s, 1, &prop->name_idx))
337 goto err;
338 prop->oper = OSSL_PROPERTY_OPER_EQ;
339 if (prop->name_idx == 0) {
340 ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
341 "Unknown name HERE-->%s", start);
342 goto err;
343 }
344 if (match_ch(&s, '=')) {
345 if (!parse_value(ctx, &s, prop, 1)) {
346 ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_VALUE,
347 "HERE-->%s", start);
348 goto err;
349 }
350 } else {
351 /* A name alone means a true Boolean */
352 prop->type = OSSL_PROPERTY_TYPE_STRING;
353 prop->v.str_val = OSSL_PROPERTY_TRUE;
354 }
355
356 if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop))
357 goto err;
358 prop = NULL;
359 done = !match_ch(&s, ',');
360 }
361 if (*s != '\0') {
362 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
363 "HERE-->%s", s);
364 goto err;
365 }
366 res = stack_to_property_list(ctx, sk);
367
368err:
369 OPENSSL_free(prop);
370 sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
371 return res;
372}
373
374OSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s,
375 int create_values)
376{
377 STACK_OF(OSSL_PROPERTY_DEFINITION) *sk;
378 OSSL_PROPERTY_LIST *res = NULL;
379 OSSL_PROPERTY_DEFINITION *prop = NULL;
380 int done;
381
382 if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
383 return NULL;
384
385 s = skip_space(s);
386 done = *s == '\0';
387 while (!done) {
388 prop = OPENSSL_malloc(sizeof(*prop));
389 if (prop == NULL)
390 goto err;
391 memset(&prop->v, 0, sizeof(prop->v));
392
393 if (match_ch(&s, '-')) {
394 prop->oper = OSSL_PROPERTY_OVERRIDE;
395 prop->optional = 0;
396 if (!parse_name(ctx, &s, 1, &prop->name_idx))
397 goto err;
398 goto skip_value;
399 }
400 prop->optional = match_ch(&s, '?');
401 if (!parse_name(ctx, &s, 1, &prop->name_idx))
402 goto err;
403
404 if (match_ch(&s, '=')) {
405 prop->oper = OSSL_PROPERTY_OPER_EQ;
406 } else if (MATCH(&s, "!=")) {
407 prop->oper = OSSL_PROPERTY_OPER_NE;
408 } else {
409 /* A name alone is a Boolean comparison for true */
410 prop->oper = OSSL_PROPERTY_OPER_EQ;
411 prop->type = OSSL_PROPERTY_TYPE_STRING;
412 prop->v.str_val = OSSL_PROPERTY_TRUE;
413 goto skip_value;
414 }
415 if (!parse_value(ctx, &s, prop, create_values))
416 prop->type = OSSL_PROPERTY_TYPE_VALUE_UNDEFINED;
417
418skip_value:
419 if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop))
420 goto err;
421 prop = NULL;
422 done = !match_ch(&s, ',');
423 }
424 if (*s != '\0') {
425 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
426 "HERE-->%s", s);
427 goto err;
428 }
429 res = stack_to_property_list(ctx, sk);
430
431err:
432 OPENSSL_free(prop);
433 sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
434 return res;
435}
436
437/*
438 * Compare a query against a definition.
439 * Return the number of clauses matched or -1 if a mandatory clause is false.
440 */
441int ossl_property_match_count(const OSSL_PROPERTY_LIST *query,
442 const OSSL_PROPERTY_LIST *defn)
443{
444 const OSSL_PROPERTY_DEFINITION *const q = query->properties;
445 const OSSL_PROPERTY_DEFINITION *const d = defn->properties;
446 int i = 0, j = 0, matches = 0;
447 OSSL_PROPERTY_OPER oper;
448
449 while (i < query->num_properties) {
450 if ((oper = q[i].oper) == OSSL_PROPERTY_OVERRIDE) {
451 i++;
452 continue;
453 }
454 if (j < defn->num_properties) {
455 if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */
456 j++;
457 continue;
458 }
459 if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */
460 const int eq = q[i].type == d[j].type
461 && memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0;
462
463 if ((eq && oper == OSSL_PROPERTY_OPER_EQ)
464 || (!eq && oper == OSSL_PROPERTY_OPER_NE))
465 matches++;
466 else if (!q[i].optional)
467 return -1;
468 i++;
469 j++;
470 continue;
471 }
472 }
473
474 /*
475 * Handle the cases of a missing value and a query with no corresponding
476 * definition. The former fails for any comparison except inequality,
477 * the latter is treated as a comparison against the Boolean false.
478 */
479 if (q[i].type == OSSL_PROPERTY_TYPE_VALUE_UNDEFINED) {
480 if (oper == OSSL_PROPERTY_OPER_NE)
481 matches++;
482 else if (!q[i].optional)
483 return -1;
484 } else if (q[i].type != OSSL_PROPERTY_TYPE_STRING
485 || (oper == OSSL_PROPERTY_OPER_EQ
486 && q[i].v.str_val != OSSL_PROPERTY_FALSE)
487 || (oper == OSSL_PROPERTY_OPER_NE
488 && q[i].v.str_val == OSSL_PROPERTY_FALSE)) {
489 if (!q[i].optional)
490 return -1;
491 } else {
492 matches++;
493 }
494 i++;
495 }
496 return matches;
497}
498
499void ossl_property_free(OSSL_PROPERTY_LIST *p)
500{
501 OPENSSL_free(p);
502}
503
504/*
505 * Merge two property lists.
506 * If there is a common name, the one from the first list is used.
507 */
508OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
509 const OSSL_PROPERTY_LIST *b)
510{
511 const OSSL_PROPERTY_DEFINITION *const ap = a->properties;
512 const OSSL_PROPERTY_DEFINITION *const bp = b->properties;
513 const OSSL_PROPERTY_DEFINITION *copy;
514 OSSL_PROPERTY_LIST *r;
515 int i, j, n;
516 const int t = a->num_properties + b->num_properties;
517
518 r = OPENSSL_malloc(sizeof(*r)
519 + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
520 if (r == NULL)
521 return NULL;
522
523 r->has_optional = 0;
524 for (i = j = n = 0; i < a->num_properties || j < b->num_properties; n++) {
525 if (i >= a->num_properties) {
526 copy = &bp[j++];
527 } else if (j >= b->num_properties) {
528 copy = &ap[i++];
529 } else if (ap[i].name_idx <= bp[j].name_idx) {
530 if (ap[i].name_idx == bp[j].name_idx)
531 j++;
532 copy = &ap[i++];
533 } else {
534 copy = &bp[j++];
535 }
536 memcpy(r->properties + n, copy, sizeof(r->properties[0]));
537 r->has_optional |= copy->optional;
538 }
539 r->num_properties = n;
540 if (n != t)
541 r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
542 return r;
543}
544
545int ossl_property_parse_init(OSSL_LIB_CTX *ctx)
546{
547 static const char *const predefined_names[] = {
548 "provider", /* Name of provider (default, legacy, fips) */
549 "version", /* Version number of this provider */
550 "fips", /* FIPS validated or FIPS supporting algorithm */
551 "output", /* Output type for encoders */
552 "input", /* Input type for decoders */
553 "structure", /* Structure name for encoders and decoders */
554 };
555 size_t i;
556
557 for (i = 0; i < OSSL_NELEM(predefined_names); i++)
558 if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
559 goto err;
560
561 /*
562 * Pre-populate the two Boolean values. We must do them before any other
563 * values and in this order so that we get the same index as the global
564 * OSSL_PROPERTY_TRUE and OSSL_PROPERTY_FALSE values
565 */
566 if ((ossl_property_value(ctx, "yes", 1) != OSSL_PROPERTY_TRUE)
567 || (ossl_property_value(ctx, "no", 1) != OSSL_PROPERTY_FALSE))
568 goto err;
569
570 return 1;
571err:
572 return 0;
573}
574
575static void put_char(char ch, char **buf, size_t *remain, size_t *needed)
576{
577 if (*remain == 0) {
578 ++*needed;
579 return;
580 }
581 if(*remain == 1)
582 **buf = '\0';
583 else
584 **buf = ch;
585 ++*buf;
586 ++*needed;
587 --*remain;
588}
589
590static void put_str(const char *str, char **buf, size_t *remain, size_t *needed)
591{
592 size_t olen, len;
593
594 len = olen = strlen(str);
595 *needed += len;
596
597 if (*remain == 0)
598 return;
599
600 if(*remain < len + 1)
601 len = *remain - 1;
602
603 if(len > 0) {
604 strncpy(*buf, str, len);
605 *buf += len;
606 *remain -= len;
607 }
608
609 if(len < olen && *remain == 1) {
610 **buf = '\0';
611 ++*buf;
612 --*remain;
613 }
614}
615
616static void put_num(int64_t val, char **buf, size_t *remain, size_t *needed)
617{
618 int64_t tmpval = val;
619 size_t len = 1;
620
621 if (tmpval < 0) {
622 len++;
623 tmpval = -tmpval;
624 }
625 for (; tmpval > 9; len++, tmpval /= 10);
626
627 *needed += len;
628
629 if (*remain == 0)
630 return;
631
632 BIO_snprintf(*buf, *remain, "%lld", (long long int)val);
633 if (*remain < len) {
634 *buf += *remain;
635 *remain = 0;
636 } else {
637 *buf += len;
638 *remain -= len;
639 }
640}
641
642size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx,
643 const OSSL_PROPERTY_LIST *list, char *buf,
644 size_t bufsize)
645{
646 int i;
647 const OSSL_PROPERTY_DEFINITION *prop = NULL;
648 size_t needed = 0;
649 const char *val;
650
651 if (list == NULL) {
652 if (bufsize > 0)
653 *buf = '\0';
654 return 1;
655 }
656 if (list->num_properties != 0)
657 prop = &list->properties[list->num_properties - 1];
658 for (i = 0; i < list->num_properties; i++, prop--) {
659 /* Skip invalid names */
660 if (prop->name_idx == 0)
661 continue;
662
663 if (needed > 0)
664 put_char(',', &buf, &bufsize, &needed);
665
666 if (prop->optional)
667 put_char('?', &buf, &bufsize, &needed);
668 else if (prop->oper == OSSL_PROPERTY_OVERRIDE)
669 put_char('-', &buf, &bufsize, &needed);
670
671 val = ossl_property_name_str(ctx, prop->name_idx);
672 if (val == NULL)
673 return 0;
674 put_str(val, &buf, &bufsize, &needed);
675
676 switch (prop->oper) {
677 case OSSL_PROPERTY_OPER_NE:
678 put_char('!', &buf, &bufsize, &needed);
679 /* fall through */
680 case OSSL_PROPERTY_OPER_EQ:
681 put_char('=', &buf, &bufsize, &needed);
682 /* put value */
683 switch (prop->type) {
684 case OSSL_PROPERTY_TYPE_STRING:
685 val = ossl_property_value_str(ctx, prop->v.str_val);
686 if (val == NULL)
687 return 0;
688 put_str(val, &buf, &bufsize, &needed);
689 break;
690
691 case OSSL_PROPERTY_TYPE_NUMBER:
692 put_num(prop->v.int_val, &buf, &bufsize, &needed);
693 break;
694
695 default:
696 return 0;
697 }
698 break;
699 default:
700 /* do nothing */
701 break;
702 }
703 }
704
705 put_char('\0', &buf, &bufsize, &needed);
706 return needed;
707}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette