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