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
DEFINE_STACK_OF(OSSL_PROPERTY_DEFINITION)22 DEFINE_STACK_OF(OSSL_PROPERTY_DEFINITION)
23
24 static const char *skip_space(const char *s)
25 {
26 while (ossl_isspace(*s))
27 s++;
28 return s;
29 }
30
match_ch(const char * t[],char m)31 static 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
match(const char * t[],const char m[],size_t m_len)44 static 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
parse_name(OSSL_LIB_CTX * ctx,const char * t[],int create,OSSL_PROPERTY_IDX * idx)55 static 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
parse_number(const char * t[],OSSL_PROPERTY_DEFINITION * res)95 static 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
parse_hex(const char * t[],OSSL_PROPERTY_DEFINITION * res)116 static 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
parse_oct(const char * t[],OSSL_PROPERTY_DEFINITION * res)141 static 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
parse_string(OSSL_LIB_CTX * ctx,const char * t[],char delim,OSSL_PROPERTY_DEFINITION * res,const int create)162 static 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
parse_unquoted(OSSL_LIB_CTX * ctx,const char * t[],OSSL_PROPERTY_DEFINITION * res,const int create)193 static 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 if ((res->v.str_val = ossl_property_value(ctx, v, create)) == 0)
219 err = 1;
220 *t = skip_space(s);
221 res->type = OSSL_PROPERTY_TYPE_STRING;
222 return !err;
223 }
224
parse_value(OSSL_LIB_CTX * ctx,const char * t[],OSSL_PROPERTY_DEFINITION * res,int create)225 static int parse_value(OSSL_LIB_CTX *ctx, const char *t[],
226 OSSL_PROPERTY_DEFINITION *res, int create)
227 {
228 const char *s = *t;
229 int r = 0;
230
231 if (*s == '"' || *s == '\'') {
232 s++;
233 r = parse_string(ctx, &s, s[-1], res, create);
234 } else if (*s == '+') {
235 s++;
236 r = parse_number(&s, res);
237 } else if (*s == '-') {
238 s++;
239 r = parse_number(&s, res);
240 res->v.int_val = -res->v.int_val;
241 } else if (*s == '0' && s[1] == 'x') {
242 s += 2;
243 r = parse_hex(&s, res);
244 } else if (*s == '0' && ossl_isdigit(s[1])) {
245 s++;
246 r = parse_oct(&s, res);
247 } else if (ossl_isdigit(*s)) {
248 return parse_number(t, res);
249 } else if (ossl_isalpha(*s))
250 return parse_unquoted(ctx, t, res, create);
251 if (r)
252 *t = s;
253 return r;
254 }
255
pd_compare(const OSSL_PROPERTY_DEFINITION * const * p1,const OSSL_PROPERTY_DEFINITION * const * p2)256 static int pd_compare(const OSSL_PROPERTY_DEFINITION *const *p1,
257 const OSSL_PROPERTY_DEFINITION *const *p2)
258 {
259 const OSSL_PROPERTY_DEFINITION *pd1 = *p1;
260 const OSSL_PROPERTY_DEFINITION *pd2 = *p2;
261
262 if (pd1->name_idx < pd2->name_idx)
263 return -1;
264 if (pd1->name_idx > pd2->name_idx)
265 return 1;
266 return 0;
267 }
268
pd_free(OSSL_PROPERTY_DEFINITION * pd)269 static void pd_free(OSSL_PROPERTY_DEFINITION *pd)
270 {
271 OPENSSL_free(pd);
272 }
273
274 /*
275 * Convert a stack of property definitions and queries into a fixed array.
276 * The items are sorted for efficient query. The stack is not freed.
277 * This function also checks for duplicated names and returns an error if
278 * any exist.
279 */
280 static OSSL_PROPERTY_LIST *
stack_to_property_list(OSSL_LIB_CTX * ctx,STACK_OF (OSSL_PROPERTY_DEFINITION)* sk)281 stack_to_property_list(OSSL_LIB_CTX *ctx,
282 STACK_OF(OSSL_PROPERTY_DEFINITION) *sk)
283 {
284 const int n = sk_OSSL_PROPERTY_DEFINITION_num(sk);
285 OSSL_PROPERTY_LIST *r;
286 OSSL_PROPERTY_IDX prev_name_idx = 0;
287 int i;
288
289 r = OPENSSL_malloc(sizeof(*r)
290 + (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0]));
291 if (r != NULL) {
292 sk_OSSL_PROPERTY_DEFINITION_sort(sk);
293
294 r->has_optional = 0;
295 for (i = 0; i < n; i++) {
296 r->properties[i] = *sk_OSSL_PROPERTY_DEFINITION_value(sk, i);
297 r->has_optional |= r->properties[i].optional;
298
299 /* Check for duplicated names */
300 if (i > 0 && r->properties[i].name_idx == prev_name_idx) {
301 OPENSSL_free(r);
302 ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
303 "Duplicated name `%s'",
304 ossl_property_name_str(ctx, prev_name_idx));
305 return NULL;
306 }
307 prev_name_idx = r->properties[i].name_idx;
308 }
309 r->num_properties = n;
310 }
311 return r;
312 }
313
ossl_parse_property(OSSL_LIB_CTX * ctx,const char * defn)314 OSSL_PROPERTY_LIST *ossl_parse_property(OSSL_LIB_CTX *ctx, const char *defn)
315 {
316 OSSL_PROPERTY_DEFINITION *prop = NULL;
317 OSSL_PROPERTY_LIST *res = NULL;
318 STACK_OF(OSSL_PROPERTY_DEFINITION) *sk;
319 const char *s = defn;
320 int done;
321
322 if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
323 return NULL;
324
325 s = skip_space(s);
326 done = *s == '\0';
327 while (!done) {
328 const char *start = s;
329
330 prop = OPENSSL_malloc(sizeof(*prop));
331 if (prop == NULL)
332 goto err;
333 memset(&prop->v, 0, sizeof(prop->v));
334 prop->optional = 0;
335 if (!parse_name(ctx, &s, 1, &prop->name_idx))
336 goto err;
337 prop->oper = OSSL_PROPERTY_OPER_EQ;
338 if (prop->name_idx == 0) {
339 ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
340 "Unknown name HERE-->%s", start);
341 goto err;
342 }
343 if (match_ch(&s, '=')) {
344 if (!parse_value(ctx, &s, prop, 1)) {
345 ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_VALUE,
346 "HERE-->%s", start);
347 goto err;
348 }
349 } else {
350 /* A name alone means a true Boolean */
351 prop->type = OSSL_PROPERTY_TYPE_STRING;
352 prop->v.str_val = OSSL_PROPERTY_TRUE;
353 }
354
355 if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop))
356 goto err;
357 prop = NULL;
358 done = !match_ch(&s, ',');
359 }
360 if (*s != '\0') {
361 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
362 "HERE-->%s", s);
363 goto err;
364 }
365 res = stack_to_property_list(ctx, sk);
366
367 err:
368 OPENSSL_free(prop);
369 sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
370 return res;
371 }
372
ossl_parse_query(OSSL_LIB_CTX * ctx,const char * s,int create_values)373 OSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s,
374 int create_values)
375 {
376 STACK_OF(OSSL_PROPERTY_DEFINITION) *sk;
377 OSSL_PROPERTY_LIST *res = NULL;
378 OSSL_PROPERTY_DEFINITION *prop = NULL;
379 int done;
380
381 if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
382 return NULL;
383
384 s = skip_space(s);
385 done = *s == '\0';
386 while (!done) {
387 prop = OPENSSL_malloc(sizeof(*prop));
388 if (prop == NULL)
389 goto err;
390 memset(&prop->v, 0, sizeof(prop->v));
391
392 if (match_ch(&s, '-')) {
393 prop->oper = OSSL_PROPERTY_OVERRIDE;
394 prop->optional = 0;
395 if (!parse_name(ctx, &s, 1, &prop->name_idx))
396 goto err;
397 goto skip_value;
398 }
399 prop->optional = match_ch(&s, '?');
400 if (!parse_name(ctx, &s, 1, &prop->name_idx))
401 goto err;
402
403 if (match_ch(&s, '=')) {
404 prop->oper = OSSL_PROPERTY_OPER_EQ;
405 } else if (MATCH(&s, "!=")) {
406 prop->oper = OSSL_PROPERTY_OPER_NE;
407 } else {
408 /* A name alone is a Boolean comparison for true */
409 prop->oper = OSSL_PROPERTY_OPER_EQ;
410 prop->type = OSSL_PROPERTY_TYPE_STRING;
411 prop->v.str_val = OSSL_PROPERTY_TRUE;
412 goto skip_value;
413 }
414 if (!parse_value(ctx, &s, prop, create_values))
415 prop->type = OSSL_PROPERTY_TYPE_VALUE_UNDEFINED;
416
417 skip_value:
418 if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop))
419 goto err;
420 prop = NULL;
421 done = !match_ch(&s, ',');
422 }
423 if (*s != '\0') {
424 ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
425 "HERE-->%s", s);
426 goto err;
427 }
428 res = stack_to_property_list(ctx, sk);
429
430 err:
431 OPENSSL_free(prop);
432 sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
433 return res;
434 }
435
436 /*
437 * Compare a query against a definition.
438 * Return the number of clauses matched or -1 if a mandatory clause is false.
439 */
ossl_property_match_count(const OSSL_PROPERTY_LIST * query,const OSSL_PROPERTY_LIST * defn)440 int ossl_property_match_count(const OSSL_PROPERTY_LIST *query,
441 const OSSL_PROPERTY_LIST *defn)
442 {
443 const OSSL_PROPERTY_DEFINITION *const q = query->properties;
444 const OSSL_PROPERTY_DEFINITION *const d = defn->properties;
445 int i = 0, j = 0, matches = 0;
446 OSSL_PROPERTY_OPER oper;
447
448 while (i < query->num_properties) {
449 if ((oper = q[i].oper) == OSSL_PROPERTY_OVERRIDE) {
450 i++;
451 continue;
452 }
453 if (j < defn->num_properties) {
454 if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */
455 j++;
456 continue;
457 }
458 if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */
459 const int eq = q[i].type == d[j].type
460 && memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0;
461
462 if ((eq && oper == OSSL_PROPERTY_OPER_EQ)
463 || (!eq && oper == OSSL_PROPERTY_OPER_NE))
464 matches++;
465 else if (!q[i].optional)
466 return -1;
467 i++;
468 j++;
469 continue;
470 }
471 }
472
473 /*
474 * Handle the cases of a missing value and a query with no corresponding
475 * definition. The former fails for any comparison except inequality,
476 * the latter is treated as a comparison against the Boolean false.
477 */
478 if (q[i].type == OSSL_PROPERTY_TYPE_VALUE_UNDEFINED) {
479 if (oper == OSSL_PROPERTY_OPER_NE)
480 matches++;
481 else if (!q[i].optional)
482 return -1;
483 } else if (q[i].type != OSSL_PROPERTY_TYPE_STRING
484 || (oper == OSSL_PROPERTY_OPER_EQ
485 && q[i].v.str_val != OSSL_PROPERTY_FALSE)
486 || (oper == OSSL_PROPERTY_OPER_NE
487 && q[i].v.str_val == OSSL_PROPERTY_FALSE)) {
488 if (!q[i].optional)
489 return -1;
490 } else {
491 matches++;
492 }
493 i++;
494 }
495 return matches;
496 }
497
ossl_property_free(OSSL_PROPERTY_LIST * p)498 void ossl_property_free(OSSL_PROPERTY_LIST *p)
499 {
500 OPENSSL_free(p);
501 }
502
503 /*
504 * Merge two property lists.
505 * If there is a common name, the one from the first list is used.
506 */
ossl_property_merge(const OSSL_PROPERTY_LIST * a,const OSSL_PROPERTY_LIST * b)507 OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
508 const OSSL_PROPERTY_LIST *b)
509 {
510 const OSSL_PROPERTY_DEFINITION *const ap = a->properties;
511 const OSSL_PROPERTY_DEFINITION *const bp = b->properties;
512 const OSSL_PROPERTY_DEFINITION *copy;
513 OSSL_PROPERTY_LIST *r;
514 int i, j, n;
515 const int t = a->num_properties + b->num_properties;
516
517 r = OPENSSL_malloc(sizeof(*r)
518 + (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
519 if (r == NULL)
520 return NULL;
521
522 r->has_optional = 0;
523 for (i = j = n = 0; i < a->num_properties || j < b->num_properties; n++) {
524 if (i >= a->num_properties) {
525 copy = &bp[j++];
526 } else if (j >= b->num_properties) {
527 copy = &ap[i++];
528 } else if (ap[i].name_idx <= bp[j].name_idx) {
529 if (ap[i].name_idx == bp[j].name_idx)
530 j++;
531 copy = &ap[i++];
532 } else {
533 copy = &bp[j++];
534 }
535 memcpy(r->properties + n, copy, sizeof(r->properties[0]));
536 r->has_optional |= copy->optional;
537 }
538 r->num_properties = n;
539 if (n != t)
540 r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
541 return r;
542 }
543
ossl_property_parse_init(OSSL_LIB_CTX * ctx)544 int ossl_property_parse_init(OSSL_LIB_CTX *ctx)
545 {
546 static const char *const predefined_names[] = {
547 "provider", /* Name of provider (default, legacy, fips) */
548 "version", /* Version number of this provider */
549 "fips", /* FIPS validated or FIPS supporting algorithm */
550 "output", /* Output type for encoders */
551 "input", /* Input type for decoders */
552 "structure", /* Structure name for encoders and decoders */
553 };
554 size_t i;
555
556 for (i = 0; i < OSSL_NELEM(predefined_names); i++)
557 if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
558 goto err;
559
560 /*
561 * Pre-populate the two Boolean values. We must do them before any other
562 * values and in this order so that we get the same index as the global
563 * OSSL_PROPERTY_TRUE and OSSL_PROPERTY_FALSE values
564 */
565 if ((ossl_property_value(ctx, "yes", 1) != OSSL_PROPERTY_TRUE)
566 || (ossl_property_value(ctx, "no", 1) != OSSL_PROPERTY_FALSE))
567 goto err;
568
569 return 1;
570 err:
571 return 0;
572 }
573
put_char(char ch,char ** buf,size_t * remain,size_t * needed)574 static void put_char(char ch, char **buf, size_t *remain, size_t *needed)
575 {
576 if (*remain == 0) {
577 ++*needed;
578 return;
579 }
580 if (*remain == 1)
581 **buf = '\0';
582 else
583 **buf = ch;
584 ++*buf;
585 ++*needed;
586 --*remain;
587 }
588
put_str(const char * str,char ** buf,size_t * remain,size_t * needed)589 static void put_str(const char *str, char **buf, size_t *remain, size_t *needed)
590 {
591 size_t olen, len;
592
593 len = olen = strlen(str);
594 *needed += len;
595
596 if (*remain == 0)
597 return;
598
599 if (*remain < len + 1)
600 len = *remain - 1;
601
602 if (len > 0) {
603 memcpy(*buf, str, len);
604 *buf += len;
605 *remain -= len;
606 }
607
608 if (len < olen && *remain == 1) {
609 **buf = '\0';
610 ++*buf;
611 --*remain;
612 }
613 }
614
put_num(int64_t val,char ** buf,size_t * remain,size_t * needed)615 static void put_num(int64_t val, char **buf, size_t *remain, size_t *needed)
616 {
617 int64_t tmpval = val;
618 size_t len = 1;
619
620 if (tmpval < 0) {
621 len++;
622 tmpval = -tmpval;
623 }
624 for (; tmpval > 9; len++, tmpval /= 10);
625
626 *needed += len;
627
628 if (*remain == 0)
629 return;
630
631 BIO_snprintf(*buf, *remain, "%lld", (long long int)val);
632 if (*remain < len) {
633 *buf += *remain;
634 *remain = 0;
635 } else {
636 *buf += len;
637 *remain -= len;
638 }
639 }
640
ossl_property_list_to_string(OSSL_LIB_CTX * ctx,const OSSL_PROPERTY_LIST * list,char * buf,size_t bufsize)641 size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx,
642 const OSSL_PROPERTY_LIST *list, char *buf,
643 size_t bufsize)
644 {
645 int i;
646 const OSSL_PROPERTY_DEFINITION *prop = NULL;
647 size_t needed = 0;
648 const char *val;
649
650 if (list == NULL) {
651 if (bufsize > 0)
652 *buf = '\0';
653 return 1;
654 }
655 if (list->num_properties != 0)
656 prop = &list->properties[list->num_properties - 1];
657 for (i = 0; i < list->num_properties; i++, prop--) {
658 /* Skip invalid names */
659 if (prop->name_idx == 0)
660 continue;
661
662 if (needed > 0)
663 put_char(',', &buf, &bufsize, &needed);
664
665 if (prop->optional)
666 put_char('?', &buf, &bufsize, &needed);
667 else if (prop->oper == OSSL_PROPERTY_OVERRIDE)
668 put_char('-', &buf, &bufsize, &needed);
669
670 val = ossl_property_name_str(ctx, prop->name_idx);
671 if (val == NULL)
672 return 0;
673 put_str(val, &buf, &bufsize, &needed);
674
675 switch (prop->oper) {
676 case OSSL_PROPERTY_OPER_NE:
677 put_char('!', &buf, &bufsize, &needed);
678 /* fall through */
679 case OSSL_PROPERTY_OPER_EQ:
680 put_char('=', &buf, &bufsize, &needed);
681 /* put value */
682 switch (prop->type) {
683 case OSSL_PROPERTY_TYPE_STRING:
684 val = ossl_property_value_str(ctx, prop->v.str_val);
685 if (val == NULL)
686 return 0;
687 put_str(val, &buf, &bufsize, &needed);
688 break;
689
690 case OSSL_PROPERTY_TYPE_NUMBER:
691 put_num(prop->v.int_val, &buf, &bufsize, &needed);
692 break;
693
694 default:
695 return 0;
696 }
697 break;
698 default:
699 /* do nothing */
700 break;
701 }
702 }
703
704 put_char('\0', &buf, &bufsize, &needed);
705 return needed;
706 }
707