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 <stdarg.h>
12#include <openssl/evp.h>
13#include "testutil.h"
14#include "internal/nelem.h"
15#include "internal/property.h"
16#include "../crypto/property/property_local.h"
17
18/*
19 * We make our OSSL_PROVIDER for testing purposes.  All we really need is
20 * a pointer.  We know that as long as we don't try to use the method
21 * cache flush functions, the provider pointer is merely a pointer being
22 * passed around, and used as a tag of sorts.
23 */
24struct ossl_provider_st {
25    int x;
26};
27
28static int add_property_names(const char *n, ...)
29{
30    va_list args;
31    int res = 1;
32
33    va_start(args, n);
34    do {
35        if (!TEST_int_ne(ossl_property_name(NULL, n, 1), 0))
36            res = 0;
37    } while ((n = va_arg(args, const char *)) != NULL);
38    va_end(args);
39    return res;
40}
41
42static int up_ref(void *p)
43{
44    return 1;
45}
46
47static void down_ref(void *p)
48{
49}
50
51static int test_property_string(void)
52{
53    OSSL_METHOD_STORE *store;
54    int res = 0;
55    OSSL_PROPERTY_IDX i, j;
56
57    if (TEST_ptr(store = ossl_method_store_new(NULL))
58        && TEST_int_eq(ossl_property_name(NULL, "fnord", 0), 0)
59        && TEST_int_ne(ossl_property_name(NULL, "fnord", 1), 0)
60        && TEST_int_ne(ossl_property_name(NULL, "name", 1), 0)
61        /* Property value checks */
62        && TEST_int_eq(ossl_property_value(NULL, "fnord", 0), 0)
63        && TEST_int_ne(i = ossl_property_value(NULL, "no", 0), 0)
64        && TEST_int_ne(j = ossl_property_value(NULL, "yes", 0), 0)
65        && TEST_int_ne(i, j)
66        && TEST_int_eq(ossl_property_value(NULL, "yes", 1), j)
67        && TEST_int_eq(ossl_property_value(NULL, "no", 1), i)
68        && TEST_int_ne(i = ossl_property_value(NULL, "illuminati", 1), 0)
69        && TEST_int_eq(j = ossl_property_value(NULL, "fnord", 1), i + 1)
70        && TEST_int_eq(ossl_property_value(NULL, "fnord", 1), j)
71        /* Check name and values are distinct */
72        && TEST_int_eq(ossl_property_value(NULL, "cold", 0), 0)
73        && TEST_int_ne(ossl_property_name(NULL, "fnord", 0),
74                       ossl_property_value(NULL, "fnord", 0)))
75        res = 1;
76    ossl_method_store_free(store);
77    return res;
78}
79
80static const struct {
81    const char *defn;
82    const char *query;
83    int e;
84} parser_tests[] = {
85    { "", "sky=blue", -1 },
86    { "", "sky!=blue", 1 },
87    { "groan", "", 0 },
88    { "cold=yes", "cold=yes", 1 },
89    { "cold=yes", "cold", 1 },
90    { "cold=yes", "cold!=no", 1 },
91    { "groan", "groan=yes", 1 },
92    { "groan", "groan=no", -1 },
93    { "groan", "groan!=yes", -1 },
94    { "cold=no", "cold", -1 },
95    { "cold=no", "?cold", 0 },
96    { "cold=no", "cold=no", 1 },
97    { "groan", "cold", -1 },
98    { "groan", "cold=no", 1 },
99    { "groan", "cold!=yes", 1 },
100    { "groan=blue", "groan=yellow", -1 },
101    { "groan=blue", "?groan=yellow", 0 },
102    { "groan=blue", "groan!=yellow", 1 },
103    { "groan=blue", "?groan!=yellow", 1 },
104    { "today=monday, tomorrow=3", "today!=2", 1 },
105    { "today=monday, tomorrow=3", "today!='monday'", -1 },
106    { "today=monday, tomorrow=3", "tomorrow=3", 1 },
107    { "n=0x3", "n=3", 1 },
108    { "n=0x3", "n=-3", -1 },
109    { "n=0x33", "n=51", 1 },
110    { "n=0x123456789abcdef", "n=0x123456789abcdef", 1 },
111    { "n=0x7fffffffffffffff", "n=0x7fffffffffffffff", 1 },   /* INT64_MAX */
112    { "n=9223372036854775807", "n=9223372036854775807", 1 }, /* INT64_MAX */
113    { "n=0777777777777777777777", "n=0777777777777777777777", 1 }, /* INT64_MAX */
114    { "n=033", "n=27", 1 },
115    { "n=0", "n=00", 1 },
116    { "n=0x0", "n=0", 1 },
117    { "n=0, sky=blue", "?n=0, sky=blue", 2 },
118    { "n=1, sky=blue", "?n=0, sky=blue", 1 },
119};
120
121static int test_property_parse(int n)
122{
123    OSSL_METHOD_STORE *store;
124    OSSL_PROPERTY_LIST *p = NULL, *q = NULL;
125    int r = 0;
126
127    if (TEST_ptr(store = ossl_method_store_new(NULL))
128        && add_property_names("sky", "groan", "cold", "today", "tomorrow", "n",
129                              NULL)
130        && TEST_ptr(p = ossl_parse_property(NULL, parser_tests[n].defn))
131        && TEST_ptr(q = ossl_parse_query(NULL, parser_tests[n].query, 0))
132        && TEST_int_eq(ossl_property_match_count(q, p), parser_tests[n].e))
133        r = 1;
134    ossl_property_free(p);
135    ossl_property_free(q);
136    ossl_method_store_free(store);
137    return r;
138}
139
140static int test_property_query_value_create(void)
141{
142    OSSL_METHOD_STORE *store;
143    OSSL_PROPERTY_LIST *p = NULL, *q = NULL, *o = NULL;
144    int r = 0;
145
146    /* The property value used here must not be used in other test cases */
147    if (TEST_ptr(store = ossl_method_store_new(NULL))
148        && add_property_names("wood", NULL)
149        && TEST_ptr(p = ossl_parse_query(NULL, "wood=oak", 0)) /* undefined */
150        && TEST_ptr(q = ossl_parse_query(NULL, "wood=oak", 1)) /* creates */
151        && TEST_ptr(o = ossl_parse_query(NULL, "wood=oak", 0)) /* defined */
152        && TEST_int_eq(ossl_property_match_count(q, p), -1)
153        && TEST_int_eq(ossl_property_match_count(q, o), 1))
154        r = 1;
155    ossl_property_free(o);
156    ossl_property_free(p);
157    ossl_property_free(q);
158    ossl_method_store_free(store);
159    return r;
160}
161
162static const struct {
163    int query;
164    const char *ps;
165} parse_error_tests[] = {
166    { 0, "n=1, n=1" },          /* duplicate name */
167    { 0, "n=1, a=hi, n=1" },    /* duplicate name */
168    { 1, "n=1, a=bye, ?n=0" },  /* duplicate name */
169    { 0, "a=abc,#@!, n=1" },    /* non-ASCII character located */
170    { 1, "a='Hello" },          /* Unterminated string */
171    { 0, "a=\"World" },         /* Unterminated string */
172    { 0, "a=_abd_" },           /* Unquoted string not starting with alphabetic */
173    { 1, "a=2, n=012345678" },  /* Bad octal digit */
174    { 0, "n=0x28FG, a=3" },     /* Bad hex digit */
175    { 0, "n=145d, a=2" },       /* Bad decimal digit */
176    { 0, "n=0x8000000000000000, a=3" },     /* Hex overflow */
177    { 0, "n=922337203000000000d, a=2" },    /* Decimal overflow */
178    { 0, "a=2, n=1000000000000000000000" }, /* Octal overflow */
179    { 1, "@='hello'" },         /* Invalid name */
180    { 1, "n0123456789012345678901234567890123456789"
181         "0123456789012345678901234567890123456789"
182         "0123456789012345678901234567890123456789"
183         "0123456789012345678901234567890123456789=yes" }, /* Name too long */
184    { 0, ".n=3" },              /* Invalid name */
185    { 1, "fnord.fnord.=3" }     /* Invalid name */
186};
187
188static int test_property_parse_error(int n)
189{
190    OSSL_METHOD_STORE *store;
191    OSSL_PROPERTY_LIST *p = NULL;
192    int r = 0;
193    const char *ps;
194
195    if (!TEST_ptr(store = ossl_method_store_new(NULL))
196        || !add_property_names("a", "n", NULL))
197        goto err;
198    ps = parse_error_tests[n].ps;
199    if (parse_error_tests[n].query) {
200        if (!TEST_ptr_null(p = ossl_parse_query(NULL, ps, 1)))
201            goto err;
202    } else if (!TEST_ptr_null(p = ossl_parse_property(NULL, ps))) {
203        goto err;
204    }
205    r = 1;
206 err:
207    ossl_property_free(p);
208    ossl_method_store_free(store);
209    return r;
210}
211
212static const struct {
213    const char *q_global;
214    const char *q_local;
215    const char *prop;
216} merge_tests[] = {
217    { "", "colour=blue", "colour=blue" },
218    { "colour=blue", "", "colour=blue" },
219    { "colour=red", "colour=blue", "colour=blue" },
220    { "clouds=pink, urn=red", "urn=blue, colour=green",
221        "urn=blue, colour=green, clouds=pink" },
222    { "pot=gold", "urn=blue", "pot=gold, urn=blue" },
223    { "night", "day", "day=yes, night=yes" },
224    { "day", "night", "day=yes, night=yes" },
225    { "", "", "" },
226    /*
227     * The following four leave 'day' unspecified in the query, and will match
228     * any definition
229     */
230    { "day=yes", "-day", "day=no" },
231    { "day=yes", "-day", "day=yes" },
232    { "day=yes", "-day", "day=arglebargle" },
233    { "day=yes", "-day", "pot=sesquioxidizing" },
234    { "day, night", "-night, day", "day=yes, night=no" },
235    { "-day", "day=yes", "day=yes" },
236};
237
238static int test_property_merge(int n)
239{
240    OSSL_METHOD_STORE *store;
241    OSSL_PROPERTY_LIST *q_global = NULL, *q_local = NULL;
242    OSSL_PROPERTY_LIST *q_combined = NULL, *prop = NULL;
243    int r = 0;
244
245    if (TEST_ptr(store = ossl_method_store_new(NULL))
246        && add_property_names("colour", "urn", "clouds", "pot", "day", "night",
247                              NULL)
248        && TEST_ptr(prop = ossl_parse_property(NULL, merge_tests[n].prop))
249        && TEST_ptr(q_global = ossl_parse_query(NULL, merge_tests[n].q_global,
250                                                0))
251        && TEST_ptr(q_local = ossl_parse_query(NULL, merge_tests[n].q_local, 0))
252        && TEST_ptr(q_combined = ossl_property_merge(q_local, q_global))
253        && TEST_int_ge(ossl_property_match_count(q_combined, prop), 0))
254        r = 1;
255    ossl_property_free(q_global);
256    ossl_property_free(q_local);
257    ossl_property_free(q_combined);
258    ossl_property_free(prop);
259    ossl_method_store_free(store);
260    return r;
261}
262
263static int test_property_defn_cache(void)
264{
265    OSSL_METHOD_STORE *store;
266    OSSL_PROPERTY_LIST *red = NULL, *blue = NULL, *blue2 = NULL;
267    int r;
268
269    r = TEST_ptr(store = ossl_method_store_new(NULL))
270        && add_property_names("red", "blue", NULL)
271        && TEST_ptr(red = ossl_parse_property(NULL, "red"))
272        && TEST_ptr(blue = ossl_parse_property(NULL, "blue"))
273        && TEST_ptr_ne(red, blue)
274        && TEST_true(ossl_prop_defn_set(NULL, "red", &red));
275
276    if (!r)  {
277        ossl_property_free(red);
278        red = NULL;
279        ossl_property_free(blue);
280        blue = NULL;
281    }
282
283    r = r && TEST_true(ossl_prop_defn_set(NULL, "blue", &blue));
284    if (!r) {
285        ossl_property_free(blue);
286        blue = NULL;
287    }
288
289    r = r && TEST_ptr_eq(ossl_prop_defn_get(NULL, "red"), red)
290        && TEST_ptr_eq(ossl_prop_defn_get(NULL, "blue"), blue)
291        && TEST_ptr(blue2 = ossl_parse_property(NULL, "blue"))
292        && TEST_ptr_ne(blue2, blue)
293        && TEST_true(ossl_prop_defn_set(NULL, "blue", &blue2));
294    if (!r) {
295        ossl_property_free(blue2);
296        blue2 = NULL;
297    }
298
299    r = r && TEST_ptr_eq(blue2, blue)
300        && TEST_ptr_eq(ossl_prop_defn_get(NULL, "blue"), blue);
301
302    ossl_method_store_free(store);
303    return r;
304}
305
306static const struct {
307    const char *defn;
308    const char *query;
309    int e;
310} definition_tests[] = {
311    { "alpha", "alpha=yes", 1 },
312    { "alpha=no", "alpha", -1 },
313    { "alpha=1", "alpha=1", 1 },
314    { "alpha=2", "alpha=1",-1 },
315    { "alpha", "omega", -1 },
316    { "alpha", "?omega", 0 },
317    { "alpha", "?omega=1", 0 },
318    { "alpha", "?omega=no", 1 },
319    { "alpha", "?omega=yes", 0 },
320    { "alpha, omega", "?omega=yes", 1 },
321    { "alpha, omega", "?omega=no", 0 }
322};
323
324static int test_definition_compares(int n)
325{
326    OSSL_METHOD_STORE *store;
327    OSSL_PROPERTY_LIST *d = NULL, *q = NULL;
328    int r;
329
330    r = TEST_ptr(store = ossl_method_store_new(NULL))
331        && add_property_names("alpha", "omega", NULL)
332        && TEST_ptr(d = ossl_parse_property(NULL, definition_tests[n].defn))
333        && TEST_ptr(q = ossl_parse_query(NULL, definition_tests[n].query, 0))
334        && TEST_int_eq(ossl_property_match_count(q, d), definition_tests[n].e);
335
336    ossl_property_free(d);
337    ossl_property_free(q);
338    ossl_method_store_free(store);
339    return r;
340}
341
342static int test_register_deregister(void)
343{
344    static const struct {
345        int nid;
346        const char *prop;
347        char *impl;
348    } impls[] = {
349        { 6, "position=1", "a" },
350        { 6, "position=2", "b" },
351        { 6, "position=3", "c" },
352        { 6, "position=4", "d" },
353    };
354    size_t i;
355    int ret = 0;
356    OSSL_METHOD_STORE *store;
357    OSSL_PROVIDER prov = { 1 };
358
359    if (!TEST_ptr(store = ossl_method_store_new(NULL))
360        || !add_property_names("position", NULL))
361        goto err;
362
363    for (i = 0; i < OSSL_NELEM(impls); i++)
364        if (!TEST_true(ossl_method_store_add(store, &prov, impls[i].nid,
365                                             impls[i].prop, impls[i].impl,
366                                             &up_ref, &down_ref))) {
367            TEST_note("iteration %zd", i + 1);
368            goto err;
369        }
370
371    /* Deregister in a different order to registration */
372    for (i = 0; i < OSSL_NELEM(impls); i++) {
373        const size_t j = (1 + i * 3) % OSSL_NELEM(impls);
374        int nid = impls[j].nid;
375        void *impl = impls[j].impl;
376
377        if (!TEST_true(ossl_method_store_remove(store, nid, impl))
378            || !TEST_false(ossl_method_store_remove(store, nid, impl))) {
379            TEST_note("iteration %zd, position %zd", i + 1, j + 1);
380            goto err;
381        }
382    }
383
384    if (TEST_false(ossl_method_store_remove(store, impls[0].nid, impls[0].impl)))
385        ret = 1;
386err:
387    ossl_method_store_free(store);
388    return ret;
389}
390
391static int test_property(void)
392{
393    static OSSL_PROVIDER fake_provider1 = { 1 };
394    static OSSL_PROVIDER fake_provider2 = { 2 };
395    static const OSSL_PROVIDER *fake_prov1 = &fake_provider1;
396    static const OSSL_PROVIDER *fake_prov2 = &fake_provider2;
397    static const struct {
398        const OSSL_PROVIDER **prov;
399        int nid;
400        const char *prop;
401        char *impl;
402    } impls[] = {
403        { &fake_prov1, 1, "fast=no, colour=green", "a" },
404        { &fake_prov1, 1, "fast, colour=blue", "b" },
405        { &fake_prov1, 1, "", "-" },
406        { &fake_prov2, 9, "sky=blue, furry", "c" },
407        { &fake_prov2, 3, NULL, "d" },
408        { &fake_prov2, 6, "sky.colour=blue, sky=green, old.data", "e" },
409    };
410    static struct {
411        const OSSL_PROVIDER **prov;
412        int nid;
413        const char *prop;
414        char *expected;
415    } queries[] = {
416        { &fake_prov1, 1, "fast", "b" },
417        { &fake_prov1, 1, "fast=yes", "b" },
418        { &fake_prov1, 1, "fast=no, colour=green", "a" },
419        { &fake_prov1, 1, "colour=blue, fast", "b" },
420        { &fake_prov1, 1, "colour=blue", "b" },
421        { &fake_prov2, 9, "furry", "c" },
422        { &fake_prov2, 6, "sky.colour=blue", "e" },
423        { &fake_prov2, 6, "old.data", "e" },
424        { &fake_prov2, 9, "furry=yes, sky=blue", "c" },
425        { &fake_prov1, 1, "", "a" },
426        { &fake_prov2, 3, "", "d" },
427    };
428    OSSL_METHOD_STORE *store;
429    size_t i;
430    int ret = 0;
431    void *result;
432
433    if (!TEST_ptr(store = ossl_method_store_new(NULL))
434        || !add_property_names("fast", "colour", "sky", "furry", NULL))
435        goto err;
436
437    for (i = 0; i < OSSL_NELEM(impls); i++)
438        if (!TEST_true(ossl_method_store_add(store, *impls[i].prov,
439                                             impls[i].nid, impls[i].prop,
440                                             impls[i].impl,
441                                             &up_ref, &down_ref))) {
442            TEST_note("iteration %zd", i + 1);
443            goto err;
444        }
445    /*
446     * The first check of queries is with NULL given as provider.  All
447     * queries are expected to succeed.
448     */
449    for (i = 0; i < OSSL_NELEM(queries); i++) {
450        const OSSL_PROVIDER *nullprov = NULL;
451        OSSL_PROPERTY_LIST *pq = NULL;
452
453        if (!TEST_true(ossl_method_store_fetch(store,
454                                               queries[i].nid, queries[i].prop,
455                                               &nullprov, &result))
456            || !TEST_str_eq((char *)result, queries[i].expected)) {
457            TEST_note("iteration %zd", i + 1);
458            ossl_property_free(pq);
459            goto err;
460        }
461        ossl_property_free(pq);
462    }
463    /*
464     * The second check of queries is with &address1 given as provider.
465     */
466    for (i = 0; i < OSSL_NELEM(queries); i++) {
467        OSSL_PROPERTY_LIST *pq = NULL;
468
469        result = NULL;
470        if (queries[i].prov == &fake_prov1) {
471            if (!TEST_true(ossl_method_store_fetch(store,
472                                                   queries[i].nid,
473                                                   queries[i].prop,
474                                                   &fake_prov1, &result))
475                || !TEST_ptr_eq(fake_prov1, &fake_provider1)
476                || !TEST_str_eq((char *)result, queries[i].expected)) {
477                TEST_note("iteration %zd", i + 1);
478                ossl_property_free(pq);
479                goto err;
480            }
481        } else {
482            if (!TEST_false(ossl_method_store_fetch(store,
483                                                    queries[i].nid,
484                                                    queries[i].prop,
485                                                    &fake_prov1, &result))
486                || !TEST_ptr_eq(fake_prov1, &fake_provider1)
487                || !TEST_ptr_null(result)) {
488                TEST_note("iteration %zd", i + 1);
489                ossl_property_free(pq);
490                goto err;
491            }
492        }
493        ossl_property_free(pq);
494    }
495    /*
496     * The third check of queries is with &address2 given as provider.
497     */
498    for (i = 0; i < OSSL_NELEM(queries); i++) {
499        OSSL_PROPERTY_LIST *pq = NULL;
500
501        result = NULL;
502        if (queries[i].prov == &fake_prov2) {
503            if (!TEST_true(ossl_method_store_fetch(store,
504                                                   queries[i].nid,
505                                                   queries[i].prop,
506                                                   &fake_prov2, &result))
507                || !TEST_ptr_eq(fake_prov2, &fake_provider2)
508                || !TEST_str_eq((char *)result, queries[i].expected)) {
509                TEST_note("iteration %zd", i + 1);
510                ossl_property_free(pq);
511                goto err;
512            }
513        } else {
514            if (!TEST_false(ossl_method_store_fetch(store,
515                                                    queries[i].nid,
516                                                    queries[i].prop,
517                                                    &fake_prov2, &result))
518                || !TEST_ptr_eq(fake_prov2, &fake_provider2)
519                || !TEST_ptr_null(result)) {
520                TEST_note("iteration %zd", i + 1);
521                ossl_property_free(pq);
522                goto err;
523            }
524        }
525        ossl_property_free(pq);
526    }
527    ret = 1;
528err:
529    ossl_method_store_free(store);
530    return ret;
531}
532
533static int test_query_cache_stochastic(void)
534{
535    const int max = 10000, tail = 10;
536    OSSL_METHOD_STORE *store;
537    int i, res = 0;
538    char buf[50];
539    void *result;
540    int errors = 0;
541    int v[10001];
542    OSSL_PROVIDER prov = { 1 };
543
544    if (!TEST_ptr(store = ossl_method_store_new(NULL))
545        || !add_property_names("n", NULL))
546        goto err;
547
548    for (i = 1; i <= max; i++) {
549        v[i] = 2 * i;
550        BIO_snprintf(buf, sizeof(buf), "n=%d\n", i);
551        if (!TEST_true(ossl_method_store_add(store, &prov, i, buf, "abc",
552                                             &up_ref, &down_ref))
553                || !TEST_true(ossl_method_store_cache_set(store, &prov, i,
554                                                          buf, v + i,
555                                                          &up_ref, &down_ref))
556                || !TEST_true(ossl_method_store_cache_set(store, &prov, i,
557                                                          "n=1234", "miss",
558                                                          &up_ref, &down_ref))) {
559            TEST_note("iteration %d", i);
560            goto err;
561        }
562    }
563    for (i = 1; i <= max; i++) {
564        BIO_snprintf(buf, sizeof(buf), "n=%d\n", i);
565        if (!ossl_method_store_cache_get(store, NULL, i, buf, &result)
566            || result != v + i)
567            errors++;
568    }
569    /* There is a tiny probability that this will fail when it shouldn't */
570    res = TEST_int_gt(errors, tail) && TEST_int_lt(errors, max - tail);
571
572err:
573    ossl_method_store_free(store);
574    return res;
575}
576
577static int test_fips_mode(void)
578{
579    int ret = 0;
580    OSSL_LIB_CTX *ctx = NULL;
581
582    if (!TEST_ptr(ctx = OSSL_LIB_CTX_new()))
583        goto err;
584
585    ret = TEST_true(EVP_set_default_properties(ctx, "default=yes,fips=yes"))
586          && TEST_true(EVP_default_properties_is_fips_enabled(ctx))
587          && TEST_true(EVP_set_default_properties(ctx, "fips=no,default=yes"))
588          && TEST_false(EVP_default_properties_is_fips_enabled(ctx))
589          && TEST_true(EVP_set_default_properties(ctx, "fips=no"))
590          && TEST_false(EVP_default_properties_is_fips_enabled(ctx))
591          && TEST_true(EVP_set_default_properties(ctx, "fips!=no"))
592          && TEST_true(EVP_default_properties_is_fips_enabled(ctx))
593          && TEST_true(EVP_set_default_properties(ctx, "fips=no"))
594          && TEST_false(EVP_default_properties_is_fips_enabled(ctx))
595          && TEST_true(EVP_set_default_properties(ctx, "fips=no,default=yes"))
596          && TEST_true(EVP_default_properties_enable_fips(ctx, 1))
597          && TEST_true(EVP_default_properties_is_fips_enabled(ctx))
598          && TEST_true(EVP_default_properties_enable_fips(ctx, 0))
599          && TEST_false(EVP_default_properties_is_fips_enabled(ctx));
600err:
601    OSSL_LIB_CTX_free(ctx);
602    return ret;
603}
604
605static struct {
606    const char *in;
607    const char *out;
608} to_string_tests[] = {
609    { "fips=yes", "fips=yes" },
610    { "fips!=yes", "fips!=yes" },
611    { "fips = yes", "fips=yes" },
612    { "fips", "fips=yes" },
613    { "fips=no", "fips=no" },
614    { "-fips", "-fips" },
615    { "?fips=yes", "?fips=yes" },
616    { "fips=yes,provider=fips", "fips=yes,provider=fips" },
617    { "fips = yes , provider = fips", "fips=yes,provider=fips" },
618    { "fips=yes,provider!=fips", "fips=yes,provider!=fips" },
619    { "fips=yes,?provider=fips", "fips=yes,?provider=fips" },
620    { "fips=yes,-provider", "fips=yes,-provider" },
621      /* foo is an unknown internal name */
622    { "foo=yes,fips=yes", "fips=yes"},
623    { "", "" },
624    { "fips=3", "fips=3" },
625    { "fips=-3", "fips=-3" },
626    { "provider='foo bar'", "provider='foo bar'" },
627    { "provider=\"foo bar'\"", "provider=\"foo bar'\"" },
628    { "provider=abc***", "provider='abc***'" },
629    { NULL, "" }
630};
631
632static int test_property_list_to_string(int i)
633{
634    OSSL_PROPERTY_LIST *pl = NULL;
635    int ret = 0;
636    size_t bufsize;
637    char *buf = NULL;
638
639    if (to_string_tests[i].in != NULL
640            && !TEST_ptr(pl = ossl_parse_query(NULL, to_string_tests[i].in, 1)))
641        goto err;
642    bufsize = ossl_property_list_to_string(NULL, pl, NULL, 0);
643    if (!TEST_size_t_gt(bufsize, 0))
644        goto err;
645    buf = OPENSSL_malloc(bufsize);
646    if (!TEST_ptr(buf)
647            || !TEST_size_t_eq(ossl_property_list_to_string(NULL, pl, buf,
648                                                            bufsize),
649                               bufsize)
650            || !TEST_str_eq(to_string_tests[i].out, buf)
651            || !TEST_size_t_eq(bufsize, strlen(to_string_tests[i].out) + 1))
652        goto err;
653
654    ret = 1;
655 err:
656    OPENSSL_free(buf);
657    ossl_property_free(pl);
658    return ret;
659}
660
661int setup_tests(void)
662{
663    ADD_TEST(test_property_string);
664    ADD_TEST(test_property_query_value_create);
665    ADD_ALL_TESTS(test_property_parse, OSSL_NELEM(parser_tests));
666    ADD_ALL_TESTS(test_property_parse_error, OSSL_NELEM(parse_error_tests));
667    ADD_ALL_TESTS(test_property_merge, OSSL_NELEM(merge_tests));
668    ADD_TEST(test_property_defn_cache);
669    ADD_ALL_TESTS(test_definition_compares, OSSL_NELEM(definition_tests));
670    ADD_TEST(test_register_deregister);
671    ADD_TEST(test_property);
672    ADD_TEST(test_query_cache_stochastic);
673    ADD_TEST(test_fips_mode);
674    ADD_ALL_TESTS(test_property_list_to_string, OSSL_NELEM(to_string_tests));
675    return 1;
676}
677