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 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 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 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 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 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 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 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 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 * 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 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 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 */ 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 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 */ 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 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 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 589 static void put_str(const char *str, char **buf, size_t *remain, size_t *needed) 590 { 591 size_t olen, len, i; 592 char quote = '\0'; 593 int quotes; 594 595 len = olen = strlen(str); 596 *needed += len; 597 598 /* 599 * Check to see if we need quotes or not. 600 * Characters that are legal in a PropertyName don't need quoting. 601 * We simply assume all others require quotes. 602 */ 603 for (i = 0; i < len; i++) 604 if (!ossl_isalnum(str[i]) && str[i] != '.' && str[i] != '_') { 605 /* Default to single quotes ... */ 606 if (quote == '\0') 607 quote = '\''; 608 /* ... but use double quotes if a single is present */ 609 if (str[i] == '\'') 610 quote = '"'; 611 } 612 613 quotes = quote != '\0'; 614 if (*remain == 0) { 615 *needed += 2 * quotes; 616 return; 617 } 618 619 if (quotes) 620 put_char(quote, buf, remain, needed); 621 622 if (*remain < len + 1 + quotes) 623 len = *remain - 1; 624 625 if (len > 0) { 626 memcpy(*buf, str, len); 627 *buf += len; 628 *remain -= len; 629 } 630 631 if (quotes) 632 put_char(quote, buf, remain, needed); 633 634 if (len < olen && *remain == 1) { 635 **buf = '\0'; 636 ++*buf; 637 --*remain; 638 } 639 } 640 641 static void put_num(int64_t val, char **buf, size_t *remain, size_t *needed) 642 { 643 int64_t tmpval = val; 644 size_t len = 1; 645 646 if (tmpval < 0) { 647 len++; 648 tmpval = -tmpval; 649 } 650 for (; tmpval > 9; len++, tmpval /= 10); 651 652 *needed += len; 653 654 if (*remain == 0) 655 return; 656 657 BIO_snprintf(*buf, *remain, "%lld", (long long int)val); 658 if (*remain < len) { 659 *buf += *remain; 660 *remain = 0; 661 } else { 662 *buf += len; 663 *remain -= len; 664 } 665 } 666 667 size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx, 668 const OSSL_PROPERTY_LIST *list, char *buf, 669 size_t bufsize) 670 { 671 int i; 672 const OSSL_PROPERTY_DEFINITION *prop = NULL; 673 size_t needed = 0; 674 const char *val; 675 676 if (list == NULL) { 677 if (bufsize > 0) 678 *buf = '\0'; 679 return 1; 680 } 681 if (list->num_properties != 0) 682 prop = &list->properties[list->num_properties - 1]; 683 for (i = 0; i < list->num_properties; i++, prop--) { 684 /* Skip invalid names */ 685 if (prop->name_idx == 0) 686 continue; 687 688 if (needed > 0) 689 put_char(',', &buf, &bufsize, &needed); 690 691 if (prop->optional) 692 put_char('?', &buf, &bufsize, &needed); 693 else if (prop->oper == OSSL_PROPERTY_OVERRIDE) 694 put_char('-', &buf, &bufsize, &needed); 695 696 val = ossl_property_name_str(ctx, prop->name_idx); 697 if (val == NULL) 698 return 0; 699 put_str(val, &buf, &bufsize, &needed); 700 701 switch (prop->oper) { 702 case OSSL_PROPERTY_OPER_NE: 703 put_char('!', &buf, &bufsize, &needed); 704 /* fall through */ 705 case OSSL_PROPERTY_OPER_EQ: 706 put_char('=', &buf, &bufsize, &needed); 707 /* put value */ 708 switch (prop->type) { 709 case OSSL_PROPERTY_TYPE_STRING: 710 val = ossl_property_value_str(ctx, prop->v.str_val); 711 if (val == NULL) 712 return 0; 713 put_str(val, &buf, &bufsize, &needed); 714 break; 715 716 case OSSL_PROPERTY_TYPE_NUMBER: 717 put_num(prop->v.int_val, &buf, &bufsize, &needed); 718 break; 719 720 default: 721 return 0; 722 } 723 break; 724 default: 725 /* do nothing */ 726 break; 727 } 728 } 729 730 put_char('\0', &buf, &bufsize, &needed); 731 return needed; 732 } 733