See ChangeLog: Tue Feb 16 14:10:02 CET 1999 Werner Koch
[libgcrypt.git] / cipher / pubkey.c
1 /* pubkey.c  -  pubkey dispatcher
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG 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 General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * 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 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include "util.h"
28 #include "errors.h"
29 #include "mpi.h"
30 #include "cipher.h"
31 #include "elgamal.h"
32 #include "dsa.h"
33 #include "dynload.h"
34
35
36 #define TABLE_SIZE 10
37
38 struct pubkey_table_s {
39     const char *name;
40     int algo;
41     int npkey;
42     int nskey;
43     int nenc;
44     int nsig;
45     int use;
46     int (*generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
47     int (*check_secret_key)( int algo, MPI *skey );
48     int (*encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey );
49     int (*decrypt)( int algo, MPI *result, MPI *data, MPI *skey );
50     int (*sign)( int algo, MPI *resarr, MPI data, MPI *skey );
51     int (*verify)( int algo, MPI hash, MPI *data, MPI *pkey,
52                    int (*cmp)(void *, MPI), void *opaquev );
53     unsigned (*get_nbits)( int algo, MPI *pkey );
54 };
55
56 static struct pubkey_table_s pubkey_table[TABLE_SIZE];
57
58
59
60 static int
61 dummy_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
62 { log_bug("no generate() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
63
64 static int
65 dummy_check_secret_key( int algo, MPI *skey )
66 { log_bug("no check_secret_key() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
67
68 static int
69 dummy_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
70 { log_bug("no encrypt() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
71
72 static int
73 dummy_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
74 { log_bug("no decrypt() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
75
76 static int
77 dummy_sign( int algo, MPI *resarr, MPI data, MPI *skey )
78 { log_bug("no sign() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
79
80 static int
81 dummy_verify( int algo, MPI hash, MPI *data, MPI *pkey,
82                 int (*cmp)(void *, MPI), void *opaquev )
83 { log_bug("no verify() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; }
84
85 static unsigned
86 dummy_get_nbits( int algo, MPI *pkey )
87 { log_bug("no get_nbits() for %d\n", algo ); return 0; }
88
89
90 /****************
91  * Put the static entries into the table.
92  */
93 static void
94 setup_pubkey_table(void)
95 {
96     int i;
97
98     i = 0;
99     pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL;
100     pubkey_table[i].name = elg_get_info( pubkey_table[i].algo,
101                                          &pubkey_table[i].npkey,
102                                          &pubkey_table[i].nskey,
103                                          &pubkey_table[i].nenc,
104                                          &pubkey_table[i].nsig,
105                                          &pubkey_table[i].use );
106     pubkey_table[i].generate         = elg_generate;
107     pubkey_table[i].check_secret_key = elg_check_secret_key;
108     pubkey_table[i].encrypt          = elg_encrypt;
109     pubkey_table[i].decrypt          = elg_decrypt;
110     pubkey_table[i].sign             = elg_sign;
111     pubkey_table[i].verify           = elg_verify;
112     pubkey_table[i].get_nbits        = elg_get_nbits;
113     if( !pubkey_table[i].name )
114         BUG();
115     i++;
116     pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL_E;
117     pubkey_table[i].name = elg_get_info( pubkey_table[i].algo,
118                                          &pubkey_table[i].npkey,
119                                          &pubkey_table[i].nskey,
120                                          &pubkey_table[i].nenc,
121                                          &pubkey_table[i].nsig,
122                                          &pubkey_table[i].use );
123     pubkey_table[i].generate         = elg_generate;
124     pubkey_table[i].check_secret_key = elg_check_secret_key;
125     pubkey_table[i].encrypt          = elg_encrypt;
126     pubkey_table[i].decrypt          = elg_decrypt;
127     pubkey_table[i].sign             = elg_sign;
128     pubkey_table[i].verify           = elg_verify;
129     pubkey_table[i].get_nbits        = elg_get_nbits;
130     if( !pubkey_table[i].name )
131         BUG();
132     i++;
133     pubkey_table[i].algo = PUBKEY_ALGO_DSA;
134     pubkey_table[i].name = dsa_get_info( pubkey_table[i].algo,
135                                          &pubkey_table[i].npkey,
136                                          &pubkey_table[i].nskey,
137                                          &pubkey_table[i].nenc,
138                                          &pubkey_table[i].nsig,
139                                          &pubkey_table[i].use );
140     pubkey_table[i].generate         = dsa_generate;
141     pubkey_table[i].check_secret_key = dsa_check_secret_key;
142     pubkey_table[i].encrypt          = dummy_encrypt;
143     pubkey_table[i].decrypt          = dummy_decrypt;
144     pubkey_table[i].sign             = dsa_sign;
145     pubkey_table[i].verify           = dsa_verify;
146     pubkey_table[i].get_nbits        = dsa_get_nbits;
147     if( !pubkey_table[i].name )
148         BUG();
149     i++;
150
151     for( ; i < TABLE_SIZE; i++ )
152         pubkey_table[i].name = NULL;
153 }
154
155
156 /****************
157  * Try to load all modules and return true if new modules are available
158  */
159 static int
160 load_pubkey_modules(void)
161 {
162     static int initialized = 0;
163     static int done = 0;
164     void *context = NULL;
165     struct pubkey_table_s *ct;
166     int ct_idx;
167     int i;
168     const char *name;
169     int any = 0;
170
171
172     if( !initialized ) {
173         cipher_modules_constructor();
174         setup_pubkey_table();
175         initialized = 1;
176         return 1;
177     }
178     if( done )
179         return 0;
180     done = 1;
181     for(ct_idx=0, ct = pubkey_table; ct_idx < TABLE_SIZE; ct_idx++,ct++ ) {
182         if( !ct->name )
183             break;
184     }
185     if( ct_idx >= TABLE_SIZE-1 )
186         BUG(); /* table already full */
187     /* now load all extensions */
188     while( (name = enum_gnupgext_pubkeys( &context, &ct->algo,
189                                 &ct->npkey, &ct->nskey, &ct->nenc,
190                                 &ct->nsig,  &ct->use,
191                                 &ct->generate,
192                                 &ct->check_secret_key,
193                                 &ct->encrypt,
194                                 &ct->decrypt,
195                                 &ct->sign,
196                                 &ct->verify,
197                                 &ct->get_nbits )) ) {
198         for(i=0; pubkey_table[i].name; i++ )
199             if( pubkey_table[i].algo == ct->algo )
200                 break;
201         if( pubkey_table[i].name ) {
202             log_info("skipping pubkey %d: already loaded\n", ct->algo );
203             continue;
204         }
205
206         if( !ct->generate  )  ct->generate = dummy_generate;
207         if( !ct->check_secret_key )  ct->check_secret_key =
208                                                     dummy_check_secret_key;
209         if( !ct->encrypt   )  ct->encrypt  = dummy_encrypt;
210         if( !ct->decrypt   )  ct->decrypt  = dummy_decrypt;
211         if( !ct->sign      )  ct->sign     = dummy_sign;
212         if( !ct->verify    )  ct->verify   = dummy_verify;
213         if( !ct->get_nbits )  ct->get_nbits= dummy_get_nbits;
214         /* put it into the table */
215         if( g10_opt_verbose > 1 )
216             log_info("loaded pubkey %d (%s)\n", ct->algo, name);
217         ct->name = name;
218         ct_idx++;
219         ct++;
220         any = 1;
221         /* check whether there are more available table slots */
222         if( ct_idx >= TABLE_SIZE-1 ) {
223             log_info("pubkey table full; ignoring other extensions\n");
224             break;
225         }
226     }
227     enum_gnupgext_pubkeys( &context, NULL, NULL, NULL, NULL, NULL, NULL,
228                                NULL, NULL, NULL, NULL, NULL, NULL, NULL );
229     return any;
230 }
231
232
233 /****************
234  * Map a string to the pubkey algo
235  */
236 int
237 string_to_pubkey_algo( const char *string )
238 {
239     int i;
240     const char *s;
241
242     do {
243         for(i=0; (s=pubkey_table[i].name); i++ )
244             if( !stricmp( s, string ) )
245                 return pubkey_table[i].algo;
246     } while( load_pubkey_modules() );
247     return 0;
248 }
249
250
251 /****************
252  * Map a pubkey algo to a string
253  */
254 const char *
255 pubkey_algo_to_string( int algo )
256 {
257     int i;
258
259     do {
260         for(i=0; pubkey_table[i].name; i++ )
261             if( pubkey_table[i].algo == algo )
262                 return pubkey_table[i].name;
263     } while( load_pubkey_modules() );
264     return NULL;
265 }
266
267
268
269 int
270 check_pubkey_algo( int algo )
271 {
272     return check_pubkey_algo2( algo, 0 );
273 }
274
275 /****************
276  * a use of 0 means: don't care
277  */
278 int
279 check_pubkey_algo2( int algo, unsigned use )
280 {
281     int i;
282
283     do {
284         for(i=0; pubkey_table[i].name; i++ )
285             if( pubkey_table[i].algo == algo ) {
286                 if( (use & PUBKEY_USAGE_SIG)
287                     && !(pubkey_table[i].use & PUBKEY_USAGE_SIG) )
288                     return G10ERR_WR_PUBKEY_ALGO;
289                 if( (use & PUBKEY_USAGE_ENC)
290                     && !(pubkey_table[i].use & PUBKEY_USAGE_ENC) )
291                     return G10ERR_WR_PUBKEY_ALGO;
292                 return 0; /* okay */
293             }
294     } while( load_pubkey_modules() );
295     return G10ERR_PUBKEY_ALGO;
296 }
297
298
299
300
301 /****************
302  * Return the number of public key material numbers
303  */
304 int
305 pubkey_get_npkey( int algo )
306 {
307     int i;
308     do {
309         for(i=0; pubkey_table[i].name; i++ )
310             if( pubkey_table[i].algo == algo )
311                 return pubkey_table[i].npkey;
312     } while( load_pubkey_modules() );
313     if( is_RSA(algo) )    /* special hack, so that we are able to */
314         return 2;         /* see the RSA keyids */
315     return 0;
316 }
317
318 /****************
319  * Return the number of secret key material numbers
320  */
321 int
322 pubkey_get_nskey( int algo )
323 {
324     int i;
325     do {
326         for(i=0; pubkey_table[i].name; i++ )
327             if( pubkey_table[i].algo == algo )
328                 return pubkey_table[i].nskey;
329     } while( load_pubkey_modules() );
330     if( is_RSA(algo) )    /* special hack, so that we are able to */
331         return 6;         /* see the RSA keyids */
332     return 0;
333 }
334
335 /****************
336  * Return the number of signature material numbers
337  */
338 int
339 pubkey_get_nsig( int algo )
340 {
341     int i;
342     do {
343         for(i=0; pubkey_table[i].name; i++ )
344             if( pubkey_table[i].algo == algo )
345                 return pubkey_table[i].nsig;
346     } while( load_pubkey_modules() );
347     if( is_RSA(algo) )    /* special hack, so that we are able to */
348         return 1;         /* see the RSA keyids */
349     return 0;
350 }
351
352 /****************
353  * Return the number of encryption material numbers
354  */
355 int
356 pubkey_get_nenc( int algo )
357 {
358     int i;
359     do {
360         for(i=0; pubkey_table[i].name; i++ )
361             if( pubkey_table[i].algo == algo )
362                 return pubkey_table[i].nenc;
363     } while( load_pubkey_modules() );
364     if( is_RSA(algo) )    /* special hack, so that we are able to */
365         return 1;         /* see the RSA keyids */
366     return 0;
367 }
368
369 /****************
370  * Get the number of nbits from the public key
371  */
372 unsigned
373 pubkey_nbits( int algo, MPI *pkey )
374 {
375     int i;
376
377     do {
378         for(i=0; pubkey_table[i].name; i++ )
379             if( pubkey_table[i].algo == algo )
380                 return (*pubkey_table[i].get_nbits)( algo, pkey );
381     } while( load_pubkey_modules() );
382     if( is_RSA(algo) )  /* we always wanna see the length of a key :-) */
383         return mpi_get_nbits( pkey[0] );
384     return 0;
385 }
386
387
388 int
389 pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
390 {
391     int i;
392
393     do {
394         for(i=0; pubkey_table[i].name; i++ )
395             if( pubkey_table[i].algo == algo )
396                 return (*pubkey_table[i].generate)( algo, nbits,
397                                                     skey, retfactors );
398     } while( load_pubkey_modules() );
399     return G10ERR_PUBKEY_ALGO;
400 }
401
402
403 int
404 pubkey_check_secret_key( int algo, MPI *skey )
405 {
406     int i;
407
408     do {
409         for(i=0; pubkey_table[i].name; i++ )
410             if( pubkey_table[i].algo == algo )
411                 return (*pubkey_table[i].check_secret_key)( algo, skey );
412     } while( load_pubkey_modules() );
413     return G10ERR_PUBKEY_ALGO;
414 }
415
416
417 /****************
418  * This is the interface to the public key encryption.
419  * Encrypt DATA with PKEY and put it into RESARR which
420  * should be an array of MPIs of size PUBKEY_MAX_NENC (or less if the
421  * algorithm allows this - check with pubkey_get_nenc() )
422  */
423 int
424 pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
425 {
426     int i, rc;
427
428     /* FIXME: check that data fits into the key (in xxx_encrypt)*/
429
430     if( DBG_CIPHER ) {
431         log_debug("pubkey_encrypt: algo=%d\n", algo );
432         for(i=0; i < pubkey_get_npkey(algo); i++ )
433             log_mpidump("  pkey:", pkey[i] );
434         log_mpidump("  data:", data );
435     }
436
437     do {
438         for(i=0; pubkey_table[i].name; i++ )
439             if( pubkey_table[i].algo == algo ) {
440                 rc = (*pubkey_table[i].encrypt)( algo, resarr, data, pkey );
441                 goto ready;
442             }
443     } while( load_pubkey_modules() );
444     rc = G10ERR_PUBKEY_ALGO;
445   ready:
446     if( !rc && DBG_CIPHER ) {
447         for(i=0; i < pubkey_get_nenc(algo); i++ )
448             log_mpidump("  encr:", resarr[i] );
449     }
450     return rc;
451 }
452
453
454
455 /****************
456  * This is the interface to the public key decryption.
457  * ALGO gives the algorithm to use and this implicitly determines
458  * the size of the arrays.
459  * result is a pointer to a mpi variable which will receive a
460  * newly allocated mpi or NULL in case of an error.
461  */
462 int
463 pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
464 {
465     int i, rc;
466
467     *result = NULL; /* so the caller can always do an mpi_free */
468     if( DBG_CIPHER ) {
469         log_debug("pubkey_decrypt: algo=%d\n", algo );
470         for(i=0; i < pubkey_get_nskey(algo); i++ )
471             log_mpidump("  skey:", skey[i] );
472         for(i=0; i < pubkey_get_nenc(algo); i++ )
473             log_mpidump("  data:", data[i] );
474     }
475
476     do {
477         for(i=0; pubkey_table[i].name; i++ )
478             if( pubkey_table[i].algo == algo ) {
479                 rc = (*pubkey_table[i].decrypt)( algo, result, data, skey );
480                 goto ready;
481             }
482     } while( load_pubkey_modules() );
483     rc = G10ERR_PUBKEY_ALGO;
484   ready:
485     if( !rc && DBG_CIPHER ) {
486         log_mpidump(" plain:", *result );
487     }
488     return rc;
489 }
490
491
492 /****************
493  * This is the interface to the public key signing.
494  * Sign data with skey and put the result into resarr which
495  * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the
496  * algorithm allows this - check with pubkey_get_nsig() )
497  */
498 int
499 pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
500 {
501     int i, rc;
502
503     if( DBG_CIPHER ) {
504         log_debug("pubkey_sign: algo=%d\n", algo );
505         for(i=0; i < pubkey_get_nskey(algo); i++ )
506             log_mpidump("  skey:", skey[i] );
507         log_mpidump("  data:", data );
508     }
509
510     do {
511         for(i=0; pubkey_table[i].name; i++ )
512             if( pubkey_table[i].algo == algo ) {
513                 rc = (*pubkey_table[i].sign)( algo, resarr, data, skey );
514                 goto ready;
515             }
516     } while( load_pubkey_modules() );
517     rc = G10ERR_PUBKEY_ALGO;
518   ready:
519     if( !rc && DBG_CIPHER ) {
520         for(i=0; i < pubkey_get_nsig(algo); i++ )
521             log_mpidump("   sig:", resarr[i] );
522     }
523     return rc;
524 }
525
526 /****************
527  * Verify a public key signature.
528  * Return 0 if the signature is good
529  */
530 int
531 pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
532                     int (*cmp)(void *, MPI), void *opaquev )
533 {
534     int i, rc;
535
536     do {
537         for(i=0; pubkey_table[i].name; i++ )
538             if( pubkey_table[i].algo == algo ) {
539                 rc = (*pubkey_table[i].verify)( algo, hash, data, pkey,
540                                                             cmp, opaquev );
541                 goto ready;
542             }
543     } while( load_pubkey_modules() );
544     rc = G10ERR_PUBKEY_ALGO;
545   ready:
546     return rc;
547 }
548