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