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