* pubkey.c (gcry_pk_get_keygrip): Implemented keygrips for DSA
[libgcrypt.git] / cipher / pubkey.c
1 /* pubkey.c  -  pubkey dispatcher
2  * Copyright (C) 1998,1999,2000,2002,2003 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser general Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #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 {
62   const char* name; int algo;
63   const char* common_elements;
64   const char* public_elements;
65   const char* secret_elements;
66   const char* grip_elements;
67 } algo_info_table[] = {
68   { "dsa"        ,      PUBKEY_ALGO_DSA       , "pqgy", "", "x",    "pqgy" },
69   { "rsa"        ,      PUBKEY_ALGO_RSA       , "ne",   "", "dpqu", "n" },
70   { "elg"        ,      PUBKEY_ALGO_ELGAMAL   , "pgy",  "", "x",    "pgy"  },
71   { "openpgp-dsa",      PUBKEY_ALGO_DSA       , "pqgy", "", "x",    "pqgy" },
72   { "openpgp-rsa",      PUBKEY_ALGO_RSA       , "ne",   "", "dpqu"  "n"},
73   { "openpgp-elg",      PUBKEY_ALGO_ELGAMAL_E , "pgy",  "", "x",    "pgy" },
74   { "openpgp-elg-sig",  PUBKEY_ALGO_ELGAMAL   , "pgy",  "", "x",    "pgy" },
75   { "oid.1.2.840.113549.1.1.1",
76                         PUBKEY_ALGO_RSA       , "ne",   "", "dpqu", "n" },
77   { NULL }
78 };
79
80 static struct {
81     const char* name; int algo;
82     const char* elements;
83 } sig_info_table[] = {
84   { "dsa"                     , PUBKEY_ALGO_DSA       , "rs" },
85   { "rsa"                     , PUBKEY_ALGO_RSA       , "s"  },
86   { "elg"                     , PUBKEY_ALGO_ELGAMAL   , "rs" },
87   { "openpgp-dsa"             , PUBKEY_ALGO_DSA       , "rs" },
88   { "openpgp-rsa"             , PUBKEY_ALGO_RSA       , "s"  },
89   { "openpgp-elg-sig"         , PUBKEY_ALGO_ELGAMAL   , "rs" },
90   { "oid.1.2.840.113549.1.1.1", PUBKEY_ALGO_RSA       , "s"  },
91   { NULL }
92 };
93
94 static struct {
95     const char* name; int algo;
96     const char* elements;
97 } enc_info_table[] = {
98   { "elg"            ,          PUBKEY_ALGO_ELGAMAL   , "ab" },
99   { "rsa"            ,          PUBKEY_ALGO_RSA       , "a"  },
100   { "openpgp-rsa"    ,          PUBKEY_ALGO_RSA       , "a"  },
101   { "openpgp-elg"    ,          PUBKEY_ALGO_ELGAMAL_E , "ab" },
102   { "openpgp-elg-sig",          PUBKEY_ALGO_ELGAMAL   , "ab" },
103   { "oid.1.2.840.113549.1.1.1", PUBKEY_ALGO_RSA       , "a"  },
104   { NULL }
105 };
106
107
108 static int pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
109 static int pubkey_sign( int algo, MPI *resarr, MPI hash, MPI *skey );
110 static int pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
111                       int (*cmp)(void *, MPI), void *opaque );
112
113 static int
114 dummy_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
115 { log_bug("no generate() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
116
117 static int
118 dummy_check_secret_key( int algo, MPI *skey )
119 { log_bug("no check_secret_key() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
120
121 static int
122 dummy_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
123 { log_bug("no encrypt() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
124
125 static int
126 dummy_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
127 { log_bug("no decrypt() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
128
129 static int
130 dummy_sign( int algo, MPI *resarr, MPI data, MPI *skey )
131 { log_bug("no sign() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
132
133 static int
134 dummy_verify( int algo, MPI hash, MPI *data, MPI *pkey,
135                 int (*cmp)(void *, MPI), void *opaquev )
136 { log_bug("no verify() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
137
138 static unsigned
139 dummy_get_nbits( int algo, MPI *pkey )
140 { log_bug("no get_nbits() for %d\n", algo ); return 0; }
141
142
143 /****************
144  * Put the static entries into the table.
145  * This is out constructor function which fill the table
146  * of algorithms with the one we have statically linked.
147  */
148 static void
149 setup_pubkey_table(void)
150 {
151     int i;
152
153     i = 0;
154     pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL;
155     pubkey_table[i].name = _gcry_elg_get_info( pubkey_table[i].algo,
156                                          &pubkey_table[i].npkey,
157                                          &pubkey_table[i].nskey,
158                                          &pubkey_table[i].nenc,
159                                          &pubkey_table[i].nsig,
160                                          &pubkey_table[i].use );
161     pubkey_table[i].generate         = _gcry_elg_generate;
162     pubkey_table[i].check_secret_key = _gcry_elg_check_secret_key;
163     pubkey_table[i].encrypt          = _gcry_elg_encrypt;
164     pubkey_table[i].decrypt          = _gcry_elg_decrypt;
165     pubkey_table[i].sign             = _gcry_elg_sign;
166     pubkey_table[i].verify           = _gcry_elg_verify;
167     pubkey_table[i].get_nbits        = _gcry_elg_get_nbits;
168     if( !pubkey_table[i].name )
169         BUG();
170     i++;
171     pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL_E;
172     pubkey_table[i].name = _gcry_elg_get_info( pubkey_table[i].algo,
173                                          &pubkey_table[i].npkey,
174                                          &pubkey_table[i].nskey,
175                                          &pubkey_table[i].nenc,
176                                          &pubkey_table[i].nsig,
177                                          &pubkey_table[i].use );
178     pubkey_table[i].generate         = _gcry_elg_generate;
179     pubkey_table[i].check_secret_key = _gcry_elg_check_secret_key;
180     pubkey_table[i].encrypt          = _gcry_elg_encrypt;
181     pubkey_table[i].decrypt          = _gcry_elg_decrypt;
182     pubkey_table[i].sign             = _gcry_elg_sign;
183     pubkey_table[i].verify           = _gcry_elg_verify;
184     pubkey_table[i].get_nbits        = _gcry_elg_get_nbits;
185     if( !pubkey_table[i].name )
186         BUG();
187     i++;
188     pubkey_table[i].algo = PUBKEY_ALGO_DSA;
189     pubkey_table[i].name = _gcry_dsa_get_info( pubkey_table[i].algo,
190                                          &pubkey_table[i].npkey,
191                                          &pubkey_table[i].nskey,
192                                          &pubkey_table[i].nenc,
193                                          &pubkey_table[i].nsig,
194                                          &pubkey_table[i].use );
195     pubkey_table[i].generate         = _gcry_dsa_generate;
196     pubkey_table[i].check_secret_key = _gcry_dsa_check_secret_key;
197     pubkey_table[i].encrypt          = dummy_encrypt;
198     pubkey_table[i].decrypt          = dummy_decrypt;
199     pubkey_table[i].sign             = _gcry_dsa_sign;
200     pubkey_table[i].verify           = _gcry_dsa_verify;
201     pubkey_table[i].get_nbits        = _gcry_dsa_get_nbits;
202     if( !pubkey_table[i].name )
203         BUG();
204     i++;
205
206     pubkey_table[i].algo = PUBKEY_ALGO_RSA;
207     pubkey_table[i].name = _gcry_rsa_get_info( pubkey_table[i].algo,
208                                          &pubkey_table[i].npkey,
209                                          &pubkey_table[i].nskey,
210                                          &pubkey_table[i].nenc,
211                                          &pubkey_table[i].nsig,
212                                          &pubkey_table[i].use );
213     pubkey_table[i].generate         = _gcry_rsa_generate;
214     pubkey_table[i].check_secret_key = _gcry_rsa_check_secret_key;
215     pubkey_table[i].encrypt          = _gcry_rsa_encrypt;
216     pubkey_table[i].decrypt          = _gcry_rsa_decrypt;
217     pubkey_table[i].sign             = _gcry_rsa_sign;
218     pubkey_table[i].verify           = _gcry_rsa_verify;
219     pubkey_table[i].get_nbits        = _gcry_rsa_get_nbits;
220     if( !pubkey_table[i].name )
221         BUG();
222     i++;
223     pubkey_table[i].algo = PUBKEY_ALGO_RSA_E;
224     pubkey_table[i].name = _gcry_rsa_get_info( pubkey_table[i].algo,
225                                          &pubkey_table[i].npkey,
226                                          &pubkey_table[i].nskey,
227                                          &pubkey_table[i].nenc,
228                                          &pubkey_table[i].nsig,
229                                          &pubkey_table[i].use );
230     pubkey_table[i].generate         = _gcry_rsa_generate;
231     pubkey_table[i].check_secret_key = _gcry_rsa_check_secret_key;
232     pubkey_table[i].encrypt          = _gcry_rsa_encrypt;
233     pubkey_table[i].decrypt          = _gcry_rsa_decrypt;
234     pubkey_table[i].sign             = dummy_sign;
235     pubkey_table[i].verify           = dummy_verify;
236     pubkey_table[i].get_nbits        = _gcry_rsa_get_nbits;
237     if( !pubkey_table[i].name )
238         BUG();
239     i++;
240     pubkey_table[i].algo = PUBKEY_ALGO_RSA_S;
241     pubkey_table[i].name = _gcry_rsa_get_info( pubkey_table[i].algo,
242                                          &pubkey_table[i].npkey,
243                                          &pubkey_table[i].nskey,
244                                          &pubkey_table[i].nenc,
245                                          &pubkey_table[i].nsig,
246                                          &pubkey_table[i].use );
247     pubkey_table[i].generate         = _gcry_rsa_generate;
248     pubkey_table[i].check_secret_key = _gcry_rsa_check_secret_key;
249     pubkey_table[i].encrypt          = dummy_encrypt;
250     pubkey_table[i].decrypt          = dummy_decrypt;
251     pubkey_table[i].sign             = _gcry_rsa_sign;
252     pubkey_table[i].verify           = _gcry_rsa_verify;
253     pubkey_table[i].get_nbits        = _gcry_rsa_get_nbits;
254     if( !pubkey_table[i].name )
255         BUG();
256     i++;
257
258     for( ; i < TABLE_SIZE; i++ )
259         pubkey_table[i].name = NULL;
260 }
261
262 static void
263 release_mpi_array( MPI *array )
264 {
265     for( ; *array; array++ ) {
266         mpi_free(*array);
267         *array = NULL;
268     }
269 }
270
271 /****************
272  * Try to load all modules and return true if new modules are available
273  */
274 static int
275 load_pubkey_modules(void)
276 {
277     static int initialized = 0;
278     static int done = 0;
279     void *context = NULL;
280     struct pubkey_table_s *ct;
281     int ct_idx;
282     int i;
283     const char *name;
284     int any = 0;
285
286
287     if( !initialized ) {
288         _gcry_cipher_modules_constructor();
289         setup_pubkey_table();
290         initialized = 1;
291         return 1;
292     }
293     if( done )
294         return 0;
295     done = 1;
296     for(ct_idx=0, ct = pubkey_table; ct_idx < TABLE_SIZE; ct_idx++,ct++ ) {
297         if( !ct->name )
298             break;
299     }
300     if( ct_idx >= TABLE_SIZE-1 )
301         BUG(); /* table already full */
302     /* now load all extensions */
303     while( (name = _gcry_enum_gnupgext_pubkeys( &context, &ct->algo,
304                                 &ct->npkey, &ct->nskey, &ct->nenc,
305                                 &ct->nsig,  &ct->use,
306                                 &ct->generate,
307                                 &ct->check_secret_key,
308                                 &ct->encrypt,
309                                 &ct->decrypt,
310                                 &ct->sign,
311                                 &ct->verify,
312                                 &ct->get_nbits )) ) {
313         for(i=0; pubkey_table[i].name; i++ )
314             if( pubkey_table[i].algo == ct->algo )
315                 break;
316         if( pubkey_table[i].name ) {
317             log_info("skipping pubkey %d: already loaded\n", ct->algo );
318             continue;
319         }
320
321         if( !ct->generate  )  ct->generate = dummy_generate;
322         if( !ct->check_secret_key )  ct->check_secret_key =
323                                                     dummy_check_secret_key;
324         if( !ct->encrypt   )  ct->encrypt  = dummy_encrypt;
325         if( !ct->decrypt   )  ct->decrypt  = dummy_decrypt;
326         if( !ct->sign      )  ct->sign     = dummy_sign;
327         if( !ct->verify    )  ct->verify   = dummy_verify;
328         if( !ct->get_nbits )  ct->get_nbits= dummy_get_nbits;
329         /* put it into the table */
330         if( _gcry_log_verbosity( 2 ) )
331             log_info("loaded pubkey %d (%s)\n", ct->algo, name);
332         ct->name = name;
333         ct_idx++;
334         ct++;
335         any = 1;
336         /* check whether there are more available table slots */
337         if( ct_idx >= TABLE_SIZE-1 ) {
338             log_info("pubkey table full; ignoring other extensions\n");
339             break;
340         }
341     }
342     _gcry_enum_gnupgext_pubkeys( &context, NULL, NULL, NULL, NULL, NULL, NULL,
343                                NULL, NULL, NULL, NULL, NULL, NULL, NULL );
344     return any;
345 }
346
347
348 /****************
349  * Map a string to the pubkey algo
350  */
351 int
352 gcry_pk_map_name( const char *string )
353 {
354     int i;
355     const char *s;
356
357     do {
358         for(i=0; (s=pubkey_table[i].name); i++ )
359             if( !stricmp( s, string ) )
360                 return pubkey_table[i].algo;
361     } while( load_pubkey_modules() );
362     return 0;
363 }
364
365
366 /****************
367  * Map a pubkey algo to a string
368  */
369 const char *
370 gcry_pk_algo_name( int algo )
371 {
372     int i;
373
374     do {
375         for(i=0; pubkey_table[i].name; i++ )
376             if( pubkey_table[i].algo == algo )
377                 return pubkey_table[i].name;
378     } while( load_pubkey_modules() );
379     return NULL;
380 }
381
382
383 static void
384 disable_pubkey_algo( int algo )
385 {
386     int i;
387
388     for(i=0; i < DIM(disabled_algos); i++ ) {
389         if( !disabled_algos[i] || disabled_algos[i] == algo ) {
390             disabled_algos[i] = algo;
391             return;
392         }
393     }
394     log_fatal("can't disable pubkey algo %d: table full\n", algo );
395 }
396
397
398 /****************
399  * a use of 0 means: don't care
400  */
401 static int
402 check_pubkey_algo( int algo, unsigned use )
403 {
404     int i;
405
406     do {
407         for(i=0; pubkey_table[i].name; i++ )
408             if( pubkey_table[i].algo == algo ) {
409                 if( (use & GCRY_PK_USAGE_SIGN)
410                     && !(pubkey_table[i].use & GCRY_PK_USAGE_SIGN) )
411                     return GCRYERR_WRONG_PK_ALGO;
412                 if( (use & GCRY_PK_USAGE_ENCR)
413                     && !(pubkey_table[i].use & GCRY_PK_USAGE_ENCR) )
414                     return GCRYERR_WRONG_PK_ALGO;
415
416                 for(i=0; i < DIM(disabled_algos); i++ ) {
417                     if( disabled_algos[i] == algo )
418                         return GCRYERR_INV_PK_ALGO;
419                 }
420                 return 0; /* okay */
421             }
422     } while( load_pubkey_modules() );
423     return GCRYERR_INV_PK_ALGO;
424 }
425
426
427
428
429 /****************
430  * Return the number of public key material numbers
431  */
432 static int
433 pubkey_get_npkey( int algo )
434 {
435     int i;
436     do {
437         for(i=0; pubkey_table[i].name; i++ )
438             if( pubkey_table[i].algo == algo )
439                 return pubkey_table[i].npkey;
440     } while( load_pubkey_modules() );
441     return 0;
442 }
443
444 /****************
445  * Return the number of secret key material numbers
446  */
447 static int
448 pubkey_get_nskey( int algo )
449 {
450     int i;
451     do {
452         for(i=0; pubkey_table[i].name; i++ )
453             if( pubkey_table[i].algo == algo )
454                 return pubkey_table[i].nskey;
455     } while( load_pubkey_modules() );
456     return 0;
457 }
458
459 /****************
460  * Return the number of signature material numbers
461  */
462 static int
463 pubkey_get_nsig( int algo )
464 {
465     int i;
466     do {
467         for(i=0; pubkey_table[i].name; i++ )
468             if( pubkey_table[i].algo == algo )
469                 return pubkey_table[i].nsig;
470     } while( load_pubkey_modules() );
471     return 0;
472 }
473
474 /****************
475  * Return the number of encryption material numbers
476  */
477 static int
478 pubkey_get_nenc( int algo )
479 {
480     int i;
481     do {
482         for(i=0; pubkey_table[i].name; i++ )
483             if( pubkey_table[i].algo == algo )
484                 return pubkey_table[i].nenc;
485     } while( load_pubkey_modules() );
486     return 0;
487 }
488
489
490 static int
491 pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
492 {
493     int i;
494
495     do {
496         for(i=0; pubkey_table[i].name; i++ )
497             if( pubkey_table[i].algo == algo )
498                 return (*pubkey_table[i].generate)( algo, nbits,
499                                                     skey, retfactors );
500     } while( load_pubkey_modules() );
501     return GCRYERR_INV_PK_ALGO;
502 }
503
504
505 static int
506 pubkey_check_secret_key( int algo, MPI *skey )
507 {
508     int i;
509
510     do {
511         for(i=0; pubkey_table[i].name; i++ )
512             if( pubkey_table[i].algo == algo )
513                 return (*pubkey_table[i].check_secret_key)( algo, skey );
514     } while( load_pubkey_modules() );
515     return GCRYERR_INV_PK_ALGO;
516 }
517
518
519 /****************
520  * This is the interface to the public key encryption.
521  * Encrypt DATA with PKEY and put it into RESARR which
522  * should be an array of MPIs of size PUBKEY_MAX_NENC (or less if the
523  * algorithm allows this - check with pubkey_get_nenc() )
524  */
525 static int
526 pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
527 {
528     int i, rc;
529
530     if( DBG_CIPHER ) {
531         log_debug("pubkey_encrypt: algo=%d\n", algo );
532         for(i=0; i < pubkey_get_npkey(algo); i++ )
533             log_mpidump("  pkey:", pkey[i] );
534         log_mpidump("  data:", data );
535     }
536
537     do {
538         for(i=0; pubkey_table[i].name; i++ )
539             if( pubkey_table[i].algo == algo ) {
540                 rc = (*pubkey_table[i].encrypt)( algo, resarr, data, pkey );
541                 goto ready;
542             }
543     } while( load_pubkey_modules() );
544     rc = GCRYERR_INV_PK_ALGO;
545   ready:
546     if( !rc && DBG_CIPHER ) {
547         for(i=0; i < pubkey_get_nenc(algo); i++ )
548             log_mpidump("  encr:", resarr[i] );
549     }
550     return rc;
551 }
552
553
554
555 /****************
556  * This is the interface to the public key decryption.
557  * ALGO gives the algorithm to use and this implicitly determines
558  * the size of the arrays.
559  * result is a pointer to a mpi variable which will receive a
560  * newly allocated mpi or NULL in case of an error.
561  */
562 static int
563 pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
564 {
565     int i, rc;
566
567     *result = NULL; /* so the caller can always do a mpi_free */
568     if( DBG_CIPHER ) {
569         log_debug("pubkey_decrypt: algo=%d\n", algo );
570         for(i=0; i < pubkey_get_nskey(algo); i++ )
571             log_mpidump("  skey:", skey[i] );
572         for(i=0; i < pubkey_get_nenc(algo); i++ )
573             log_mpidump("  data:", data[i] );
574     }
575
576     do {
577         for(i=0; pubkey_table[i].name; i++ )
578             if( pubkey_table[i].algo == algo ) {
579                 rc = (*pubkey_table[i].decrypt)( algo, result, data, skey );
580                 goto ready;
581             }
582     } while( load_pubkey_modules() );
583     rc = GCRYERR_INV_PK_ALGO;
584   ready:
585     if( !rc && DBG_CIPHER ) {
586         log_mpidump(" plain:", *result );
587     }
588     return rc;
589 }
590
591
592 /****************
593  * This is the interface to the public key signing.
594  * Sign data with skey and put the result into resarr which
595  * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the
596  * algorithm allows this - check with pubkey_get_nsig() )
597  */
598 static int
599 pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
600 {
601     int i, rc;
602
603     if( DBG_CIPHER ) {
604         log_debug("pubkey_sign: algo=%d\n", algo );
605         for(i=0; i < pubkey_get_nskey(algo); i++ )
606             log_mpidump("  skey:", skey[i] );
607         log_mpidump("  data:", data );
608     }
609
610     do {
611         for(i=0; pubkey_table[i].name; i++ )
612             if( pubkey_table[i].algo == algo ) {
613                 rc = (*pubkey_table[i].sign)( algo, resarr, data, skey );
614                 goto ready;
615             }
616     } while( load_pubkey_modules() );
617     rc = GCRYERR_INV_PK_ALGO;
618   ready:
619     if( !rc && DBG_CIPHER ) {
620         for(i=0; i < pubkey_get_nsig(algo); i++ )
621             log_mpidump("   sig:", resarr[i] );
622     }
623     return rc;
624 }
625
626 /****************
627  * Verify a public key signature.
628  * Return 0 if the signature is good
629  */
630 static int
631 pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
632                     int (*cmp)(void *, MPI), void *opaquev )
633 {
634     int i, rc;
635
636     if( DBG_CIPHER ) {
637         log_debug("pubkey_verify: algo=%d\n", algo );
638         for(i=0; i < pubkey_get_npkey(algo); i++ )
639             log_mpidump("  pkey:", pkey[i] );
640         for(i=0; i < pubkey_get_nsig(algo); i++ )
641             log_mpidump("   sig:", data[i] );
642         log_mpidump("  hash:", hash );
643     }
644
645     do {
646         for(i=0; pubkey_table[i].name; i++ )
647             if( pubkey_table[i].algo == algo ) {
648                 rc = (*pubkey_table[i].verify)( algo, hash, data, pkey,
649                                                             cmp, opaquev );
650                 goto ready;
651             }
652     } while( load_pubkey_modules() );
653     rc = GCRYERR_INV_PK_ALGO;
654   ready:
655     return rc;
656 }
657
658
659
660 /****************
661  * Convert a S-Exp with either a private or a public key to our
662  * internal format. Currently we do only support the following
663  * algorithms:
664  *    dsa
665  *    rsa
666  *    openpgp-dsa
667  *    openpgp-rsa
668  *    openpgp-elg
669  *    openpgp-elg-sig
670  * Provide a SE with the first element be either "private-key" or
671  * or "public-key". the followed by a list with its first element
672  * be one of the above algorithm identifiers and the following
673  * elements are pairs with parameter-id and value.
674  * NOTE: we look through the list to find a list beginning with
675  * "private-key" or "public-key" - the first one found is used.
676  *
677  * FIXME: Allow for encrypted secret keys here.
678  *
679  * Returns: A pointer to an allocated array of MPIs if the return value is
680  *          zero; the caller has to release this array.
681  *
682  * Example of a DSA public key:
683  *  (private-key
684  *    (dsa
685  *      (p <mpi>)
686  *      (g <mpi>)
687  *      (y <mpi>)
688  *      (x <mpi>)
689  *    )
690  *  )
691  * The <mpi> are expected to be in GCRYMPI_FMT_USG
692  */
693 static int
694 sexp_to_key( GCRY_SEXP sexp, int want_private, MPI **retarray,
695              int *retalgo, int *r_algotblidx)
696 {
697     GCRY_SEXP list, l2;
698     const char *name;
699     const char *s;
700     size_t n;
701     int i, idx;
702     int algo;
703     const char *elems1, *elems2;
704     GCRY_MPI *array;
705
706     /* check that the first element is valid */
707     list = gcry_sexp_find_token( sexp, want_private? "private-key"
708                                                     :"public-key", 0 );
709     if( !list )
710         return GCRYERR_INV_OBJ; /* Does not contain a public- or private-key object */
711     l2 = gcry_sexp_cadr( list );
712     gcry_sexp_release ( list );
713     list = l2;
714     name = gcry_sexp_nth_data( list, 0, &n );
715     if( !name ) {
716         gcry_sexp_release ( list );
717         return GCRYERR_INV_OBJ; /* invalid structure of object */
718     }
719     for(i=0; (s=algo_info_table[i].name); i++ ) {
720         if( strlen(s) == n && !memcmp( s, name, n ) )
721             break;
722     }
723     if( !s ) {
724         gcry_sexp_release ( list );
725         return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
726     }
727     if (r_algotblidx)
728       *r_algotblidx = i;
729     algo = algo_info_table[i].algo;
730     elems1 = algo_info_table[i].common_elements;
731     elems2 = want_private? algo_info_table[i].secret_elements
732                          : algo_info_table[i].public_elements;
733     array = gcry_calloc( strlen(elems1)+strlen(elems2)+1, sizeof *array );
734     if( !array ) {
735         gcry_sexp_release ( list );
736         return GCRYERR_NO_MEM;
737     }
738
739     idx = 0;
740     for(s=elems1; *s; s++, idx++ ) {
741         l2 = gcry_sexp_find_token( list, s, 1 );
742         if( !l2 ) {
743             for(i=0; i<idx; i++)
744                 gcry_free( array[i] );
745             gcry_free( array );
746             gcry_sexp_release ( list );
747             return GCRYERR_NO_OBJ; /* required parameter not found */
748         }
749         array[idx] = gcry_sexp_nth_mpi( l2, 1, GCRYMPI_FMT_USG );
750         gcry_sexp_release ( l2 );
751         if( !array[idx] ) {
752             for(i=0; i<idx; i++)
753                 gcry_free( array[i] );
754             gcry_free( array );
755             gcry_sexp_release ( list );
756             return GCRYERR_INV_OBJ; /* required parameter is invalid */
757         }
758     }
759     for(s=elems2; *s; s++, idx++ ) {
760         l2 = gcry_sexp_find_token( list, s, 1 );
761         if( !l2 ) {
762             for(i=0; i<idx; i++)
763                 gcry_free( array[i] );
764             gcry_free( array );
765             gcry_sexp_release ( list );
766             return GCRYERR_NO_OBJ; /* required parameter not found */
767         }
768         array[idx] = gcry_sexp_nth_mpi( l2, 1, GCRYMPI_FMT_USG );
769         gcry_sexp_release ( l2 );
770         if( !array[idx] ) {
771             for(i=0; i<idx; i++)
772                 gcry_free( array[i] );
773             gcry_free( array );
774             gcry_sexp_release ( list );
775             return GCRYERR_INV_OBJ; /* required parameter is invalid */
776         }
777     }
778
779     gcry_sexp_release ( list );
780     *retarray = array;
781     *retalgo = algo;
782
783     return 0;
784 }
785
786 static int
787 sexp_to_sig( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
788 {
789     GCRY_SEXP list, l2;
790     const char *name;
791     const char *s;
792     size_t n;
793     int i, idx;
794     int algo;
795     const char *elems;
796     GCRY_MPI *array;
797
798     /* check that the first element is valid */
799     list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
800     if( !list )
801         return GCRYERR_INV_OBJ; /* Does not contain a signature value object */
802     l2 = gcry_sexp_cadr( list );
803     gcry_sexp_release ( list );
804     list = l2;
805     if( !list )
806         return GCRYERR_NO_OBJ; /* no cadr for the sig object */
807     name = gcry_sexp_nth_data( list, 0, &n );
808     if( !name ) {
809         gcry_sexp_release ( list );
810         return GCRYERR_INV_OBJ; /* invalid structure of object */
811     }
812     for(i=0; (s=sig_info_table[i].name); i++ ) {
813         if( strlen(s) == n && !memcmp( s, name, n ) )
814             break;
815     }
816     if( !s ) {
817         gcry_sexp_release ( list );
818         return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
819     }
820     algo = sig_info_table[i].algo;
821     elems = sig_info_table[i].elements;
822     array = gcry_calloc( (strlen(elems)+1) , sizeof *array );
823     if( !array ) {
824         gcry_sexp_release ( list );
825         return GCRYERR_NO_MEM;
826     }
827
828     idx = 0;
829     for(s=elems; *s; s++, idx++ ) {
830         l2 = gcry_sexp_find_token( list, s, 1 );
831         if( !l2 ) {
832             gcry_free( array );
833             gcry_sexp_release ( list );
834             return GCRYERR_NO_OBJ; /* required parameter not found */
835         }
836         array[idx] = gcry_sexp_nth_mpi( l2, 1, GCRYMPI_FMT_USG );
837         gcry_sexp_release ( l2 );
838         if( !array[idx] ) {
839             gcry_free( array );
840             gcry_sexp_release ( list );
841             return GCRYERR_INV_OBJ; /* required parameter is invalid */
842         }
843     }
844
845     gcry_sexp_release ( list );
846     *retarray = array;
847     *retalgo = algo;
848
849     return 0;
850 }
851
852
853 /****************
854  * Take sexp and return an array of MPI as used for our internal decrypt
855  * function.
856  * s_data = (enc-val
857  *           [(flags [pkcs1])
858  *            (<algo>
859  *              (<param_name1> <mpi>)
860  *              ...
861  *              (<param_namen> <mpi>)
862  *            ))
863  */
864 static int
865 sexp_to_enc( GCRY_SEXP sexp, MPI **retarray, int *retalgo, int *ret_want_pkcs1)
866 {
867     GCRY_SEXP list, l2;
868     const char *name;
869     const char *s;
870     size_t n;
871     int i, idx;
872     int algo;
873     const char *elems;
874     GCRY_MPI *array;
875
876     *ret_want_pkcs1 = 0;
877     /* check that the first element is valid */
878     list = gcry_sexp_find_token( sexp, "enc-val" , 0 );
879     if( !list )
880         return GCRYERR_INV_OBJ; /* Does not contain a encrypted value object */
881     l2 = gcry_sexp_nth (list, 1);
882     if (!l2 ) {
883         gcry_sexp_release (list);
884         return GCRYERR_NO_OBJ; /* no cdr for the data object */
885     }
886     name = gcry_sexp_nth_data (l2, 0, &n);
887     if (!name) {
888         gcry_sexp_release (l2);
889         gcry_sexp_release (list);
890         return GCRYERR_INV_OBJ; /* invalid structure of object */
891     }
892     if ( n == 5 && !memcmp (name, "flags", 5)) {
893       /* There is a flags element - process it */
894       const char *s;
895
896       for (i=gcry_sexp_length (l2)-1; i > 0; i--)
897         {
898           s = gcry_sexp_nth_data (l2, i, &n);
899           if (!s)
900             ; /* not a data element - ignore */
901           else if ( n == 3 && !memcmp (s, "raw", 3))
902             ; /* just a dummy because it is the default */
903           else if ( n == 5 && !memcmp (s, "pkcs1", 5))
904             *ret_want_pkcs1 = 1;
905           else
906             {
907               gcry_sexp_release (l2);
908               gcry_sexp_release (list);
909               return GCRYERR_INV_FLAG;
910             }
911         }
912       
913       /* Get the next which has the actual data */
914       gcry_sexp_release (l2);
915       l2 = gcry_sexp_nth (list, 2);
916       if (!l2 ) {
917         gcry_sexp_release (list);
918         return GCRYERR_NO_OBJ; /* no cdr for the data object */
919       }
920       name = gcry_sexp_nth_data (l2, 0, &n);
921       if (!name) {
922         gcry_sexp_release (l2);
923         gcry_sexp_release (list);
924         return GCRYERR_INV_OBJ; /* invalid structure of object */
925       }
926     }
927     gcry_sexp_release (list);
928     list = l2; l2 = NULL;
929     
930     for(i=0; (s=enc_info_table[i].name); i++ ) {
931         if( strlen(s) == n && !memcmp( s, name, n ) )
932             break;
933     }
934     if( !s ) {
935         gcry_sexp_release (list);
936         return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
937     }
938
939     algo = enc_info_table[i].algo;
940     elems = enc_info_table[i].elements;
941     array = gcry_calloc( (strlen(elems)+1) , sizeof *array );
942     if( !array ) {
943         gcry_sexp_release ( list );
944         return GCRYERR_NO_MEM;
945     }
946
947     idx = 0;
948     for(s=elems; *s; s++, idx++ ) {
949         l2 = gcry_sexp_find_token( list, s, 1 );
950         if( !l2 ) {
951             gcry_free( array );
952             gcry_sexp_release ( list );
953             return GCRYERR_NO_OBJ; /* required parameter not found */
954         }
955         array[idx] = gcry_sexp_nth_mpi( l2, 1, GCRYMPI_FMT_USG );
956         gcry_sexp_release ( l2 );
957         if( !array[idx] ) {
958             gcry_free( array );
959             gcry_sexp_release ( list );
960             return GCRYERR_INV_OBJ; /* required parameter is invalid */
961         }
962     }
963
964     gcry_sexp_release ( list );
965     *retarray = array;
966     *retalgo = algo;
967
968     return 0;
969 }
970
971 /* Take the hash value and convert into an MPI, suitable for for
972    passing to the low level functions.  We currently support the
973    old style way of passing just a MPI and the modern interface which
974    allows to pass flags so that we can choose between raw and pkcs1
975    padding - may be more padding options later. 
976
977    (<mpi>)
978    or
979    (data
980     [(flags [pkcs1])]
981     [(hash <algo> <value>)]
982     [(value <text>)]
983    )
984    
985    Either the VALUE or the HASH element must be present for use
986    with signatures.  VALUE is used for encryption.
987
988    NBITS is the length of the key in bits. 
989
990 */
991 static int 
992 sexp_data_to_mpi (GcrySexp input, unsigned int nbits, GcryMPI *ret_mpi,
993                   int for_encryption)
994 {
995   int rc = 0;
996   GcrySexp ldata, lhash, lvalue;
997   int i;
998   size_t n;
999   const char *s;
1000   int is_raw = 0, is_pkcs1 = 0, unknown_flag=0; 
1001
1002   *ret_mpi = NULL;
1003   ldata = gcry_sexp_find_token (input, "data", 0);
1004   if (!ldata)
1005     { /* assume old style */
1006       *ret_mpi = gcry_sexp_nth_mpi (input, 0, 0);
1007       return *ret_mpi? 0 : GCRYERR_INV_OBJ;
1008     }
1009
1010   /* see whether there is a flags object */
1011   {
1012     GcrySexp lflags = gcry_sexp_find_token (ldata, "flags", 0);
1013     if (lflags)
1014       { /* parse the flags list. */
1015         for (i=gcry_sexp_length (lflags)-1; i > 0; i--)
1016           {
1017             s = gcry_sexp_nth_data (lflags, i, &n);
1018             if (!s)
1019               ; /* not a data element*/
1020             else if ( n == 3 && !memcmp (s, "raw", 3))
1021               is_raw = 1;
1022             else if ( n == 5 && !memcmp (s, "pkcs1", 5))
1023               is_pkcs1 = 1;
1024             else
1025               unknown_flag = 1;
1026           }
1027         gcry_sexp_release (lflags);
1028       }
1029   }
1030
1031   if (!is_pkcs1 && !is_raw)
1032     is_raw = 1; /* default to raw */
1033
1034   /* Get HASH or MPI */
1035   lhash = gcry_sexp_find_token (ldata, "hash", 0);
1036   lvalue = lhash? NULL : gcry_sexp_find_token (ldata, "value", 0);
1037
1038   if (!(!lhash ^ !lvalue))
1039     rc = GCRYERR_INV_OBJ; /* none or both given */
1040   else if (unknown_flag)
1041     rc = GCRYERR_INV_FLAG;
1042   else if (is_raw && is_pkcs1 && !for_encryption)
1043     rc = GCRYERR_CONFLICT;
1044   else if (is_raw && lvalue)
1045     {
1046       *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, 0);
1047       if (!*ret_mpi)
1048         rc = GCRYERR_INV_OBJ;
1049     }
1050   else if (is_pkcs1 && lvalue && for_encryption)
1051     { /* create pkcs#1 block type 2 padding */
1052       unsigned char *frame = NULL;
1053       size_t nframe = (nbits+7) / 8;
1054       const void * value;
1055       size_t valuelen;
1056       unsigned char *p;
1057
1058       if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
1059         rc = GCRYERR_INV_OBJ;
1060       else if (valuelen + 7 > nframe || !nframe)
1061         {
1062           /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
1063           rc = GCRYERR_TOO_SHORT; /* the key is too short */
1064         }
1065       else if ( !(frame = gcry_malloc_secure (nframe)))
1066         rc = GCRYERR_NO_MEM;
1067       else
1068         {
1069           n = 0;
1070           frame[n++] = 0;
1071           frame[n++] = 2; /* block type */
1072           i = nframe - 3 - valuelen;
1073           assert (i > 0);
1074           p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
1075           /* replace zero bytes by new values*/
1076           for (;;)
1077             {
1078               int j, k;
1079               unsigned char *pp;
1080               
1081               /* count the zero bytes */
1082               for (j=k=0; j < i; j++)
1083                 {
1084                   if (!p[j])
1085                     k++;
1086                 }
1087               if (!k)
1088                 break; /* okay: no (more) zero bytes */
1089               
1090               k += k/128; /* better get some more */
1091               pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
1092               for (j=0; j < i && k; j++)
1093                 {
1094                   if (!p[j])
1095                     p[j] = pp[--k];
1096                 }
1097               gcry_free (pp);
1098             }
1099           memcpy (frame+n, p, i);
1100           n += i;
1101           gcry_free (p);
1102           
1103           frame[n++] = 0;
1104           memcpy (frame+n, value, valuelen);
1105           n += valuelen;
1106           assert (n == nframe);
1107
1108           gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, &nframe);
1109         }
1110
1111       gcry_free(frame);
1112     }
1113   else if (is_pkcs1 && lhash && !for_encryption)
1114     { /* create pkcs#1 block type 1 padding */
1115       if (gcry_sexp_length (lhash) != 3)
1116         rc = GCRYERR_INV_OBJ;
1117       else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
1118         rc = GCRYERR_INV_OBJ;
1119       else
1120         {
1121           static struct { const char *name; int algo; } hashnames[] = 
1122           { { "sha1",   GCRY_MD_SHA1 },
1123             { "md5",    GCRY_MD_MD5 },
1124             { "rmd160", GCRY_MD_RMD160 },
1125             { "sha256", GCRY_MD_SHA256 },
1126             { "sha384", GCRY_MD_SHA384 },
1127             { "sha512", GCRY_MD_SHA512 },
1128             { "md2",    GCRY_MD_MD2 },
1129             { "md4",    GCRY_MD_MD4 },
1130             { "tiger",  GCRY_MD_TIGER },
1131             { "haval",  GCRY_MD_HAVAL },
1132             { NULL }
1133           };
1134           int algo;
1135           byte asn[100];
1136           byte *frame = NULL;
1137           size_t nframe = (nbits+7) / 8;
1138           const void * value;
1139           size_t valuelen;
1140           size_t asnlen, dlen;
1141             
1142           for (i=0; hashnames[i].name; i++)
1143             {
1144               if ( strlen (hashnames[i].name) == n
1145                    && !memcmp (hashnames[i].name, s, n))
1146                 break;
1147             }
1148
1149           algo = hashnames[i].algo;
1150           asnlen = DIM(asn);
1151           dlen = gcry_md_get_algo_dlen (algo);
1152
1153           if (!hashnames[i].name)
1154             rc = GCRYERR_INV_MD_ALGO;
1155           else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
1156                     || !valuelen )
1157             rc = GCRYERR_INV_OBJ;
1158           else if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
1159             rc = GCRYERR_NOT_IMPL; /* we don't have all of the above algos */
1160           else if ( valuelen != dlen )
1161             {
1162               /* hash value does not match the length of digest for
1163                  the given algo */
1164               rc = GCRYERR_CONFLICT;
1165             }
1166           else if( !dlen || dlen + asnlen + 4 > nframe)
1167             {
1168               /* can't encode an DLEN byte digest MD into a NFRAME byte frame */
1169               rc = GCRYERR_TOO_SHORT;
1170             }
1171           else if ( !(frame = gcry_malloc (nframe)) )
1172             rc = GCRYERR_NO_MEM;
1173           else
1174             { /* assemble the pkcs#1 block type 1 */
1175               n = 0;
1176               frame[n++] = 0;
1177               frame[n++] = 1; /* block type */
1178               i = nframe - valuelen - asnlen - 3 ;
1179               assert (i > 1);
1180               memset (frame+n, 0xff, i );
1181               n += i;
1182               frame[n++] = 0;
1183               memcpy (frame+n, asn, asnlen);
1184               n += asnlen;
1185               memcpy (frame+n, value, valuelen );
1186               n += valuelen;
1187               assert (n == nframe);
1188       
1189               /* convert it into an MPI */
1190               gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, &nframe);
1191             }
1192           
1193           gcry_free (frame);
1194         }
1195     }
1196   else
1197     rc = GCRYERR_CONFLICT;
1198    
1199   gcry_sexp_release (ldata);
1200   gcry_sexp_release (lhash);
1201   gcry_sexp_release (lvalue);
1202   return rc;
1203 }
1204
1205
1206 /*
1207    Do a PK encrypt operation
1208   
1209    Caller has to provide a public key as the SEXP pkey and data as a
1210    SEXP with just one MPI in it. Alternativly S_DATA might be a
1211    complex S-Expression, similar to the one used for signature
1212    verification.  This provides a flag which allows to handle PKCS#1
1213    block type 2 padding.  The function returns a a sexp which may be
1214    passed to to pk_decrypt.
1215   
1216    Returns: 0 or an errorcode.
1217   
1218    s_data = See comment for sexp_data_to_mpi
1219    s_pkey = <key-as-defined-in-sexp_to_key>
1220    r_ciph = (enc-val
1221                (<algo>
1222                  (<param_name1> <mpi>)
1223                  ...
1224                  (<param_namen> <mpi>)
1225                ))
1226
1227 */
1228 int
1229 gcry_pk_encrypt (GCRY_SEXP *r_ciph, GCRY_SEXP s_data, GCRY_SEXP s_pkey)
1230 {
1231     MPI *pkey, data, *ciph;
1232     const char *key_algo_name, *algo_name, *algo_elems;
1233     int i, rc, algo;
1234
1235     *r_ciph = NULL;
1236     /* get the key */
1237     rc = sexp_to_key( s_pkey, 0, &pkey, &algo, &i);
1238     if( rc ) 
1239         return rc;
1240     key_algo_name = algo_info_table[i].name;
1241     assert (key_algo_name);
1242
1243     /* get the name and the required size of the return value */
1244     for(i=0; (algo_name = enc_info_table[i].name); i++ ) {
1245         if( enc_info_table[i].algo == algo )
1246             break;
1247     }
1248     /* get the name and the required size of the result array.  We
1249        compare using the algorithm name and not the algo number - this way
1250        we get the correct name for the return value */
1251     for(i=0; (algo_name = enc_info_table[i].name); i++ ) {
1252         if( !strcmp (algo_name, key_algo_name) )
1253             break;
1254     }
1255     if( !algo_name ) {
1256         release_mpi_array( pkey );
1257         gcry_free (pkey);
1258         return GCRYERR_INV_PK_ALGO;
1259     }
1260     algo_elems = enc_info_table[i].elements;
1261
1262     /* get the stuff we want to encrypt */
1263     rc = sexp_data_to_mpi (s_data, gcry_pk_get_nbits (s_pkey), &data, 1);
1264     if (rc) {
1265         release_mpi_array( pkey );
1266         gcry_free (pkey);
1267         return GCRYERR_INV_OBJ;
1268     }
1269
1270     /* Now we can encrypt data to ciph */
1271     ciph = gcry_xcalloc( (strlen(algo_elems)+1) , sizeof *ciph );
1272     rc = pubkey_encrypt( algo, ciph, data, pkey );
1273     release_mpi_array( pkey );
1274     gcry_free (pkey); pkey = NULL;
1275     mpi_free( data );
1276     if( rc ) {
1277         release_mpi_array( ciph );
1278         gcry_free( ciph );
1279         return rc;
1280     }
1281
1282     /* We did it.  Now build the return list */
1283     {
1284         char *string, *p;
1285         size_t nelem, needed= strlen(algo_name) + 20;
1286
1287         /* count elements, so that we can allocate enough space */
1288         for(nelem=0; algo_elems[nelem]; nelem++ )
1289             needed += 10; /* 6 + a safety margin */
1290         /* build the string */
1291         string = p = gcry_xmalloc ( needed );
1292         p = stpcpy ( p, "(enc-val(" );
1293         p = stpcpy ( p, algo_name );
1294         for(i=0; algo_elems[i]; i++ ) {
1295             *p++ = '(';
1296             *p++ = algo_elems[i];
1297             p = stpcpy ( p, "%m)" );
1298         }
1299         strcpy ( p, "))" );
1300         /* and now the ugly part:  we don't have a function to
1301          * pass an array to a format string, so we have to do it this way :-(
1302          */
1303         switch ( nelem ) {
1304           case 1: rc = gcry_sexp_build ( r_ciph, NULL, string,
1305                      ciph[0]
1306                   ); break;
1307           case 2: rc = gcry_sexp_build ( r_ciph, NULL, string,
1308                      ciph[0], ciph[1]
1309                   ); break;
1310           case 3: rc = gcry_sexp_build ( r_ciph, NULL, string,
1311                      ciph[0], ciph[1], ciph[2]
1312                   ); break;
1313           case 4: rc = gcry_sexp_build ( r_ciph, NULL, string,
1314                      ciph[0], ciph[1], ciph[2], ciph[3]
1315                   ); break;
1316           case 5: rc = gcry_sexp_build ( r_ciph, NULL, string,
1317                      ciph[0], ciph[1], ciph[2], ciph[3], ciph[4]
1318                   ); break;
1319           case 6: rc = gcry_sexp_build ( r_ciph, NULL, string,
1320                      ciph[0], ciph[1], ciph[2], ciph[3], ciph[4], ciph[5]
1321                   ); break;
1322           default: BUG ();
1323         }
1324         if ( rc )
1325             BUG ();
1326         gcry_free ( string );
1327     }
1328     release_mpi_array( ciph );
1329     gcry_free( ciph );
1330
1331
1332     return 0;
1333 }
1334
1335 /****************
1336  * Do a PK decrypt operation
1337  *
1338  * Caller has to provide a secret key as the SEXP skey and data in a format
1339  * as created by gcry_pk_encrypt.  Currently the function returns
1340  * simply a MPI.  Later versions of this functions may return a more
1341  * complex data structure.
1342  *
1343  * Returns: 0 or an errorcode.
1344  *
1345  * s_data = (enc-val
1346  *            (<algo>
1347  *              (<param_name1> <mpi>)
1348  *              ...
1349  *              (<param_namen> <mpi>)
1350  *            ))
1351  * s_skey = <key-as-defined-in-sexp_to_key>
1352  * r_plain= (<mpi>)   FIXME: Return a more structered value
1353  */
1354 int
1355 gcry_pk_decrypt( GCRY_SEXP *r_plain, GCRY_SEXP s_data, GCRY_SEXP s_skey )
1356 {
1357     MPI *skey, *data, plain;
1358     int rc, algo, dataalgo, want_pkcs1;
1359
1360     *r_plain = NULL;
1361     rc = sexp_to_key( s_skey, 1, &skey, &algo, NULL );
1362     if( rc ) {
1363         return rc;
1364     }
1365     rc = sexp_to_enc( s_data, &data, &dataalgo, &want_pkcs1 );
1366     if( rc ) {
1367         release_mpi_array( skey );
1368         gcry_free (skey);
1369         return rc;
1370     }
1371     if( algo != dataalgo ) {
1372         release_mpi_array( skey );
1373         gcry_free (skey);
1374         release_mpi_array( data );
1375         gcry_free (data);
1376         return -1; /* fixme: add real errornumber - algo does not match */
1377     }
1378
1379     rc = pubkey_decrypt( algo, &plain, data, skey );
1380     if( rc ) {
1381         release_mpi_array( skey );
1382         gcry_free (skey);
1383         release_mpi_array( data );
1384         gcry_free (data);
1385         return -1; /* fixme: add real errornumber - decryption failed */
1386     }
1387
1388     if ( gcry_sexp_build( r_plain, NULL, "%m", plain ) )
1389         BUG ();
1390
1391     mpi_free( plain );
1392     release_mpi_array( data );
1393     gcry_free (data);
1394     release_mpi_array( skey );
1395     gcry_free (skey);
1396     return 0;
1397 }
1398
1399
1400
1401 /****************
1402  * Create a signature.
1403  *
1404  * Caller has to provide a secret key as the SEXP skey and data
1405  * expressed as a SEXP list hash with only one element which should
1406  * instantly be available as a MPI. Alternatively the structure given
1407  * below may be used for S_HASH, it provides the abiliy to pass flags
1408  * to the operation; the only flag defined by now is "pkcs1" which
1409  * does PKCS#1 block type 1 style padding.
1410  *
1411  * Returns: 0 or an errorcode.
1412  *          In case of 0 the function returns a new SEXP with the
1413  *          signature value; the structure of this signature depends on the
1414  *          other arguments but is always suitable to be passed to
1415  *          gcry_pk_verify
1416  *
1417  * s_hash = See comment for sexp_data_to_mpi
1418  *             
1419  * s_skey = <key-as-defined-in-sexp_to_key>
1420  * r_sig  = (sig-val
1421  *            (<algo>
1422  *              (<param_name1> <mpi>)
1423  *              ...
1424  *              (<param_namen> <mpi>)
1425  * )) */
1426 int
1427 gcry_pk_sign( GCRY_SEXP *r_sig, GCRY_SEXP s_hash, GCRY_SEXP s_skey )
1428 {
1429     MPI *skey, hash;
1430     MPI *result;
1431     int i, algo, rc;
1432     const char *key_algo_name, *algo_name, *algo_elems;
1433
1434     *r_sig = NULL;
1435     rc = sexp_to_key( s_skey, 1, &skey, &algo, &i);
1436     if( rc )
1437         return rc;
1438     key_algo_name = algo_info_table[i].name;
1439     assert (key_algo_name);
1440
1441     /* get the name and the required size of the result array.  We
1442        compare using the algorithm name and not the algo number - this way
1443        we get the correct name for the return value */
1444     for(i=0; (algo_name = sig_info_table[i].name); i++ ) {
1445         if( !strcmp (algo_name, key_algo_name) )
1446             break;
1447     }
1448     if( !algo_name ) {
1449         release_mpi_array( skey );
1450         gcry_free (skey);
1451         return -4; /* oops: unknown algorithm */
1452     }
1453     assert (sig_info_table[i].algo == algo);
1454     algo_elems = sig_info_table[i].elements;
1455
1456     /* get the stuff we want to sign */
1457     /* Note that pk_get_nbits does also work on a private key */
1458     rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_skey), &hash, 0);
1459     if (rc) {
1460         release_mpi_array( skey );
1461         gcry_free (skey);
1462         return rc; 
1463     }
1464     result = gcry_xcalloc( (strlen(algo_elems)+1) , sizeof *result );
1465     rc = pubkey_sign( algo, result, hash, skey );
1466     release_mpi_array( skey );
1467     gcry_free (skey); skey = NULL;
1468     mpi_free( hash );
1469     if( rc ) {
1470         gcry_free( result );
1471         return rc;
1472     }
1473
1474     {
1475         char *string, *p;
1476         size_t nelem, needed= strlen(algo_name) + 20;
1477
1478         /* count elements, so that we can allocate enough space */
1479         for(nelem=0; algo_elems[nelem]; nelem++ )
1480             needed += 10; /* 6 + a safety margin */
1481         /* build the string */
1482         string = p = gcry_xmalloc ( needed );
1483         p = stpcpy ( p, "(sig-val(" );
1484         p = stpcpy ( p, algo_name );
1485         for(i=0; algo_elems[i]; i++ ) {
1486             *p++ = '(';
1487             *p++ = algo_elems[i];
1488             p = stpcpy ( p, "%m)" );
1489         }
1490         strcpy ( p, "))" );
1491         /* and now the ugly part:  we don't have a function to
1492          * pass an array to a format string, so we have to do it this way :-(
1493          */
1494         switch ( nelem ) {
1495           case 1: rc = gcry_sexp_build ( r_sig, NULL, string,
1496                      result[0]
1497                   ); break;
1498           case 2: rc = gcry_sexp_build ( r_sig, NULL, string,
1499                      result[0], result[1]
1500                   ); break;
1501           case 3: rc = gcry_sexp_build ( r_sig, NULL, string,
1502                      result[0], result[1], result[2]
1503                   ); break;
1504           case 4: rc = gcry_sexp_build ( r_sig, NULL, string,
1505                      result[0], result[1], result[2], result[3]
1506                   ); break;
1507           case 5: rc = gcry_sexp_build ( r_sig, NULL, string,
1508                      result[0], result[1], result[2], result[3], result[4]
1509                   ); break;
1510           case 6: rc = gcry_sexp_build ( r_sig, NULL, string,
1511                      result[0], result[1], result[2], result[3], result[4], result[5]
1512                   ); break;
1513           default: BUG ();
1514         }
1515         if ( rc )
1516             BUG ();
1517         gcry_free ( string );
1518     }
1519     release_mpi_array( result );
1520     gcry_free( result );
1521
1522     return 0;
1523 }
1524
1525
1526 /****************
1527  * Verify a sgnature.  Caller has to supply the public key pkey,
1528  * the signature sig and his hashvalue data.  Public key has to be
1529  * a standard public key given as an S-Exp, sig is a S-Exp as returned
1530  * from gcry_pk_sign and data must be an S-Exp like the one in sign too.
1531  */
1532 int
1533 gcry_pk_verify( GCRY_SEXP s_sig, GCRY_SEXP s_hash, GCRY_SEXP s_pkey )
1534 {
1535     MPI *pkey, hash, *sig;
1536     int algo, sigalgo;
1537     int rc;
1538
1539     rc = sexp_to_key( s_pkey, 0, &pkey, &algo, NULL );
1540     if( rc )
1541         return rc;
1542     rc = sexp_to_sig( s_sig, &sig, &sigalgo );
1543     if( rc ) {
1544         release_mpi_array( pkey );
1545         gcry_free (pkey);
1546         return rc;
1547     }
1548     if( algo != sigalgo ) {
1549         release_mpi_array( pkey );
1550         gcry_free (pkey);
1551         release_mpi_array( sig );
1552         gcry_free (sig);
1553         return -1; /* fixme: add real errornumber - algo does not match */
1554     }
1555
1556     rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_pkey), &hash, 0);
1557     if (rc) {
1558         release_mpi_array( pkey );
1559         gcry_free (pkey);
1560         release_mpi_array( sig );
1561         gcry_free (sig);
1562         return -1; /* fixme: get a real errorcode for this */
1563     }
1564
1565     rc = pubkey_verify( algo, hash, sig, pkey, NULL, NULL );
1566     release_mpi_array( pkey );
1567     gcry_free (pkey);
1568     release_mpi_array( sig );
1569     gcry_free (sig);
1570     mpi_free(hash);
1571
1572     return rc;
1573 }
1574
1575
1576 /****************
1577  * Test a key.  This may be used either for a public or a secret key
1578  * to see whether internal structre is valid.
1579  *
1580  * Returns: 0 or an errorcode.
1581  *
1582  * s_key = <key-as-defined-in-sexp_to_key>
1583  */
1584 int
1585 gcry_pk_testkey( GCRY_SEXP s_key )
1586 {
1587     MPI *key;
1588     int rc, algo;
1589
1590     /* Note we currently support only secret key checking */
1591     rc = sexp_to_key( s_key, 1, &key, &algo, NULL );
1592     if( rc ) {
1593         return rc;
1594     }
1595
1596     rc = pubkey_check_secret_key( algo, key );
1597     release_mpi_array( key );
1598     gcry_free (key);
1599     return rc;
1600 }
1601
1602
1603 /****************
1604  * Create a public key pair and return it in r_key.
1605  * How the key is created depends on s_parms:
1606  * (genkey
1607  *  (algo
1608  *    (parameter_name_1 ....)
1609  *     ....
1610  *    (parameter_name_n ....)
1611  * ))
1612  * The key is returned in a format depending on the
1613  * algorithm. Both, private and secret keys are returned
1614  * and optionally some additional informatin.
1615  * For elgamal we return this structure:
1616  * (key-data
1617  *  (public-key
1618  *    (elg
1619  *      (p <mpi>)
1620  *      (g <mpi>)
1621  *      (y <mpi>)
1622  *    )
1623  *  )
1624  *  (private-key
1625  *    (elg
1626  *      (p <mpi>)
1627  *      (g <mpi>)
1628  *      (y <mpi>)
1629  *      (x <mpi>)
1630  *    )
1631  *  )
1632  *  (misc-key-info
1633  *     (pm1-factors n1 n2 ... nn)
1634  *  )
1635  * )
1636  */
1637 int
1638 gcry_pk_genkey( GCRY_SEXP *r_key, GCRY_SEXP s_parms )
1639 {
1640     GCRY_SEXP list, l2;
1641     const char *name;
1642     const char *s, *s2;
1643     size_t n;
1644     int rc, i;
1645     const char *algo_name;
1646     int algo;
1647     char sec_elems[20], pub_elems[20];
1648     GCRY_MPI skey[10], *factors;
1649     unsigned int nbits;
1650
1651     *r_key = NULL;
1652     list = gcry_sexp_find_token( s_parms, "genkey", 0 );
1653     if( !list )
1654         return GCRYERR_INV_OBJ; /* Does not contain genkey data */
1655     l2 = gcry_sexp_cadr( list );
1656     gcry_sexp_release ( list );
1657     list = l2;
1658     if( !list )
1659         return GCRYERR_NO_OBJ; /* no cdr for the genkey */
1660     name = gcry_sexp_nth_data( list, 0, &n );
1661     if( !name ) {
1662         gcry_sexp_release ( list );
1663         return GCRYERR_INV_OBJ; /* algo string missing */
1664     }
1665     for(i=0; (s=algo_info_table[i].name); i++ ) {
1666         if( strlen(s) == n && !memcmp( s, name, n ) )
1667             break;
1668     }
1669     if( !s ) {
1670         gcry_sexp_release ( list );
1671         return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
1672     }
1673
1674     algo = algo_info_table[i].algo;
1675     algo_name = algo_info_table[i].name;
1676     
1677     s = algo_info_table[i].common_elements;
1678     s2 = algo_info_table[i].public_elements;
1679     if( strlen( s ) + strlen( s2 ) > DIM( pub_elems ) )
1680         return GCRYERR_INTERNAL; /* check bound failed */
1681     strcpy( pub_elems, s );
1682     strcat( pub_elems, s2 );
1683
1684     s = algo_info_table[i].common_elements;
1685     s2 = algo_info_table[i].secret_elements;
1686     if( strlen( s ) + strlen( s2 ) > DIM( sec_elems ) )
1687         return GCRYERR_INTERNAL; /* check bound failed */
1688     strcpy( sec_elems, s );
1689     strcat( sec_elems, s2 );
1690
1691     l2 = gcry_sexp_find_token( list, "nbits", 0 );
1692     gcry_sexp_release ( list );
1693     list = l2;
1694     if( !list )
1695         return GCRYERR_NO_OBJ; /* no nbits parameter */
1696     name = gcry_sexp_nth_data( list, 1, &n );
1697     if( !name ) {
1698         gcry_sexp_release ( list );
1699         return GCRYERR_INV_OBJ; /* nbits without a cdr */
1700     }
1701     {
1702         char *p = gcry_xmalloc(n+1);
1703         memcpy(p, name, n );
1704         p[n] = 0;
1705         nbits = (unsigned int)strtol( p, NULL, 0 );
1706         gcry_free( p );
1707     }
1708     gcry_sexp_release ( list );
1709
1710     rc = pubkey_generate( algo, nbits, skey, &factors );
1711     if( rc ) {
1712         return rc;
1713     }
1714
1715     {
1716         char *string, *p;
1717         size_t nelem=0, needed=0;
1718         GCRY_MPI mpis[30];
1719
1720
1721         /* count elements, so that we can allocate enough space */
1722         for(i=0; pub_elems[i]; i++, nelem++ )
1723             needed += 10; /* 6 + a safety margin */
1724         for(i=0; sec_elems[i]; i++, nelem++ )
1725             needed += 10; /* 6 + a safety margin */
1726         for(i=0; factors[i]; i++, nelem++ )
1727             needed += 10; /* 6 + a safety margin */
1728         needed += 2* strlen(algo_name) +  300;
1729         if ( nelem > DIM(mpis) )
1730             BUG ();
1731
1732         /* build the string */
1733         nelem = 0;
1734         string = p = gcry_xmalloc ( needed );
1735         p = stpcpy ( p, "(key-data" );
1736
1737         p = stpcpy ( p, "(public-key(" );
1738         p = stpcpy ( p, algo_name );
1739         for(i=0; pub_elems[i]; i++ ) {
1740             *p++ = '(';
1741             *p++ = pub_elems[i];
1742             p = stpcpy ( p, "%m)" );
1743             mpis[nelem++] = skey[i];
1744         }
1745         p = stpcpy ( p, "))" );
1746
1747         p = stpcpy ( p, "(private-key(" );
1748         p = stpcpy ( p, algo_name );
1749         for(i=0; sec_elems[i]; i++ ) {
1750             *p++ = '(';
1751             *p++ = sec_elems[i];
1752             p = stpcpy ( p, "%m)" );
1753             mpis[nelem++] = skey[i];
1754         }
1755         p = stpcpy ( p, "))" );
1756         /* Very ugly hack to make release_mpi_array() work FIXME */
1757         skey[i] = NULL;
1758
1759         p = stpcpy ( p, "(misc-key-info(pm1-factors" );
1760         for(i=0; factors[i]; i++ ) {
1761             p = stpcpy ( p, "%m" );
1762             mpis[nelem++] = factors[i];
1763         }
1764         strcpy ( p, ")))" );
1765
1766         while ( nelem < DIM(mpis) )
1767             mpis[nelem++] = NULL;
1768
1769         /* and now the ugly part:  we don't have a function to
1770          * pass an array to a format string, so we have just pass everything
1771          * we have. which normally should be no problem as only those
1772          * with a corresponding %m are used
1773          */
1774         if ( gcry_sexp_build ( r_key, NULL, string,
1775                    mpis[0], mpis[1], mpis[2], mpis[3], mpis[4], mpis[5],
1776                    mpis[6], mpis[7], mpis[8], mpis[9], mpis[10], mpis[11],
1777                    mpis[12], mpis[13], mpis[14], mpis[15], mpis[16], mpis[17],
1778                    mpis[18], mpis[19], mpis[20], mpis[21], mpis[22], mpis[23],
1779                    mpis[24], mpis[25], mpis[26], mpis[27], mpis[28], mpis[29]
1780                   ) )
1781             BUG ();
1782         assert ( DIM(mpis) == 30 );
1783         gcry_free ( string );
1784     }
1785     release_mpi_array ( skey );
1786     /* no free:  skey is a static array */
1787     release_mpi_array ( factors );
1788     gcry_free (factors);
1789
1790     return 0;
1791 }
1792
1793 /****************
1794  * Get the number of nbits from the public key
1795  * Hmmm: Should we have really this function or is it
1796  * better to have a more general function to retrieve
1797  * different propoerties of the key?
1798  */
1799 unsigned int
1800 gcry_pk_get_nbits( GCRY_SEXP key )
1801 {
1802     int rc, i, algo;
1803     MPI *keyarr;
1804     unsigned int nbits = 0;
1805
1806     rc = sexp_to_key( key, 0, &keyarr, &algo, NULL );
1807     if( rc == GCRYERR_INV_OBJ )
1808         rc = sexp_to_key( key, 1, &keyarr, &algo, NULL );
1809     if( rc )
1810         return 0;
1811
1812     do {
1813         for(i=0; pubkey_table[i].name; i++ )
1814             if( pubkey_table[i].algo == algo ) {
1815                 nbits = (*pubkey_table[i].get_nbits)( algo, keyarr );
1816                 goto leave;
1817             }
1818     } while( load_pubkey_modules() );
1819     if( is_RSA(algo) )  /* we always wanna see the length of a key :-) */
1820         nbits = mpi_get_nbits( keyarr[0] );
1821   leave:
1822     release_mpi_array( keyarr );
1823     gcry_free (keyarr);
1824     return nbits;
1825 }
1826
1827 /* Return the so called KEYGRIP which is the SHA-1 hash of the public
1828    key parameters expressed in a way depended on the algorithm.
1829
1830    ARRAY must either be 20 bytes long or NULL; in the latter case a
1831    newly allocated array of that size is returned, otherwise ARRAY or
1832    NULL is returned to indicate an error which is most likely an
1833    unknown algorithm.  The function accepts public or secret keys. */
1834 unsigned char *
1835 gcry_pk_get_keygrip (GCRY_SEXP key, unsigned char *array)
1836 {
1837   GCRY_SEXP list=NULL, l2;
1838   const char *s, *name;
1839   size_t n;
1840   int i, idx;
1841   int is_rsa;
1842   const char *elems;
1843   GCRY_MD_HD md = NULL;
1844
1845   /* check that the first element is valid */
1846   list = gcry_sexp_find_token (key, "public-key", 0);
1847   if (!list)
1848     list = gcry_sexp_find_token (key, "private-key", 0);
1849   if (!list)
1850     list = gcry_sexp_find_token (key, "protected-private-key", 0);
1851   if (!list)
1852     return NULL; /* no public- or private-key object */
1853
1854   l2 = gcry_sexp_cadr (list);
1855   gcry_sexp_release (list);
1856   list = l2;
1857
1858   name = gcry_sexp_nth_data( list, 0, &n );
1859   if (!name)
1860     goto fail; /* invalid structure of object */
1861
1862   for (i=0; (s=algo_info_table[i].name); i++ ) 
1863     {
1864       if (strlen(s) == n && !memcmp (s, name, n))
1865         break;
1866     }
1867   
1868   if(!s)
1869     goto fail; /* unknown algorithm */
1870
1871   is_rsa = algo_info_table[i].algo == PUBKEY_ALGO_RSA;
1872   elems = algo_info_table[i].grip_elements;
1873   if (!elems)
1874     goto fail; /* no grip parameter */
1875     
1876   md = gcry_md_open (GCRY_MD_SHA1, 0);
1877   if (!md)
1878     goto fail;
1879
1880   idx = 0;
1881   for (s=elems; *s; s++, idx++)
1882     {
1883       const char *data;
1884       size_t datalen;
1885
1886       l2 = gcry_sexp_find_token (list, s, 1);
1887       if (!l2)
1888         goto fail;
1889       data = gcry_sexp_nth_data (l2, 1, &datalen);
1890       gcry_sexp_release (l2);
1891       if (!data)
1892         goto fail;
1893       if (!is_rsa)
1894         {
1895           char buf[30];
1896
1897           sprintf (buf, "(1:%c%u:", *s, (unsigned int)datalen);
1898           gcry_md_write (md, buf, strlen (buf));
1899         }
1900       /* pkcs-15 says that for RSA only the modulus should be hashed -
1901          however, it is not clear wether this is meant to has the raw
1902          bytes assuming this is an unsigned integer or whether the DER
1903          required 0 should be prefixed. We hash th raw bytes.  For
1904          non-RSA we hash S-expressions. */
1905       gcry_md_write (md, data, datalen);
1906       if (!is_rsa)
1907         gcry_md_write (md, ")", 1);
1908     }
1909   
1910   if (!array)
1911     {
1912       array = gcry_malloc (20);
1913       if (!array)
1914         goto fail;
1915     }
1916   memcpy (array, gcry_md_read (md, GCRY_MD_SHA1), 20);
1917   gcry_md_close (md);
1918   gcry_sexp_release (list);
1919   return array;
1920
1921  fail:
1922   gcry_md_close (md);
1923   gcry_sexp_release (list);
1924   return NULL;
1925 }
1926
1927
1928
1929 int
1930 gcry_pk_ctl( int cmd, void *buffer, size_t buflen)
1931 {
1932     switch( cmd ) {
1933       case GCRYCTL_DISABLE_ALGO:
1934         /* this one expects a buffer pointing to an
1935          * integer with the algo number.
1936          */
1937         if( !buffer || buflen != sizeof(int) )
1938             return set_lasterr( GCRYERR_INV_CIPHER_ALGO );
1939         disable_pubkey_algo( *(int*)buffer );
1940         break;
1941
1942       default:
1943         return set_lasterr( GCRYERR_INV_OP );
1944     }
1945     return 0;
1946 }
1947
1948
1949 /****************
1950  * Return information about the given algorithm
1951  * WHAT select the kind of information returned:
1952  *  GCRYCTL_TEST_ALGO:
1953  *      Returns 0 when the specified algorithm is available for use.
1954  *      Buffer must be NULL, nbytes  may have the address of a variable
1955  *      with the required usage of the algorithm. It may be 0 for don't
1956  *      care or a combination of the GCRY_PK_USAGE_xxx flags;
1957  *  GCRYCTL_GET_ALGO_USAGE:
1958  *      Return the usage glafs for the give algo.  An invalid alog
1959  *      does return 0.  Disabled algos are ignored here becuase we
1960  *      only want to know whether the algo is at all capable of
1961  *      the usage.
1962  *
1963  * On error the value -1 is returned and the error reason may be
1964  * retrieved by gcry_errno().
1965  * Note:  Because this function is in most cases used to return an
1966  * integer value, we can make it easier for the caller to just look at
1967  * the return value.  The caller will in all cases consult the value
1968  * and thereby detecting whether a error occured or not (i.e. while checking
1969  * the block size)
1970  */
1971 int
1972 gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes)
1973 {
1974     switch( what ) {
1975       case GCRYCTL_TEST_ALGO: {
1976             int use = nbytes? *nbytes: 0;
1977             if( buffer ) {
1978                 set_lasterr( GCRYERR_INV_ARG );
1979                 return -1;
1980             }
1981             if( check_pubkey_algo( algo, use ) ) {
1982                 set_lasterr( GCRYERR_INV_PK_ALGO );
1983                 return -1;
1984             }
1985         }
1986         break;
1987
1988       case GCRYCTL_GET_ALGO_USAGE: 
1989           do {
1990               int i;
1991               for(i=0; pubkey_table[i].name; i++ )
1992                   if( pubkey_table[i].algo == algo ) 
1993                       return pubkey_table[i].use;
1994           } while( load_pubkey_modules() );
1995           return 0;
1996          
1997       case GCRYCTL_GET_ALGO_NPKEY: return pubkey_get_npkey( algo );
1998       case GCRYCTL_GET_ALGO_NSKEY: return pubkey_get_nskey( algo );
1999       case GCRYCTL_GET_ALGO_NSIGN: return pubkey_get_nsig( algo );
2000       case GCRYCTL_GET_ALGO_NENCR: return pubkey_get_nenc( algo );
2001
2002       default:
2003         set_lasterr( GCRYERR_INV_OP );
2004         return -1;
2005     }
2006     return 0;
2007 }
2008
2009
2010