1/*
2 * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <stddef.h>
11#include <openssl/provider.h>
12#include "testutil.h"
13
14extern OSSL_provider_init_fn PROVIDER_INIT_FUNCTION_NAME;
15
16static char buf[256];
17static OSSL_PARAM greeting_request[] = {
18    { "greeting", OSSL_PARAM_UTF8_STRING, buf, sizeof(buf) },
19    { NULL, 0, NULL, 0, 0 }
20};
21
22static unsigned int digestsuccess = 0;
23static OSSL_PARAM digest_check[] = {
24    { "digest-check", OSSL_PARAM_UNSIGNED_INTEGER, &digestsuccess,
25      sizeof(digestsuccess) },
26    { NULL, 0, NULL, 0, 0 }
27};
28
29static unsigned int stopsuccess = 0;
30static OSSL_PARAM stop_property_mirror[] = {
31    { "stop-property-mirror", OSSL_PARAM_UNSIGNED_INTEGER, &stopsuccess,
32      sizeof(stopsuccess) },
33    { NULL, 0, NULL, 0, 0 }
34};
35
36static int test_provider(OSSL_LIB_CTX **libctx, const char *name,
37                         OSSL_PROVIDER *legacy)
38{
39    OSSL_PROVIDER *prov = NULL;
40    const char *greeting = NULL;
41    char expected_greeting[256];
42    int ok = 0;
43    long err;
44    int dolegacycheck = (legacy != NULL);
45    OSSL_PROVIDER *deflt = NULL, *base = NULL;
46
47    BIO_snprintf(expected_greeting, sizeof(expected_greeting),
48                 "Hello OpenSSL %.20s, greetings from %s!",
49                 OPENSSL_VERSION_STR, name);
50
51
52    /*
53     * We set properties that we know the providers we are using don't have.
54     * This should mean that the p_test provider will fail any fetches - which
55     * is something we test inside the provider.
56     */
57    EVP_set_default_properties(*libctx, "fips=yes");
58    /*
59     * Check that it is possible to have a built-in provider mirrored in
60     * a child lib ctx.
61     */
62    if (!TEST_ptr(base = OSSL_PROVIDER_load(*libctx, "base")))
63        goto err;
64    if (!TEST_ptr(prov = OSSL_PROVIDER_load(*libctx, name)))
65        goto err;
66
67    /*
68     * Once the provider is loaded we clear the default properties and fetches
69     * should start working again.
70     */
71    EVP_set_default_properties(*libctx, "");
72    if (dolegacycheck) {
73        if (!TEST_true(OSSL_PROVIDER_get_params(prov, digest_check))
74                || !TEST_true(digestsuccess))
75            goto err;
76
77        /*
78         * Check that a provider can prevent property mirroring if it sets its
79         * own properties explicitly
80         */
81        if (!TEST_true(OSSL_PROVIDER_get_params(prov, stop_property_mirror))
82                || !TEST_true(stopsuccess))
83            goto err;
84        EVP_set_default_properties(*libctx, "fips=yes");
85        if (!TEST_true(OSSL_PROVIDER_get_params(prov, digest_check))
86                || !TEST_true(digestsuccess))
87            goto err;
88        EVP_set_default_properties(*libctx, "");
89    }
90    if (!TEST_true(OSSL_PROVIDER_get_params(prov, greeting_request))
91            || !TEST_ptr(greeting = greeting_request[0].data)
92            || !TEST_size_t_gt(greeting_request[0].data_size, 0)
93            || !TEST_str_eq(greeting, expected_greeting))
94        goto err;
95
96    /* Make sure we got the error we were expecting */
97    err = ERR_peek_last_error();
98    if (!TEST_int_gt(err, 0)
99            || !TEST_int_eq(ERR_GET_REASON(err), 1))
100        goto err;
101
102    OSSL_PROVIDER_unload(legacy);
103    legacy = NULL;
104
105    if (dolegacycheck) {
106        /* Legacy provider should also be unloaded from child libctx */
107        if (!TEST_true(OSSL_PROVIDER_get_params(prov, digest_check))
108                || !TEST_false(digestsuccess))
109            goto err;
110        /*
111         * Loading the legacy provider again should make it available again in
112         * the child libctx. Loading and unloading the default provider should
113         * have no impact on the child because the child loads it explicitly
114         * before this point.
115         */
116        legacy = OSSL_PROVIDER_load(*libctx, "legacy");
117        deflt = OSSL_PROVIDER_load(*libctx, "default");
118        if (!TEST_ptr(deflt)
119                || !TEST_true(OSSL_PROVIDER_available(*libctx, "default")))
120            goto err;
121        OSSL_PROVIDER_unload(deflt);
122        deflt = NULL;
123        if (!TEST_ptr(legacy)
124                || !TEST_false(OSSL_PROVIDER_available(*libctx, "default"))
125                || !TEST_true(OSSL_PROVIDER_get_params(prov, digest_check))
126                || !TEST_true(digestsuccess))
127        goto err;
128        OSSL_PROVIDER_unload(legacy);
129        legacy = NULL;
130    }
131
132    if (!TEST_true(OSSL_PROVIDER_unload(base)))
133        goto err;
134    base = NULL;
135    if (!TEST_true(OSSL_PROVIDER_unload(prov)))
136        goto err;
137    prov = NULL;
138
139    /*
140     * We must free the libctx to force the provider to really be unloaded from
141     * memory
142     */
143    OSSL_LIB_CTX_free(*libctx);
144    *libctx = NULL;
145
146    /* We print out all the data to make sure it can still be accessed */
147    ERR_print_errors_fp(stderr);
148    ok = 1;
149 err:
150    OSSL_PROVIDER_unload(base);
151    OSSL_PROVIDER_unload(deflt);
152    OSSL_PROVIDER_unload(legacy);
153    legacy = NULL;
154    OSSL_PROVIDER_unload(prov);
155    OSSL_LIB_CTX_free(*libctx);
156    *libctx = NULL;
157    return ok;
158}
159
160static int test_builtin_provider(void)
161{
162    OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
163    const char *name = "p_test_builtin";
164    int ok;
165
166    ok =
167        TEST_ptr(libctx)
168        && TEST_true(OSSL_PROVIDER_add_builtin(libctx, name,
169                                               PROVIDER_INIT_FUNCTION_NAME))
170        && test_provider(&libctx, name, NULL);
171
172    OSSL_LIB_CTX_free(libctx);
173
174    return ok;
175}
176
177/* Test relies on fetching the MD4 digest from the legacy provider */
178#ifndef OPENSSL_NO_MD4
179static int test_builtin_provider_with_child(void)
180{
181    OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
182    const char *name = "p_test";
183    OSSL_PROVIDER *legacy;
184
185    if (!TEST_ptr(libctx))
186        return 0;
187
188    legacy = OSSL_PROVIDER_load(libctx, "legacy");
189    if (legacy == NULL) {
190        /*
191         * In this case we assume we've been built with "no-legacy" and skip
192         * this test (there is no OPENSSL_NO_LEGACY)
193         */
194        OSSL_LIB_CTX_free(libctx);
195        return 1;
196    }
197
198    if (!TEST_true(OSSL_PROVIDER_add_builtin(libctx, name,
199                                             PROVIDER_INIT_FUNCTION_NAME))) {
200        OSSL_LIB_CTX_free(libctx);
201        return 0;
202    }
203
204    /* test_provider will free libctx and unload legacy as part of the test */
205    return test_provider(&libctx, name, legacy);
206}
207#endif
208
209#ifndef NO_PROVIDER_MODULE
210static int test_loaded_provider(void)
211{
212    OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
213    const char *name = "p_test";
214
215    if (!TEST_ptr(libctx))
216        return 0;
217
218    /* test_provider will free libctx as part of the test */
219    return test_provider(&libctx, name, NULL);
220}
221#endif
222
223typedef enum OPTION_choice {
224    OPT_ERR = -1,
225    OPT_EOF = 0,
226    OPT_LOADED,
227    OPT_TEST_ENUM
228} OPTION_CHOICE;
229
230const OPTIONS *test_get_options(void)
231{
232    static const OPTIONS test_options[] = {
233        OPT_TEST_OPTIONS_DEFAULT_USAGE,
234        { "loaded", OPT_LOADED, '-', "Run test with a loaded provider" },
235        { NULL }
236    };
237    return test_options;
238}
239
240int setup_tests(void)
241{
242    OPTION_CHOICE o;
243    int loaded = 0;
244
245    while ((o = opt_next()) != OPT_EOF) {
246        switch (o) {
247        case OPT_TEST_CASES:
248            break;
249        case OPT_LOADED:
250            loaded = 1;
251            break;
252        default:
253            return 0;
254        }
255    }
256
257    if (!loaded) {
258        ADD_TEST(test_builtin_provider);
259#ifndef OPENSSL_NO_MD4
260        ADD_TEST(test_builtin_provider_with_child);
261#endif
262    }
263#ifndef NO_PROVIDER_MODULE
264    else {
265        ADD_TEST(test_loaded_provider);
266    }
267#endif
268    return 1;
269}
270
271