2003-07-08 Moritz Schulte <moritz@g10code.com>
[libgcrypt.git] / cipher / ac.c
1 /* ac.c - Alternative interface for asymmetric cryptography.
2    Copyright (C) 2003 Free Software Foundation, Inc.
3  
4    This file is part of Libgcrypt.
5   
6    Libgcrypt is free software; you can redistribute it and/or modify
7    it under the terms of the GNU Lesser general Public License as
8    published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10   
11    Libgcrypt is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU Lesser General Public License for more details.
15   
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <stddef.h>
28
29 #include "g10lib.h"
30
31 \f
32
33 /* At the moment the ac interface is a wrapper around the pk
34    interface, but this might change somewhen in the future, depending
35    on how much people prefer the ac interface.  */
36
37 /* Mapping of flag numbers to the according strings as it is expected
38    for S-expressions.  */
39 struct number_string
40 {
41   int number;
42   const char *string;
43 } gcry_ac_flags[] =
44   {
45     { GCRY_AC_FLAG_DATA_NO_BLINDING, "no-blinding" },
46     { 0, NULL },
47   };
48
49 /* The positions in this list correspond to the values contained in
50    the gcry_ac_key_type_t enumeration list.  */
51 const char *ac_key_identifiers[] =
52   {
53     "private-key",
54     "public-key",
55   };
56
57 /* These specifications are needed for key-pair generation; the caller
58    is allowed to pass additional, algorithm-specific `specs' to
59    gcry_ac_key_pair_generate.  This list is used for decoding the
60    provided values according to the selected algorithm.  */
61 struct gcry_ac_key_generate_spec
62 {
63   int algorithm;                /* Algorithm for which this flag is
64                                    relevant.  */
65   const char *name;             /* Name of this flag.  */
66   size_t offset;                /* Offset in the cipher-specific spec
67                                    structure at which the MPI value
68                                    associated with this flag is to be
69                                    found.  */
70 } gcry_ac_key_generate_specs[] =
71   {
72     { GCRY_AC_RSA, "rsa-use-e", offsetof (gcry_ac_key_spec_rsa_t, e) },
73     { 0 },
74   };
75
76 /* Handle structure.  */
77 struct gcry_ac_handle
78 {
79   int algorithm;                /* Algorithm ID associated with this
80                                    handle.  */
81   const char *algorithm_name;   /* Name of the algorithm.  */
82   unsigned int flags;           /* Flags, not used yet.  */
83   gcry_module_t module;         /* Reference to the algorithm
84                                    module.  */
85 };
86
87 /* A named MPI value.  */
88 typedef struct gcry_ac_mpi
89 {
90   const char *name;
91   gcry_mpi_t mpi;
92 } gcry_ac_mpi_t;
93
94 /* A data set, that is simply a list of named MPI values.  */
95 struct gcry_ac_data
96 {
97   gcry_ac_mpi_t *data;          /* List of named values.      */
98   unsigned int data_n;          /* Number of values in DATA.  */
99 };
100
101 /* The key in `native' ac form and as an S-expression. */
102 struct gcry_ac_key
103 {
104   gcry_ac_data_t data;          /* Data in native ac structure.  */
105   gcry_sexp_t data_sexp;        /* Data as an S-expression.      */
106   gcry_ac_key_type_t type;      /* Type of the key.              */
107 };
108
109 /* Two keys.  */
110 struct gcry_ac_key_pair
111 {
112   gcry_ac_key_t public;
113   gcry_ac_key_t secret;
114 };
115
116 \f
117
118 /*
119  * Primitive functions for the manipulation of `data sets'.
120  */
121
122 /* Return in AC_MPI a pointer to the named MPI contained in DATA that
123    is labelled with NAME or NULL in case there is no MPI with the that
124    name.  */
125 static void
126 gcry_ac_data_search (gcry_ac_data_t data,
127                      const char *name,
128                      gcry_ac_mpi_t **ac_mpi)
129 {
130   gcry_ac_mpi_t *ac_mpi_found = NULL;
131   int i;
132
133   /* Search.  */
134   for (i = 0; i < data->data_n; i++)
135     if (! strcmp (name, data->data[i].name))
136       ac_mpi_found = &data->data[i];
137
138   *ac_mpi = ac_mpi_found;
139 }
140
141 /* Add MPI to DATA, with the label being NAME.  */
142 static gpg_err_code_t
143 gcry_ac_data_add (gcry_ac_data_t data,
144                   const char *name, gcry_mpi_t mpi)
145 {
146   gpg_err_code_t err = GPG_ERR_NO_ERROR;
147   gcry_ac_mpi_t *ac_mpis = NULL;
148
149   /* Allocate.  */
150   ac_mpis = realloc (data->data,
151                      sizeof (gcry_ac_mpi_t) * (data->data_n + 1));
152   if (! ac_mpis)
153     err = gpg_err_code_from_errno (errno);
154
155   if (! err)
156     {
157       /* Fill. */
158       if (ac_mpis != data->data)
159         data->data = ac_mpis;
160       data->data[data->data_n].name = name;
161       data->data[data->data_n].mpi = mpi;
162       data->data_n++;
163     }
164
165   return err;
166 }
167
168 /* Create a copy of the data set DATA and store it in DATA_CP.  */
169 static gpg_err_code_t
170 gcry_ac_data_copy_internal (gcry_ac_data_t *data_cp, gcry_ac_data_t data)
171 {
172   gpg_err_code_t err = GPG_ERR_NO_ERROR;
173   gcry_ac_data_t data_new = NULL;
174   int i = 0;
175
176   /* Allocate data set.  */
177   data_new = gcry_malloc (sizeof (struct gcry_ac_data));
178   if (! data_new)
179     err = gpg_err_code_from_errno (errno);
180   else
181     data_new->data_n = data->data_n;
182
183   if (! err)
184     {
185       /* Allocate space for named MPIs.  */
186       data_new->data = gcry_malloc (sizeof (gcry_ac_mpi_t) * data->data_n);
187       if (! data_new->data)
188         err = gpg_err_code_from_errno (errno);
189     }
190
191   if (! err)
192     {
193       /* Copy named MPIs.  */
194       
195       for (i = 0; i < data_new->data_n && (! err); i++)
196         {
197           data_new->data[i].name = NULL;
198           data_new->data[i].mpi = NULL;
199
200           /* Name.  */
201           data_new->data[i].name = strdup (data->data[i].name);
202           if (! data_new->data[i].name)
203             err = gpg_err_code_from_errno (errno);
204
205           if (! err)
206             {
207               /* MPI.  */
208               data_new->data[i].mpi = gcry_mpi_copy (data->data[i].mpi);
209               if (! data_new->data[i].mpi)
210                 err = gpg_err_code_from_errno (errno);
211             }
212         }
213     }
214
215   if (! err)
216     /* Copy out.  */
217     *data_cp = data_new;
218   else
219     {
220       /* Deallocate resources.  */
221       if (data_new)
222         {
223           if (data_new->data)
224             {
225               for (; i >= 0; i--)
226                 {
227                   if (data_new->data[i].name)
228                     free ((void *) data_new->data[i].name);
229                   if (data_new->data[i].mpi)
230                     gcry_mpi_release (data_new->data[i].mpi);
231                 }
232               gcry_free (data_new->data);
233             }
234           gcry_free (data_new);
235         }
236     }
237
238   return err;
239 }
240
241 \f
242
243 /* 
244  * Functions for converting data between the native ac and the
245  * S-expression structure.
246  */
247
248 /* Extract the S-Expression DATA_SEXP into DATA under the control of
249    TYPE and NAME.  This function assumes that S-Expressions are of the
250    following structure:
251
252      (IDENTIFIER <data to be ignored>
253                  (ALGORITHM <list of named MPI values>))
254
255   IDENTIFIER is one of `private-key', `public-key', `enc-val',
256   `sig-val'; ALGORITHM is the name of the algorithm used.  */
257 static gpg_err_code_t
258 gcry_ac_data_extract (const char *identifier, const char *algorithm,
259                       gcry_sexp_t data_sexp, gcry_ac_data_t *data)
260 {
261   gpg_err_code_t err = GPG_ERR_NO_ERROR;
262   gcry_sexp_t data_element_sexp = NULL;
263   gcry_sexp_t inner_data_sexp = NULL;
264   size_t inner_data_n;
265
266   const char *name;
267   size_t name_n;
268
269   gcry_mpi_t data_elem_mpi = NULL;
270   char *data_elem_name = NULL;
271
272   gcry_ac_data_t data_new = NULL;
273
274   int i = 0;
275
276   /* Verify that the S-expression contains the correct identifier.  */
277   name = gcry_sexp_nth_data (data_sexp, 0, &name_n);
278   if (! name)
279     err = GPG_ERR_INTERNAL;
280   else if (strncmp (identifier, name, name_n))
281     err = GPG_ERR_INTERNAL;
282
283   if (! err)
284     {
285       /* Extract inner S-expression.  */
286       inner_data_sexp = gcry_sexp_find_token (data_sexp, algorithm, 0);
287       if (! inner_data_sexp)
288         err = GPG_ERR_INTERNAL;
289       else
290         /* Count data elements, this includes the name of the
291            algorithm.  */
292         inner_data_n = gcry_sexp_length (inner_data_sexp);
293     }
294
295   if (! err)
296     {
297       /* Allocate new data set.  */
298       data_new = gcry_malloc (sizeof (struct gcry_ac_data));
299       if (! data_new)
300         err = gpg_err_code_from_errno (errno);
301       else
302         {
303           data_new->data = gcry_malloc (sizeof (gcry_ac_mpi_t) * (inner_data_n - 1));
304           if (! data_new->data)
305             err = gpg_err_code_from_errno (errno);
306         }
307     }
308
309   if (! err)
310     {
311       /* Iterate through list of data elements and add them to the
312          data set.  */
313
314       for (i = 1; i < inner_data_n; i++)
315         {
316           data_new->data[i - 1].name = NULL;
317           data_new->data[i - 1].mpi = NULL;
318
319           /* Get the S-expression of the named MPI, that contains the
320              name and the MPI value.  */
321           data_element_sexp = gcry_sexp_nth (inner_data_sexp, i);
322           if (! data_element_sexp)
323             err = GPG_ERR_INTERNAL;
324
325           if (! err)
326             {
327               /* Extract the name.  */
328               name = gcry_sexp_nth_data (data_element_sexp, 0, &name_n);
329               if (! name)
330                 err = GPG_ERR_INTERNAL;
331             }
332
333           if (! err)
334             {
335               /* Extract the MPI value.  */
336               data_elem_mpi = gcry_sexp_nth_mpi (data_element_sexp, 1,
337                                                  GCRYMPI_FMT_USG);
338               if (! data_elem_mpi)
339                 err = GPG_ERR_INTERNAL;
340             }
341
342           if (! err)
343             {
344               /* Duplicate the name.  */
345               data_elem_name = gcry_malloc (name_n + 1);
346               if (! data_elem_name)
347                 
348                 err = gpg_err_code_from_errno (errno);
349               else
350                 {
351                   strncpy (data_elem_name, name, name_n);
352                   data_elem_name[name_n] = 0;
353                 }
354             }
355
356           /* Done.  */
357
358           if (data_element_sexp)
359             gcry_sexp_release (data_element_sexp);
360
361           if (! err)
362             {
363               data_new->data[i - 1].name = data_elem_name;
364               data_new->data[i - 1].mpi = data_elem_mpi;
365             }
366           else
367             break;
368         }
369     }
370
371   if (! err)
372     {
373       /* Copy out.  */
374       data_new->data_n = inner_data_n - 1;
375       *data = data_new;
376     }
377   else
378     {
379       /* Deallocate resources.  */
380
381       if (data_new)
382         {
383           if (data_new->data)
384             {
385               int j;
386              
387               for (j = 0; j < i - 1; j++)
388                 {
389                   if (data_new->data[j].name)
390                     gcry_free ((void *) data_new->data[j].name);
391                   if (data_new->data[j].mpi)
392                     gcry_mpi_release (data_new->data[j].mpi);
393                 }
394
395               gcry_free (data_new->data);
396             }
397           gcry_free (data_new);
398         }
399     }
400
401   return err;
402 }
403
404 /* Construct an S-expression from the DATA and store it in
405    DATA_SEXP. The S-expression will be of the following structure:
406
407      (IDENTIFIER (flags [...])
408                  (ALGORITHM <list of named MPI values>))  */
409 static gpg_err_code_t
410 gcry_ac_data_construct (const char *identifier, unsigned int flags,
411                         const char *algorithm, gcry_ac_data_t data,
412                         gcry_sexp_t *data_sexp)
413 {
414   gpg_err_code_t err = GPG_ERR_NO_ERROR;
415   void **arg_list = NULL;
416
417   gcry_sexp_t data_sexp_new = NULL;
418
419   size_t data_format_n = 0;
420   char *data_format = NULL;
421
422   int i;
423
424   /* We build a list of arguments to pass to
425      gcry_sexp_build_array().  */
426   arg_list = gcry_malloc (sizeof (void *) * data->data_n);
427   if (! arg_list)
428     err = gpg_err_code_from_errno (errno);
429   else
430     /* Fill list with MPIs.  */
431     for (i = 0; i < data->data_n; i++)
432       arg_list[i] = (void *) &data->data[i].mpi;
433
434   if (! err)
435     {
436       /* Calculate size of format string.  */
437
438       data_format_n = 12 + strlen (identifier) + strlen (algorithm);
439       for (i = 0; i < data->data_n; i++)
440         /* Per-element sizes.  */
441         data_format_n += 4 + strlen (data->data[i].name);
442
443       /* Add flags.  */
444       for (i = 0; gcry_ac_flags[i].number; i++)
445         if (flags & gcry_ac_flags[i].number)
446           data_format_n += strlen (gcry_ac_flags[i].string) + 1;
447
448       /* Done.  */
449       data_format = gcry_malloc (data_format_n);
450       if (! data_format)
451         err = gpg_err_code_from_errno (errno);
452     }
453
454   if (! err)
455     {
456       /* Construct the format string.  */
457
458       *data_format = 0;
459       strcat (data_format, "(");
460       strcat (data_format, identifier);
461       strcat (data_format, "(flags");
462       for (i = 0; gcry_ac_flags[i].number; i++)
463         if (flags & gcry_ac_flags[i].number)
464           {
465             strcat (data_format, " ");
466             strcat (data_format, gcry_ac_flags[i].string);
467           }
468       strcat (data_format, ")(");
469       strcat (data_format, algorithm);
470       for (i = 0; i < data->data_n; i++)
471         {
472           strcat (data_format, "(");
473           strcat (data_format, data->data[i].name);
474           strcat (data_format, "%m)");
475         }
476       strcat (data_format, "))");
477
478       /* Create final S-expression.  */
479       err = gcry_sexp_build_array (&data_sexp_new, NULL,
480                                    data_format, arg_list);
481     }
482
483   if (err)
484     {
485       /* Deallocate resources.  */
486
487       if (arg_list)
488         gcry_free (arg_list);
489       if (data_format)
490         gcry_free (data_format);
491       if (data_sexp_new)
492         gcry_sexp_release (data_sexp_new);
493     }
494
495   else
496     /* Copy-out.  */
497     *data_sexp = data_sexp_new;
498
499   return err;
500 }
501
502 \f
503
504 /* 
505  * Functions for working with data sets.
506  */
507
508 /* Creates a new, empty data set and stores it in DATA.  */
509 gpg_error_t
510 gcry_ac_data_new (gcry_ac_data_t *data)
511 {
512   gpg_err_code_t err = GPG_ERR_NO_ERROR;
513   gcry_ac_data_t data_new = NULL;
514
515   data_new = gcry_malloc (sizeof (struct gcry_ac_data));
516   if (! data_new)
517     err = gpg_err_code_from_errno (errno);
518
519   if (! err)
520     {
521       data_new->data = NULL;
522       data_new->data_n = 0;
523       *data = data_new;
524     }
525
526   return gpg_error (err);
527 }
528
529 /* Destroys the data set DATA.  */
530 void
531 gcry_ac_data_destroy (gcry_ac_data_t data)
532 {
533   int i;
534
535   for (i = 0; i < data->data_n; i++)
536     {
537       gcry_free ((void *) data->data[i].name);
538       gcry_mpi_release (data->data[i].mpi);
539     }
540   gcry_free (data->data);
541   gcry_free (data);
542 }
543
544 /* Adds the value MPI to the data set DATA with the label NAME.  If
545    there is already a value with that label, it is replaced, otherwise
546    a new value is added. */
547 gpg_error_t
548 gcry_ac_data_set (gcry_ac_data_t data,
549                   const char *name, gcry_mpi_t mpi)
550 {
551   gpg_err_code_t err = GPG_ERR_NO_ERROR;
552   gcry_ac_mpi_t *ac_mpi;
553
554   gcry_ac_data_search (data, name, &ac_mpi);
555   if (ac_mpi)
556     {
557       /* An entry for NAME does already exist, replace it.  */
558       if (ac_mpi->mpi != mpi)
559         {
560           gcry_mpi_release (ac_mpi->mpi);
561           ac_mpi->mpi = mpi;
562         }
563     }
564   else
565     {
566       /* Create a new entry.  */
567
568       gcry_mpi_t mpi_cp = NULL;
569       char *name_cp = NULL;
570
571       name_cp = strdup (name);
572       if (name_cp)
573         mpi_cp = gcry_mpi_copy (mpi);
574       if (! (name_cp && mpi_cp))
575         err = gpg_err_code_from_errno (errno);
576
577       if (! err)
578         err = gcry_ac_data_add (data, name_cp, mpi_cp);
579
580       if (err)
581         {
582           if (name_cp)
583             gcry_free (name_cp);
584           if (mpi_cp)
585             gcry_mpi_release (mpi_cp);
586         }
587     }
588
589   return gpg_error (err);
590 }
591
592 /* Create a copy of the data set DATA and store it in DATA_CP.  */
593 gpg_error_t
594 gcry_ac_data_copy (gcry_ac_data_t *data_cp, gcry_ac_data_t data)
595 {
596   gpg_err_code_t err = GPG_ERR_NO_ERROR;
597
598   err = gcry_ac_data_copy_internal (data_cp, data);
599
600   return gpg_error (err);
601 }
602
603 /* Returns the number of named MPI values inside of the data set
604    DATA.  */
605 unsigned int
606 gcry_ac_data_length (gcry_ac_data_t data)
607 {
608   return data->data_n;
609 }
610
611 /* Stores the value labelled with NAME found in the data set DATA in
612    MPI.  The returned MPI value will be released in case
613    gcry_ac_data_set is used to associate the label NAME with a
614    different MPI value.  */
615 gpg_error_t
616 gcry_ac_data_get_name (gcry_ac_data_t data, const char *name,
617                        gcry_mpi_t *mpi)
618 {
619   gpg_err_code_t err = GPG_ERR_NO_DATA;
620   gcry_mpi_t mpi_found = NULL;
621   int i;
622   
623   for (i = 0; i < data->data_n && (! mpi_found); i++)
624     if (! strcmp (data->data[i].name, name))
625       {
626         mpi_found = data->data[i].mpi;
627         err = GPG_ERR_NO_ERROR;
628       }
629
630   if (! err)
631     *mpi = mpi_found;
632
633   return gpg_error (err);
634 }
635
636 /* Stores in NAME and MPI the named MPI value contained in the data
637    set DATA with the index INDEX.  NAME or MPI may be NULL.  The
638    returned MPI value will be released in case gcry_ac_data_set is
639    used to associate the label NAME with a different MPI value.  */
640 gpg_error_t
641 gcry_ac_data_get_index (gcry_ac_data_t data, unsigned int index,
642                         const char **name, gcry_mpi_t *mpi)
643 {
644   gpg_err_code_t err = GPG_ERR_NO_ERROR;
645
646   if (index < data->data_n)
647     {
648       if (name)
649         *name = data->data[index].name;
650       if (mpi)
651         *mpi = data->data[index].mpi;
652     }
653   else
654     err = GPG_ERR_NO_DATA;
655
656   return gpg_error (err);
657 }
658
659 /* Destroys any values contained in the data set DATA.  */
660 void
661 gcry_ac_data_clear (gcry_ac_data_t data)
662 {
663   gcry_free (data->data);
664   data->data = NULL;
665   data->data_n = 0;
666 }
667
668 \f
669
670 /*
671  * Handle management.
672  */
673
674 /* Creates a new handle for the algorithm ALGORITHM and store it in
675    HANDLE.  FLAGS is not used yet.  */
676 gpg_error_t
677 gcry_ac_open (gcry_ac_handle_t *handle,
678               gcry_ac_id_t algorithm, unsigned int flags)
679 {
680   gpg_err_code_t err = GPG_ERR_NO_ERROR;
681   gcry_module_t module = NULL;
682   gcry_ac_handle_t handle_new;
683   const char *algorithm_name;
684
685   /* Get name.  */
686   algorithm_name = gcry_pk_algo_name (algorithm);
687   if (! *algorithm_name)
688     err = GPG_ERR_PUBKEY_ALGO;
689
690   if (! err)
691     /* Acquire reference to the pubkey module.  */
692     err = _gcry_pk_module_lookup (algorithm, &module);
693   
694   if (! err)
695     {
696       /* Allocate.  */
697       handle_new = gcry_malloc (sizeof (struct gcry_ac_handle));
698       if (! handle_new)
699         err = gpg_err_code_from_errno (errno);
700     }
701
702   if (! err)
703     {
704       /* Done.  */
705       handle_new->algorithm = algorithm;
706       handle_new->algorithm_name = algorithm_name;
707       handle_new->flags = flags;
708       handle_new->module = module;
709       *handle = handle_new;
710     }
711   else
712     {
713       /* Deallocate resources.  */
714       if (module)
715         _gcry_pk_module_release (module);
716     }
717
718   return gpg_error (err);
719 }
720
721 /* Destroys the handle HANDLE.  */
722 void
723 gcry_ac_close (gcry_ac_handle_t handle)
724 {
725   /* Release reference to pubkey module.  */
726   _gcry_pk_module_release (handle->module);
727   gcry_free (handle);
728 }
729
730 \f
731
732 /* 
733  * Key management.
734  */
735
736 /* Creates a new key of type TYPE, consisting of the MPI values
737    contained in the data set DATA and stores it in KEY.  */
738 gpg_error_t
739 gcry_ac_key_init (gcry_ac_key_t *key,
740                   gcry_ac_handle_t handle,
741                   gcry_ac_key_type_t type,
742                   gcry_ac_data_t data)
743 {
744   gpg_err_code_t err = GPG_ERR_NO_ERROR;
745   gcry_ac_data_t data_new = NULL;
746   gcry_sexp_t data_sexp = NULL;
747   gcry_ac_key_t key_new = NULL;
748
749   /* Allocate.  */
750   key_new = gcry_malloc (sizeof (struct gcry_ac_key));
751   if (! key_new)
752     err = gpg_err_code_from_errno (errno);
753
754   if (! err)
755     /* Create S-expression from data set.  */
756     err = gcry_ac_data_construct (ac_key_identifiers[type], 0,
757                                   handle->algorithm_name, data, &data_sexp);
758
759   if (! err)
760     /* Copy data set.  */
761     err = gcry_ac_data_copy_internal (&data_new, data);
762
763   if (! err)
764     {
765       /* Done.  */
766       key_new->data_sexp = data_sexp;
767       key_new->data = data_new;
768       key_new->type = type;
769       *key = key_new;
770     }
771   else
772     {
773       /* Deallocate resources.  */
774       if (key_new)
775         gcry_free (key_new);
776       if (data_sexp)
777         gcry_sexp_release (data_sexp);
778     }
779
780   return gpg_error (err);
781 }
782
783 /* Generates a new key pair via the handle HANDLE of NBITS bits and
784    stores it in KEY_PAIR.  In case non-standard settings are wanted, a
785    pointer to a structure of type gcry_ac_key_spec_<algorithm>_t,
786    matching the selected algorithm, can be given as KEY_SPEC.  */
787 gpg_error_t
788 gcry_ac_key_pair_generate (gcry_ac_handle_t handle,
789                            gcry_ac_key_pair_t *key_pair,
790                            unsigned int nbits,
791                            void *key_spec)
792 {
793   gpg_err_code_t err = GPG_ERR_NO_ERROR;
794
795   gcry_ac_key_pair_t key_pair_new = NULL;
796
797   gcry_sexp_t genkey_sexp_request = NULL;
798   gcry_sexp_t genkey_sexp_reply = NULL;
799
800   char *genkey_format = NULL;
801   size_t genkey_format_n = 0;
802
803   void **arg_list = NULL;
804   size_t arg_list_n = 0;
805
806   unsigned int i = 0;
807
808   /* Allocate key pair.  */
809   key_pair_new = gcry_malloc (sizeof (struct gcry_ac_key_pair));
810   if (! key_pair_new)
811     err = gpg_err_code_from_errno (errno);
812
813   if (! err)
814     {
815       /* Allocate keys.  */
816       key_pair_new->secret = gcry_malloc (sizeof (struct gcry_ac_key));
817       key_pair_new->public = gcry_malloc (sizeof (struct gcry_ac_key));
818
819       if (! (key_pair_new->secret || key_pair_new->public))
820         err = gpg_err_code_from_errno (errno);
821       else
822         {
823           key_pair_new->secret->type = GCRY_AC_KEY_SECRET;
824           key_pair_new->public->type = GCRY_AC_KEY_PUBLIC;
825           key_pair_new->secret->data_sexp = NULL;
826           key_pair_new->public->data_sexp = NULL;
827           key_pair_new->secret->data = NULL;
828           key_pair_new->public->data = NULL;
829         }
830     }
831
832   if (! err)
833     {
834       /* Calculate size of the format string, that is used for
835          creating the request S-expression.  */
836       genkey_format_n = 23;
837
838       /* Respect any relevant algorithm specific commands.  */
839       if (key_spec)
840         for (i = 0; gcry_ac_key_generate_specs[i].algorithm; i++)
841           if (handle->algorithm == gcry_ac_key_generate_specs[i].algorithm)
842             genkey_format_n += 6;
843
844       /* Create format string.  */
845       genkey_format = gcry_malloc (genkey_format_n);
846       if (! genkey_format)
847         err = gpg_err_code_from_errno (errno);
848       else
849         {
850           /* Fill format string.  */
851           *genkey_format = 0;
852           strcat (genkey_format, "(genkey(%s(nbits%d)");
853           if (key_spec)
854             for (i = 0; gcry_ac_key_generate_specs[i].algorithm; i++)
855               if (handle->algorithm == gcry_ac_key_generate_specs[i].algorithm)
856                 strcat (genkey_format, "(%s%m)");
857           strcat (genkey_format, "))");
858         }
859     }
860
861   if (! err)
862     {
863       /* Build list of argument pointers, the algorithm name and the
864          nbits are needed always.  */
865       arg_list_n = 2;
866
867       /* Now the algorithm specific arguments.  */
868       if (key_spec)
869         for (i = 0; gcry_ac_key_generate_specs[i].algorithm; i++)
870           if (handle->algorithm == gcry_ac_key_generate_specs[i].algorithm)
871             arg_list_n += 2;
872
873       /* Allocate list.  */
874       arg_list = gcry_malloc (sizeof (void *) * arg_list_n);
875       if (! arg_list)
876         err = gpg_err_code_from_errno (errno);
877       else
878         {
879           /* Fill argument list. */
880           
881           int j;
882
883           arg_list[0] = (void *) &handle->algorithm_name;
884           arg_list[1] = (void *) &nbits;
885
886           if (key_spec)
887             for (j = 2, i = 0; gcry_ac_key_generate_specs[i].algorithm; i++)
888               if (handle->algorithm == gcry_ac_key_generate_specs[i].algorithm)
889                 {
890                   /* Add name of this specification flag and the
891                      according member of the spec strucuture.  */
892                   arg_list[j++] = (void *) (&gcry_ac_key_generate_specs[i].name);
893                   arg_list[j++] = (void *) (((char *) key_spec)
894                                             + gcry_ac_key_generate_specs[i].offset);
895                 }
896         }
897     }
898
899   if (! err)
900     /* Construct final request S-expression.  */
901     err = gpg_err_code (gcry_sexp_build_array (&genkey_sexp_request, NULL,
902                                                genkey_format, arg_list));
903
904   if (! err)
905     /* Perform genkey operation.  */
906     err = gpg_err_code (gcry_pk_genkey (&genkey_sexp_reply,
907                                         genkey_sexp_request));
908
909   /* Split keys.  */
910   if (! err)
911     {
912       key_pair_new->secret->data_sexp = gcry_sexp_find_token (genkey_sexp_reply,
913                                                               "private-key", 0);
914       if (! key_pair_new->secret->data_sexp)
915         err = GPG_ERR_INTERNAL;
916     }
917   if (! err)
918     {
919       key_pair_new->public->data_sexp = gcry_sexp_find_token (genkey_sexp_reply,
920                                                               "public-key", 0);
921       if (! key_pair_new->public->data_sexp)
922         err = GPG_ERR_INTERNAL;
923     }
924
925   /* Extract key material.  */
926   if (! err)
927     err = gcry_ac_data_extract ("private-key", handle->algorithm_name,
928                                 key_pair_new->secret->data_sexp,
929                                 &key_pair_new->secret->data);
930   if (! err)
931     err = gcry_ac_data_extract ("public-key", handle->algorithm_name,
932                                 key_pair_new->public->data_sexp,
933                                 &key_pair_new->public->data);
934
935   /* Done.  */
936
937   if (! err)
938     *key_pair = key_pair_new;
939   else
940     {
941       /* Deallocate resources.  */
942
943       if (key_pair_new)
944         {
945           if (key_pair_new->secret)
946             gcry_ac_key_destroy (key_pair_new->secret);
947           if (key_pair_new->public)
948             gcry_ac_key_destroy (key_pair_new->public);
949
950           gcry_free (key_pair_new);
951         }
952
953       if (arg_list)
954         gcry_free (arg_list);
955
956       if (genkey_format)
957         gcry_free (genkey_format);
958
959       if (genkey_sexp_request)
960         gcry_sexp_release (genkey_sexp_request);
961       if (genkey_sexp_reply)
962         gcry_sexp_release (genkey_sexp_reply);
963     }
964
965   return gpg_error (err);
966 }
967
968 /* Returns the key of type WHICH out of the key pair KEY_PAIR.  */
969 gcry_ac_key_t
970 gcry_ac_key_pair_extract (gcry_ac_key_pair_t key_pair,
971                           gcry_ac_key_type_t witch)
972 {
973   gcry_ac_key_t key = NULL;
974
975   switch (witch)
976     {
977     case GCRY_AC_KEY_SECRET:
978       key = key_pair->secret;
979       break;
980
981     case GCRY_AC_KEY_PUBLIC:
982       key = key_pair->public;
983       break;
984     }
985
986   return key;
987 }
988
989 /* Destroys the key KEY.  */
990 void
991 gcry_ac_key_destroy (gcry_ac_key_t key)
992 {
993   int i;
994
995   if (key->data)
996     {
997       for (i = 0; i < key->data->data_n; i++)
998         if (key->data->data[i].mpi != NULL)
999           gcry_mpi_release (key->data->data[i].mpi);
1000       gcry_free (key->data);
1001     }
1002   if (key->data_sexp)
1003     gcry_sexp_release (key->data_sexp);
1004   gcry_free (key);
1005 }
1006
1007 /* Destroys the key pair KEY_PAIR.  */
1008 void
1009 gcry_ac_key_pair_destroy (gcry_ac_key_pair_t key_pair)
1010 {
1011   gcry_ac_key_destroy (key_pair->secret);
1012   gcry_ac_key_destroy (key_pair->public);
1013   gcry_free (key_pair);
1014 }
1015
1016 /* Verifies that the key KEY is sane.  */
1017 gpg_error_t
1018 gcry_ac_key_test (gcry_ac_key_t key)
1019 {
1020   gpg_err_code_t err = GPG_ERR_NO_ERROR;
1021
1022   err = gpg_err_code (gcry_pk_testkey (key->data_sexp));
1023
1024   return gpg_error (err);
1025 }
1026
1027 /* Stores the number of bits of the key KEY in NBITS.  */
1028 gpg_error_t
1029 gcry_ac_key_get_nbits (gcry_ac_key_t key, unsigned int *nbits)
1030 {
1031   gpg_err_code_t err = GPG_ERR_NO_ERROR;
1032   unsigned int n;
1033
1034   n = gcry_pk_get_nbits (key->data_sexp);
1035   if (n)
1036     *nbits = n;
1037   else
1038     err = GPG_ERR_PUBKEY_ALGO;
1039
1040   return gpg_error (err);
1041 }
1042
1043 /* Writes the 20 byte long key grip of the key KEY to KEY_GRIP.  */
1044 gpg_error_t
1045 gcry_ac_key_get_grip (gcry_ac_key_t key, unsigned char *key_grip)
1046 {
1047   gpg_err_code_t err = GPG_ERR_NO_ERROR;
1048   unsigned char *ret;
1049
1050   ret = gcry_pk_get_keygrip (key->data_sexp, key_grip);
1051   if (! ret)
1052     err = GPG_ERR_INTERNAL;     /* FIXME.  */
1053
1054   return gpg_error (err);
1055 }
1056
1057 \f
1058
1059 /* 
1060  * Functions performing cryptographic operations.
1061  */
1062
1063 /* Encrypts the plain text MPI value DATA_PLAIN with the key public
1064    KEY under the control of the flags FLAGS and stores the resulting
1065    data set into DATA_ENCRYPTED.  */
1066 gpg_error_t
1067 gcry_ac_data_encrypt (gcry_ac_handle_t handle,
1068                       unsigned int flags,
1069                       gcry_ac_key_t key,
1070                       gcry_mpi_t data_plain,
1071                       gcry_ac_data_t *data_encrypted)
1072 {
1073   gpg_err_code_t err = GPG_ERR_NO_ERROR;
1074   gcry_sexp_t sexp_request = NULL;
1075   gcry_sexp_t sexp_reply = NULL;
1076   char *request_format = NULL;
1077   size_t request_format_n = 0;
1078   gcry_ac_data_t data;
1079   
1080   int i;
1081
1082   if (key->type != GCRY_AC_KEY_PUBLIC)
1083     err = GPG_ERR_WRONG_KEY_USAGE;
1084
1085   if (! err)
1086     {
1087       /* Calculate request format string.  */
1088
1089       request_format_n += 23;
1090       for (i = 0; gcry_ac_flags[i].number; i++)
1091         if (flags & gcry_ac_flags[i].number)
1092           request_format_n += strlen (gcry_ac_flags[i].string) + 1;
1093
1094       /* Allocate request format string.  */
1095       request_format = gcry_malloc (request_format_n);
1096       if (! request_format)
1097         err = gpg_err_code_from_errno (errno);
1098     }
1099
1100   if (! err)
1101     {
1102       /* Fill format string.  */
1103       *request_format = 0;
1104       strcat (request_format, "(data(flags");
1105       for (i = 0; gcry_ac_flags[i].number; i++)
1106         if (flags & gcry_ac_flags[i].number)
1107           {
1108             strcat (request_format, " ");
1109             strcat (request_format, gcry_ac_flags[i].string);
1110           }
1111       strcat (request_format, ")(value%m))");
1112
1113       /* Create S-expression.  */
1114       err = gcry_sexp_build (&sexp_request, NULL,
1115                              request_format, data_plain);
1116     }
1117
1118   if (! err)
1119     /* Encrypt.  */
1120     err = gcry_pk_encrypt (&sexp_reply, sexp_request, key->data_sexp);
1121
1122   if (! err)
1123     /* Extract data.  */
1124     err = gcry_ac_data_extract ("enc-val", handle->algorithm_name,
1125                                 sexp_reply, &data);
1126
1127   /* Deallocate resources.  */
1128
1129   if (sexp_request)
1130     gcry_sexp_release (sexp_request);
1131   if (sexp_reply)
1132     gcry_sexp_release (sexp_reply);
1133
1134   if (! err)
1135     /* Copy out.  */
1136     *data_encrypted = data;
1137
1138   return gpg_error (err);
1139 }
1140
1141 /* Decrypts the encrypted data contained in the data set
1142    DATA_ENCRYPTED with the secret key KEY under the control of the
1143    flags FLAGS and stores the resulting plain text MPI value in
1144    DATA_PLAIN.  */
1145 gpg_error_t
1146 gcry_ac_data_decrypt (gcry_ac_handle_t handle,
1147                       unsigned int flags,
1148                       gcry_ac_key_t key,
1149                       gcry_mpi_t *data_plain,
1150                       gcry_ac_data_t data_encrypted)
1151 {
1152   gpg_err_code_t err = GPG_ERR_NO_ERROR;
1153   gcry_mpi_t data_decrypted = NULL;
1154   gcry_sexp_t sexp_request = NULL;
1155   gcry_sexp_t sexp_reply = NULL;
1156
1157   if (key->type != GCRY_AC_KEY_SECRET)
1158     err = GPG_ERR_WRONG_KEY_USAGE;
1159
1160   if (! err)
1161     /* Create S-expression from data.  */
1162     err = gcry_ac_data_construct ("enc-val", flags, handle->algorithm_name,
1163                                   data_encrypted, &sexp_request);
1164
1165   if (! err)
1166     /* Decrypt.  */
1167     err = gcry_pk_decrypt (&sexp_reply, sexp_request, key->data_sexp);
1168
1169   if (! err)
1170     {
1171       /* Extract plain text. */
1172
1173       gcry_sexp_t l;
1174
1175       l = gcry_sexp_find_token (sexp_reply, "value", 0);
1176       if (! l)
1177         err = GPG_ERR_GENERAL;
1178       else
1179         {
1180           data_decrypted = gcry_sexp_nth_mpi (l, 1, GCRYMPI_FMT_USG);
1181           if (! data_decrypted)
1182             err = GPG_ERR_GENERAL;
1183           gcry_sexp_release (l);
1184         }
1185     }
1186
1187   /* Done.  */
1188
1189   if (err)
1190     {
1191       /* Deallocate resources.  */
1192       if (sexp_request)
1193         gcry_sexp_release (sexp_request);
1194       if (sexp_reply)
1195         gcry_sexp_release (sexp_reply);
1196     }
1197   else
1198     *data_plain = data_decrypted;
1199
1200   return gpg_error (err);
1201
1202 }
1203
1204 /* Signs the data contained in DATA with the secret key KEY and stores
1205    the resulting signature data set in DATA_SIGNATURE.  */
1206 gpg_error_t
1207 gcry_ac_data_sign (gcry_ac_handle_t handle,
1208                    gcry_ac_key_t key,
1209                    gcry_mpi_t data,
1210                    gcry_ac_data_t *data_signature)
1211 {
1212   gpg_err_code_t err = GPG_ERR_NO_ERROR;
1213   gcry_sexp_t sexp_request = NULL;
1214   gcry_sexp_t sexp_reply = NULL;
1215   gcry_ac_data_t ac_data;
1216
1217   if (key->type != GCRY_AC_KEY_SECRET)
1218     err = GPG_ERR_WRONG_KEY_USAGE;
1219
1220   if (! err)
1221     /* Create S-expression holding the data.  */
1222     err = gcry_sexp_build (&sexp_request, NULL,
1223                            "(data(flags)(value%m))", data);
1224   if (! err)
1225     /* Sign.  */
1226     err = gcry_pk_sign (&sexp_reply, sexp_request, key->data_sexp);
1227
1228   if (! err)
1229     /* Extract data.  */
1230     err = gcry_ac_data_extract ("sig-val", handle->algorithm_name,
1231                                 sexp_reply, &ac_data);
1232
1233   /* Done.  */
1234
1235   if (sexp_request)
1236     gcry_sexp_release (sexp_request);
1237   if (sexp_reply)
1238     gcry_sexp_release (sexp_reply);
1239
1240   if (! err)
1241     *data_signature = ac_data;
1242
1243   return gpg_error (err);
1244 }
1245
1246 /* Verifies that the signature contained in the data set
1247    DATA_SIGNATURE is indeed the result of signing the data contained
1248    in DATA with the secret key belonging to the public key KEY.  */
1249 gpg_error_t
1250 gcry_ac_data_verify (gcry_ac_handle_t handle,
1251                      gcry_ac_key_t key,
1252                      gcry_mpi_t data,
1253                      gcry_ac_data_t data_signature)
1254 {
1255   gpg_err_code_t err = GPG_ERR_NO_ERROR;
1256   gcry_sexp_t sexp_request = NULL;
1257   gcry_sexp_t sexp_data = NULL;
1258
1259   if (key->type != GCRY_AC_KEY_PUBLIC)
1260     err = GPG_ERR_WRONG_KEY_USAGE;
1261
1262   if (! err)
1263     /* Construct S-expression holding the signature data.  */
1264     err = gcry_ac_data_construct ("sig-val", 0, handle->algorithm_name,
1265                                   data_signature, &sexp_request);
1266
1267   if (! err)
1268     /* Construct S-expression holding the data.  */
1269     err = gcry_sexp_build (&sexp_data, NULL,
1270                            "(data(flags)(value%m))", data);
1271
1272   if (! err)
1273     /* Verify signature.  */
1274     err = gcry_pk_verify (sexp_request, sexp_data, key->data_sexp);
1275
1276   /* Done.  */
1277
1278   if (sexp_request)
1279     gcry_sexp_release (sexp_request);
1280   if (sexp_data)
1281     gcry_sexp_release (sexp_data);
1282
1283   return gpg_error (err);
1284 }
1285
1286 \f
1287
1288 /* 
1289  * General functions.
1290  */
1291
1292 /* Stores the textual representation of the algorithm whose id is
1293    given in ALGORITHM in NAME.  */
1294 gpg_error_t
1295 gcry_ac_id_to_name (gcry_ac_id_t algorithm, const char **name)
1296 {
1297   gpg_err_code_t err = GPG_ERR_NO_ERROR;
1298   const char *n;
1299
1300   n = gcry_pk_algo_name (algorithm);
1301   if (*n)
1302     *name = n;
1303   else
1304     err = GPG_ERR_PUBKEY_ALGO;
1305
1306   return gpg_error (err);
1307 }
1308
1309 /* Stores the numeric ID of the algorithm whose textual representation
1310    is contained in NAME in ALGORITHM.  */
1311 gpg_error_t
1312 gcry_ac_name_to_id (const char *name, gcry_ac_id_t *algorithm)
1313 {
1314   gpg_err_code_t err = GPG_ERR_NO_ERROR;
1315   int algo;
1316
1317   algo = gcry_pk_map_name (name);
1318   if (algo)
1319     *algorithm = algo;
1320   else
1321     err = GPG_ERR_PUBKEY_ALGO;
1322     
1323   return gpg_error (err);
1324 }