1/*
2 * Copyright 2020-2021 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 <string.h>
12#include <openssl/provider.h>
13#include <openssl/params.h>
14#include <openssl/core_names.h>
15#include <openssl/self_test.h>
16#include <openssl/evp.h>
17#include "testutil.h"
18
19typedef enum OPTION_choice {
20    OPT_ERR = -1,
21    OPT_EOF = 0,
22    OPT_PROVIDER_NAME,
23    OPT_CONFIG_FILE,
24    OPT_TEST_ENUM
25} OPTION_CHOICE;
26
27struct self_test_arg {
28    int count;
29};
30
31static OSSL_LIB_CTX *libctx = NULL;
32static char *provider_name = NULL;
33static struct self_test_arg self_test_args = { 0 };
34
35const OPTIONS *test_get_options(void)
36{
37    static const OPTIONS test_options[] = {
38        OPT_TEST_OPTIONS_DEFAULT_USAGE,
39        { "provider_name", OPT_PROVIDER_NAME, 's',
40          "The name of the provider to load" },
41        { "config", OPT_CONFIG_FILE, '<',
42          "The configuration file to use for the libctx" },
43        { NULL }
44    };
45    return test_options;
46}
47
48static int self_test_events(const OSSL_PARAM params[], void *arg,
49                            const char *title, int corrupt)
50{
51    struct self_test_arg *args = arg;
52    const OSSL_PARAM *p = NULL;
53    const char *phase = NULL, *type = NULL, *desc = NULL;
54    int ret = 0;
55
56    if (args->count == 0)
57        BIO_printf(bio_out, "\n%s\n", title);
58    args->count++;
59
60    p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_PHASE);
61    if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING)
62        goto err;
63    phase = (const char *)p->data;
64
65    p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_DESC);
66    if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING)
67        goto err;
68    desc = (const char *)p->data;
69
70    p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_TYPE);
71    if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING)
72        goto err;
73    type = (const char *)p->data;
74
75    if (strcmp(phase, OSSL_SELF_TEST_PHASE_START) == 0)
76        BIO_printf(bio_out, "%s : (%s) : ", desc, type);
77    else if (strcmp(phase, OSSL_SELF_TEST_PHASE_PASS) == 0
78             || strcmp(phase, OSSL_SELF_TEST_PHASE_FAIL) == 0)
79        BIO_printf(bio_out, "%s\n", phase);
80    /*
81     * The self test code will internally corrupt the KAT test result if an
82     * error is returned during the corrupt phase.
83     */
84    if (corrupt && strcmp(phase, OSSL_SELF_TEST_PHASE_CORRUPT) == 0)
85        goto err;
86    ret = 1;
87err:
88    return ret;
89}
90
91static int self_test_on_demand_fail(const OSSL_PARAM params[], void *arg)
92{
93    return self_test_events(params, arg, "On Demand Failure", 1);
94}
95
96static int self_test_on_demand(const OSSL_PARAM params[], void *arg)
97{
98    return self_test_events(params, arg, "On Demand", 0);
99}
100
101static int self_test_on_load(const OSSL_PARAM params[], void *arg)
102{
103    return self_test_events(params, arg, "On Loading", 0);
104}
105
106static int get_provider_params(const OSSL_PROVIDER *prov)
107{
108    int ret = 0;
109    OSSL_PARAM params[5];
110    char *name, *version, *buildinfo;
111    int status;
112    const OSSL_PARAM *gettable, *p;
113
114    if (!TEST_ptr(gettable = OSSL_PROVIDER_gettable_params(prov))
115        || !TEST_ptr(p = OSSL_PARAM_locate_const(gettable, OSSL_PROV_PARAM_NAME))
116        || !TEST_ptr(p = OSSL_PARAM_locate_const(gettable, OSSL_PROV_PARAM_VERSION))
117        || !TEST_ptr(p = OSSL_PARAM_locate_const(gettable, OSSL_PROV_PARAM_STATUS))
118        || !TEST_ptr(p = OSSL_PARAM_locate_const(gettable, OSSL_PROV_PARAM_BUILDINFO)))
119        goto end;
120
121    params[0] = OSSL_PARAM_construct_utf8_ptr(OSSL_PROV_PARAM_NAME, &name, 0);
122    params[1] = OSSL_PARAM_construct_utf8_ptr(OSSL_PROV_PARAM_VERSION,
123                                              &version, 0);
124    params[2] = OSSL_PARAM_construct_int(OSSL_PROV_PARAM_STATUS, &status);
125    params[3] = OSSL_PARAM_construct_utf8_ptr(OSSL_PROV_PARAM_BUILDINFO,
126                                              &buildinfo, 0);
127    params[4] = OSSL_PARAM_construct_end();
128    OSSL_PARAM_set_all_unmodified(params);
129    if (!TEST_true(OSSL_PROVIDER_get_params(prov, params)))
130        goto end;
131    if (!TEST_true(OSSL_PARAM_modified(params + 0))
132        || !TEST_true(OSSL_PARAM_modified(params + 1))
133        || !TEST_true(OSSL_PARAM_modified(params + 2))
134        || !TEST_true(OSSL_PARAM_modified(params + 3))
135        || !TEST_true(status == 1))
136        goto end;
137
138    ret = 1;
139end:
140    return ret;
141}
142
143static int test_provider_status(void)
144{
145    int ret = 0;
146    unsigned int status = 0;
147    OSSL_PROVIDER *prov = NULL;
148    OSSL_PARAM params[2];
149    EVP_MD *fetch = NULL;
150
151    if (!TEST_ptr(prov = OSSL_PROVIDER_load(libctx, provider_name)))
152        goto err;
153    if (!get_provider_params(prov))
154        goto err;
155
156    /* Test that the provider status is ok */
157    params[0] = OSSL_PARAM_construct_uint(OSSL_PROV_PARAM_STATUS, &status);
158    params[1] = OSSL_PARAM_construct_end();
159    if (!TEST_true(OSSL_PROVIDER_get_params(prov, params))
160        || !TEST_true(status == 1))
161        goto err;
162    if (!TEST_ptr(fetch = EVP_MD_fetch(libctx, "SHA256", NULL)))
163        goto err;
164    EVP_MD_free(fetch);
165    fetch = NULL;
166
167    /* Test that the provider self test is ok */
168    self_test_args.count = 0;
169    OSSL_SELF_TEST_set_callback(libctx, self_test_on_demand, &self_test_args);
170    if (!TEST_true(OSSL_PROVIDER_self_test(prov)))
171        goto err;
172
173    /* Setup a callback that corrupts the self tests and causes status failures */
174    self_test_args.count = 0;
175    OSSL_SELF_TEST_set_callback(libctx, self_test_on_demand_fail, &self_test_args);
176    if (!TEST_false(OSSL_PROVIDER_self_test(prov)))
177        goto err;
178    if (!TEST_true(OSSL_PROVIDER_get_params(prov, params))
179        || !TEST_uint_eq(status, 0))
180        goto err;
181    if (!TEST_ptr_null(fetch = EVP_MD_fetch(libctx, "SHA256", NULL)))
182        goto err;
183
184    ret = 1;
185err:
186    EVP_MD_free(fetch);
187    OSSL_PROVIDER_unload(prov);
188    return ret;
189}
190
191static int test_provider_gettable_params(void)
192{
193    OSSL_PROVIDER *prov;
194    int ret;
195
196    if (!TEST_ptr(prov = OSSL_PROVIDER_load(libctx, provider_name)))
197        return 0;
198    ret = get_provider_params(prov);
199    OSSL_PROVIDER_unload(prov);
200    return ret;
201}
202
203int setup_tests(void)
204{
205    OPTION_CHOICE o;
206    char *config_file = NULL;
207
208    while ((o = opt_next()) != OPT_EOF) {
209        switch (o) {
210        case OPT_CONFIG_FILE:
211            config_file = opt_arg();
212            break;
213        case OPT_PROVIDER_NAME:
214            provider_name = opt_arg();
215            break;
216        case OPT_TEST_CASES:
217           break;
218        default:
219        case OPT_ERR:
220            return 0;
221        }
222    }
223
224    libctx = OSSL_LIB_CTX_new();
225    if (libctx == NULL)
226        return 0;
227
228    if (strcmp(provider_name, "fips") == 0) {
229        self_test_args.count = 0;
230        OSSL_SELF_TEST_set_callback(libctx, self_test_on_load, &self_test_args);
231        if (!OSSL_LIB_CTX_load_config(libctx, config_file)) {
232            opt_printf_stderr("Failed to load config\n");
233            return 0;
234        }
235        ADD_TEST(test_provider_status);
236    } else {
237        ADD_TEST(test_provider_gettable_params);
238    }
239    return 1;
240}
241
242void cleanup_tests(void)
243{
244    OSSL_LIB_CTX_free(libctx);
245}
246