summaryrefslogtreecommitdiffstats
path: root/doc/internal/man3/evp_generic_fetch.pod
blob: 34f157e3536b70d2031474c9cd8d3c82d9f24782 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
=pod

=head1 NAME

evp_generic_fetch, evp_generic_fetch_by_number
- generic algorithm fetchers and method creators for EVP

=head1 SYNOPSIS

 /* Only for EVP source */
 #include "evp_local.h"

 void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
                         const char *name, const char *properties,
                         void *(*new_method)(int name_id,
                                             const OSSL_DISPATCH *fns,
                                             OSSL_PROVIDER *prov,
                                             void *method_data),
                         void *method_data,
                         int (*up_ref_method)(void *),
                         void (*free_method)(void *));

 void *evp_generic_fetch_by_number(OPENSSL_CTX *ctx, int operation_id,
                                   int name_id, const char *properties,
                                   void *(*new_method)(int name_id,
                                                       const OSSL_DISPATCH *fns,
                                                       OSSL_PROVIDER *prov,
                                                       void *method_data),
                                   void *method_data,
                                   int (*up_ref_method)(void *),
                                   void (*free_method)(void *));

=head1 DESCRIPTION

evp_generic_fetch() calls ossl_method_construct() with the given
I<libctx>, I<operation_id>, I<name>, and I<properties> and uses
it to create an EVP method with the help of the functions
I<new_method>, I<up_ref_method>, and I<free_method>.

evp_generic_fetch_by_number() does the same thing as evp_generic_fetch(), 
but takes a I<name_id> instead of a number.
I<name_id> must always be nonzero; as a matter of fact, it being zero
is considered a programming error.
This is meant to be used when one method needs to fetch an associated
other method, and is typically called from inside the given function
I<new_method>.

The three functions I<new_method>, I<up_ref_method>, and
I<free_method> are supposed to:

=over 4

=item new_method()

creates an internal method from function pointers found in the
dispatch table I<fns>, with name identity I<name_id>.
The provider I<prov> and I<method_data> are also passed to be used as
new_method() sees fit.

=item up_ref_method()

increments the reference counter for the given method, if there is
one.

=item free_method()

frees the given method.

=back

=head1 RETURN VALUES

evp_generic_fetch() returns a method on success, or NULL on error.

=head1 EXAMPLES

This is a short example of the fictitious EVP API and operation called
B<EVP_FOO>.

To begin with, let's assume something like this in
F<include/openssl/core_dispatch.h>:

    #define OSSL_OP_FOO                           100

    #define OSSL_FUNC_FOO_NEWCTX_FUNC            2001
    #define OSSL_FUNC_FOO_INIT                   2002
    #define OSSL_FUNC_FOO_OPERATE                2003
    #define OSSL_FUNC_FOO_CLEANCTX_FUNC          2004
    #define OSSL_FUNC_FOO_FREECTX_FUNC           2005

    OSSL_CORE_MAKE_FUNC(void *, foo_newctx, (void))
    OSSL_CORE_MAKE_FUNC(int, foo_init, (void *vctx))
    OSSL_CORE_MAKE_FUNC(int, foo_operate, (void *vctx,
                                           unsigned char *out, size_t *out_l,
                                           unsigned char *in, size_t in_l))
    OSSL_CORE_MAKE_FUNC(void, foo_cleanctx, (void *vctx))
    OSSL_CORE_MAKE_FUNC(void, foo_freectx, (void *vctx))

