property_parse.c 22 KB

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