xref: /freebsd-src/crypto/openssl/test/filterprov.c (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
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