And here's the implementation of the FOO method fetcher:

    /* typedef struct evp_foo_st EVP_FOO */
    struct evp_foo_st {
        OSSL_PROVIDER *prov;
        int name_id;
	CRYPTO_REF_COUNT refcnt;
        OSSL_FUNC_foo_newctx_fn *newctx;
        OSSL_FUNC_foo_init_fn *init;
        OSSL_FUNC_foo_operate_fn *operate;
        OSSL_FUNC_foo_cleanctx_fn *cleanctx;
        OSSL_FUNC_foo_freectx_fn *freectx;
    };

    /*
     * In this example, we have a public method creator and destructor.
     * It's not absolutely necessary, but is in the spirit of OpenSSL.
     */
    EVP_FOO *EVP_FOO_meth_from_dispatch(int name_id,
                                        const OSSL_DISPATCH *fns,
                                        OSSL_PROVIDER *prov,
                                        void *data)
    {
        EVP_FOO *foo = NULL;

        if ((foo = OPENSSL_zalloc(sizeof(*foo))) == NULL)
            return NULL;

        foo->name_id = name_id;

        for (; fns->function_id != 0; fns++) {
            switch (fns->function_id) {
            case OSSL_FUNC_FOO_NEWCTX:
                foo->newctx = OSSL_FUNC_foo_newctx(fns);
                break;
            case OSSL_FUNC_FOO_INIT:
                foo->init = OSSL_FUNC_foo_init(fns);
                break;
            case OSSL_FUNC_FOO_OPERATE:
                foo->operate = OSSL_FUNC_foo_operate(fns);
                break;
            case OSSL_FUNC_FOO_CLEANCTX:
                foo->cleanctx = OSSL_FUNC_foo_cleanctx(fns);
                break;
            case OSSL_FUNC_FOO_FREECTX:
                foo->freectx = OSSL_FUNC_foo_freectx(fns);
                break;
            }
        }
        foo->prov = prov;
        if (prov)
            ossl_provider_up_ref(prov);

        return foo;
    }

    EVP_FOO_meth_free(EVP_FOO *foo)
    {
        if (foo != NULL) {
            OSSL_PROVIDER *prov = foo->prov;

            OPENSSL_free(foo);
            ossl_provider_free(prov);
        }
    }

    static void *foo_from_dispatch(const OSSL_DISPATCH *fns,
                                   OSSL_PROVIDER *prov)
    {
        return EVP_FOO_meth_from_dispatch(fns, prov);
    }

    static int foo_up_ref(void *vfoo)
    {
        EVP_FOO *foo = vfoo;
        int ref = 0;

        CRYPTO_UP_REF(&foo->refcnt, &ref, foo_lock);
        return 1;
    }

    static void foo_free(void *vfoo)
    {
        EVP_FOO_meth_free(vfoo);
    }

    EVP_FOO *EVP_FOO_fetch(OPENSSL_CTX *ctx,
                           const char *name,
                           const char *properties)
    {
        EVP_FOO *foo =
            evp_generic_fetch(ctx, OSSL_OP_FOO, name, properties,
                              foo_from_dispatch, foo_up_ref, foo_free);

        /*
         * If this method exists in legacy form, with a constant NID for the
         * given |name|, this is the spot to find that NID and set it in
         * the newly constructed EVP_FOO instance.
         */

        return foo;

    }

And finally, the library functions:

    /* typedef struct evp_foo_st EVP_FOO_CTX */
    struct evp_foo_ctx_st {
        const EVP_FOO *foo;
        void *provctx;		/* corresponding provider context */
    };

    int EVP_FOO_CTX_reset(EVP_FOO_CTX *c)
    {
        if (c == NULL)
            return 1;
        if (c->foo != NULL && c->foo->cleanctx != NULL)
            c->foo->cleanctx(c->provctx);
        return 1;
    }

    EVP_FOO_CTX *EVP_FOO_CTX_new(void)
    {
        return OPENSSL_zalloc(sizeof(EVP_FOO_CTX));
    }

    void EVP_FOO_CTX_free(EVP_FOO_CTX *c)
    {
        EVP_FOO_CTX_reset(c);
        c->foo->freectx(c->provctx);
        OPENSSL_free(c);
    }

    int EVP_FooInit(EVP_FOO_CTX *c, const EVP_FOO *foo)
    {
        int ok = 1;

        c->foo = foo;
        if (c->provctx == NULL)
            c->provctx = c->foo->newctx();

        ok = c->foo->init(c->provctx);

        return ok;
    }

    int EVP_FooOperate(EVP_FOO_CTX *c, unsigned char *out, size_t *outl,
                       const unsigned char *in, size_t inl)
    {
        int ok = 1;

        ok = c->foo->update(c->provctx, out, inl, &outl, in, inl);
        return ok;
    }

=head1 SEE ALSO

L<ossl_method_construct(3)>

=head1 HISTORY

The functions described here were all added in OpenSSL 3.0.

=head1 COPYRIGHT

Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the "License").  You may not use
this file except in compliance with the License.  You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.

=cut