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