711468af5470e84c0969be277598f607eb0602e8
[libgcrypt.git] / cipher / dynload.c
1 /* dynload.c - load cipher extensions
2  *      Copyright (C) 1998, 2001, 2002 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser general Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 /*
22  Note: We don't support dynamically loaded modules anymore.  This
23  would be troublesome for thread-safety and it is better done by the
24  application.  One of the next releases will have an API to support
25  additional ciphers.
26 */
27
28
29 #include <config.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include "g10lib.h"
35 #include "cipher.h"
36 #include "dynload.h"
37
38
39 typedef struct ext_list {
40     struct ext_list *next;
41     int internal;
42     int handle;   /* if the function has been loaded, this is true */
43     int  failed;  /* already tried but failed */
44     void * (*enumfunc)(int, int*, int*, int*);
45     char *hintstr; /* pointer into name */
46     char name[1];
47 } *EXTLIST;
48
49 static EXTLIST extensions;
50
51 typedef struct {
52     EXTLIST r;
53     int seq1;
54     int seq2;
55     void *sym;
56     int reqalgo;
57 } ENUMCONTEXT;
58
59
60 void
61 _gcry_register_internal_cipher_extension(
62                         const char *module_id,
63                         void * (*enumfunc)(int, int*, int*, int*)
64                                   )
65 {
66     EXTLIST r, el;
67
68     el = gcry_xcalloc( 1, sizeof *el + strlen(module_id) );
69     strcpy(el->name, module_id );
70     el->internal = 1;
71
72     /* check that it is not already registered */
73     for(r = extensions; r; r = r->next ) {
74         if( !strcmp (r->name, el->name) ) {
75             log_info("extension `%s' already registered\n", el->name );
76             gcry_free(el);
77             return;
78         }
79     }
80     /* and register */
81     el->enumfunc = enumfunc;
82     el->handle = 1;
83     el->next = extensions;
84     extensions = el;
85 }
86
87
88 static int
89 load_extension( EXTLIST el )
90 {
91     return -1;
92 }
93
94
95
96 int
97 _gcry_enum_gnupgext_digests( void **enum_context,
98             int *algo,
99             const char *(**r_get_info)( int, size_t*,byte**, int*, int*,
100                                        void (**)(void*),
101                                        void (**)(void*,byte*,size_t),
102                                        void (**)(void*),byte *(**)(void*)) )
103 {
104     EXTLIST r;
105     ENUMCONTEXT *ctx;
106
107     if( !*enum_context ) { /* init context */
108         ctx = gcry_xcalloc( 1, sizeof( *ctx ) );
109         ctx->r = extensions;
110         ctx->reqalgo = *algo;
111         *enum_context = ctx;
112     }
113     else if( !algo ) { /* release the context */
114         gcry_free(*enum_context);
115         *enum_context = NULL;
116         return 0;
117     }
118     else
119         ctx = *enum_context;
120
121     for( r = ctx->r; r; r = r->next )  {
122         int class, vers;
123
124         if( r->failed )
125             continue;
126         if( !r->handle && load_extension(r) )
127             continue;
128         /* get a digest info function */
129         if( ctx->sym )
130             goto inner_loop;
131         while( (ctx->sym = (*r->enumfunc)(10, &ctx->seq1, &class, &vers)) ) {
132             void *sym;
133             /* must check class because enumfunc may be wrong coded */
134             if( vers != 1 || class != 10 )
135                 continue;
136           inner_loop:
137             *r_get_info = ctx->sym;
138             while( (sym = (*r->enumfunc)(11, &ctx->seq2, &class, &vers)) ) {
139                 if( vers != 1 || class != 11 )
140                     continue;
141                 *algo = *(int*)sym;
142                 ctx->r = r;
143                 return 1;
144             }
145             ctx->seq2 = 0;
146         }
147         ctx->seq1 = 0;
148     }
149     ctx->r = r;
150     return 0;
151 }
152
153 const char *
154 _gcry_enum_gnupgext_ciphers( void **enum_context, int *algo,
155                        size_t *keylen, size_t *blocksize, size_t *contextsize,
156                        int  (**setkeyf)( void *c, byte *key, unsigned keylen ),
157                        void (**encryptf)( void *c, byte *outbuf, byte *inbuf ),
158                        void (**decryptf)( void *c, byte *outbuf, byte *inbuf )
159                      )
160 {
161     EXTLIST r;
162     ENUMCONTEXT *ctx;
163     const char * (*finfo)(int, size_t*, size_t*, size_t*,
164                           int  (**)( void *, byte *, unsigned),
165                           void (**)( void *, byte *, byte *),
166                           void (**)( void *, byte *, byte *));
167
168     if( !*enum_context ) { /* init context */
169         ctx = gcry_xcalloc( 1, sizeof( *ctx ) );
170         ctx->r = extensions;
171         *enum_context = ctx;
172     }
173     else if( !algo ) { /* release the context */
174         gcry_free(*enum_context);
175         *enum_context = NULL;
176         return NULL;
177     }
178     else
179         ctx = *enum_context;
180
181     for( r = ctx->r; r; r = r->next )  {
182         int class, vers;
183
184         if( r->failed )
185             continue;
186         if( !r->handle && load_extension(r) )
187             continue;
188         /* get a cipher info function */
189         if( ctx->sym )
190             goto inner_loop;
191         while( (ctx->sym = (*r->enumfunc)(20, &ctx->seq1, &class, &vers)) ) {
192             void *sym;
193             /* must check class because enumfunc may be wrong coded */
194             if( vers != 1 || class != 20 )
195                 continue;
196           inner_loop:
197             finfo = ctx->sym;
198             while( (sym = (*r->enumfunc)(21, &ctx->seq2, &class, &vers)) ) {
199                 const char *algname;
200                 if( vers != 1 || class != 21 )
201                     continue;
202                 *algo = *(int*)sym;
203                 algname = (*finfo)( *algo, keylen, blocksize, contextsize,
204                                     setkeyf, encryptf, decryptf );
205                 if( algname ) {
206                     ctx->r = r;
207                     return algname;
208                 }
209             }
210             ctx->seq2 = 0;
211         }
212         ctx->seq1 = 0;
213     }
214     ctx->r = r;
215     return NULL;
216 }
217
218 const char *
219 _gcry_enum_gnupgext_pubkeys( void **enum_context, int *algo,
220     int *npkey, int *nskey, int *nenc, int *nsig, int *use,
221     int (**generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors ),
222     int (**check_secret_key)( int algo, MPI *skey ),
223     int (**encryptf)( int algo, MPI *resarr, MPI data, MPI *pkey ),
224     int (**decryptf)( int algo, MPI *result, MPI *data, MPI *skey ),
225     int (**sign)( int algo, MPI *resarr, MPI data, MPI *skey ),
226     int (**verify)( int algo, MPI hash, MPI *data, MPI *pkey,
227                     int (*cmp)(void *, MPI), void *opaquev ),
228     unsigned (**get_nbits)( int algo, MPI *pkey ) )
229 {
230     EXTLIST r;
231     ENUMCONTEXT *ctx;
232     const char * (*finfo)( int, int *, int *, int *, int *, int *,
233                            int (**)( int, unsigned, MPI *, MPI **),
234                            int (**)( int, MPI * ),
235                            int (**)( int, MPI *, MPI , MPI * ),
236                            int (**)( int, MPI *, MPI *, MPI * ),
237                            int (**)( int, MPI *, MPI , MPI * ),
238                            int (**)( int, MPI , MPI *, MPI *,
239                                             int (*)(void*,MPI), void *),
240                            unsigned (**)( int , MPI * ) );
241
242     if( !*enum_context ) { /* init context */
243         ctx = gcry_xcalloc( 1, sizeof( *ctx ) );
244         ctx->r = extensions;
245         *enum_context = ctx;
246     }
247     else if( !algo ) { /* release the context */
248         gcry_free(*enum_context);
249         *enum_context = NULL;
250         return NULL;
251     }
252     else
253         ctx = *enum_context;
254
255     for( r = ctx->r; r; r = r->next )  {
256         int class, vers;
257
258         if( r->failed )
259             continue;
260         if( !r->handle && load_extension(r) )
261             continue;
262         /* get a pubkey info function */
263         if( ctx->sym )
264             goto inner_loop;
265         while( (ctx->sym = (*r->enumfunc)(30, &ctx->seq1, &class, &vers)) ) {
266             void *sym;
267             if( vers != 1 || class != 30 )
268                 continue;
269           inner_loop:
270             finfo = ctx->sym;
271             while( (sym = (*r->enumfunc)(31, &ctx->seq2, &class, &vers)) ) {
272                 const char *algname;
273                 if( vers != 1 || class != 31 )
274                     continue;
275                 *algo = *(int*)sym;
276                 algname = (*finfo)( *algo, npkey, nskey, nenc, nsig, use,
277                                     generate, check_secret_key, encryptf,
278                                     decryptf, sign, verify, get_nbits );
279                 if( algname ) {
280                     ctx->r = r;
281                     return algname;
282                 }
283             }
284             ctx->seq2 = 0;
285         }
286         ctx->seq1 = 0;
287     }
288     ctx->r = r;
289     return NULL;
290 }
291
292
293 int (*
294 _gcry_dynload_getfnc_gather_random())(void (*)(const void*, size_t, int), int,
295                                                             size_t, int)
296 {
297     EXTLIST r;
298     void *sym;
299
300     for( r = extensions; r; r = r->next )  {
301         int seq, class, vers;
302
303         if( r->failed )
304             continue;
305         if( !r->handle && load_extension(r) )
306             continue;
307         seq = 0;
308         while( (sym = (*r->enumfunc)(40, &seq, &class, &vers)) ) {
309             if( vers != 1 || class != 40 )
310                 continue;
311             return (int (*)(void (*)(const void*, size_t, int), int,
312                                                         size_t, int))sym;
313         }
314     }
315     return NULL;
316 }
317
318
319 void (*
320 _gcry_dynload_getfnc_fast_random_poll())( void (*)(const void*, size_t, int), int)
321 {
322     EXTLIST r;
323     void *sym;
324
325     for( r = extensions; r; r = r->next )  {
326         int seq, class, vers;
327
328         if( r->failed )
329             continue;
330         if( !r->handle && load_extension(r) )
331             continue;
332         seq = 0;
333         while( (sym = (*r->enumfunc)(41, &seq, &class, &vers)) ) {
334             if( vers != 1 || class != 41 )
335                 continue;
336             return (void (*)( void (*)(const void*, size_t, int), int))sym;
337         }
338     }
339     return NULL;
340 }
341