See ChangeLog: Mon Nov 15 21:36:02 CET 1999 Werner Koch
[gnupg.git] / cipher / pubkey.c
1 /* pubkey.c  -  pubkey dispatcher
2  *      Copyright (C) 1998, 1999 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 "util.h"
30 #include "mpi.h"
31 #include "cipher.h"
32 #include "elgamal.h"
33 #include "dsa.h"
34 #include "dynload.h"
35
36 /* FIXME: use set_lasterr() */
37
38 #define TABLE_SIZE 10
39
40 struct pubkey_table_s {
41     const char *name;
42     int algo;
43     int npkey;
44     int nskey;
45     int nenc;
46     int nsig;
47     int use;
48     int (*generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
49     int (*check_secret_key)( int algo, MPI *skey );
50     int (*encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey );
51     int (*decrypt)( int algo, MPI *result, MPI *data, MPI *skey );
52     int (*sign)( int algo, MPI *resarr, MPI data, MPI *skey );
53     int (*verify)( int algo, MPI hash, MPI *data, MPI *pkey,
54                    int (*cmp)(void *, MPI), void *opaquev );
55     unsigned (*get_nbits)( int algo, MPI *pkey );
56 };
57
58 static struct pubkey_table_s pubkey_table[TABLE_SIZE];
59 static int disabled_algos[TABLE_SIZE];
60
61 static struct { const char* name; int algo;
62                 const char* common_elements;
63                 const char* public_elements;
64                 const char* secret_elements;
65 } algo_info_table[] = {
66         {  "dsa"            , PUBKEY_ALGO_DSA       , "pqgy", "", "x"    },
67         {  "rsa"            , PUBKEY_ALGO_RSA       , "ne",   "", "dpqu" },
68         {  "elg"            , PUBKEY_ALGO_ELGAMAL   , "pgy",  "", "x"    },
69         {  "openpgp-dsa"    , PUBKEY_ALGO_DSA       , "pqgy", "", "x"    },
70         {  "openpgp-rsa"    , PUBKEY_ALGO_RSA       , "pqgy", "", "x"    },
71         {  "openpgp-elg"    , PUBKEY_ALGO_ELGAMAL_E , "pgy",  "", "x"    },
72         {  "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL   , "pgy",  "", "x"    },
73         {  NULL }};
74
75 static struct {
76     const char* name; int algo;
77     const char* elements;
78 } sig_info_table[] = {
79         {  "dsa"            , PUBKEY_ALGO_DSA       , "rs" },
80         {  "rsa"            , PUBKEY_ALGO_RSA       , "s"  },
81         {  "elg"            , PUBKEY_ALGO_ELGAMAL   , "rs" },
82         {  "openpgp-dsa"    , PUBKEY_ALGO_DSA       , "rs" },
83         {  "openpgp-rsa"    , PUBKEY_ALGO_RSA       , "s"  },
84         {  "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL   , "rs" },
85         {  NULL }};
86
87 static struct {
88     const char* name; int algo;
89     const char* elements;
90 } enc_info_table[] = {
91         {  "elg"            , PUBKEY_ALGO_ELGAMAL   , "ab" },
92         {  "rsa"            , PUBKEY_ALGO_RSA       , "a"  },
93         {  "openpgp-rsa"    , PUBKEY_ALGO_RSA       , "a"  },
94         {  "openpgp-elg"    , PUBKEY_ALGO_ELGAMAL_E , "ab" },
95         {  "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL   , "ab" },
96         {  NULL }};
97
98
99 static int pubkey_sign( int algo, MPI *resarr, MPI hash, MPI *skey );
100 static int pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
101                       int (*cmp)(void *, MPI), void *opaque );
102
103 static int
104 dummy_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
105 { log_bug("no generate() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
106
107 static int
108 dummy_check_secret_key( int algo, MPI *skey )
109 { log_bug("no check_secret_key() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
110
111 static int
112 dummy_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
113 { log_bug("no encrypt() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
114
115 static int
116 dummy_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
117 { log_bug("no decrypt() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
118
119 static int
120 dummy_sign( int algo, MPI *resarr, MPI data, MPI *skey )
121 { log_bug("no sign() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
122
123 static int
124 dummy_verify( int algo, MPI hash, MPI *data, MPI *pkey,
125                 int (*cmp)(void *, MPI), void *opaquev )
126 { log_bug("no verify() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
127
128 static unsigned
129 dummy_get_nbits( int algo, MPI *pkey )
130 { log_bug("no get_nbits() for %d\n", algo ); return 0; }
131
132
133 /****************
134  * Put the static entries into the table.
135  * This is out constructor function which fill the table
136  * of algorithms with the one we have statically linked.
137  */
138 static void
139 setup_pubkey_table(void)
140 {
141     int i;
142
143     i = 0;
144     pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL;
145     pubkey_table[i].name = elg_get_info( pubkey_table[i].algo,
146                                          &pubkey_table[i].npkey,
147                                          &pubkey_table[i].nskey,
148                                          &pubkey_table[i].nenc,
149                                          &pubkey_table[i].nsig,
150                                          &pubkey_table[i].use );
151     pubkey_table[i].generate         = elg_generate;
152     pubkey_table[i].check_secret_key = elg_check_secret_key;
153     pubkey_table[i].encrypt          = elg_encrypt;
154     pubkey_table[i].decrypt          = elg_decrypt;
155     pubkey_table[i].sign             = elg_sign;
156     pubkey_table[i].verify           = elg_verify;
157     pubkey_table[i].get_nbits        = elg_get_nbits;
158     if( !pubkey_table[i].name )
159         BUG();
160     i++;
161     pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL_E;
162     pubkey_table[i].name = elg_get_info( pubkey_table[i].algo,
163                                          &pubkey_table[i].npkey,
164                                          &pubkey_table[i].nskey,
165                                          &pubkey_table[i].nenc,
166                                          &pubkey_table[i].nsig,
167                                          &pubkey_table[i].use );
168     pubkey_table[i].generate         = elg_generate;
169     pubkey_table[i].check_secret_key = elg_check_secret_key;
170     pubkey_table[i].encrypt          = elg_encrypt;
171     pubkey_table[i].decrypt          = elg_decrypt;
172     pubkey_table[i].sign             = elg_sign;
173     pubkey_table[i].verify           = elg_verify;
174     pubkey_table[i].get_nbits        = elg_get_nbits;
175     if( !pubkey_table[i].name )
176         BUG();
177     i++;
178     pubkey_table[i].algo = PUBKEY_ALGO_DSA;
179     pubkey_table[i].name = dsa_get_info( pubkey_table[i].algo,
180                                          &pubkey_table[i].npkey,
181                                          &pubkey_table[i].nskey,
182                                          &pubkey_table[i].nenc,
183                                          &pubkey_table[i].nsig,
184                                          &pubkey_table[i].use );
185     pubkey_table[i].generate         = dsa_generate;
186     pubkey_table[i].check_secret_key = dsa_check_secret_key;
187     pubkey_table[i].encrypt          = dummy_encrypt;
188     pubkey_table[i].decrypt          = dummy_decrypt;
189     pubkey_table[i].sign             = dsa_sign;
190     pubkey_table[i].verify           = dsa_verify;
191     pubkey_table[i].get_nbits        = dsa_get_nbits;
192     if( !pubkey_table[i].name )
193         BUG();
194     i++;
195
196     for( ; i < TABLE_SIZE; i++ )
197         pubkey_table[i].name = NULL;
198 }
199
200
201 /****************
202  * Try to load all modules and return true if new modules are available
203  */
204 static int
205 load_pubkey_modules(void)
206 {
207     static int initialized = 0;
208     static int done = 0;
209     void *context = NULL;
210     struct pubkey_table_s *ct;
211     int ct_idx;
212     int i;
213     const char *name;
214     int any = 0;
215
216
217     if( !initialized ) {
218         cipher_modules_constructor();
219         setup_pubkey_table();
220         initialized = 1;
221         return 1;
222     }
223     if( done )
224         return 0;
225     done = 1;
226     for(ct_idx=0, ct = pubkey_table; ct_idx < TABLE_SIZE; ct_idx++,ct++ ) {
227         if( !ct->name )
228             break;
229     }
230     if( ct_idx >= TABLE_SIZE-1 )
231         BUG(); /* table already full */
232     /* now load all extensions */
233     while( (name = enum_gnupgext_pubkeys( &context, &ct->algo,
234                                 &ct->npkey, &ct->nskey, &ct->nenc,
235                                 &ct->nsig,  &ct->use,
236                                 &ct->generate,
237                                 &ct->check_secret_key,
238                                 &ct->encrypt,
239                                 &ct->decrypt,
240                                 &ct->sign,
241                                 &ct->verify,
242                                 &ct->get_nbits )) ) {
243         for(i=0; pubkey_table[i].name; i++ )
244             if( pubkey_table[i].algo == ct->algo )
245                 break;
246         if( pubkey_table[i].name ) {
247             log_info("skipping pubkey %d: already loaded\n", ct->algo );
248             continue;
249         }
250
251         if( !ct->generate  )  ct->generate = dummy_generate;
252         if( !ct->check_secret_key )  ct->check_secret_key =
253                                                     dummy_check_secret_key;
254         if( !ct->encrypt   )  ct->encrypt  = dummy_encrypt;
255         if( !ct->decrypt   )  ct->decrypt  = dummy_decrypt;
256         if( !ct->sign      )  ct->sign     = dummy_sign;
257         if( !ct->verify    )  ct->verify   = dummy_verify;
258         if( !ct->get_nbits )  ct->get_nbits= dummy_get_nbits;
259         /* put it into the table */
260         if( g10_opt_verbose > 1 )
261             log_info("loaded pubkey %d (%s)\n", ct->algo, name);
262         ct->name = name;
263         ct_idx++;
264         ct++;
265         any = 1;
266         /* check whether there are more available table slots */
267         if( ct_idx >= TABLE_SIZE-1 ) {
268             log_info("pubkey table full; ignoring other extensions\n");
269             break;
270         }
271     }
272     enum_gnupgext_pubkeys( &context, NULL, NULL, NULL, NULL, NULL, NULL,
273                                NULL, NULL, NULL, NULL, NULL, NULL, NULL );
274     return any;
275 }
276
277
278 /****************
279  * Map a string to the pubkey algo
280  */
281 int
282 gcry_pk_map_name( const char *string )
283 {
284     int i;
285     const char *s;
286
287     do {
288         for(i=0; (s=pubkey_table[i].name); i++ )
289             if( !stricmp( s, string ) )
290                 return pubkey_table[i].algo;
291     } while( load_pubkey_modules() );
292     return 0;
293 }
294
295
296 /****************
297  * Map a pubkey algo to a string
298  */
299 const char *
300 gcry_pk_algo_name( int algo )
301 {
302     int i;
303
304     do {
305         for(i=0; pubkey_table[i].name; i++ )
306             if( pubkey_table[i].algo == algo )
307                 return pubkey_table[i].name;
308     } while( load_pubkey_modules() );
309     return NULL;
310 }
311
312
313 static void
314 disable_pubkey_algo( int algo )
315 {
316     int i;
317
318     for(i=0; i < DIM(disabled_algos); i++ ) {
319         if( !disabled_algos[i] || disabled_algos[i] == algo ) {
320             disabled_algos[i] = algo;
321             return;
322         }
323     }
324     log_fatal("can't disable pubkey algo %d: table full\n", algo );
325 }
326
327
328 /****************
329  * a use of 0 means: don't care
330  */
331 static int
332 check_pubkey_algo( int algo, unsigned use )
333 {
334     int i;
335
336     do {
337         for(i=0; pubkey_table[i].name; i++ )
338             if( pubkey_table[i].algo == algo ) {
339                 if( (use & GCRY_PK_USAGE_SIGN)
340                     && !(pubkey_table[i].use & GCRY_PK_USAGE_SIGN) )
341                     return GCRYERR_WRONG_PK_ALGO;
342                 if( (use & GCRY_PK_USAGE_ENCR)
343                     && !(pubkey_table[i].use & GCRY_PK_USAGE_ENCR) )
344                     return GCRYERR_WRONG_PK_ALGO;
345
346                 for(i=0; i < DIM(disabled_algos); i++ ) {
347                     if( disabled_algos[i] == algo )
348                         return GCRYERR_INV_PK_ALGO;
349                 }
350                 return 0; /* okay */
351             }
352     } while( load_pubkey_modules() );
353     return GCRYERR_INV_PK_ALGO;
354 }
355
356
357
358
359 /****************
360  * Return the number of public key material numbers
361  */
362 static int
363 pubkey_get_npkey( int algo )
364 {
365     int i;
366     do {
367         for(i=0; pubkey_table[i].name; i++ )
368             if( pubkey_table[i].algo == algo )
369                 return pubkey_table[i].npkey;
370     } while( load_pubkey_modules() );
371     if( is_RSA(algo) )    /* special hack, so that we are able to */
372         return 2;         /* see the RSA keyids */
373     return 0;
374 }
375
376 /****************
377  * Return the number of secret key material numbers
378  */
379 static int
380 pubkey_get_nskey( int algo )
381 {
382     int i;
383     do {
384         for(i=0; pubkey_table[i].name; i++ )
385             if( pubkey_table[i].algo == algo )
386                 return pubkey_table[i].nskey;
387     } while( load_pubkey_modules() );
388     if( is_RSA(algo) )    /* special hack, so that we are able to */
389         return 6;         /* see the RSA keyids */
390     return 0;
391 }
392
393 /****************
394  * Return the number of signature material numbers
395  */
396 static int
397 pubkey_get_nsig( int algo )
398 {
399     int i;
400     do {
401         for(i=0; pubkey_table[i].name; i++ )
402             if( pubkey_table[i].algo == algo )
403                 return pubkey_table[i].nsig;
404     } while( load_pubkey_modules() );
405     if( is_RSA(algo) )    /* special hack, so that we are able to */
406         return 1;         /* see the RSA keyids */
407     return 0;
408 }
409
410 /****************
411  * Return the number of encryption material numbers
412  */
413 static int
414 pubkey_get_nenc( int algo )
415 {
416     int i;
417     do {
418         for(i=0; pubkey_table[i].name; i++ )
419             if( pubkey_table[i].algo == algo )
420                 return pubkey_table[i].nenc;
421     } while( load_pubkey_modules() );
422     if( is_RSA(algo) )    /* special hack, so that we are able to */
423         return 1;         /* see the RSA keyids */
424     return 0;
425 }
426
427 /****************
428  * Get the number of nbits from the public key
429  * FIXME: This should also take a S-Expt but must be optimized in
430  * some way becuase it is used in keylistsings ans such (store it with the
431  * S-Exp as some private data?)
432  */
433 unsigned
434 pubkey_nbits( int algo, MPI *pkey )
435 {
436     int i;
437
438     do {
439         for(i=0; pubkey_table[i].name; i++ )
440             if( pubkey_table[i].algo == algo )
441                 return (*pubkey_table[i].get_nbits)( algo, pkey );
442     } while( load_pubkey_modules() );
443     if( is_RSA(algo) )  /* we always wanna see the length of a key :-) */
444         return mpi_get_nbits( pkey[0] );
445     return 0;
446 }
447
448
449 int
450 pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
451 {
452     int i;
453
454     do {
455         for(i=0; pubkey_table[i].name; i++ )
456             if( pubkey_table[i].algo == algo )
457                 return (*pubkey_table[i].generate)( algo, nbits,
458                                                     skey, retfactors );
459     } while( load_pubkey_modules() );
460     return GCRYERR_INV_PK_ALGO;
461 }
462
463
464 int
465 pubkey_check_secret_key( int algo, MPI *skey )
466 {
467     int i;
468
469     do {
470         for(i=0; pubkey_table[i].name; i++ )
471             if( pubkey_table[i].algo == algo )
472                 return (*pubkey_table[i].check_secret_key)( algo, skey );
473     } while( load_pubkey_modules() );
474     return GCRYERR_INV_PK_ALGO;
475 }
476
477
478 /****************
479  * This is the interface to the public key encryption.
480  * Encrypt DATA with PKEY and put it into RESARR which
481  * should be an array of MPIs of size PUBKEY_MAX_NENC (or less if the
482  * algorithm allows this - check with pubkey_get_nenc() )
483  */
484 int
485 pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
486 {
487     int i, rc;
488
489     if( DBG_CIPHER ) {
490         log_debug("pubkey_encrypt: algo=%d\n", algo );
491         for(i=0; i < pubkey_get_npkey(algo); i++ )
492             log_mpidump("  pkey:", pkey[i] );
493         log_mpidump("  data:", data );
494     }
495
496     do {
497         for(i=0; pubkey_table[i].name; i++ )
498             if( pubkey_table[i].algo == algo ) {
499                 rc = (*pubkey_table[i].encrypt)( algo, resarr, data, pkey );
500                 goto ready;
501             }
502     } while( load_pubkey_modules() );
503     rc = GCRYERR_INV_PK_ALGO;
504   ready:
505     if( !rc && DBG_CIPHER ) {
506         for(i=0; i < pubkey_get_nenc(algo); i++ )
507             log_mpidump("  encr:", resarr[i] );
508     }
509     return rc;
510 }
511
512
513
514 /****************
515  * This is the interface to the public key decryption.
516  * ALGO gives the algorithm to use and this implicitly determines
517  * the size of the arrays.
518  * result is a pointer to a mpi variable which will receive a
519  * newly allocated mpi or NULL in case of an error.
520  */
521 int
522 pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
523 {
524     int i, rc;
525
526     *result = NULL; /* so the caller can always do an mpi_free */
527     if( DBG_CIPHER ) {
528         log_debug("pubkey_decrypt: algo=%d\n", algo );
529         for(i=0; i < pubkey_get_nskey(algo); i++ )
530             log_mpidump("  skey:", skey[i] );
531         for(i=0; i < pubkey_get_nenc(algo); i++ )
532             log_mpidump("  data:", data[i] );
533     }
534
535     do {
536         for(i=0; pubkey_table[i].name; i++ )
537             if( pubkey_table[i].algo == algo ) {
538                 rc = (*pubkey_table[i].decrypt)( algo, result, data, skey );
539                 goto ready;
540             }
541     } while( load_pubkey_modules() );
542     rc = GCRYERR_INV_PK_ALGO;
543   ready:
544     if( !rc && DBG_CIPHER ) {
545         log_mpidump(" plain:", *result );
546     }
547     return rc;
548 }
549
550
551 /****************
552  * This is the interface to the public key signing.
553  * Sign data with skey and put the result into resarr which
554  * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the
555  * algorithm allows this - check with pubkey_get_nsig() )
556  */
557 static int
558 pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
559 {
560     int i, rc;
561
562     if( DBG_CIPHER ) {
563         log_debug("pubkey_sign: algo=%d\n", algo );
564         for(i=0; i < pubkey_get_nskey(algo); i++ )
565             log_mpidump("  skey:", skey[i] );
566         log_mpidump("  data:", data );
567     }
568
569     do {
570         for(i=0; pubkey_table[i].name; i++ )
571             if( pubkey_table[i].algo == algo ) {
572                 rc = (*pubkey_table[i].sign)( algo, resarr, data, skey );
573                 goto ready;
574             }
575     } while( load_pubkey_modules() );
576     rc = GCRYERR_INV_PK_ALGO;
577   ready:
578     if( !rc && DBG_CIPHER ) {
579         for(i=0; i < pubkey_get_nsig(algo); i++ )
580             log_mpidump("   sig:", resarr[i] );
581     }
582     return rc;
583 }
584
585 /****************
586  * Verify a public key signature.
587  * Return 0 if the signature is good
588  */
589 static int
590 pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
591                     int (*cmp)(void *, MPI), void *opaquev )
592 {
593     int i, rc;
594
595     do {
596         for(i=0; pubkey_table[i].name; i++ )
597             if( pubkey_table[i].algo == algo ) {
598                 rc = (*pubkey_table[i].verify)( algo, hash, data, pkey,
599                                                             cmp, opaquev );
600                 goto ready;
601             }
602     } while( load_pubkey_modules() );
603     rc = GCRYERR_INV_PK_ALGO;
604   ready:
605     return rc;
606 }
607
608
609 static void
610 release_mpi_array( MPI *array )
611 {
612     for( ; *array; array++ ) {
613         mpi_free(*array);
614         *array = NULL;
615     }
616 }
617
618 /****************
619  * Convert a S-Exp with either a private or a public key to our
620  * internal format. Currently we do only support the following
621  * algorithms:
622  *    dsa
623  *    rsa
624  *    openpgp-dsa
625  *    openpgp-rsa
626  *    openpgp-elg
627  *    openpgp-elg-sig
628  * Provide a SE with the first element be either "private-key" or
629  * or "public-key". the followed by a list with its first element
630  * be one of the above algorithm identifiers and the following
631  * elements are pairs with parameter-id and value.
632  * NOTE: we look through the list to find a list beginning with
633  * "private-key" or "public-key" - the first one found is used.
634  *
635  * FIXME: Allow for encrypted secret keys here.
636  *
637  * Returns: A pointer to an allocated array of MPIs if the return value is
638  *          zero; the caller has to release this array.
639  */
640 static int
641 sexp_to_key( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
642 {
643     GCRY_SEXP list, l2;
644     const char *name;
645     const char *s;
646     size_t n;
647     int i, idx;
648     int algo;
649     const char *elems1, *elems2;
650     GCRY_MPI *array;
651
652     /* check that the first element is valid */
653     list = gcry_sexp_find_token( sexp, want_private? "private-key"
654                                                     :"public-key", 0 );
655     if( !list )
656         return GCRYERR_INV_OBJ; /* Does not contain a public- or private-key object */
657     list = gcry_sexp_cdr( list );
658     if( !list )
659         return GCRYERR_NO_OBJ; /* no cdr for the key object */
660     name = gcry_sexp_car_data( list, &n );
661     if( !name )
662         return GCRYERR_INV_OBJ; /* invalid structure of object */
663     for(i=0; (s=algo_info_table[i].name); i++ ) {
664         if( strlen(s) == n && !memcmp( s, name, n ) )
665             break;
666     }
667     if( !s )
668         return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
669     algo = algo_info_table[i].algo;
670     elems1 = algo_info_table[i].common_elements;
671     elems2 = want_private? algo_info_table[i].secret_elements
672                          : algo_info_table[i].public_elements;
673     array = g10_calloc( strlen(elems1)+strlen(elems2)+1, sizeof *array );
674     if( !array )
675         return GCRYERR_NO_MEM;
676
677     idx = 0;
678     for(s=elems1; *s; s++, idx++ ) {
679         l2 = gcry_sexp_find_token( list, s, 1 );
680         if( !l2 ) {
681             g10_free( array );
682             return GCRYERR_NO_OBJ; /* required parameter not found */
683         }
684         array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
685         if( !array[idx] ) {
686             g10_free( array );
687             return GCRYERR_INV_OBJ; /* required parameter is invalid */
688         }
689     }
690     for(s=elems2; *s; s++, idx++ ) {
691         l2 = gcry_sexp_find_token( list, s, 1 );
692         if( !l2 ) {
693             g10_free( array );
694             return GCRYERR_NO_OBJ; /* required parameter not found */
695         }
696         /* FIXME: put the MPI in secure memory when needed */
697         array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
698         if( !array[idx] ) {
699             g10_free( array );
700             return GCRYERR_INV_OBJ; /* required parameter is invalid */
701         }
702     }
703
704     *retarray = array;
705     *retalgo = algo;
706
707     return 0;
708 }
709
710 static int
711 sexp_to_sig( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
712 {
713     GCRY_SEXP list, l2;
714     const char *name;
715     const char *s;
716     size_t n;
717     int i, idx;
718     int algo;
719     const char *elems;
720     GCRY_MPI *array;
721
722     /* check that the first element is valid */
723     list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
724     if( !list )
725         return GCRYERR_INV_OBJ; /* Does not contain a signature value object */
726     list = gcry_sexp_cdr( list );
727     if( !list )
728         return GCRYERR_NO_OBJ; /* no cdr for the sig object */
729     name = gcry_sexp_car_data( list, &n );
730     if( !name )
731         return GCRYERR_INV_OBJ; /* invalid structure of object */
732     for(i=0; (s=sig_info_table[i].name); i++ ) {
733         if( strlen(s) == n && !memcmp( s, name, n ) )
734             break;
735     }
736     if( !s )
737         return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
738     algo = sig_info_table[i].algo;
739     elems = sig_info_table[i].elements;
740     array = g10_calloc( (strlen(elems)+1) , sizeof *array );
741     if( !array )
742         return GCRYERR_NO_MEM;
743
744     idx = 0;
745     for(s=elems; *s; s++, idx++ ) {
746         l2 = gcry_sexp_find_token( list, s, 1 );
747         if( !l2 ) {
748             g10_free( array );
749             return GCRYERR_NO_OBJ; /* required parameter not found */
750         }
751         array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
752         if( !array[idx] ) {
753             g10_free( array );
754             return GCRYERR_INV_OBJ; /* required parameter is invalid */
755         }
756     }
757
758     *retarray = array;
759     *retalgo = algo;
760
761     return 0;
762 }
763
764
765
766
767
768 int
769 gcry_pk_encrypt( GCRY_SEXP *result, GCRY_SEXP data, GCRY_SEXP pkey )
770 {
771         /* ... */
772     return 0;
773 }
774
775 int
776 gcry_pk_decrypt( GCRY_SEXP *result, GCRY_SEXP data, GCRY_SEXP skey )
777 {
778         /* ... */
779     return 0;
780 }
781
782
783
784 /****************
785  * Create a signature.
786  *
787  * Caller has to provide a secret kez as the SEXP skey and data expressed
788  * as a SEXP list hash with only one emelennt which should instantly be
789  * available as a MPI.  Later versions of this functions may provide padding
790  * and other things depending on data.
791  *
792  * Returns: 0 or an errorcode.
793  *          In case of 0 the function returns a new SEXP with the
794  *          signature value; the structure of this signature depends on the
795  *          other arguments but is always suitable to be passed to
796  *          gcry_pk_verify
797  */
798 int
799 gcry_pk_sign( GCRY_SEXP *r_sig, GCRY_SEXP s_hash, GCRY_SEXP s_skey )
800 {
801     MPI *skey, hash;
802     MPI *result;
803     int i, algo, rc;
804     const char *algo_name, *algo_elems;
805     GCRY_SEXP s;
806
807     rc = sexp_to_key( s_skey, 1, &skey, &algo );
808     if( rc )
809         return rc;
810
811     /* get the name and the required size of the result array */
812     for(i=0; (algo_name = sig_info_table[i].name); i++ ) {
813         if( sig_info_table[i].algo == algo )
814             break;
815     }
816     if( !algo_name ) {
817         release_mpi_array( skey );
818         return -4; /* oops: unknown algorithm */
819     }
820     algo_elems = sig_info_table[i].elements;
821
822     /* get the stuff we want to sign */
823     hash = gcry_sexp_car_mpi( s_hash, 0 );
824     if( !hash ) {
825         release_mpi_array( skey );
826         return -1; /* fixme: get a real errorcode for this */
827     }
828     result = g10_xcalloc( (strlen(algo_elems)+1) , sizeof *result );
829     rc = pubkey_sign( algo, result, hash, skey );
830     release_mpi_array( skey );
831     mpi_free( hash );
832     if( rc ) {
833         g10_free( result );
834         return rc;
835     }
836
837     s = SEXP_NEW( algo_name, 0 );
838     for(i=0; algo_elems[i]; i++ ) {
839         char tmp[2];
840         tmp[0] = algo_elems[i];
841         tmp[1] = 0;
842         s = gcry_sexp_append( s, gcry_sexp_new_name_mpi( tmp, result[i] ) );
843     }
844     g10_free( result );
845     *r_sig = SEXP_CONS( SEXP_NEW( "sig-val", 0 ), s );
846     gcry_sexp_dump( *r_sig );
847     return 0;
848 }
849
850
851 /****************
852  * Verify a sgnature.  Caller has to supply the public key pkey,
853  * the signature sig and his hashvalue data.  Public key has to be
854  * a standard public key given as an S-Exp, sig is a S-Exp as returned
855  * from gcry_pk_sign and data must be an S-Exp like the one in sign too.
856  */
857 int
858 gcry_pk_verify( GCRY_SEXP s_sig, GCRY_SEXP s_hash, GCRY_SEXP s_pkey )
859 {
860     MPI *pkey, hash, *sig;
861     int algo, sigalgo;
862     int rc;
863
864     rc = sexp_to_key( s_pkey, 0, &pkey, &algo );
865     if( rc )
866         return rc;
867     rc = sexp_to_sig( s_sig, &sig, &sigalgo );
868     if( rc ) {
869         release_mpi_array( pkey );
870         return rc;
871     }
872     if( algo != sigalgo ) {
873         release_mpi_array( pkey );
874         release_mpi_array( sig );
875         return -1; /* fixme: add real errornumber - algo does not match */
876     }
877
878     hash = gcry_sexp_car_mpi( s_hash, 0 );
879     if( !hash ) {
880         release_mpi_array( pkey );
881         release_mpi_array( sig );
882         return -1; /* fixme: get a real errorcode for this */
883     }
884
885     rc = pubkey_verify( algo, hash, sig, pkey, NULL, NULL );
886     release_mpi_array( pkey );
887     release_mpi_array( sig );
888     mpi_free(hash);
889
890     return rc;
891 }
892
893
894 int
895 gcry_pk_ctl( int cmd, void *buffer, size_t buflen)
896 {
897     switch( cmd ) {
898       case GCRYCTL_DISABLE_ALGO:
899         /* this one expects a buffer pointing to an
900          * integer with the algo number.
901          */
902         if( !buffer || buflen != sizeof(int) )
903             return set_lasterr( GCRYERR_INV_CIPHER_ALGO );
904         disable_pubkey_algo( *(int*)buffer );
905         break;
906
907       default:
908         return set_lasterr( GCRYERR_INV_OP );
909     }
910     return 0;
911 }
912
913
914 /****************
915  * Return information about the given algorithm
916  * WHAT select the kind of information returned:
917  *  GCRYCTL_TEST_ALGO:
918  *      Returns 0 when the specified algorithm is available for use.
919  *      Buffer must be NULL, nbytes  may have the address of a variable
920  *      with the required usage of the algorithm. It may be 0 for don't
921  *      care or a combination of the GCRY_PK_USAGE_xxx flags;
922  *
923  * On error the value -1 is returned and the error reason may be
924  * retrieved by gcry_errno().
925  * Note:  Because this function is in most caes used to return an
926  * integer value, we can make it easier for the caller to just look at
927  * the return value.  The caller will in all cases consult the value
928  * and thereby detecting whether a error occured or not (i.e. while checking
929  * the block size)
930  */
931 int
932 gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes)
933 {
934     switch( what ) {
935       case GCRYCTL_TEST_ALGO: {
936             int use = nbytes? *nbytes: 0;
937             if( buffer ) {
938                 set_lasterr( GCRYERR_INV_ARG );
939                 return -1;
940             }
941             if( check_pubkey_algo( algo, use ) ) {
942                 set_lasterr( GCRYERR_INV_PK_ALGO );
943                 return -1;
944             }
945         }
946         break;
947
948       case GCRYCTL_GET_ALGO_NPKEY: return pubkey_get_npkey( algo );
949       case GCRYCTL_GET_ALGO_NSKEY: return pubkey_get_nskey( algo );
950       case GCRYCTL_GET_ALGO_NSIGN: return pubkey_get_nsig( algo );
951       case GCRYCTL_GET_ALGO_NENCR: return pubkey_get_nenc( algo );
952
953       default:
954         set_lasterr( GCRYERR_INV_OP );
955         return -1;
956     }
957     return 0;
958 }
959
960