* cipher.c (gcry_cipher_map_name): Look also for OIDs prefixed
[libgcrypt.git] / cipher / pubkey.c
1 /* pubkey.c  -  pubkey dispatcher
2  *      Copyright (C) 1998, 1999, 2000 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 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  * 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 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
28 #include "g10lib.h"
29 #include "mpi.h"
30 #include "cipher.h"
31 #include "elgamal.h"
32 #include "dsa.h"
33 #include "rsa.h"
34 #include "dynload.h"
35
36 /* FIXME: use set_lasterr() */
37
38 #define TABLE_SIZE 10
39
40 struct pubkey_table_s {
41     const char *name;
42     int algo;
43     int npkey;
44     int nskey;
45     int nenc;
46     int nsig;
47     int use;
48     int (*generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
49     int (*check_secret_key)( int algo, MPI *skey );
50     int (*encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey );
51     int (*decrypt)( int algo, MPI *result, MPI *data, MPI *skey );
52     int (*sign)( int algo, MPI *resarr, MPI data, MPI *skey );
53     int (*verify)( int algo, MPI hash, MPI *data, MPI *pkey,
54                    int (*cmp)(void *, MPI), void *opaquev );
55     unsigned (*get_nbits)( int algo, MPI *pkey );
56 };
57
58 static struct pubkey_table_s pubkey_table[TABLE_SIZE];
59 static int disabled_algos[TABLE_SIZE];
60
61 static struct { const char* name; int algo;
62                 const char* common_elements;
63                 const char* public_elements;
64                 const char* secret_elements;
65 } algo_info_table[] = {
66   { "dsa"            ,          PUBKEY_ALGO_DSA       , "pqgy", "", "x"    },
67   { "rsa"            ,          PUBKEY_ALGO_RSA       , "ne",   "", "dpqu" },
68   { "elg"            ,          PUBKEY_ALGO_ELGAMAL   , "pgy",  "", "x"    },
69   { "openpgp-dsa"    ,          PUBKEY_ALGO_DSA       , "pqgy", "", "x"    },
70   { "openpgp-rsa"    ,          PUBKEY_ALGO_RSA       , "ne",   "", "dpqu" },
71   { "openpgp-elg"    ,          PUBKEY_ALGO_ELGAMAL_E , "pgy",  "", "x"    },
72   { "openpgp-elg-sig",          PUBKEY_ALGO_ELGAMAL   , "pgy",  "", "x"    },
73   { "oid.1.2.840.113549.1.1.1", PUBKEY_ALGO_RSA       , "ne",   "", "dpqu" },
74   { NULL }
75 };
76
77 static struct {
78     const char* name; int algo;
79     const char* elements;
80 } sig_info_table[] = {
81   { "dsa"                     , PUBKEY_ALGO_DSA       , "rs" },
82   { "rsa"                     , PUBKEY_ALGO_RSA       , "s"  },
83   { "elg"                     , PUBKEY_ALGO_ELGAMAL   , "rs" },
84   { "openpgp-dsa"             , PUBKEY_ALGO_DSA       , "rs" },
85   { "openpgp-rsa"             , PUBKEY_ALGO_RSA       , "s"  },
86   { "openpgp-elg-sig"         , PUBKEY_ALGO_ELGAMAL   , "rs" },
87   { "oid.1.2.840.113549.1.1.1", PUBKEY_ALGO_RSA       , "s"  },
88   { NULL }
89 };
90
91 static struct {
92     const char* name; int algo;
93     const char* elements;
94 } enc_info_table[] = {
95   { "elg"            ,          PUBKEY_ALGO_ELGAMAL   , "ab" },
96   { "rsa"            ,          PUBKEY_ALGO_RSA       , "a"  },
97   { "openpgp-rsa"    ,          PUBKEY_ALGO_RSA       , "a"  },
98   { "openpgp-elg"    ,          PUBKEY_ALGO_ELGAMAL_E , "ab" },
99   { "openpgp-elg-sig",          PUBKEY_ALGO_ELGAMAL   , "ab" },
100   { "oid.1.2.840.113549.1.1.1", PUBKEY_ALGO_RSA       , "a"  },
101   { NULL }
102 };
103
104
105 static int pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
106 static int pubkey_sign( int algo, MPI *resarr, MPI hash, MPI *skey );
107 static int pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
108                       int (*cmp)(void *, MPI), void *opaque );
109
110 static int
111 dummy_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
112 { log_bug("no generate() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
113
114 static int
115 dummy_check_secret_key( int algo, MPI *skey )
116 { log_bug("no check_secret_key() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
117
118 static int
119 dummy_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
120 { log_bug("no encrypt() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
121
122 static int
123 dummy_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
124 { log_bug("no decrypt() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
125
126 static int
127 dummy_sign( int algo, MPI *resarr, MPI data, MPI *skey )
128 { log_bug("no sign() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
129
130 static int
131 dummy_verify( int algo, MPI hash, MPI *data, MPI *pkey,
132                 int (*cmp)(void *, MPI), void *opaquev )
133 { log_bug("no verify() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
134
135 static unsigned
136 dummy_get_nbits( int algo, MPI *pkey )
137 { log_bug("no get_nbits() for %d\n", algo ); return 0; }
138
139
140 /****************
141  * Put the static entries into the table.
142  * This is out constructor function which fill the table
143  * of algorithms with the one we have statically linked.
144  */
145 static void
146 setup_pubkey_table(void)
147 {
148     int i;
149
150     i = 0;
151     pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL;
152     pubkey_table[i].name = _gcry_elg_get_info( pubkey_table[i].algo,
153                                          &pubkey_table[i].npkey,
154                                          &pubkey_table[i].nskey,
155                                          &pubkey_table[i].nenc,
156                                          &pubkey_table[i].nsig,
157                                          &pubkey_table[i].use );
158     pubkey_table[i].generate         = _gcry_elg_generate;
159     pubkey_table[i].check_secret_key = _gcry_elg_check_secret_key;
160     pubkey_table[i].encrypt          = _gcry_elg_encrypt;
161     pubkey_table[i].decrypt          = _gcry_elg_decrypt;
162     pubkey_table[i].sign             = _gcry_elg_sign;
163     pubkey_table[i].verify           = _gcry_elg_verify;
164     pubkey_table[i].get_nbits        = _gcry_elg_get_nbits;
165     if( !pubkey_table[i].name )
166         BUG();
167     i++;
168     pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL_E;
169     pubkey_table[i].name = _gcry_elg_get_info( pubkey_table[i].algo,
170                                          &pubkey_table[i].npkey,
171                                          &pubkey_table[i].nskey,
172                                          &pubkey_table[i].nenc,
173                                          &pubkey_table[i].nsig,
174                                          &pubkey_table[i].use );
175     pubkey_table[i].generate         = _gcry_elg_generate;
176     pubkey_table[i].check_secret_key = _gcry_elg_check_secret_key;
177     pubkey_table[i].encrypt          = _gcry_elg_encrypt;
178     pubkey_table[i].decrypt          = _gcry_elg_decrypt;
179     pubkey_table[i].sign             = _gcry_elg_sign;
180     pubkey_table[i].verify           = _gcry_elg_verify;
181     pubkey_table[i].get_nbits        = _gcry_elg_get_nbits;
182     if( !pubkey_table[i].name )
183         BUG();
184     i++;
185     pubkey_table[i].algo = PUBKEY_ALGO_DSA;
186     pubkey_table[i].name = _gcry_dsa_get_info( pubkey_table[i].algo,
187                                          &pubkey_table[i].npkey,
188                                          &pubkey_table[i].nskey,
189                                          &pubkey_table[i].nenc,
190                                          &pubkey_table[i].nsig,
191                                          &pubkey_table[i].use );
192     pubkey_table[i].generate         = _gcry_dsa_generate;
193     pubkey_table[i].check_secret_key = _gcry_dsa_check_secret_key;
194     pubkey_table[i].encrypt          = dummy_encrypt;
195     pubkey_table[i].decrypt          = dummy_decrypt;
196     pubkey_table[i].sign             = _gcry_dsa_sign;
197     pubkey_table[i].verify           = _gcry_dsa_verify;
198     pubkey_table[i].get_nbits        = _gcry_dsa_get_nbits;
199     if( !pubkey_table[i].name )
200         BUG();
201     i++;
202
203     pubkey_table[i].algo = PUBKEY_ALGO_RSA;
204     pubkey_table[i].name = _gcry_rsa_get_info( pubkey_table[i].algo,
205                                          &pubkey_table[i].npkey,
206                                          &pubkey_table[i].nskey,
207                                          &pubkey_table[i].nenc,
208                                          &pubkey_table[i].nsig,
209                                          &pubkey_table[i].use );
210     pubkey_table[i].generate         = _gcry_rsa_generate;
211     pubkey_table[i].check_secret_key = _gcry_rsa_check_secret_key;
212     pubkey_table[i].encrypt          = _gcry_rsa_encrypt;
213     pubkey_table[i].decrypt          = _gcry_rsa_decrypt;
214     pubkey_table[i].sign             = _gcry_rsa_sign;
215     pubkey_table[i].verify           = _gcry_rsa_verify;
216     pubkey_table[i].get_nbits        = _gcry_rsa_get_nbits;
217     if( !pubkey_table[i].name )
218         BUG();
219     i++;
220     pubkey_table[i].algo = PUBKEY_ALGO_RSA_E;
221     pubkey_table[i].name = _gcry_rsa_get_info( pubkey_table[i].algo,
222                                          &pubkey_table[i].npkey,
223                                          &pubkey_table[i].nskey,
224                                          &pubkey_table[i].nenc,
225                                          &pubkey_table[i].nsig,
226                                          &pubkey_table[i].use );
227     pubkey_table[i].generate         = _gcry_rsa_generate;
228     pubkey_table[i].check_secret_key = _gcry_rsa_check_secret_key;
229     pubkey_table[i].encrypt          = _gcry_rsa_encrypt;
230     pubkey_table[i].decrypt          = _gcry_rsa_decrypt;
231     pubkey_table[i].sign             = dummy_sign;
232     pubkey_table[i].verify           = dummy_verify;
233     pubkey_table[i].get_nbits        = _gcry_rsa_get_nbits;
234     if( !pubkey_table[i].name )
235         BUG();
236     i++;
237     pubkey_table[i].algo = PUBKEY_ALGO_RSA_S;
238     pubkey_table[i].name = _gcry_rsa_get_info( pubkey_table[i].algo,
239                                          &pubkey_table[i].npkey,
240                                          &pubkey_table[i].nskey,
241                                          &pubkey_table[i].nenc,
242                                          &pubkey_table[i].nsig,
243                                          &pubkey_table[i].use );
244     pubkey_table[i].generate         = _gcry_rsa_generate;
245     pubkey_table[i].check_secret_key = _gcry_rsa_check_secret_key;
246     pubkey_table[i].encrypt          = dummy_encrypt;
247     pubkey_table[i].decrypt          = dummy_decrypt;
248     pubkey_table[i].sign             = _gcry_rsa_sign;
249     pubkey_table[i].verify           = _gcry_rsa_verify;
250     pubkey_table[i].get_nbits        = _gcry_rsa_get_nbits;
251     if( !pubkey_table[i].name )
252         BUG();
253     i++;
254
255     for( ; i < TABLE_SIZE; i++ )
256         pubkey_table[i].name = NULL;
257 }
258
259 static void
260 release_mpi_array( MPI *array )
261 {
262     for( ; *array; array++ ) {
263         mpi_free(*array);
264         *array = NULL;
265     }
266 }
267
268 /****************
269  * Try to load all modules and return true if new modules are available
270  */
271 static int
272 load_pubkey_modules(void)
273 {
274     static int initialized = 0;
275     static int done = 0;
276     void *context = NULL;
277     struct pubkey_table_s *ct;
278     int ct_idx;
279     int i;
280     const char *name;
281     int any = 0;
282
283
284     if( !initialized ) {
285         _gcry_cipher_modules_constructor();
286         setup_pubkey_table();
287         initialized = 1;
288         return 1;
289     }
290     if( done )
291         return 0;
292     done = 1;
293     for(ct_idx=0, ct = pubkey_table; ct_idx < TABLE_SIZE; ct_idx++,ct++ ) {
294         if( !ct->name )
295             break;
296     }
297     if( ct_idx >= TABLE_SIZE-1 )
298         BUG(); /* table already full */
299     /* now load all extensions */
300     while( (name = _gcry_enum_gnupgext_pubkeys( &context, &ct->algo,
301                                 &ct->npkey, &ct->nskey, &ct->nenc,
302                                 &ct->nsig,  &ct->use,
303                                 &ct->generate,
304                                 &ct->check_secret_key,
305                                 &ct->encrypt,
306                                 &ct->decrypt,
307                                 &ct->sign,
308                                 &ct->verify,
309                                 &ct->get_nbits )) ) {
310         for(i=0; pubkey_table[i].name; i++ )
311             if( pubkey_table[i].algo == ct->algo )
312                 break;
313         if( pubkey_table[i].name ) {
314             log_info("skipping pubkey %d: already loaded\n", ct->algo );
315             continue;
316         }
317
318         if( !ct->generate  )  ct->generate = dummy_generate;
319         if( !ct->check_secret_key )  ct->check_secret_key =
320                                                     dummy_check_secret_key;
321         if( !ct->encrypt   )  ct->encrypt  = dummy_encrypt;
322         if( !ct->decrypt   )  ct->decrypt  = dummy_decrypt;
323         if( !ct->sign      )  ct->sign     = dummy_sign;
324         if( !ct->verify    )  ct->verify   = dummy_verify;
325         if( !ct->get_nbits )  ct->get_nbits= dummy_get_nbits;
326         /* put it into the table */
327         if( _gcry_log_verbosity( 2 ) )
328             log_info("loaded pubkey %d (%s)\n", ct->algo, name);
329         ct->name = name;
330         ct_idx++;
331         ct++;
332         any = 1;
333         /* check whether there are more available table slots */
334         if( ct_idx >= TABLE_SIZE-1 ) {
335             log_info("pubkey table full; ignoring other extensions\n");
336             break;
337         }
338     }
339     _gcry_enum_gnupgext_pubkeys( &context, NULL, NULL, NULL, NULL, NULL, NULL,
340                                NULL, NULL, NULL, NULL, NULL, NULL, NULL );
341     return any;
342 }
343
344
345 /****************
346  * Map a string to the pubkey algo
347  */
348 int
349 gcry_pk_map_name( const char *string )
350 {
351     int i;
352     const char *s;
353
354     do {
355         for(i=0; (s=pubkey_table[i].name); i++ )
356             if( !stricmp( s, string ) )
357                 return pubkey_table[i].algo;
358     } while( load_pubkey_modules() );
359     return 0;
360 }
361
362
363 /****************
364  * Map a pubkey algo to a string
365  */
366 const char *
367 gcry_pk_algo_name( int algo )
368 {
369     int i;
370
371     do {
372         for(i=0; pubkey_table[i].name; i++ )
373             if( pubkey_table[i].algo == algo )
374                 return pubkey_table[i].name;
375     } while( load_pubkey_modules() );
376     return NULL;
377 }
378
379
380 static void
381 disable_pubkey_algo( int algo )
382 {
383     int i;
384
385     for(i=0; i < DIM(disabled_algos); i++ ) {
386         if( !disabled_algos[i] || disabled_algos[i] == algo ) {
387             disabled_algos[i] = algo;
388             return;
389         }
390     }
391     log_fatal("can't disable pubkey algo %d: table full\n", algo );
392 }
393
394
395 /****************
396  * a use of 0 means: don't care
397  */
398 static int
399 check_pubkey_algo( int algo, unsigned use )
400 {
401     int i;
402
403     do {
404         for(i=0; pubkey_table[i].name; i++ )
405             if( pubkey_table[i].algo == algo ) {
406                 if( (use & GCRY_PK_USAGE_SIGN)
407                     && !(pubkey_table[i].use & GCRY_PK_USAGE_SIGN) )
408                     return GCRYERR_WRONG_PK_ALGO;
409                 if( (use & GCRY_PK_USAGE_ENCR)
410                     && !(pubkey_table[i].use & GCRY_PK_USAGE_ENCR) )
411                     return GCRYERR_WRONG_PK_ALGO;
412
413                 for(i=0; i < DIM(disabled_algos); i++ ) {
414                     if( disabled_algos[i] == algo )
415                         return GCRYERR_INV_PK_ALGO;
416                 }
417                 return 0; /* okay */
418             }
419     } while( load_pubkey_modules() );
420     return GCRYERR_INV_PK_ALGO;
421 }
422
423
424
425
426 /****************
427  * Return the number of public key material numbers
428  */
429 static int
430 pubkey_get_npkey( int algo )
431 {
432     int i;
433     do {
434         for(i=0; pubkey_table[i].name; i++ )
435             if( pubkey_table[i].algo == algo )
436                 return pubkey_table[i].npkey;
437     } while( load_pubkey_modules() );
438     return 0;
439 }
440
441 /****************
442  * Return the number of secret key material numbers
443  */
444 static int
445 pubkey_get_nskey( int algo )
446 {
447     int i;
448     do {
449         for(i=0; pubkey_table[i].name; i++ )
450             if( pubkey_table[i].algo == algo )
451                 return pubkey_table[i].nskey;
452     } while( load_pubkey_modules() );
453     return 0;
454 }
455
456 /****************
457  * Return the number of signature material numbers
458  */
459 static int
460 pubkey_get_nsig( int algo )
461 {
462     int i;
463     do {
464         for(i=0; pubkey_table[i].name; i++ )
465             if( pubkey_table[i].algo == algo )
466                 return pubkey_table[i].nsig;
467     } while( load_pubkey_modules() );
468     return 0;
469 }
470
471 /****************
472  * Return the number of encryption material numbers
473  */
474 static int
475 pubkey_get_nenc( int algo )
476 {
477     int i;
478     do {
479         for(i=0; pubkey_table[i].name; i++ )
480             if( pubkey_table[i].algo == algo )
481                 return pubkey_table[i].nenc;
482     } while( load_pubkey_modules() );
483     return 0;
484 }
485
486
487 static int
488 pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
489 {
490     int i;
491
492     do {
493         for(i=0; pubkey_table[i].name; i++ )
494             if( pubkey_table[i].algo == algo )
495                 return (*pubkey_table[i].generate)( algo, nbits,
496                                                     skey, retfactors );
497     } while( load_pubkey_modules() );
498     return GCRYERR_INV_PK_ALGO;
499 }
500
501
502 static int
503 pubkey_check_secret_key( int algo, MPI *skey )
504 {
505     int i;
506
507     do {
508         for(i=0; pubkey_table[i].name; i++ )
509             if( pubkey_table[i].algo == algo )
510                 return (*pubkey_table[i].check_secret_key)( algo, skey );
511     } while( load_pubkey_modules() );
512     return GCRYERR_INV_PK_ALGO;
513 }
514
515
516 /****************
517  * This is the interface to the public key encryption.
518  * Encrypt DATA with PKEY and put it into RESARR which
519  * should be an array of MPIs of size PUBKEY_MAX_NENC (or less if the
520  * algorithm allows this - check with pubkey_get_nenc() )
521  */
522 static int
523 pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
524 {
525     int i, rc;
526
527     if( DBG_CIPHER ) {
528         log_debug("pubkey_encrypt: algo=%d\n", algo );
529         for(i=0; i < pubkey_get_npkey(algo); i++ )
530             log_mpidump("  pkey:", pkey[i] );
531         log_mpidump("  data:", data );
532     }
533
534     do {
535         for(i=0; pubkey_table[i].name; i++ )
536             if( pubkey_table[i].algo == algo ) {
537                 rc = (*pubkey_table[i].encrypt)( algo, resarr, data, pkey );
538                 goto ready;
539             }
540     } while( load_pubkey_modules() );
541     rc = GCRYERR_INV_PK_ALGO;
542   ready:
543     if( !rc && DBG_CIPHER ) {
544         for(i=0; i < pubkey_get_nenc(algo); i++ )
545             log_mpidump("  encr:", resarr[i] );
546     }
547     return rc;
548 }
549
550
551
552 /****************
553  * This is the interface to the public key decryption.
554  * ALGO gives the algorithm to use and this implicitly determines
555  * the size of the arrays.
556  * result is a pointer to a mpi variable which will receive a
557  * newly allocated mpi or NULL in case of an error.
558  */
559 static int
560 pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
561 {
562     int i, rc;
563
564     *result = NULL; /* so the caller can always do a mpi_free */
565     if( DBG_CIPHER ) {
566         log_debug("pubkey_decrypt: algo=%d\n", algo );
567         for(i=0; i < pubkey_get_nskey(algo); i++ )
568             log_mpidump("  skey:", skey[i] );
569         for(i=0; i < pubkey_get_nenc(algo); i++ )
570             log_mpidump("  data:", data[i] );
571     }
572
573     do {
574         for(i=0; pubkey_table[i].name; i++ )
575             if( pubkey_table[i].algo == algo ) {
576                 rc = (*pubkey_table[i].decrypt)( algo, result, data, skey );
577                 goto ready;
578             }
579     } while( load_pubkey_modules() );
580     rc = GCRYERR_INV_PK_ALGO;
581   ready:
582     if( !rc && DBG_CIPHER ) {
583         log_mpidump(" plain:", *result );
584     }
585     return rc;
586 }
587
588
589 /****************
590  * This is the interface to the public key signing.
591  * Sign data with skey and put the result into resarr which
592  * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the
593  * algorithm allows this - check with pubkey_get_nsig() )
594  */
595 static int
596 pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
597 {
598     int i, rc;
599
600     if( DBG_CIPHER ) {
601         log_debug("pubkey_sign: algo=%d\n", algo );
602         for(i=0; i < pubkey_get_nskey(algo); i++ )
603             log_mpidump("  skey:", skey[i] );
604         log_mpidump("  data:", data );
605     }
606
607     do {
608         for(i=0; pubkey_table[i].name; i++ )
609             if( pubkey_table[i].algo == algo ) {
610                 rc = (*pubkey_table[i].sign)( algo, resarr, data, skey );
611                 goto ready;
612             }
613     } while( load_pubkey_modules() );
614     rc = GCRYERR_INV_PK_ALGO;
615   ready:
616     if( !rc && DBG_CIPHER ) {
617         for(i=0; i < pubkey_get_nsig(algo); i++ )
618             log_mpidump("   sig:", resarr[i] );
619     }
620     return rc;
621 }
622
623 /****************
624  * Verify a public key signature.
625  * Return 0 if the signature is good
626  */
627 static int
628 pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
629                     int (*cmp)(void *, MPI), void *opaquev )
630 {
631     int i, rc;
632
633     do {
634         for(i=0; pubkey_table[i].name; i++ )
635             if( pubkey_table[i].algo == algo ) {
636                 rc = (*pubkey_table[i].verify)( algo, hash, data, pkey,
637                                                             cmp, opaquev );
638                 goto ready;
639             }
640     } while( load_pubkey_modules() );
641     rc = GCRYERR_INV_PK_ALGO;
642   ready:
643     return rc;
644 }
645
646
647
648 /****************
649  * Convert a S-Exp with either a private or a public key to our
650  * internal format. Currently we do only support the following
651  * algorithms:
652  *    dsa
653  *    rsa
654  *    openpgp-dsa
655  *    openpgp-rsa
656  *    openpgp-elg
657  *    openpgp-elg-sig
658  * Provide a SE with the first element be either "private-key" or
659  * or "public-key". the followed by a list with its first element
660  * be one of the above algorithm identifiers and the following
661  * elements are pairs with parameter-id and value.
662  * NOTE: we look through the list to find a list beginning with
663  * "private-key" or "public-key" - the first one found is used.
664  *
665  * FIXME: Allow for encrypted secret keys here.
666  *
667  * Returns: A pointer to an allocated array of MPIs if the return value is
668  *          zero; the caller has to release this array.
669  *
670  * Example of a DSA public key:
671  *  (private-key
672  *    (dsa
673  *      (p <mpi>)
674  *      (g <mpi>)
675  *      (y <mpi>)
676  *      (x <mpi>)
677  *    )
678  *  )
679  * The <mpi> are expected to be in GCRYMPI_FMT_USG
680  */
681 static int
682 sexp_to_key( GCRY_SEXP sexp, int want_private, MPI **retarray,
683              int *retalgo, int *r_algotblidx)
684 {
685     GCRY_SEXP list, l2;
686     const char *name;
687     const char *s;
688     size_t n;
689     int i, idx;
690     int algo;
691     const char *elems1, *elems2;
692     GCRY_MPI *array;
693
694     /* check that the first element is valid */
695     list = gcry_sexp_find_token( sexp, want_private? "private-key"
696                                                     :"public-key", 0 );
697     if( !list )
698         return GCRYERR_INV_OBJ; /* Does not contain a public- or private-key object */
699     l2 = gcry_sexp_cadr( list );
700     gcry_sexp_release ( list );
701     list = l2;
702     name = gcry_sexp_nth_data( list, 0, &n );
703     if( !name ) {
704         gcry_sexp_release ( list );
705         return GCRYERR_INV_OBJ; /* invalid structure of object */
706     }
707     for(i=0; (s=algo_info_table[i].name); i++ ) {
708         if( strlen(s) == n && !memcmp( s, name, n ) )
709             break;
710     }
711     if( !s ) {
712         gcry_sexp_release ( list );
713         return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
714     }
715     if (r_algotblidx)
716       *r_algotblidx = i;
717     algo = algo_info_table[i].algo;
718     elems1 = algo_info_table[i].common_elements;
719     elems2 = want_private? algo_info_table[i].secret_elements
720                          : algo_info_table[i].public_elements;
721     array = gcry_calloc( strlen(elems1)+strlen(elems2)+1, sizeof *array );
722     if( !array ) {
723         gcry_sexp_release ( list );
724         return GCRYERR_NO_MEM;
725     }
726
727     idx = 0;
728     for(s=elems1; *s; s++, idx++ ) {
729         l2 = gcry_sexp_find_token( list, s, 1 );
730         if( !l2 ) {
731             for(i=0; i<idx; i++)
732                 gcry_free( array[i] );
733             gcry_free( array );
734             gcry_sexp_release ( list );
735             return GCRYERR_NO_OBJ; /* required parameter not found */
736         }
737         array[idx] = gcry_sexp_nth_mpi( l2, 1, GCRYMPI_FMT_USG );
738         gcry_sexp_release ( l2 );
739         if( !array[idx] ) {
740             for(i=0; i<idx; i++)
741                 gcry_free( array[i] );
742             gcry_free( array );
743             gcry_sexp_release ( list );
744             return GCRYERR_INV_OBJ; /* required parameter is invalid */
745         }
746     }
747     for(s=elems2; *s; s++, idx++ ) {
748         l2 = gcry_sexp_find_token( list, s, 1 );
749         if( !l2 ) {
750             for(i=0; i<idx; i++)
751                 gcry_free( array[i] );
752             gcry_free( array );
753             gcry_sexp_release ( list );
754             return GCRYERR_NO_OBJ; /* required parameter not found */
755         }
756         array[idx] = gcry_sexp_nth_mpi( l2, 1, GCRYMPI_FMT_USG );
757         gcry_sexp_release ( l2 );
758         if( !array[idx] ) {
759             for(i=0; i<idx; i++)
760                 gcry_free( array[i] );
761             gcry_free( array );
762             gcry_sexp_release ( list );
763             return GCRYERR_INV_OBJ; /* required parameter is invalid */
764         }
765     }
766
767     gcry_sexp_release ( list );
768     *retarray = array;
769     *retalgo = algo;
770
771     return 0;
772 }
773
774 static int
775 sexp_to_sig( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
776 {
777     GCRY_SEXP list, l2;
778     const char *name;
779     const char *s;
780     size_t n;
781     int i, idx;
782     int algo;
783     const char *elems;
784     GCRY_MPI *array;
785
786     /* check that the first element is valid */
787     list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
788     if( !list )
789         return GCRYERR_INV_OBJ; /* Does not contain a signature value object */
790     l2 = gcry_sexp_cadr( list );
791     gcry_sexp_release ( list );
792     list = l2;
793     if( !list )
794         return GCRYERR_NO_OBJ; /* no cadr for the sig object */
795     name = gcry_sexp_nth_data( list, 0, &n );
796     if( !name ) {
797         gcry_sexp_release ( list );
798         return GCRYERR_INV_OBJ; /* invalid structure of object */
799     }
800     for(i=0; (s=sig_info_table[i].name); i++ ) {
801         if( strlen(s) == n && !memcmp( s, name, n ) )
802             break;
803     }
804     if( !s ) {
805         gcry_sexp_release ( list );
806         return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
807     }
808     algo = sig_info_table[i].algo;
809     elems = sig_info_table[i].elements;
810     array = gcry_calloc( (strlen(elems)+1) , sizeof *array );
811     if( !array ) {
812         gcry_sexp_release ( list );
813         return GCRYERR_NO_MEM;
814     }
815
816     idx = 0;
817     for(s=elems; *s; s++, idx++ ) {
818         l2 = gcry_sexp_find_token( list, s, 1 );
819         if( !l2 ) {
820             gcry_free( array );
821             gcry_sexp_release ( list );
822             return GCRYERR_NO_OBJ; /* required parameter not found */
823         }
824         array[idx] = gcry_sexp_nth_mpi( l2, 1, GCRYMPI_FMT_USG );
825         gcry_sexp_release ( l2 );
826         if( !array[idx] ) {
827             gcry_free( array );
828             gcry_sexp_release ( list );
829             return GCRYERR_INV_OBJ; /* required parameter is invalid */
830         }
831     }
832
833     gcry_sexp_release ( list );
834     *retarray = array;
835     *retalgo = algo;
836
837     return 0;
838 }
839
840
841 /****************
842  * Take sexp and return an array of MPI as used for our internal decrypt
843  * function.
844  */
845 static int
846 sexp_to_enc( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
847 {
848     GCRY_SEXP list, l2;
849     const char *name;
850     const char *s;
851     size_t n;
852     int i, idx;
853     int algo;
854     const char *elems;
855     GCRY_MPI *array;
856
857     /* check that the first element is valid */
858     list = gcry_sexp_find_token( sexp, "enc-val" , 0 );
859     if( !list )
860         return GCRYERR_INV_OBJ; /* Does not contain a encrypted value object */
861     l2 = gcry_sexp_cadr( list );
862     gcry_sexp_release ( list );
863     list = l2;
864     if( !list ) {
865         gcry_sexp_release ( list );
866         return GCRYERR_NO_OBJ; /* no cdr for the data object */
867     }
868     name = gcry_sexp_nth_data( list, 0, &n );
869     if( !name ) {
870         gcry_sexp_release ( list );
871         return GCRYERR_INV_OBJ; /* invalid structure of object */
872     }
873     for(i=0; (s=enc_info_table[i].name); i++ ) {
874         if( strlen(s) == n && !memcmp( s, name, n ) )
875             break;
876     }
877     if( !s ) {
878         gcry_sexp_release ( list );
879         return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
880     }
881
882     algo = enc_info_table[i].algo;
883     elems = enc_info_table[i].elements;
884     array = gcry_calloc( (strlen(elems)+1) , sizeof *array );
885     if( !array ) {
886         gcry_sexp_release ( list );
887         return GCRYERR_NO_MEM;
888     }
889
890     idx = 0;
891     for(s=elems; *s; s++, idx++ ) {
892         l2 = gcry_sexp_find_token( list, s, 1 );
893         if( !l2 ) {
894             gcry_free( array );
895             gcry_sexp_release ( list );
896             return GCRYERR_NO_OBJ; /* required parameter not found */
897         }
898         array[idx] = gcry_sexp_nth_mpi( l2, 1, GCRYMPI_FMT_USG );
899         gcry_sexp_release ( l2 );
900         if( !array[idx] ) {
901             gcry_free( array );
902             gcry_sexp_release ( list );
903             return GCRYERR_INV_OBJ; /* required parameter is invalid */
904         }
905     }
906
907     gcry_sexp_release ( list );
908     *retarray = array;
909     *retalgo = algo;
910
911     return 0;
912 }
913
914
915 /****************
916  * Do a PK encrypt operation
917  *
918  * Caller has to provide a public key as the SEXP pkey and data as a SEXP
919  * with just one MPI in it.  The function returns a a sexp which may
920  * be passed to to pk_decrypt.
921  * Later versions of this functions may take more complex input data, for 
922  * example s_data could have a control tag which allows us to to PKCS-1
923  * encoding directly here.
924  *
925  * Returns: 0 or an errorcode.
926  *
927  * s_data = (<mpi>)
928  * s_pkey = <key-as-defined-in-sexp_to_key>
929  * r_ciph = (enc-val
930  *            (<algo>
931  *              (<param_name1> <mpi>)
932  *              ...
933  *              (<param_namen> <mpi>)
934  *            ))
935  */
936 int
937 gcry_pk_encrypt( GCRY_SEXP *r_ciph, GCRY_SEXP s_data, GCRY_SEXP s_pkey )
938 {
939     MPI *pkey, data, *ciph;
940     const char *algo_name, *algo_elems;
941     int i, rc, algo;
942
943     /* get the key */
944     rc = sexp_to_key( s_pkey, 0, &pkey, &algo, NULL );
945     if( rc ) {
946         return rc;
947     }
948
949     /* get the name and the required size of the return value */
950     for(i=0; (algo_name = enc_info_table[i].name); i++ ) {
951         if( enc_info_table[i].algo == algo )
952             break;
953     }
954     if( !algo_name ) {
955         release_mpi_array( pkey );
956         return GCRYERR_INV_PK_ALGO;
957     }
958     algo_elems = enc_info_table[i].elements;
959
960     /* get the stuff we want to encrypt */
961     data = gcry_sexp_nth_mpi( s_data, 0, 0 );
962     if( !data ) {
963         release_mpi_array( pkey );
964         return GCRYERR_INV_OBJ;
965     }
966
967     /* Now we can encrypt data to ciph */
968     ciph = gcry_xcalloc( (strlen(algo_elems)+1) , sizeof *ciph );
969     rc = pubkey_encrypt( algo, ciph, data, pkey );
970     release_mpi_array( pkey );
971     mpi_free( data );
972     if( rc ) {
973         release_mpi_array( ciph );
974         gcry_free( ciph );
975         return rc;
976     }
977
978     /* We did it.  Now build the return list */
979     {
980         char *string, *p;
981         size_t nelem, needed= strlen(algo_name) + 20;
982
983         /* count elements, so that we can allocate enough space */
984         for(nelem=0; algo_elems[nelem]; nelem++ )
985             needed += 10; /* 6 + a safety margin */
986         /* build the string */
987         string = p = gcry_xmalloc ( needed );
988         p = stpcpy ( p, "(enc-val(" );
989         p = stpcpy ( p, algo_name );
990         for(i=0; algo_elems[i]; i++ ) {
991             *p++ = '(';
992             *p++ = algo_elems[i];
993             p = stpcpy ( p, "%m)" );
994         }
995         strcpy ( p, "))" );
996         /* and now the ugly part:  we don't have a function to
997          * pass an array to a format string, so we have to do it this way :-(
998          */
999         switch ( nelem ) {
1000           case 1: rc = gcry_sexp_build ( r_ciph, NULL, string,
1001                      ciph[0]
1002                   ); break;
1003           case 2: rc = gcry_sexp_build ( r_ciph, NULL, string,
1004                      ciph[0], ciph[1]
1005                   ); break;
1006           case 3: rc = gcry_sexp_build ( r_ciph, NULL, string,
1007                      ciph[0], ciph[1], ciph[2]
1008                   ); break;
1009           case 4: rc = gcry_sexp_build ( r_ciph, NULL, string,
1010                      ciph[0], ciph[1], ciph[2], ciph[3]
1011                   ); break;
1012           case 5: rc = gcry_sexp_build ( r_ciph, NULL, string,
1013                      ciph[0], ciph[1], ciph[2], ciph[3], ciph[4]
1014                   ); break;
1015           case 6: rc = gcry_sexp_build ( r_ciph, NULL, string,
1016                      ciph[0], ciph[1], ciph[2], ciph[3], ciph[4], ciph[5]
1017                   ); break;
1018           default: BUG ();
1019         }
1020         if ( rc )
1021             BUG ();
1022         gcry_free ( string );
1023     }
1024     release_mpi_array( ciph );
1025     gcry_free( ciph );
1026
1027
1028     return 0;
1029 }
1030
1031 /****************
1032  * Do a PK decrypt operation
1033  *
1034  * Caller has to provide a secret key as the SEXP skey and data in a format
1035  * as created by gcry_pk_encrypt.  Currently the function returns
1036  * simply a MPI.  Later versions of this functions may return a more
1037  * complex data structure.
1038  *
1039  * Returns: 0 or an errorcode.
1040  *
1041  * s_data = (enc-val
1042  *            (<algo>
1043  *              (<param_name1> <mpi>)
1044  *              ...
1045  *              (<param_namen> <mpi>)
1046  *            ))
1047  * s_skey = <key-as-defined-in-sexp_to_key>
1048  * r_plain= (<mpi>)   FIXME: Return a more structered value
1049  */
1050 int
1051 gcry_pk_decrypt( GCRY_SEXP *r_plain, GCRY_SEXP s_data, GCRY_SEXP s_skey )
1052 {
1053     MPI *skey, *data, plain;
1054     int rc, algo, dataalgo;
1055
1056     rc = sexp_to_key( s_skey, 1, &skey, &algo, NULL );
1057     if( rc ) {
1058         return rc;
1059     }
1060     rc = sexp_to_enc( s_data, &data, &dataalgo );
1061     if( rc ) {
1062         release_mpi_array( skey );
1063         return rc;
1064     }
1065     if( algo != dataalgo ) {
1066         release_mpi_array( skey );
1067         release_mpi_array( data );
1068         return -1; /* fixme: add real errornumber - algo does not match */
1069     }
1070
1071     rc = pubkey_decrypt( algo, &plain, data, skey );
1072     if( rc ) {
1073         release_mpi_array( skey );
1074         release_mpi_array( data );
1075         return -1; /* fixme: add real errornumber - decryption failed */
1076     }
1077
1078     if ( gcry_sexp_build( r_plain, NULL, "%m", plain ) )
1079         BUG ();
1080
1081     mpi_free( plain );
1082     release_mpi_array( data );
1083     release_mpi_array( skey );
1084     return 0;
1085 }
1086
1087
1088
1089 /****************
1090  * Create a signature.
1091  *
1092  * Caller has to provide a secret key as the SEXP skey and data expressed
1093  * as a SEXP list hash with only one element which should instantly be
1094  * available as a MPI.  Later versions of this functions may provide padding
1095  * and other things depending on data.
1096  *
1097  * Returns: 0 or an errorcode.
1098  *          In case of 0 the function returns a new SEXP with the
1099  *          signature value; the structure of this signature depends on the
1100  *          other arguments but is always suitable to be passed to
1101  *          gcry_pk_verify
1102  *
1103  * s_hash = (<mpi>)
1104  * s_skey = <key-as-defined-in-sexp_to_key>
1105  * r_sig  = (sig-val
1106  *            (<algo>
1107  *              (<param_name1> <mpi>)
1108  *              ...
1109  *              (<param_namen> <mpi>)
1110  *            ))
1111  */
1112 int
1113 gcry_pk_sign( GCRY_SEXP *r_sig, GCRY_SEXP s_hash, GCRY_SEXP s_skey )
1114 {
1115     MPI *skey, hash;
1116     MPI *result;
1117     int i, algo, rc;
1118     const char *key_algo_name, *algo_name, *algo_elems;
1119
1120     rc = sexp_to_key( s_skey, 1, &skey, &algo, &i);
1121     if( rc )
1122         return rc;
1123     key_algo_name = algo_info_table[i].name;
1124     assert (key_algo_name);
1125
1126     /* get the name and the required size of the result array.  We
1127        compare using the algorithm name and not the algo number - this way
1128        we get the correct name for the return value */
1129     for(i=0; (algo_name = sig_info_table[i].name); i++ ) {
1130         if( !strcmp (algo_name, key_algo_name) )
1131             break;
1132     }
1133     if( !algo_name ) {
1134         release_mpi_array( skey );
1135         return -4; /* oops: unknown algorithm */
1136     }
1137     assert (sig_info_table[i].algo == algo);
1138     algo_elems = sig_info_table[i].elements;
1139
1140     /* get the stuff we want to sign */
1141     hash = gcry_sexp_nth_mpi( s_hash, 0, 0 );
1142     if( !hash ) {
1143         release_mpi_array( skey );
1144         return -1; /* fixme: get a real errorcode for this */
1145     }
1146     result = gcry_xcalloc( (strlen(algo_elems)+1) , sizeof *result );
1147     rc = pubkey_sign( algo, result, hash, skey );
1148     release_mpi_array( skey );
1149     mpi_free( hash );
1150     if( rc ) {
1151         gcry_free( result );
1152         return rc;
1153     }
1154
1155     {
1156         char *string, *p;
1157         size_t nelem, needed= strlen(algo_name) + 20;
1158
1159         /* count elements, so that we can allocate enough space */
1160         for(nelem=0; algo_elems[nelem]; nelem++ )
1161             needed += 10; /* 6 + a safety margin */
1162         /* build the string */
1163         string = p = gcry_xmalloc ( needed );
1164         p = stpcpy ( p, "(sig-val(" );
1165         p = stpcpy ( p, algo_name );
1166         for(i=0; algo_elems[i]; i++ ) {
1167             *p++ = '(';
1168             *p++ = algo_elems[i];
1169             p = stpcpy ( p, "%m)" );
1170         }
1171         strcpy ( p, "))" );
1172         /* and now the ugly part:  we don't have a function to
1173          * pass an array to a format string, so we have to do it this way :-(
1174          */
1175         switch ( nelem ) {
1176           case 1: rc = gcry_sexp_build ( r_sig, NULL, string,
1177                      result[0]
1178                   ); break;
1179           case 2: rc = gcry_sexp_build ( r_sig, NULL, string,
1180                      result[0], result[1]
1181                   ); break;
1182           case 3: rc = gcry_sexp_build ( r_sig, NULL, string,
1183                      result[0], result[1], result[2]
1184                   ); break;
1185           case 4: rc = gcry_sexp_build ( r_sig, NULL, string,
1186                      result[0], result[1], result[2], result[3]
1187                   ); break;
1188           case 5: rc = gcry_sexp_build ( r_sig, NULL, string,
1189                      result[0], result[1], result[2], result[3], result[4]
1190                   ); break;
1191           case 6: rc = gcry_sexp_build ( r_sig, NULL, string,
1192                      result[0], result[1], result[2], result[3], result[4], result[5]
1193                   ); break;
1194           default: BUG ();
1195         }
1196         if ( rc )
1197             BUG ();
1198         gcry_free ( string );
1199     }
1200     release_mpi_array( result );
1201     gcry_free( result );
1202
1203     return 0;
1204 }
1205
1206
1207 /****************
1208  * Verify a sgnature.  Caller has to supply the public key pkey,
1209  * the signature sig and his hashvalue data.  Public key has to be
1210  * a standard public key given as an S-Exp, sig is a S-Exp as returned
1211  * from gcry_pk_sign and data must be an S-Exp like the one in sign too.
1212  */
1213 int
1214 gcry_pk_verify( GCRY_SEXP s_sig, GCRY_SEXP s_hash, GCRY_SEXP s_pkey )
1215 {
1216     MPI *pkey, hash, *sig;
1217     int algo, sigalgo;
1218     int rc;
1219
1220     rc = sexp_to_key( s_pkey, 0, &pkey, &algo, NULL );
1221     if( rc )
1222         return rc;
1223     rc = sexp_to_sig( s_sig, &sig, &sigalgo );
1224     if( rc ) {
1225         release_mpi_array( pkey );
1226         return rc;
1227     }
1228     if( algo != sigalgo ) {
1229         release_mpi_array( pkey );
1230         release_mpi_array( sig );
1231         return -1; /* fixme: add real errornumber - algo does not match */
1232     }
1233
1234     hash = gcry_sexp_nth_mpi( s_hash, 0, 0 );
1235     if( !hash ) {
1236         release_mpi_array( pkey );
1237         release_mpi_array( sig );
1238         return -1; /* fixme: get a real errorcode for this */
1239     }
1240
1241     rc = pubkey_verify( algo, hash, sig, pkey, NULL, NULL );
1242     release_mpi_array( pkey );
1243     release_mpi_array( sig );
1244     mpi_free(hash);
1245
1246     return rc;
1247 }
1248
1249
1250 /****************
1251  * Test a key.  This may be used either for a public or a secret key
1252  * to see whether internal structre is valid.
1253  *
1254  * Returns: 0 or an errorcode.
1255  *
1256  * s_key = <key-as-defined-in-sexp_to_key>
1257  */
1258 int
1259 gcry_pk_testkey( GCRY_SEXP s_key )
1260 {
1261     MPI *key;
1262     int rc, algo;
1263
1264     /* Note we currently support only secret key checking */
1265     rc = sexp_to_key( s_key, 1, &key, &algo, NULL );
1266     if( rc ) {
1267         return rc;
1268     }
1269
1270     rc = pubkey_check_secret_key( algo, key );
1271     release_mpi_array( key );
1272     return rc;
1273 }
1274
1275
1276 /****************
1277  * Create a public key pair and return it in r_key.
1278  * How the key is created depends on s_parms:
1279  * (genkey
1280  *  (algo
1281  *    (parameter_name_1 ....)
1282  *     ....
1283  *    (parameter_name_n ....)
1284  * ))
1285  * The key is returned in a format depending on the
1286  * algorithm. Both, private and secret keys are returned
1287  * and optionally some additional informatin.
1288  * For elgamal we return this structure:
1289  * (key-data
1290  *  (public-key
1291  *    (elg
1292  *      (p <mpi>)
1293  *      (g <mpi>)
1294  *      (y <mpi>)
1295  *    )
1296  *  )
1297  *  (private-key
1298  *    (elg
1299  *      (p <mpi>)
1300  *      (g <mpi>)
1301  *      (y <mpi>)
1302  *      (x <mpi>)
1303  *    )
1304  *  )
1305  *  (misc-key-info
1306  *     (pm1-factors n1 n2 ... nn)
1307  *  )
1308  * )
1309  */
1310 int
1311 gcry_pk_genkey( GCRY_SEXP *r_key, GCRY_SEXP s_parms )
1312 {
1313     GCRY_SEXP list, l2;
1314     const char *name;
1315     const char *s;
1316     size_t n;
1317     int rc, i;
1318     const char *algo_name;
1319     int algo;
1320     char sec_elems[20], pub_elems[20];  /* fixme: check bounds */
1321     GCRY_MPI skey[10], *factors;
1322     unsigned int nbits;
1323
1324     list = gcry_sexp_find_token( s_parms, "genkey", 0 );
1325     if( !list )
1326         return GCRYERR_INV_OBJ; /* Does not contain genkey data */
1327     l2 = gcry_sexp_cadr( list );
1328     gcry_sexp_release ( list );
1329     list = l2;
1330     if( !list )
1331         return GCRYERR_NO_OBJ; /* no cdr for the genkey */
1332     name = gcry_sexp_nth_data( list, 0, &n );
1333     if( !name ) {
1334         gcry_sexp_release ( list );
1335         return GCRYERR_INV_OBJ; /* algo string missing */
1336     }
1337     for(i=0; (s=algo_info_table[i].name); i++ ) {
1338         if( strlen(s) == n && !memcmp( s, name, n ) )
1339             break;
1340     }
1341     if( !s ) {
1342         gcry_sexp_release ( list );
1343         return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
1344     }
1345
1346     algo = algo_info_table[i].algo;
1347     algo_name = algo_info_table[i].name;
1348     strcpy( pub_elems, algo_info_table[i].common_elements );
1349     strcat( pub_elems, algo_info_table[i].public_elements );
1350     strcpy( sec_elems, algo_info_table[i].common_elements );
1351     strcat( sec_elems, algo_info_table[i].secret_elements );
1352
1353     l2 = gcry_sexp_find_token( list, "nbits", 0 );
1354     gcry_sexp_release ( list );
1355     list = l2;
1356     if( !list )
1357         return GCRYERR_NO_OBJ; /* no nbits parameter */
1358     name = gcry_sexp_nth_data( list, 1, &n );
1359     if( !name ) {
1360         gcry_sexp_release ( list );
1361         return GCRYERR_INV_OBJ; /* nbits without a cdr */
1362     }
1363     {
1364         char *p = gcry_xmalloc(n+1);
1365         memcpy(p, name, n );
1366         p[n] = 0;
1367         nbits = (unsigned int)strtol( p, NULL, 0 );
1368         gcry_free( p );
1369     }
1370     gcry_sexp_release ( list );
1371
1372     rc = pubkey_generate( algo, nbits, skey, &factors );
1373     if( rc ) {
1374         return rc;
1375     }
1376
1377     {
1378         char *string, *p;
1379         size_t nelem=0, needed=0;
1380         GCRY_MPI mpis[30];
1381
1382
1383         /* count elements, so that we can allocate enough space */
1384         for(i=0; pub_elems[i]; i++, nelem++ )
1385             needed += 10; /* 6 + a safety margin */
1386         for(i=0; sec_elems[i]; i++, nelem++ )
1387             needed += 10; /* 6 + a safety margin */
1388         for(i=0; factors[i]; i++, nelem++ )
1389             needed += 10; /* 6 + a safety margin */
1390         needed += 2* strlen(algo_name) +  300;
1391         if ( nelem > DIM(mpis) )
1392             BUG ();
1393
1394         /* build the string */
1395         nelem = 0;
1396         string = p = gcry_xmalloc ( needed );
1397         p = stpcpy ( p, "(key-data" );
1398
1399         p = stpcpy ( p, "(public-key(" );
1400         p = stpcpy ( p, algo_name );
1401         for(i=0; pub_elems[i]; i++ ) {
1402             *p++ = '(';
1403             *p++ = pub_elems[i];
1404             p = stpcpy ( p, "%m)" );
1405             mpis[nelem++] = skey[i];
1406         }
1407         p = stpcpy ( p, "))" );
1408
1409         p = stpcpy ( p, "(private-key(" );
1410         p = stpcpy ( p, algo_name );
1411         for(i=0; sec_elems[i]; i++ ) {
1412             *p++ = '(';
1413             *p++ = sec_elems[i];
1414             p = stpcpy ( p, "%m)" );
1415             mpis[nelem++] = skey[i];
1416         }
1417         p = stpcpy ( p, "))" );
1418         /* Very ugly hack to make release_mpi_array() work FIXME */
1419         skey[i] = NULL;
1420
1421         p = stpcpy ( p, "(misc-key-info(pm1-factors" );
1422         for(i=0; factors[i]; i++ ) {
1423             p = stpcpy ( p, "%m" );
1424             mpis[nelem++] = factors[i];
1425         }
1426         strcpy ( p, ")))" );
1427
1428         while ( nelem < DIM(mpis) )
1429             mpis[nelem++] = NULL;
1430
1431         /* and now the ugly part:  we don't have a function to
1432          * pass an array to a format string, so we have just pass everything
1433          * we have. which normally should be no problem as only those
1434          * with a corresponding %m are used
1435          */
1436         if ( gcry_sexp_build ( r_key, NULL, string,
1437                    mpis[0], mpis[1], mpis[2], mpis[3], mpis[4], mpis[5],
1438                    mpis[6], mpis[7], mpis[8], mpis[9], mpis[10], mpis[11],
1439                    mpis[12], mpis[13], mpis[14], mpis[15], mpis[16], mpis[17],
1440                    mpis[18], mpis[19], mpis[20], mpis[21], mpis[22], mpis[23],
1441                    mpis[24], mpis[25], mpis[26], mpis[27], mpis[28], mpis[29]
1442                   ) )
1443             BUG ();
1444         assert ( DIM(mpis) == 30 );
1445         gcry_free ( string );
1446     }
1447     release_mpi_array ( skey );
1448     release_mpi_array ( factors );
1449
1450     return 0;
1451 }
1452
1453 /****************
1454  * Get the number of nbits from the public key
1455  * Hmmm: Should we have really this function or is it
1456  * better to have a more general function to retrieve
1457  * different propoerties of the key?
1458  */
1459 unsigned int
1460 gcry_pk_get_nbits( GCRY_SEXP key )
1461 {
1462     int rc, i, algo;
1463     MPI *keyarr;
1464     unsigned int nbits = 0;
1465
1466     rc = sexp_to_key( key, 0, &keyarr, &algo, NULL );
1467     if( rc == GCRYERR_INV_OBJ )
1468         rc = sexp_to_key( key, 1, &keyarr, &algo, NULL );
1469     if( rc )
1470         return 0;
1471
1472     do {
1473         for(i=0; pubkey_table[i].name; i++ )
1474             if( pubkey_table[i].algo == algo ) {
1475                 nbits = (*pubkey_table[i].get_nbits)( algo, keyarr );
1476                 goto leave;
1477             }
1478     } while( load_pubkey_modules() );
1479     if( is_RSA(algo) )  /* we always wanna see the length of a key :-) */
1480         nbits = mpi_get_nbits( keyarr[0] );
1481   leave:
1482     release_mpi_array( keyarr );
1483     return nbits;
1484 }
1485
1486
1487
1488 int
1489 gcry_pk_ctl( int cmd, void *buffer, size_t buflen)
1490 {
1491     switch( cmd ) {
1492       case GCRYCTL_DISABLE_ALGO:
1493         /* this one expects a buffer pointing to an
1494          * integer with the algo number.
1495          */
1496         if( !buffer || buflen != sizeof(int) )
1497             return set_lasterr( GCRYERR_INV_CIPHER_ALGO );
1498         disable_pubkey_algo( *(int*)buffer );
1499         break;
1500
1501       default:
1502         return set_lasterr( GCRYERR_INV_OP );
1503     }
1504     return 0;
1505 }
1506
1507
1508 /****************
1509  * Return information about the given algorithm
1510  * WHAT select the kind of information returned:
1511  *  GCRYCTL_TEST_ALGO:
1512  *      Returns 0 when the specified algorithm is available for use.
1513  *      Buffer must be NULL, nbytes  may have the address of a variable
1514  *      with the required usage of the algorithm. It may be 0 for don't
1515  *      care or a combination of the GCRY_PK_USAGE_xxx flags;
1516  *  GCRYCTL_GET_ALGO_USAGE:
1517  *      Return the usage glafs for the give algo.  An invalid alog
1518  *      does return 0.  Disabled algos are ignored here becuase we
1519  *      only want to know whether the algo is at all capable of
1520  *      the usage.
1521  *
1522  * On error the value -1 is returned and the error reason may be
1523  * retrieved by gcry_errno().
1524  * Note:  Because this function is in most caes used to return an
1525  * integer value, we can make it easier for the caller to just look at
1526  * the return value.  The caller will in all cases consult the value
1527  * and thereby detecting whether a error occured or not (i.e. while checking
1528  * the block size)
1529  */
1530 int
1531 gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes)
1532 {
1533     switch( what ) {
1534       case GCRYCTL_TEST_ALGO: {
1535             int use = nbytes? *nbytes: 0;
1536             if( buffer ) {
1537                 set_lasterr( GCRYERR_INV_ARG );
1538                 return -1;
1539             }
1540             if( check_pubkey_algo( algo, use ) ) {
1541                 set_lasterr( GCRYERR_INV_PK_ALGO );
1542                 return -1;
1543             }
1544         }
1545         break;
1546
1547       case GCRYCTL_GET_ALGO_USAGE: 
1548           do {
1549               int i;
1550               for(i=0; pubkey_table[i].name; i++ )
1551                   if( pubkey_table[i].algo == algo ) 
1552                       return pubkey_table[i].use;
1553           } while( load_pubkey_modules() );
1554           return 0;
1555          
1556       case GCRYCTL_GET_ALGO_NPKEY: return pubkey_get_npkey( algo );
1557       case GCRYCTL_GET_ALGO_NSKEY: return pubkey_get_nskey( algo );
1558       case GCRYCTL_GET_ALGO_NSIGN: return pubkey_get_nsig( algo );
1559       case GCRYCTL_GET_ALGO_NENCR: return pubkey_get_nenc( algo );
1560
1561       default:
1562         set_lasterr( GCRYERR_INV_OP );
1563         return -1;
1564     }
1565     return 0;
1566 }
1567
1568