1=pod
2
3=head1 NAME
4
5evp_generic_fetch, evp_generic_fetch_from_prov
6- generic algorithm fetchers and method creators for EVP
7
8=head1 SYNOPSIS
9
10 /* Only for EVP source */
11 #include "evp_local.h"
12
13 void *evp_generic_fetch(OSSL_LIB_CTX *libctx, int operation_id,
14                         const char *name, const char *properties,
15                         void *(*new_method)(int name_id,
16                                             const OSSL_DISPATCH *fns,
17                                             OSSL_PROVIDER *prov,
18                                             void *method_data),
19                         void *method_data,
20                         int (*up_ref_method)(void *),
21                         void (*free_method)(void *));
22
23 void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id,
24                                   int name_id, const char *properties,
25                                   void *(*new_method)(int name_id,
26                                                       const OSSL_DISPATCH *fns,
27                                                       OSSL_PROVIDER *prov,
28                                                       void *method_data),
29                                   void *method_data,
30                                   int (*up_ref_method)(void *),
31                                   void (*free_method)(void *));
32
33=head1 DESCRIPTION
34
35evp_generic_fetch() calls ossl_method_construct() with the given
36I<libctx>, I<operation_id>, I<name>, and I<properties> and uses
37it to create an EVP method with the help of the functions
38I<new_method>, I<up_ref_method>, and I<free_method>.
39
40evp_generic_fetch_from_prov() does the same thing as evp_generic_fetch(),
41but limits the search of methods to the provider given with I<prov>.
42This is meant to be used when one method needs to fetch an associated
43method in the same provider.
44
45The three functions I<new_method>, I<up_ref_method>, and
46I<free_method> are supposed to:
47
48=over 4
49
50=item new_method()
51
52creates an internal method from function pointers found in the
53dispatch table I<fns>, with name identity I<name_id>.
54The provider I<prov> and I<method_data> are also passed to be used as
55new_method() sees fit.
56
57=item up_ref_method()
58
59increments the reference counter for the given method, if there is
60one.
61
62=item free_method()
63
64frees the given method.
65
66=back
67
68=head1 RETURN VALUES
69
70evp_generic_fetch() returns a method on success, or NULL on error.
71
72=head1 EXAMPLES
73
74This is a short example of the fictitious EVP API and operation called
75B<EVP_FOO>.
76
77To begin with, let's assume something like this in
78F<include/openssl/core_dispatch.h>:
79
80    #define OSSL_OP_FOO                           100
81
82    #define OSSL_FUNC_FOO_NEWCTX_FUNC            2001
83    #define OSSL_FUNC_FOO_INIT                   2002
84    #define OSSL_FUNC_FOO_OPERATE                2003
85    #define OSSL_FUNC_FOO_CLEANCTX_FUNC          2004
86    #define OSSL_FUNC_FOO_FREECTX_FUNC           2005
87
88    OSSL_CORE_MAKE_FUNC(void *, foo_newctx, (void))
89    OSSL_CORE_MAKE_FUNC(int, foo_init, (void *vctx))
90    OSSL_CORE_MAKE_FUNC(int, foo_operate, (void *vctx,
91                                           unsigned char *out, size_t *out_l,
92                                           unsigned char *in, size_t in_l))
93    OSSL_CORE_MAKE_FUNC(void, foo_cleanctx, (void *vctx))
94    OSSL_CORE_MAKE_FUNC(void, foo_freectx, (void *vctx))
95
96And here's the implementation of the FOO method fetcher:
97
98    /* typedef struct evp_foo_st EVP_FOO */
99    struct evp_foo_st {
100        OSSL_PROVIDER *prov;
101        int name_id;
102	CRYPTO_REF_COUNT refcnt;
103        OSSL_FUNC_foo_newctx_fn *newctx;
104        OSSL_FUNC_foo_init_fn *init;
105        OSSL_FUNC_foo_operate_fn *operate;
106        OSSL_FUNC_foo_cleanctx_fn *cleanctx;
107        OSSL_FUNC_foo_freectx_fn *freectx;
108    };
109
110    /*
111     * In this example, we have a public method creator and destructor.
112     * It's not absolutely necessary, but is in the spirit of OpenSSL.
113     */
114    EVP_FOO *EVP_FOO_meth_from_algorithm(int name_id,
115                                         const OSSL_DISPATCH *fns,
116                                         OSSL_PROVIDER *prov,
117                                         void *data)
118    {
119        EVP_FOO *foo = NULL;
120
121        if ((foo = OPENSSL_zalloc(sizeof(*foo))) == NULL)
122            return NULL;
123
124        if (!CRYPTO_NEW_REF(&foo->refcnt, 1)) {
125            OPENSSL_free(foo);
126            return NULL;
127        }
128
129        foo->name_id = name_id;
130
131        for (; fns->function_id != 0; fns++) {
132            switch (fns->function_id) {
133            case OSSL_FUNC_FOO_NEWCTX:
134                foo->newctx = OSSL_FUNC_foo_newctx(fns);
135                break;
136            case OSSL_FUNC_FOO_INIT:
137                foo->init = OSSL_FUNC_foo_init(fns);
138                break;
139            case OSSL_FUNC_FOO_OPERATE:
140                foo->operate = OSSL_FUNC_foo_operate(fns);
141                break;
142            case OSSL_FUNC_FOO_CLEANCTX:
143                foo->cleanctx = OSSL_FUNC_foo_cleanctx(fns);
144                break;
145            case OSSL_FUNC_FOO_FREECTX:
146                foo->freectx = OSSL_FUNC_foo_freectx(fns);
147                break;
148            }
149        }
150        foo->prov = prov;
151        if (prov)
152            ossl_provider_up_ref(prov);
153
154        return foo;
155    }
156
157    EVP_FOO_meth_free(EVP_FOO *foo)
158    {
159        int i;
160
161        if (foo != NULL) {
162            OSSL_PROVIDER *prov = foo->prov;
163
164            CRYPTO_DOWN_REF(&foo->refcnt, &i);
165            if (i > 0)
166                return;
167
168            CRYPTO_FREE_REF(&foo->refcnt);
169            OPENSSL_free(foo);
170            ossl_provider_free(prov);
171        }
172    }
173
174    static void *foo_from_algorithm(const OSSL_DISPATCH *fns,
175                                    OSSL_PROVIDER *prov)
176    {
177        return EVP_FOO_meth_from_algorithm(fns, prov);
178    }
179
180    static int foo_up_ref(void *vfoo)
181    {
182        EVP_FOO *foo = vfoo;
183        int ref = 0;
184
185        CRYPTO_UP_REF(&foo->refcnt, &ref);
186        return 1;
187    }
188
189    static void foo_free(void *vfoo)
190    {
191        EVP_FOO_meth_free(vfoo);
192    }
193
194    EVP_FOO *EVP_FOO_fetch(OSSL_LIB_CTX *ctx,
195                           const char *name,
196                           const char *properties)
197    {
198        EVP_FOO *foo =
199            evp_generic_fetch(ctx, OSSL_OP_FOO, name, properties,
200                              foo_from_algorithm, foo_up_ref, foo_free);
201
202        /*
203         * If this method exists in legacy form, with a constant NID for the
204         * given |name|, this is the spot to find that NID and set it in
205         * the newly constructed EVP_FOO instance.
206         */
207
208        return foo;
209
210    }
211
212And finally, the library functions:
213
214    /* typedef struct evp_foo_st EVP_FOO_CTX */
215    struct evp_foo_ctx_st {
216        const EVP_FOO *foo;
217        void *provctx;		/* corresponding provider context */
218    };
219
220    int EVP_FOO_CTX_reset(EVP_FOO_CTX *c)
221    {
222        if (c == NULL)
223            return 1;
224        if (c->foo != NULL && c->foo->cleanctx != NULL)
225            c->foo->cleanctx(c->provctx);
226        return 1;
227    }
228
229    EVP_FOO_CTX *EVP_FOO_CTX_new(void)
230    {
231        return OPENSSL_zalloc(sizeof(EVP_FOO_CTX));
232    }
233
234    void EVP_FOO_CTX_free(EVP_FOO_CTX *c)
235    {
236        EVP_FOO_CTX_reset(c);
237        c->foo->freectx(c->provctx);
238        OPENSSL_free(c);
239    }
240
241    int EVP_FooInit(EVP_FOO_CTX *c, const EVP_FOO *foo)
242    {
243        int ok = 1;
244
245        c->foo = foo;
246        if (c->provctx == NULL)
247            c->provctx = c->foo->newctx();
248
249        ok = c->foo->init(c->provctx);
250
251        return ok;
252    }
253
254    int EVP_FooOperate(EVP_FOO_CTX *c, unsigned char *out, size_t *outl,
255                       const unsigned char *in, size_t inl)
256    {
257        int ok = 1;
258
259        ok = c->foo->update(c->provctx, out, inl, &outl, in, inl);
260        return ok;
261    }
262
263=head1 SEE ALSO
264
265L<ossl_method_construct(3)>
266
267=head1 HISTORY
268
269The functions described here were all added in OpenSSL 3.0.
270
271=head1 COPYRIGHT
272
273Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
274
275Licensed under the Apache License 2.0 (the "License").  You may not use
276this file except in compliance with the License.  You can obtain a copy
277in the file LICENSE in the source distribution or at
278L<https://www.openssl.org/source/license.html>.
279
280=cut
281