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