1*e0c4386eSCy Schubert /*
2*e0c4386eSCy Schubert * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved.
3*e0c4386eSCy Schubert *
4*e0c4386eSCy Schubert * Licensed under the Apache License 2.0 (the "License"). You may not use
5*e0c4386eSCy Schubert * this file except in compliance with the License. You can obtain a copy
6*e0c4386eSCy Schubert * in the file LICENSE in the source distribution or at
7*e0c4386eSCy Schubert * https://www.openssl.org/source/license.html
8*e0c4386eSCy Schubert */
9*e0c4386eSCy Schubert
10*e0c4386eSCy Schubert /*
11*e0c4386eSCy Schubert * A filtering provider for test purposes. We pass all calls through to the
12*e0c4386eSCy Schubert * default provider except where we want other behaviour for a test.
13*e0c4386eSCy Schubert */
14*e0c4386eSCy Schubert
15*e0c4386eSCy Schubert #include <string.h>
16*e0c4386eSCy Schubert #include <openssl/core.h>
17*e0c4386eSCy Schubert #include <openssl/provider.h>
18*e0c4386eSCy Schubert #include <openssl/crypto.h>
19*e0c4386eSCy Schubert #include "testutil.h"
20*e0c4386eSCy Schubert #include "filterprov.h"
21*e0c4386eSCy Schubert
22*e0c4386eSCy Schubert #define MAX_FILTERS 10
23*e0c4386eSCy Schubert #define MAX_ALG_FILTERS 5
24*e0c4386eSCy Schubert
25*e0c4386eSCy Schubert struct filter_prov_globals_st {
26*e0c4386eSCy Schubert OSSL_LIB_CTX *libctx;
27*e0c4386eSCy Schubert OSSL_PROVIDER *deflt;
28*e0c4386eSCy Schubert struct {
29*e0c4386eSCy Schubert int operation;
30*e0c4386eSCy Schubert OSSL_ALGORITHM alg[MAX_ALG_FILTERS + 1];
31*e0c4386eSCy Schubert } dispatch[MAX_FILTERS];
32*e0c4386eSCy Schubert int num_dispatch;
33*e0c4386eSCy Schubert int no_cache;
34*e0c4386eSCy Schubert unsigned long int query_count;
35*e0c4386eSCy Schubert int error;
36*e0c4386eSCy Schubert };
37*e0c4386eSCy Schubert
38*e0c4386eSCy Schubert static struct filter_prov_globals_st ourglobals;
39*e0c4386eSCy Schubert
get_globals(void)40*e0c4386eSCy Schubert static struct filter_prov_globals_st *get_globals(void)
41*e0c4386eSCy Schubert {
42*e0c4386eSCy Schubert /*
43*e0c4386eSCy Schubert * Ideally we'd like to store this in the OSSL_LIB_CTX so that we can have
44*e0c4386eSCy Schubert * more than one instance of the filter provider at a time. But for now we
45*e0c4386eSCy Schubert * just make it simple.
46*e0c4386eSCy Schubert */
47*e0c4386eSCy Schubert return &ourglobals;
48*e0c4386eSCy Schubert }
49*e0c4386eSCy Schubert
50*e0c4386eSCy Schubert static OSSL_FUNC_provider_gettable_params_fn filter_gettable_params;
51*e0c4386eSCy Schubert static OSSL_FUNC_provider_get_params_fn filter_get_params;
52*e0c4386eSCy Schubert static OSSL_FUNC_provider_query_operation_fn filter_query;
53*e0c4386eSCy Schubert static OSSL_FUNC_provider_unquery_operation_fn filter_unquery;
54*e0c4386eSCy Schubert static OSSL_FUNC_provider_teardown_fn filter_teardown;
55*e0c4386eSCy Schubert
filter_gettable_params(void * provctx)56*e0c4386eSCy Schubert static const OSSL_PARAM *filter_gettable_params(void *provctx)
57*e0c4386eSCy Schubert {
58*e0c4386eSCy Schubert struct filter_prov_globals_st *globs = get_globals();
59*e0c4386eSCy Schubert
60*e0c4386eSCy Schubert return OSSL_PROVIDER_gettable_params(globs->deflt);
61*e0c4386eSCy Schubert }
62*e0c4386eSCy Schubert
filter_get_params(void * provctx,OSSL_PARAM params[])63*e0c4386eSCy Schubert static int filter_get_params(void *provctx, OSSL_PARAM params[])
64*e0c4386eSCy Schubert {
65*e0c4386eSCy Schubert struct filter_prov_globals_st *globs = get_globals();
66*e0c4386eSCy Schubert
67*e0c4386eSCy Schubert return OSSL_PROVIDER_get_params(globs->deflt, params);
68*e0c4386eSCy Schubert }
69*e0c4386eSCy Schubert
filter_get_capabilities(void * provctx,const char * capability,OSSL_CALLBACK * cb,void * arg)70*e0c4386eSCy Schubert static int filter_get_capabilities(void *provctx, const char *capability,
71*e0c4386eSCy Schubert OSSL_CALLBACK *cb, void *arg)
72*e0c4386eSCy Schubert {
73*e0c4386eSCy Schubert struct filter_prov_globals_st *globs = get_globals();
74*e0c4386eSCy Schubert
75*e0c4386eSCy Schubert return OSSL_PROVIDER_get_capabilities(globs->deflt, capability, cb, arg);
76*e0c4386eSCy Schubert }
77*e0c4386eSCy Schubert
filter_query(void * provctx,int operation_id,int * no_cache)78*e0c4386eSCy Schubert static const OSSL_ALGORITHM *filter_query(void *provctx,
79*e0c4386eSCy Schubert int operation_id,
80*e0c4386eSCy Schubert int *no_cache)
81*e0c4386eSCy Schubert {
82*e0c4386eSCy Schubert struct filter_prov_globals_st *globs = get_globals();
83*e0c4386eSCy Schubert int i;
84*e0c4386eSCy Schubert
85*e0c4386eSCy Schubert globs->query_count++;
86*e0c4386eSCy Schubert for (i = 0; i < globs->num_dispatch; i++) {
87*e0c4386eSCy Schubert if (globs->dispatch[i].operation == operation_id) {
88*e0c4386eSCy Schubert *no_cache = globs->no_cache;
89*e0c4386eSCy Schubert return globs->dispatch[i].alg;
90*e0c4386eSCy Schubert }
91*e0c4386eSCy Schubert }
92*e0c4386eSCy Schubert
93*e0c4386eSCy Schubert /* No filter set, so pass it down to the chained provider */
94*e0c4386eSCy Schubert return OSSL_PROVIDER_query_operation(globs->deflt, operation_id, no_cache);
95*e0c4386eSCy Schubert }
96*e0c4386eSCy Schubert
filter_unquery(void * provctx,int operation_id,const OSSL_ALGORITHM * algs)97*e0c4386eSCy Schubert static void filter_unquery(void *provctx, int operation_id,
98*e0c4386eSCy Schubert const OSSL_ALGORITHM *algs)
99*e0c4386eSCy Schubert {
100*e0c4386eSCy Schubert struct filter_prov_globals_st *globs = get_globals();
101*e0c4386eSCy Schubert int i;
102*e0c4386eSCy Schubert
103*e0c4386eSCy Schubert if (!TEST_ulong_gt(globs->query_count, 0))
104*e0c4386eSCy Schubert globs->error = 1;
105*e0c4386eSCy Schubert else
106*e0c4386eSCy Schubert globs->query_count--;
107*e0c4386eSCy Schubert
108*e0c4386eSCy Schubert for (i = 0; i < globs->num_dispatch; i++)
109*e0c4386eSCy Schubert if (globs->dispatch[i].alg == algs)
110*e0c4386eSCy Schubert return;
111*e0c4386eSCy Schubert OSSL_PROVIDER_unquery_operation(globs->deflt, operation_id, algs);
112*e0c4386eSCy Schubert }
113*e0c4386eSCy Schubert
filter_teardown(void * provctx)114*e0c4386eSCy Schubert static void filter_teardown(void *provctx)
115*e0c4386eSCy Schubert {
116*e0c4386eSCy Schubert struct filter_prov_globals_st *globs = get_globals();
117*e0c4386eSCy Schubert
118*e0c4386eSCy Schubert OSSL_PROVIDER_unload(globs->deflt);
119*e0c4386eSCy Schubert OSSL_LIB_CTX_free(globs->libctx);
120*e0c4386eSCy Schubert memset(globs, 0, sizeof(*globs));
121*e0c4386eSCy Schubert }
122*e0c4386eSCy Schubert
123*e0c4386eSCy Schubert /* Functions we provide to the core */
124*e0c4386eSCy Schubert static const OSSL_DISPATCH filter_dispatch_table[] = {
125*e0c4386eSCy Schubert { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void (*)(void))filter_gettable_params },
126*e0c4386eSCy Schubert { OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))filter_get_params },
127*e0c4386eSCy Schubert { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))filter_query },
128*e0c4386eSCy Schubert { OSSL_FUNC_PROVIDER_UNQUERY_OPERATION, (void (*)(void))filter_unquery },
129*e0c4386eSCy Schubert { OSSL_FUNC_PROVIDER_GET_CAPABILITIES, (void (*)(void))filter_get_capabilities },
130*e0c4386eSCy Schubert { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))filter_teardown },
131*e0c4386eSCy Schubert { 0, NULL }
132*e0c4386eSCy Schubert };
133*e0c4386eSCy Schubert
filter_provider_init(const OSSL_CORE_HANDLE * handle,const OSSL_DISPATCH * in,const OSSL_DISPATCH ** out,void ** provctx)134*e0c4386eSCy Schubert int filter_provider_init(const OSSL_CORE_HANDLE *handle,
135*e0c4386eSCy Schubert const OSSL_DISPATCH *in,
136*e0c4386eSCy Schubert const OSSL_DISPATCH **out,
137*e0c4386eSCy Schubert void **provctx)
138*e0c4386eSCy Schubert {
139*e0c4386eSCy Schubert memset(&ourglobals, 0, sizeof(ourglobals));
140*e0c4386eSCy Schubert ourglobals.libctx = OSSL_LIB_CTX_new();
141*e0c4386eSCy Schubert if (ourglobals.libctx == NULL)
142*e0c4386eSCy Schubert goto err;
143*e0c4386eSCy Schubert
144*e0c4386eSCy Schubert ourglobals.deflt = OSSL_PROVIDER_load(ourglobals.libctx, "default");
145*e0c4386eSCy Schubert if (ourglobals.deflt == NULL)
146*e0c4386eSCy Schubert goto err;
147*e0c4386eSCy Schubert
148*e0c4386eSCy Schubert *provctx = OSSL_PROVIDER_get0_provider_ctx(ourglobals.deflt);
149*e0c4386eSCy Schubert *out = filter_dispatch_table;
150*e0c4386eSCy Schubert return 1;
151*e0c4386eSCy Schubert
152*e0c4386eSCy Schubert err:
153*e0c4386eSCy Schubert OSSL_PROVIDER_unload(ourglobals.deflt);
154*e0c4386eSCy Schubert OSSL_LIB_CTX_free(ourglobals.libctx);
155*e0c4386eSCy Schubert return 0;
156*e0c4386eSCy Schubert }
157*e0c4386eSCy Schubert
158*e0c4386eSCy Schubert /*
159*e0c4386eSCy Schubert * Set a filter for the given operation id. The filter string is a colon
160*e0c4386eSCy Schubert * separated list of algorithms that will be made available by this provider.
161*e0c4386eSCy Schubert * Anything not in the filter will be suppressed. If a filter is not set for
162*e0c4386eSCy Schubert * a given operation id then all algorithms are made available.
163*e0c4386eSCy Schubert */
filter_provider_set_filter(int operation,const char * filterstr)164*e0c4386eSCy Schubert int filter_provider_set_filter(int operation, const char *filterstr)
165*e0c4386eSCy Schubert {
166*e0c4386eSCy Schubert int no_cache = 0;
167*e0c4386eSCy Schubert int algnum = 0, last = 0, ret = 0;
168*e0c4386eSCy Schubert struct filter_prov_globals_st *globs = get_globals();
169*e0c4386eSCy Schubert size_t namelen;
170*e0c4386eSCy Schubert char *filterstrtmp = OPENSSL_strdup(filterstr);
171*e0c4386eSCy Schubert char *name, *sep;
172*e0c4386eSCy Schubert const OSSL_ALGORITHM *provalgs = OSSL_PROVIDER_query_operation(globs->deflt,
173*e0c4386eSCy Schubert operation,
174*e0c4386eSCy Schubert &no_cache);
175*e0c4386eSCy Schubert const OSSL_ALGORITHM *algs;
176*e0c4386eSCy Schubert
177*e0c4386eSCy Schubert if (filterstrtmp == NULL)
178*e0c4386eSCy Schubert goto err;
179*e0c4386eSCy Schubert
180*e0c4386eSCy Schubert /* Nothing to filter */
181*e0c4386eSCy Schubert if (provalgs == NULL)
182*e0c4386eSCy Schubert goto err;
183*e0c4386eSCy Schubert
184*e0c4386eSCy Schubert if (globs->num_dispatch >= MAX_FILTERS)
185*e0c4386eSCy Schubert goto err;
186*e0c4386eSCy Schubert
187*e0c4386eSCy Schubert for (name = filterstrtmp; !last; name = (sep == NULL ? NULL : sep + 1)) {
188*e0c4386eSCy Schubert sep = strstr(name, ":");
189*e0c4386eSCy Schubert if (sep != NULL)
190*e0c4386eSCy Schubert *sep = '\0';
191*e0c4386eSCy Schubert else
192*e0c4386eSCy Schubert last = 1;
193*e0c4386eSCy Schubert namelen = strlen(name);
194*e0c4386eSCy Schubert
195*e0c4386eSCy Schubert for (algs = provalgs; algs->algorithm_names != NULL; algs++) {
196*e0c4386eSCy Schubert const char *found = strstr(algs->algorithm_names, name);
197*e0c4386eSCy Schubert
198*e0c4386eSCy Schubert if (found == NULL)
199*e0c4386eSCy Schubert continue;
200*e0c4386eSCy Schubert if (found[namelen] != '\0' && found[namelen] != ':')
201*e0c4386eSCy Schubert continue;
202*e0c4386eSCy Schubert if (found != algs->algorithm_names && found[-1] != ':')
203*e0c4386eSCy Schubert continue;
204*e0c4386eSCy Schubert
205*e0c4386eSCy Schubert /* We found a match */
206*e0c4386eSCy Schubert if (algnum >= MAX_ALG_FILTERS)
207*e0c4386eSCy Schubert goto err;
208*e0c4386eSCy Schubert
209*e0c4386eSCy Schubert globs->dispatch[globs->num_dispatch].alg[algnum++] = *algs;
210*e0c4386eSCy Schubert break;
211*e0c4386eSCy Schubert }
212*e0c4386eSCy Schubert if (algs->algorithm_names == NULL) {
213*e0c4386eSCy Schubert /* No match found */
214*e0c4386eSCy Schubert goto err;
215*e0c4386eSCy Schubert }
216*e0c4386eSCy Schubert }
217*e0c4386eSCy Schubert
218*e0c4386eSCy Schubert globs->dispatch[globs->num_dispatch].operation = operation;
219*e0c4386eSCy Schubert globs->no_cache = no_cache;
220*e0c4386eSCy Schubert globs->num_dispatch++;
221*e0c4386eSCy Schubert
222*e0c4386eSCy Schubert ret = 1;
223*e0c4386eSCy Schubert err:
224*e0c4386eSCy Schubert OSSL_PROVIDER_unquery_operation(globs->deflt, operation, provalgs);
225*e0c4386eSCy Schubert OPENSSL_free(filterstrtmp);
226*e0c4386eSCy Schubert return ret;
227*e0c4386eSCy Schubert }
228*e0c4386eSCy Schubert
229*e0c4386eSCy Schubert /*
230*e0c4386eSCy Schubert * Test if a filter provider is in a clean finishing state.
231*e0c4386eSCy Schubert * If it is return 1, otherwise return 0.
232*e0c4386eSCy Schubert */
filter_provider_check_clean_finish(void)233*e0c4386eSCy Schubert int filter_provider_check_clean_finish(void)
234*e0c4386eSCy Schubert {
235*e0c4386eSCy Schubert struct filter_prov_globals_st *globs = get_globals();
236*e0c4386eSCy Schubert
237*e0c4386eSCy Schubert return TEST_ulong_eq(globs->query_count, 0) && !globs->error;
238*e0c4386eSCy Schubert }
239