2003-06-16 Moritz Schulte <moritz@g10code.com>
[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 int nbits, unsigned long use_e,
222                       MPI *skey, MPI **retfactors ),
223     int (**check_secret_key)( int algo, MPI *skey ),
224     int (**encryptf)( int algo, MPI *resarr, MPI data, MPI *pkey, int flags ),
225     int (**decryptf)( int algo, MPI *result, MPI *data, MPI *skey, int flags ),
226     int (**sign)( int algo, MPI *resarr, MPI data, MPI *skey ),
227     int (**verify)( int algo, MPI hash, MPI *data, MPI *pkey,
228                     int (*cmp)(void *, MPI), void *opaquev ),
229     unsigned (**get_nbits)( int algo, MPI *pkey ) )
230 {
231     EXTLIST r;
232     ENUMCONTEXT *ctx;
233     const char * (*finfo)( int, int *, int *, int *, int *, int *,
234                            int (**)( int, unsigned int, unsigned long,
235                                      MPI *, MPI **),
236                            int (**)( int, MPI * ),
237                            int (**)( int, MPI *, MPI , MPI *, int flags ),
238                            int (**)( int, MPI *, MPI *, MPI *, int flags ),
239                            int (**)( int, MPI *, MPI , MPI * ),
240                            int (**)( int, MPI , MPI *, MPI *,
241                                             int (*)(void*,MPI), void *),
242                            unsigned (**)( int , MPI * ) );
243
244     if( !*enum_context ) { /* init context */
245         ctx = gcry_xcalloc( 1, sizeof( *ctx ) );
246         ctx->r = extensions;
247         *enum_context = ctx;
248     }
249     else if( !algo ) { /* release the context */
250         gcry_free(*enum_context);
251         *enum_context = NULL;
252         return NULL;
253     }
254     else
255         ctx = *enum_context;
256
257     for( r = ctx->r; r; r = r->next )  {
258         int class, vers;
259
260         if( r->failed )
261             continue;
262         if( !r->handle && load_extension(r) )
263             continue;
264         /* get a pubkey info function */
265         if( ctx->sym )
266             goto inner_loop;
267         while( (ctx->sym = (*r->enumfunc)(30, &ctx->seq1, &class, &vers)) ) {
268             void *sym;
269             if( vers != 1 || class != 30 )
270                 continue;
271           inner_loop:
272             finfo = ctx->sym;
273             while( (sym = (*r->enumfunc)(31, &ctx->seq2, &class, &vers)) ) {
274                 const char *algname;
275                 if( vers != 1 || class != 31 )
276                     continue;
277                 *algo = *(int*)sym;
278                 algname = (*finfo)( *algo, npkey, nskey, nenc, nsig, use,
279                                     generate, check_secret_key, encryptf,
280                                     decryptf, sign, verify, get_nbits );
281                 if( algname ) {
282                     ctx->r = r;
283                     return algname;
284                 }
285             }
286             ctx->seq2 = 0;
287         }
288         ctx->seq1 = 0;
289     }
290     ctx->r = r;
291     return NULL;
292 }
293
294
295 int (*
296 _gcry_dynload_getfnc_gather_random())(void (*)(const void*, size_t, int), int,
297                                                             size_t, int)
298 {
299     EXTLIST r;
300     void *sym;
301
302     for( r = extensions; r; r = r->next )  {
303         int seq, class, vers;
304
305         if( r->failed )
306             continue;
307         if( !r->handle && load_extension(r) )
308             continue;
309         seq = 0;
310         while( (sym = (*r->enumfunc)(40, &seq, &class, &vers)) ) {
311             if( vers != 1 || class != 40 )
312                 continue;
313             return (int (*)(void (*)(const void*, size_t, int), int,
314                                                         size_t, int))sym;
315         }
316     }
317     return NULL;
318 }
319
320
321 void (*
322 _gcry_dynload_getfnc_fast_random_poll())( void (*)(const void*, size_t, int), int)
323 {
324     EXTLIST r;
325     void *sym;
326
327     for( r = extensions; r; r = r->next )  {
328         int seq, class, vers;
329
330         if( r->failed )
331             continue;
332         if( !r->handle && load_extension(r) )
333             continue;
334         seq = 0;
335         while( (sym = (*r->enumfunc)(41, &seq, &class, &vers)) ) {
336             if( vers != 1 || class != 41 )
337                 continue;
338             return (void (*)( void (*)(const void*, size_t, int), int))sym;
339         }
340     }
341     return NULL;
342 }
343