Add generic EVP method fetcher
[oweals/openssl.git] / doc / internal / man3 / evp_generic_fetch.pod
1 =pod
2
3 =head1 NAME
4
5 evp_generic_fetch - generic algorithm fetcher and method creator for EVP
6
7 =head1 SYNOPSIS
8
9  /* Only for EVP source */
10  #include "evp_locl.h"
11
12  void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
13                          const char *algorithm, const char *properties,
14                          void *(*new_method)(int nid, const OSSL_DISPATCH *fns,
15                                              OSSL_PROVIDER *prov),
16                          int (*upref_method)(void *),
17                          void (*free_method)(void *));
18
19 =head1 DESCRIPTION
20
21 evp_generic_fetch() calls ossl_method_construct() with the given
22 C<libctx>, C<operation_id>, C<algorithm>, and C<properties> and uses
23 it to create an EVP method with the help of the functions
24 C<new_method>, C<upref_method>, and C<free_method>.
25
26 The three functions are supposed to:
27
28 =over 4
29
30 =item new_method()
31
32 creates an internal method from function pointers found in the
33 dispatch table C<fns>.
34
35 =item upref_method()
36
37 increments the reference counter for the given method, if there is
38 one.
39
40 =item free_method()
41
42 frees the given method.
43
44 =back
45
46 =head1 RETURN VALUES
47
48 evp_generic_fetch() returns a method on success, or B<NULL> on error.
49
50 =head1 EXAMPLES
51
52 This is a short example of the fictitious EVP API and operation called
53 C<EVP_FOO>.
54
55 To begin with, let's assume something like this in
56 C<include/openssl/core_numbers.h>:
57
58     #define OSSL_OP_FOO                         100
59
60     #define OSSL_OP_FOO_NEWCTX_FUNC            2001
61     #define OSSL_OP_FOO_INIT                   2002
62     #define OSSL_OP_FOO_OPERATE                2003
63     #define OSSL_OP_FOO_CLEANCTX_FUNC          2004
64     #define OSSL_OP_FOO_FREECTX_FUNC           2005
65     OSSL_CORE_MAKE_FUNC(void *,OP_foo_newctx,(void))
66     OSSL_CORE_MAKE_FUNC(int,OP_foo_init,(void *vctx))
67     OSSL_CORE_MAKE_FUNC(int,OP_foo_operate,(void *vctx,
68                                             unsigned char *out, size_t *out_l,
69                                             unsigned char *in, size_t in_l))
70     OSSL_CORE_MAKE_FUNC(void,OP_foo_cleanctx,(void *vctx))
71     OSSL_CORE_MAKE_FUNC(void,OP_foo_freectx,(void *vctx))
72
73 And here's the implementation of the FOO method fetcher:
74
75     /* typedef struct evp_foo_st EVP_FOO */
76     struct evp_foo_st {
77         OSSL_PROVIDER *prov;
78         int nid;
79         CRYPTO_REF_COUNT refcnt;
80         OSSL_OP_foo_newctx_fn *newctx;
81         OSSL_OP_foo_init_fn *init;
82         OSSL_OP_foo_operate_fn *operate;
83         OSSL_OP_foo_cleanctx_fn *cleanctx;
84         OSSL_OP_foo_freectx_fn *freectx;
85     };
86
87     /*
88      * In this example, we have a public method creator and destructor.
89      * It's not absolutely necessary, but is in the spirit of OpenSSL.
90      */
91     EVP_FOO *EVP_FOO_meth_from_dispatch(int foo_type, const OSSL_DISPATCH *fns,
92                                         OSSL_PROVIDER *prov)
93     {
94         EVP_FOO *foo = NULL;
95
96         if ((foo = OPENSSL_zalloc(sizeof(*foo))) == NULL)
97             return NULL;
98
99         for (; fns->function_id != 0; fns++) {
100             switch (fns->function_id) {
101             case OSSL_OP_FOO_NEWCTX_FUNC:
102                 foo->newctx = OSSL_get_OP_foo_newctx(fns);
103                 break;
104             case OSSL_OP_FOO_INIT:
105                 foo->init = OSSL_get_OP_foo_init(fns);
106                 break;
107             case OSSL_OP_FOO_OPERATE:
108                 foo->operate = OSSL_get_OP_foo_operate(fns);
109                 break;
110             case OSSL_OP_FOO_CLEANCTX_FUNC:
111                 foo->cleanctx = OSSL_get_OP_foo_cleanctx(fns);
112                 break;
113             case OSSL_OP_FOO_FREECTX_FUNC:
114                 foo->freectx = OSSL_get_OP_foo_freectx(fns);
115                 break;
116             }
117         }
118         foo->nid = foo_type;
119         foo->prov = prov;
120         if (prov)
121             ossl_provider_upref(prov);
122
123         return foo;
124     }
125
126     EVP_FOO_meth_free(EVP_FOO *foo)
127     {
128         if (foo != NULL) {
129             OSSL_PROVIDER *prov = foo->prov;
130
131             OPENSSL_free(foo);
132             ossl_provider_free(prov);
133         }
134     }
135
136     static void *foo_from_dispatch(int nid, const OSSL_DISPATCH *fns,
137                                    OSSL_PROVIDER *prov)
138     {
139         return EVP_FOO_meth_from_dispatch(nid, fns, prov);
140     }
141
142     static int foo_upref(void *vfoo)
143     {
144         EVP_FOO *foo = vfoo;
145         int ref = 0;
146
147         CRYPTO_UP_REF(&foo->refcnt, &ref, foo_lock);
148         return 1;
149     }
150
151     static void foo_free(void *vfoo)
152     {
153         EVP_FOO_meth_free(vfoo);
154     }
155
156     EVP_FOO *EVP_FOO_fetch(OPENSSL_CTX *ctx,
157                            const char *algorithm,
158                            const char *properties)
159     {
160         return evp_generic_fetch(ctx, OSSL_OP_FOO, algorithm, properties,
161                                  foo_from_dispatch, foo_upref, foo_free);
162     }
163
164 And finally, the library functions:
165
166     /* typedef struct evp_foo_st EVP_FOO_CTX */
167     struct evp_foo_ctx_st {
168         const EVP_FOO *foo;
169         void *provctx;          /* corresponding provider context */
170     };
171
172     int EVP_FOO_CTX_reset(EVP_FOO_CTX *c)
173     {
174         if (c == NULL)
175             return 1;
176         if (c->foo != NULL && c->foo->cleanctx != NULL)
177             c->foo->cleanctx(c->provctx);
178         return 1;
179     }
180
181     EVP_FOO_CTX *EVP_FOO_CTX_new(void)
182     {
183         return OPENSSL_zalloc(sizeof(EVP_FOO_CTX));
184     }
185
186     void EVP_FOO_CTX_free(EVP_FOO_CTX *c)
187     {
188         EVP_FOO_CTX_reset(c);
189         c->foo->freectx(c->provctx);
190         OPENSSL_free(c);
191     }
192
193     int EVP_FooInit(EVP_FOO_CTX *c, const EVP_FOO *foo)
194     {
195         int ok = 1;
196
197         c->foo = foo;
198         if (c->provctx == NULL)
199             c->provctx = c->foo->newctx();
200
201         ok = c->foo->init(c->provctx);
202
203         return ok;
204     }
205
206     int EVP_FooOperate(EVP_FOO_CTX *c, unsigned char *out, size_t *outl,
207                        const unsigned char *in, size_t inl)
208     {
209         int ok = 1;
210
211         ok = c->foo->update(c->provctx, out, inl, &outl, in, inl);
212         return ok;
213     }
214
215 =head1 SEE ALSO
216
217 L<ossl_method_construct>
218
219 =head1 HISTORY
220
221 The functions described here were all added in OpenSSL 3.0.
222
223 =head1 COPYRIGHT
224
225 Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
226
227 Licensed under the Apache License 2.0 (the "License").  You may not use
228 this file except in compliance with the License.  You can obtain a copy
229 in the file LICENSE in the source distribution or at
230 L<https://www.openssl.org/source/license.html>.
231
232 =cut