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