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