2005-01-28 Moritz Schulte <moritz@g10code.com>
[gnupg.git] / agent / command-ssh.c
1 /* command-ssh.c - gpg-agent's ssh-agent emulation layer
2  * Copyright (C) 2004, 2005 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
19  * 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <dirent.h>
30 #include <stdio.h>
31
32 #include "agent.h"
33
34 #include <gcrypt.h>
35
36 #include "estream.h"
37
38 \f
39
40 /* Request types. */
41 #define SSH_REQUEST_REQUEST_IDENTITIES    11
42 #define SSH_REQUEST_SIGN_REQUEST          13
43 #define SSH_REQUEST_ADD_IDENTITY          17
44 #define SSH_REQUEST_REMOVE_IDENTITY       18
45 #define SSH_REQUEST_REMOVE_ALL_IDENTITIES 19
46 #define SSH_REQUEST_LOCK                  22
47 #define SSH_REQUEST_UNLOCK                23
48 #define SSH_REQUEST_ADD_ID_CONSTRAINED    25
49
50 /* Options. */
51 #define SSH_OPT_CONSTRAIN_LIFETIME         1
52 #define SSH_OPT_CONSTRAIN_CONFIRM          2
53
54 /* Response types. */
55 #define SSH_RESPONSE_SUCCESS               6
56 #define SSH_RESPONSE_FAILURE               5
57 #define SSH_RESPONSE_IDENTITIES_ANSWER    12
58 #define SSH_RESPONSE_SIGN_RESPONSE        14
59
60 \f
61
62
63 /* Basic types.  */
64
65 /* A "byte".  */
66 typedef unsigned char byte_t;
67
68 typedef int (*ssh_request_handler_t) (ctrl_t ctrl,
69                                       estream_t request, estream_t response);
70
71 typedef struct ssh_request_spec
72 {
73   byte_t type;
74   ssh_request_handler_t handler;
75 } ssh_request_spec_t;
76
77 typedef gpg_error_t (*ssh_key_modifier_t) (const char *elems, gcry_mpi_t *mpis);
78 typedef gpg_error_t (*ssh_signature_encoder_t) (estream_t signature_blob,
79                                                 gcry_mpi_t *mpis);
80
81 typedef struct ssh_key_type_spec
82 {
83   const char *ssh_identifier;
84   const char *identifier;
85   const char *elems_key_secret;
86   const char *elems_key_public;
87   const char *elems_secret;
88   const char *elems_signature;
89   const char *elems_sexp_order;
90   ssh_key_modifier_t key_modifier;
91   ssh_signature_encoder_t signature_encoder;
92   unsigned int flags;
93 } ssh_key_type_spec_t;
94
95 \f
96
97 /* General utility functions.  */
98
99 static void *
100 realloc_secure (void *a, size_t n)
101 {
102   void *p;
103   
104   if (a)
105     p = gcry_realloc (a, n);
106   else
107     p = gcry_malloc_secure (n);
108   
109   return p;
110 }
111
112 /* Primitive I/O functions.  */
113
114 static gpg_error_t
115 es_read_byte (estream_t stream, byte_t *b)
116 {
117   gpg_error_t err;
118   int ret;
119
120   ret = es_fgetc (stream);
121   if (ret == EOF)
122     {
123       if (es_ferror (stream))
124         err = gpg_error_from_errno (errno);
125       else
126         err = gpg_error (GPG_ERR_EOF);
127     }
128   else
129     {
130       *b = ret & 0xFF;
131       err = 0;
132     }
133
134   return err;
135 }
136
137 static gpg_error_t
138 es_write_byte (estream_t stream, byte_t b)
139 {
140   gpg_error_t err;
141   int ret;
142
143   ret = es_fputc (b, stream);
144   if (ret == EOF)
145     err = gpg_error_from_errno (errno);
146   else
147     err = 0;
148
149   return err;
150 }
151
152 static gpg_error_t
153 es_read_uint32 (estream_t stream, uint32_t *uint32)
154 {
155   unsigned char buffer[4];
156   size_t bytes_read;
157   gpg_error_t err;
158   int ret;
159
160   ret = es_read (stream, buffer, sizeof (buffer), &bytes_read);
161   if (ret)
162     err = gpg_error_from_errno (errno);
163   else
164     {
165       if (bytes_read != sizeof (buffer))
166         err = gpg_error (GPG_ERR_EOF);
167       else
168         {
169           uint32_t n;
170
171           n = (0
172                | ((uint32_t) (buffer[0] << 24))
173                | ((uint32_t) (buffer[1] << 16))
174                | ((uint32_t) (buffer[2] <<  8))
175                | ((uint32_t) (buffer[3] <<  0)));
176           *uint32 = n;
177           err = 0;
178         }
179     }
180
181   return err;
182 }
183
184 static gpg_error_t
185 es_write_uint32 (estream_t stream, uint32_t uint32)
186 {
187   unsigned char buffer[4];
188   gpg_error_t err;
189   int ret;
190
191   buffer[0] = (uint32 >> 24) & 0xFF;
192   buffer[1] = (uint32 >> 16) & 0xFF;
193   buffer[2] = (uint32 >>  8) & 0xFF;
194   buffer[3] = (uint32 >>  0) & 0xFF;
195
196   ret = es_write (stream, buffer, sizeof (buffer), NULL);
197   if (ret)
198     err = gpg_error_from_errno (errno);
199   else
200     err = 0;
201
202   return err;
203 }
204
205 static gpg_error_t
206 es_read_data (estream_t stream, unsigned char *buffer, size_t size)
207 {
208   gpg_error_t err;
209   size_t bytes_read;
210   int ret;
211
212   ret = es_read (stream, buffer, size, &bytes_read);
213   if (ret)
214     err = gpg_error_from_errno (errno);
215   else
216     {
217       if (bytes_read != size)
218         err = gpg_error (GPG_ERR_EOF);
219       else
220         err = 0;
221     }
222
223   return err;
224 }
225
226 static gpg_error_t
227 es_write_data (estream_t stream, const unsigned char *buffer, size_t size)
228 {
229   gpg_error_t err;
230   int ret;
231
232   ret = es_write (stream, buffer, size, NULL);
233   if (ret)
234     err = gpg_error_from_errno (errno);
235   else
236     err = 0;
237
238   return err;
239 }
240
241 static gpg_error_t
242 es_read_string (estream_t stream, unsigned int secure,
243                 unsigned char **string, uint32_t *string_size)
244 {
245   gpg_error_t err;
246   unsigned char *buffer;
247   uint32_t length;
248
249   buffer = NULL;
250
251   /* Read string length.  */
252   err = es_read_uint32 (stream, &length);
253   if (err)
254     goto out;
255
256   /* Allocate space.  */
257   if (secure)
258     buffer = xtrymalloc_secure (length + 1);
259   else
260     buffer = xtrymalloc (length + 1);
261   if (! buffer)
262     {
263       /* FIXME: xtrymalloc_secure does not set errno, does it?  */
264       err = gpg_error_from_errno (errno);
265       abort ();
266       goto out;
267     }
268
269   /* Read data.  */
270   err = es_read_data (stream, buffer, length);
271   if (err)
272     goto out;
273
274   /* Finalize string object.  */
275   buffer[length] = 0;
276   *string = buffer;
277   if (string_size)
278     *string_size = length;
279
280  out:
281
282   if (err)
283     xfree (buffer);
284
285   return err;
286 }
287
288 static gpg_error_t
289 es_read_cstring (estream_t stream, char **string)
290 {
291   unsigned char *buffer;
292   gpg_error_t err;
293
294   err = es_read_string (stream, 0, &buffer, NULL);
295   if (err)
296     goto out;
297   
298   *string = (char *) buffer;
299
300  out:
301
302   return err;
303 }
304
305 static gpg_error_t
306 es_write_string (estream_t stream,
307                  const unsigned char *string, uint32_t string_n)
308 {
309   gpg_error_t err;
310
311   err = es_write_uint32 (stream, string_n);
312   if (err)
313     goto out;
314
315   err = es_write_data (stream, string, string_n);
316
317  out:
318
319   return err;
320 }
321
322 static gpg_error_t
323 es_write_cstring (estream_t stream, const char *string)
324 {
325   gpg_error_t err;
326
327   err = es_write_string (stream,
328                          (const unsigned char *) string, strlen (string));
329
330   return err;
331 }                         
332
333 static gpg_error_t
334 es_read_mpi (estream_t stream, unsigned int secure, gcry_mpi_t *mpint)
335 {
336   unsigned char *mpi_data;
337   uint32_t mpi_data_size;
338   gpg_error_t err;
339   gcry_mpi_t mpi;
340
341   mpi_data = NULL;
342
343   err = es_read_string (stream, secure, &mpi_data, &mpi_data_size);
344   if (err)
345     goto out;
346
347   err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_STD, mpi_data, mpi_data_size, NULL);
348   if (err)
349     goto out;
350
351   *mpint = mpi;
352
353  out:
354
355   xfree (mpi_data);
356
357   return err;
358 }
359
360 static gpg_error_t
361 es_write_mpi (estream_t stream, gcry_mpi_t mpint)
362 {
363   unsigned char *mpi_buffer;
364   size_t mpi_buffer_n;
365   gpg_error_t err;
366
367   mpi_buffer = NULL;
368
369   err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &mpi_buffer, &mpi_buffer_n, mpint);
370   if (err)
371     goto out;
372
373   err = es_write_string (stream, mpi_buffer, mpi_buffer_n);
374
375  out:
376
377   xfree (mpi_buffer);
378
379   return err;
380 }
381
382 static gpg_error_t
383 es_read_file (const char *filename, unsigned char **buffer, size_t *buffer_n)
384 {
385   unsigned char *buffer_new;
386   struct stat statbuf;
387   estream_t stream;
388   gpg_error_t err;
389   int ret;
390
391   buffer_new = NULL;
392   err = 0;
393   
394   stream = es_fopen (filename, "r");
395   if (! stream)
396     {
397       err = gpg_error_from_errno (errno);
398       goto out;
399     }
400
401   ret = fstat (es_fileno (stream), &statbuf);
402   if (ret)
403     {
404       err = gpg_error_from_errno (errno);
405       goto out;
406     }
407
408   buffer_new = xtrymalloc (statbuf.st_size);
409   if (! buffer_new)
410     {
411       err = gpg_error_from_errno (errno);
412       goto out;
413     }
414
415   err = es_read_data (stream, buffer_new, statbuf.st_size);
416   if (err)
417     goto out;
418
419   *buffer = buffer_new;
420   *buffer_n = statbuf.st_size;
421
422  out:
423
424   if (stream)
425     es_fclose (stream);
426
427   if (err)
428     xfree (buffer_new);
429
430   return err;
431 }
432
433 static gpg_error_t
434 es_copy (estream_t dst, estream_t src)
435 {
436   char buffer[BUFSIZ];
437   size_t bytes_read;
438   gpg_error_t err;
439   int ret;
440
441   err = 0;
442   while (1)
443     {
444       ret = es_read (src, buffer, sizeof (buffer), &bytes_read);
445       if (ret || (! bytes_read))
446         {
447           if (ret)
448             err = gpg_error_from_errno (errno);
449           break;
450         }
451       ret = es_write (dst, buffer, bytes_read, NULL);
452       if (ret)
453         {
454           err = gpg_error_from_errno (errno);
455           break;
456         }
457     }
458
459   return err;
460 }
461
462 \f
463
464 /* MPI lists.  */
465
466 static void
467 mpint_list_free (gcry_mpi_t *mpi_list)
468 {
469   if (mpi_list)
470     {
471       unsigned int i;
472
473       for (i = 0; mpi_list[i]; i++)
474         gcry_mpi_release (mpi_list[i]);
475       xfree (mpi_list);
476     }
477 }
478
479 static gpg_error_t
480 ssh_receive_mpint_list (estream_t stream, int secret,
481                         ssh_key_type_spec_t key_spec, gcry_mpi_t **mpi_list)
482 {
483   const char *elems_secret;
484   const char *elems;
485   unsigned int elems_n;
486   gcry_mpi_t *mpis;
487   unsigned int i;
488   gpg_error_t err;
489   int elem_is_secret;
490
491   mpis = NULL;
492   err = 0;
493   
494   if (secret)
495     {
496       elems = key_spec.elems_key_secret;
497       elems_secret = key_spec.elems_secret;
498     }
499   else
500     {
501       elems = key_spec.elems_key_public;
502       elems_secret = "";
503     }
504   elems_n = strlen (elems);
505
506   mpis = xtrymalloc (sizeof (*mpis) * (elems_n + 1));
507   if (! mpis)
508     {
509       err = gpg_error_from_errno (errno);
510       goto out;
511     }
512   
513   memset (mpis, 0, sizeof (*mpis) * (elems_n + 1));
514   
515   for (i = 0; i < elems_n; i++)
516     {
517       elem_is_secret = strchr (elems_secret, elems[i]) ? 1 : 0;
518       err = es_read_mpi (stream, elem_is_secret, &mpis[i]);
519       if (err)
520         break;
521     }
522   if (err)
523     goto out;
524
525   *mpi_list = mpis;
526
527  out:
528
529   if (err)
530     mpint_list_free (mpis);
531
532   return err;
533 }
534
535 \f
536
537 static gpg_error_t
538 ssh_key_modifier_rsa (const char *elems, gcry_mpi_t *mpis)
539 {
540   gcry_mpi_t p;
541   gcry_mpi_t q;
542   gcry_mpi_t u;
543
544   if (strcmp (elems, "nedupq"))
545     /* Modifying only necessary for secret keys.  */
546     goto out;
547
548   u = mpis[3];
549   p = mpis[4];
550   q = mpis[5];
551
552   if (gcry_mpi_cmp (p, q) > 0)
553     {
554       /* P shall be smaller then Q!  Swap primes.  iqmp becomes u.  */
555       gcry_mpi_t tmp;
556
557       tmp = mpis[4];
558       mpis[4] = mpis[5];
559       mpis[5] = tmp;
560     }
561   else
562     /* U needs to be recomputed.  */
563     gcry_mpi_invm (u, p, q);
564
565  out:
566
567   return 0;
568 }
569
570 static gpg_error_t
571 ssh_signature_encoder_rsa (estream_t signature_blob, gcry_mpi_t *mpis)
572 {
573   unsigned char *data;
574   size_t data_n;
575   gpg_error_t err;
576   gcry_mpi_t s;
577
578   s = mpis[0];
579
580   err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &data, &data_n, s);
581   if (err)
582     goto out;
583
584   err = es_write_string (signature_blob, data, data_n);
585   xfree (data);
586
587  out:
588
589   return err;
590 }
591
592 #define SSH_DSA_SIGNATURE_PADDING 20
593 #define SSH_DSA_SIGNATURE_ELEMS    2
594
595 static gpg_error_t
596 ssh_signature_encoder_dsa (estream_t signature_blob, gcry_mpi_t *mpis)
597 {
598   unsigned char buffer[SSH_DSA_SIGNATURE_PADDING * SSH_DSA_SIGNATURE_ELEMS];
599   unsigned char *data;
600   size_t data_n;
601   gpg_error_t err;
602   int i;
603
604   data = NULL;
605
606   for (i = 0; i < 2; i++)
607     {
608       err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &data, &data_n, mpis[i]);
609       if (err)
610         break;
611
612       if (data_n > SSH_DSA_SIGNATURE_PADDING)
613         {
614           err = gpg_error (GPG_ERR_INTERNAL); /* FIXME?  */
615           break;
616         }
617       
618       memset (buffer + (i * SSH_DSA_SIGNATURE_PADDING), 0,
619               SSH_DSA_SIGNATURE_PADDING - data_n);
620       memcpy (buffer + (i * SSH_DSA_SIGNATURE_PADDING)
621               + (SSH_DSA_SIGNATURE_PADDING - data_n), data, data_n);
622
623       xfree (data);
624       data = NULL;
625     }
626   if (err)
627     goto out;
628
629   err = es_write_string (signature_blob, buffer, sizeof (buffer));
630
631  out:
632
633   xfree (data);
634
635   return err;
636 }
637
638 #define SPEC_FLAG_USE_PKCS1V2 (1 << 0)
639
640
641 /* Table holding key type specifications.  */
642 static ssh_key_type_spec_t ssh_key_types[] =
643   {
644     {
645       "ssh-rsa", "rsa", "nedupq", "en",   "dupq", "s",  "nedpqu",
646       ssh_key_modifier_rsa, ssh_signature_encoder_rsa,
647       SPEC_FLAG_USE_PKCS1V2
648     },
649     {
650       "ssh-dss", "dsa", "pqgyx",  "pqgy", "x",    "rs", "pqgyx",
651       NULL,                 ssh_signature_encoder_dsa,
652       0
653     },
654   };
655
656 \f
657
658 /* S-Expressions.  */
659
660 static gpg_error_t
661 ssh_sexp_construct (gcry_sexp_t *sexp,
662                     ssh_key_type_spec_t key_spec, int secret,
663                     gcry_mpi_t *mpis, const char *comment)
664 {
665   gcry_sexp_t sexp_new;
666   char *sexp_template;
667   size_t sexp_template_n;
668   gpg_error_t err;
669   const char *elems;
670   size_t elems_n;
671   unsigned int i;
672   unsigned int j;
673   void **arg_list;
674
675   err = 0;
676   sexp_new = NULL;
677   arg_list = NULL;
678   if (secret)
679     elems = key_spec.elems_sexp_order;
680   else
681     elems = key_spec.elems_key_public;
682   elems_n = strlen (elems);
683
684   sexp_template_n = 33 + strlen (key_spec.identifier) + (elems_n * 6) - (! secret);
685   sexp_template = xtrymalloc (sexp_template_n);
686   if (! sexp_template)
687     {
688       err = gpg_error_from_errno (errno);
689       goto out;
690     }
691
692   arg_list = xtrymalloc (sizeof (*arg_list) * (elems_n + 1));
693   if (! arg_list)
694     {
695       err = gpg_error_from_errno (errno);
696       goto out;
697     }
698
699   sprintf (sexp_template, "(%s-key (%s ",
700            secret ? "private" : "public", key_spec.identifier);
701   for (i = 0; i < elems_n; i++)
702     {
703       sprintf (strchr (sexp_template, 0), "(%c %%m)", elems[i]);
704       if (secret)
705         {
706           for (j = 0; j < elems_n; j++)
707             if (key_spec.elems_key_secret[j] == elems[i])
708               break;
709         }
710       else
711         j = i;
712       arg_list[i] = &mpis[j];
713     }
714   arg_list[i] = &comment;
715   sprintf (strchr (sexp_template, 0), ") (comment %%s))");
716
717   err = gcry_sexp_build_array (&sexp_new, NULL, sexp_template, arg_list);
718   if (err)
719     goto out;
720
721   *sexp = sexp_new;
722
723  out:
724
725   xfree (arg_list);
726   xfree (sexp_template);
727
728   return err;
729 }
730
731 static gpg_error_t
732 ssh_sexp_extract (gcry_sexp_t sexp,
733                   ssh_key_type_spec_t key_spec, int *secret,
734                   gcry_mpi_t **mpis, const char **comment)
735 {
736   gpg_error_t err;
737   gcry_sexp_t value_list;
738   gcry_sexp_t value_pair;
739   gcry_sexp_t comment_list;
740   unsigned int i;
741   char *comment_new;
742   const char *data;
743   size_t data_n;
744   int is_secret;
745   size_t elems_n;
746   const char *elems;
747   gcry_mpi_t *mpis_new;
748   gcry_mpi_t mpi;
749
750   err = 0;
751   value_list = NULL;
752   value_pair = NULL;
753   comment_list = NULL;
754   comment_new = NULL;
755   mpis_new = NULL;
756
757   data = gcry_sexp_nth_data (sexp, 0, &data_n);
758   if (! data)
759     {
760       err = gpg_error (GPG_ERR_INV_SEXP);
761       goto out;
762     }
763
764   if ((data_n == 10) && (! strncmp (data, "public-key", 10)))
765     {
766       is_secret = 0;
767       elems = key_spec.elems_key_public;
768     }
769   else if (((data_n == 11) && (! strncmp (data, "private-key", 11)))
770            || ((data_n == 21) && (! strncmp (data, "protected-private-key", 21))))
771     {
772       is_secret = 1;
773       elems = key_spec.elems_key_secret;
774     }
775   else
776     {
777       err = gpg_error (GPG_ERR_INV_SEXP);
778       goto out;
779     }
780
781   elems_n = strlen (elems);
782   mpis_new = xtrymalloc (sizeof (*mpis_new) * (elems_n + 1));
783   if (! mpis_new)
784     {
785       err = gpg_error_from_errno (errno); /* FIXME, xtrymalloc+errno.  */
786       goto out;
787     }
788   memset (mpis_new, 0, sizeof (*mpis_new) * (elems_n + 1));
789
790   value_list = gcry_sexp_find_token (sexp, key_spec.identifier, 0);
791   if (! value_list)
792     {
793       err = gpg_error (GPG_ERR_INV_SEXP);
794       goto out;
795     }
796
797   for (i = 0; i < elems_n; i++)
798     {
799       value_pair = gcry_sexp_find_token (value_list, elems + i, 1);
800       if (! value_pair)
801         {
802           err = gpg_error (GPG_ERR_INV_SEXP);
803           break;
804         }
805
806       mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_USG);
807       if (! mpi)
808         {
809           err = gpg_error (GPG_ERR_INV_SEXP);
810           break;
811         }
812       mpis_new[i] = mpi;
813       gcry_sexp_release (value_pair);
814       value_pair = NULL;
815     }
816   if (err)
817     goto out;
818
819   /* We do not require a comment sublist to be present here.  */
820   data = NULL;
821   data_n = 0;
822
823   comment_list = gcry_sexp_find_token (sexp, "comment", 0);
824   if (comment_list)
825     data = gcry_sexp_nth_data (comment_list, 1, &data_n);
826   if (! data)
827     {
828       data = "(none)";
829       data_n = 6;
830     }
831
832   comment_new = xtrymalloc (data_n + 1);
833   if (! comment_new)
834     {
835       err = gpg_error_from_errno (errno);
836       goto out;
837     }
838   strncpy (comment_new, data, data_n);
839   comment_new[data_n] = 0;
840
841   if (secret)
842     *secret = is_secret;
843   *mpis = mpis_new;
844   *comment = comment_new;
845
846  out:
847
848   gcry_sexp_release (value_list);
849   gcry_sexp_release (value_pair);
850   gcry_sexp_release (comment_list);
851   
852   if (err)
853     {
854       xfree (comment_new);
855       mpint_list_free (mpis_new);
856     }
857
858   return err;
859 }
860
861 static gpg_error_t
862 ssh_sexp_extract_key_type (gcry_sexp_t sexp, const char **key_type)
863 {
864   gcry_sexp_t sublist;
865   char *key_type_new;
866   const char *data;
867   size_t data_n;
868   gpg_error_t err;
869
870   err = 0;
871   key_type_new = NULL;
872   
873   sublist = gcry_sexp_nth (sexp, 1);
874   if (! sublist)
875     {
876       err = gpg_error (GPG_ERR_INV_SEXP);
877       goto out;
878     }
879
880   data = gcry_sexp_nth_data (sublist, 0, &data_n);
881   if (! data)
882     {
883       err = gpg_error (GPG_ERR_INV_SEXP);
884       goto out;
885     }
886
887   key_type_new = xtrymalloc (data_n + 1);
888   if (! key_type_new)
889     {
890       err = gpg_error_from_errno (errno);
891       goto out;
892     }
893
894   strncpy (key_type_new, data, data_n);
895   key_type_new[data_n] = 0;
896   *key_type = key_type_new;
897
898  out:
899
900   gcry_sexp_release (sublist);
901
902   return err;
903 }
904
905 \f
906
907 /* Key I/O.  */
908
909 static gpg_error_t
910 ssh_key_type_lookup (const char *ssh_name, const char *name,
911                      ssh_key_type_spec_t *spec)
912 {
913   gpg_error_t err;
914   unsigned int i;
915
916   for (i = 0; i < DIM (ssh_key_types); i++)
917     if ((ssh_name && (! strcmp (ssh_name, ssh_key_types[i].ssh_identifier)))
918         || (name && (! strcmp (name, ssh_key_types[i].identifier))))
919       break;
920   
921   if (i == DIM (ssh_key_types))
922     err = gpg_error (GPG_ERR_NOT_FOUND);
923   else
924     {
925       *spec = ssh_key_types[i];
926       err = 0;
927     }
928
929   return err;
930 }
931
932 static gpg_error_t
933 ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret, int read_comment,
934                  ssh_key_type_spec_t *key_spec)
935 {
936   gpg_error_t err;
937   char *key_type;
938   char *comment;
939   gcry_sexp_t key;
940   ssh_key_type_spec_t spec;
941   gcry_mpi_t *mpi_list;
942   const char *elems;
943
944   mpi_list = NULL;
945   key_type = NULL;
946   comment = "";
947   key = NULL;
948         
949   err = es_read_cstring (stream, &key_type);
950   if (err)
951     goto out;
952
953   err = ssh_key_type_lookup (key_type, NULL, &spec);
954   if (err)
955     goto out;
956
957   err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list);
958   if (err)
959     goto out;
960
961   if (read_comment)
962     {
963       err = es_read_cstring (stream, &comment);
964       if (err)
965         goto out;
966     }
967
968   if (secret)
969     elems = spec.elems_key_secret;
970   else
971     elems = spec.elems_key_public;
972
973   if (spec.key_modifier)
974     {
975       err = (*spec.key_modifier) (elems, mpi_list);
976       if (err)
977         goto out;
978     }
979
980   err = ssh_sexp_construct (&key, spec, secret, mpi_list, comment);
981   if (err)
982     goto out;
983
984   if (key_spec)
985     *key_spec = spec;
986   *key_new = key;
987   
988  out:
989
990   mpint_list_free (mpi_list);
991   xfree (key_type);
992   if (read_comment)
993     xfree (comment);
994
995   return err;
996 }
997
998 static gpg_error_t
999 ssh_convert_key_to_blob (unsigned char **blob, size_t *blob_size,
1000                          const char *type, gcry_mpi_t *mpis)
1001 {
1002   unsigned char *blob_new;
1003   long int blob_size_new;
1004   estream_t stream;
1005   gpg_error_t err;
1006   unsigned int i;
1007
1008   blob_new = NULL;
1009   stream = NULL;
1010   err = 0;
1011
1012   stream = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+");
1013   if (! stream)
1014     {
1015       err = gpg_error_from_errno (errno);
1016       goto out;
1017     }
1018
1019   err = es_write_cstring (stream, type);
1020   if (err)
1021     goto out;
1022
1023   for (i = 0; mpis[i] && (! err); i++)
1024     err = es_write_mpi (stream, mpis[i]);
1025   if (err)
1026     goto out;
1027
1028   blob_size_new = es_ftell (stream);
1029   if (blob_size_new == -1)
1030     {
1031       err = gpg_error_from_errno (errno);
1032       goto out;
1033     }
1034   
1035   err = es_fseek (stream, 0, SEEK_SET);
1036   if (err)
1037     goto out;
1038
1039   blob_new = xtrymalloc (blob_size_new);
1040   if (! blob_new)
1041     {
1042       err = gpg_error_from_errno (errno);
1043       goto out;
1044     }
1045
1046   err = es_read_data (stream, blob_new, blob_size_new);
1047   if (err)
1048     goto out;
1049
1050   *blob = blob_new;
1051   *blob_size = blob_size_new;
1052
1053  out:
1054
1055   if (stream)
1056     es_fclose (stream);
1057   if (err)
1058     xfree (blob_new);
1059
1060   return err;
1061 }
1062                               
1063
1064 static gpg_error_t
1065 ssh_send_key_public (estream_t stream, gcry_sexp_t key_public)
1066 {
1067   ssh_key_type_spec_t spec;
1068   gcry_mpi_t *mpi_list;
1069   const char *key_type;
1070   const char *comment;
1071   unsigned char *blob;
1072   size_t blob_n;
1073   gpg_error_t err;
1074
1075   key_type = NULL;
1076   mpi_list = NULL;
1077   comment = NULL;
1078   blob = NULL;
1079
1080   err = ssh_sexp_extract_key_type (key_public, &key_type);
1081   if (err)
1082     goto out;
1083
1084   err = ssh_key_type_lookup (NULL, key_type, &spec);
1085   if (err)
1086     goto out;
1087
1088   err = ssh_sexp_extract (key_public, spec, NULL, &mpi_list, &comment);
1089   if (err)
1090     goto out;
1091
1092   err = ssh_convert_key_to_blob (&blob, &blob_n, spec.ssh_identifier, mpi_list);
1093   if (err)
1094     goto out;
1095   
1096   err = es_write_string (stream, blob, blob_n);
1097   if (err)
1098     goto out;
1099
1100   err = es_write_cstring (stream, comment);
1101   
1102  out:
1103
1104   mpint_list_free (mpi_list);
1105   xfree ((void *) key_type);
1106   xfree ((void *) comment);
1107   xfree (blob);
1108
1109   return err;
1110 }
1111
1112 static gpg_error_t
1113 ssh_read_key_public_from_blob (unsigned char *blob, size_t blob_size,
1114                                gcry_sexp_t *key_public,
1115                                ssh_key_type_spec_t *key_spec)
1116 {
1117   estream_t blob_stream;
1118   gpg_error_t err;
1119
1120   err = 0;
1121   
1122   blob_stream = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+");
1123   if (! blob_stream)
1124     {
1125       err = gpg_error_from_errno (errno);
1126       goto out;
1127     }
1128
1129   err = es_write_data (blob_stream, blob, blob_size);
1130   if (err)
1131     goto out;
1132
1133   err = es_fseek (blob_stream, 0, SEEK_SET);
1134   if (err)
1135     goto out;
1136
1137   err = ssh_receive_key (blob_stream, key_public, 0, 0, key_spec);
1138
1139  out:
1140
1141   if (blob_stream)
1142     es_fclose (blob_stream);
1143
1144   return err;
1145 }
1146
1147 \f
1148
1149 static gpg_error_t
1150 key_secret_to_public (gcry_sexp_t *key_public,
1151                       ssh_key_type_spec_t spec, gcry_sexp_t key_secret)
1152 {
1153   gpg_error_t err;
1154   gcry_sexp_t value_pair;
1155   unsigned int i;
1156   gcry_mpi_t *mpis;
1157   gcry_mpi_t mpi;
1158   void **arglist;
1159   size_t elems_n;
1160   char *template;
1161   size_t template_n;
1162   const char *elems;
1163   char *comment;
1164   const char *data;
1165   size_t data_n;
1166
1167   err = 0;
1168   mpis = NULL;
1169   arglist = NULL;
1170   comment = NULL;
1171   template = NULL;
1172   value_pair = NULL;
1173
1174   elems = spec.elems_key_public;
1175   elems_n = strlen (elems);
1176
1177   data = NULL;
1178   value_pair  = gcry_sexp_find_token (key_secret, "comment", 0);
1179   if (value_pair)
1180     data = gcry_sexp_nth_data (value_pair, 1, &data_n);
1181   if (! data)
1182     {
1183       data = "";
1184       data_n = 0;
1185     }
1186
1187   comment = xtrymalloc (data_n + 1);
1188   if (! comment)
1189     {
1190       err = gpg_error_from_errno (errno);
1191       goto out;
1192     }
1193   strncpy (comment, data, data_n);
1194   comment[data_n] = 0;
1195
1196   gcry_sexp_release (value_pair);
1197   value_pair = NULL;
1198   
1199   template_n = 29 + strlen (spec.identifier) + (elems_n * 7) + 1;
1200   template = xtrymalloc (template_n);
1201   if (! template)
1202     {
1203       err = gpg_error_from_errno (errno);
1204       goto out;
1205     }
1206
1207   mpis = xtrymalloc (sizeof (*mpis) * (elems_n + 1));
1208   if (! mpis)
1209     {
1210       err = gpg_error_from_errno (errno);       /* FIXME: errno.  */
1211       goto out;
1212     }
1213   memset (mpis, 0, sizeof (*mpis) * (elems_n + 1));
1214
1215   arglist = xtrymalloc (sizeof (*arglist) * (elems_n + 1));
1216   if (! arglist)
1217     {
1218       err = gpg_error_from_errno (errno);
1219       goto out;
1220     }
1221
1222   for (i = 0; i < elems_n; i++)
1223     {
1224       value_pair = gcry_sexp_find_token (key_secret, elems + i, 1);
1225       if (! value_pair)
1226         {
1227           err = gpg_error (GPG_ERR_INV_SEXP);
1228           break;
1229         }
1230       mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_USG);
1231       if (! mpi)
1232         {
1233           err = gpg_error (GPG_ERR_INV_SEXP);
1234           break;
1235         }
1236       gcry_sexp_release (value_pair);
1237       value_pair = NULL;
1238
1239       mpis[i] = mpi;
1240       arglist[i] = &mpis[i];
1241       mpi = NULL;
1242     }
1243   if (err)
1244     goto out;
1245
1246   sprintf (template, "(public-key (%s", spec.identifier);
1247   for (i = 0; i < elems_n; i++)
1248     sprintf (strchr (template, 0)," (%c %%m)", elems[i]);
1249   sprintf (strchr (template, 0), ") (comment %%s))");
1250   arglist[i] = &comment;
1251
1252   err = gcry_sexp_build_array (key_public, NULL, template, arglist);
1253   
1254  out:
1255
1256   gcry_sexp_release (value_pair);
1257   xfree (template);
1258   mpint_list_free (mpis);
1259   xfree (arglist);
1260   xfree (comment);
1261
1262   return err;
1263 }
1264
1265 \f
1266
1267 static char *
1268 make_cstring (const char *data, size_t data_n)
1269 {
1270   char *s;
1271
1272   s = xtrymalloc (data_n + 1);
1273   if (s)
1274     {
1275       strncpy (s, data, data_n);
1276       s[data_n] = 0;
1277     }
1278
1279   return s;
1280 }
1281
1282 \f
1283
1284 /* Request handler.  */
1285
1286 static int
1287 ssh_handler_request_identities (ctrl_t ctrl, estream_t request, estream_t response)
1288 {
1289   const char *key_type;
1290   ssh_key_type_spec_t spec;
1291   struct dirent *dir_entry;
1292   char *key_directory;
1293   size_t key_directory_n;
1294   char *key_path;
1295   unsigned char *buffer;
1296   size_t buffer_n;
1297   uint32_t key_counter;
1298   estream_t key_blobs;
1299   gcry_sexp_t key_secret;
1300   gcry_sexp_t key_public;
1301   DIR *dir;
1302   gpg_error_t err;
1303   int ret;
1304   int bad;
1305
1306   if (DBG_COMMAND)
1307     log_debug ("[ssh-agent] request identities\n");
1308
1309   /* Prepare buffer stream.  */
1310
1311   key_directory = NULL;
1312   key_secret = NULL;
1313   key_public = NULL;
1314   key_type = NULL;
1315   key_path = NULL;
1316   key_counter = 0;
1317   buffer = NULL;
1318   dir = NULL;
1319   bad = 0;
1320   err = 0;
1321
1322   key_blobs = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+");
1323   if (! key_blobs)
1324     {
1325       err = gpg_error_from_errno (errno);
1326       goto out;
1327     }
1328
1329   /* Open key directory.  */
1330   key_directory = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, NULL);
1331   if (! key_directory)
1332     {
1333       err = gpg_err_code_from_errno (errno);
1334       goto out;
1335     }
1336   key_directory_n = strlen (key_directory);
1337   
1338   key_path = xtrymalloc (key_directory_n + 46);
1339   if (! key_path)
1340     {
1341       err = gpg_err_code_from_errno (errno);
1342       goto out;
1343     }
1344
1345   sprintf (key_path, "%s/", key_directory);
1346   sprintf (key_path + key_directory_n + 41, ".key");
1347
1348   dir = opendir (key_directory);
1349   if (! dir)
1350     {
1351       err = gpg_err_code_from_errno (errno);
1352       goto out;
1353     }
1354
1355   /* Iterate over key files.  */
1356
1357   /* FIXME: make sure that buffer gets deallocated properly.  */
1358
1359   while (1)
1360     {
1361       dir_entry = readdir (dir);
1362       if (dir_entry)
1363         {
1364           if ((strlen (dir_entry->d_name) == 44)
1365               && (! strncmp (dir_entry->d_name + 40, ".key", 4)))
1366             {
1367               strncpy (key_path + key_directory_n + 1, dir_entry->d_name, 40);
1368
1369               /* Read file content.  */
1370               err = es_read_file (key_path, &buffer, &buffer_n);
1371               if (err)
1372                 break;
1373               
1374               err = gcry_sexp_sscan (&key_secret, NULL, buffer, buffer_n);
1375               if (err)
1376                 break;
1377
1378               xfree (buffer);
1379               buffer = NULL;
1380
1381               err = ssh_sexp_extract_key_type (key_secret, &key_type);
1382               if (err)
1383                 break;
1384
1385               err = ssh_key_type_lookup (NULL, key_type, &spec);
1386               if (err)
1387                 break;
1388
1389               xfree ((void *) key_type);
1390               key_type = NULL;
1391
1392               err = key_secret_to_public (&key_public, spec, key_secret);
1393               if (err)
1394                 break;
1395
1396               gcry_sexp_release (key_secret);
1397               key_secret = NULL;
1398               
1399               err = ssh_send_key_public (key_blobs, key_public);
1400               if (err)
1401                 break;
1402
1403               gcry_sexp_release (key_public);
1404               key_public = NULL;
1405
1406               key_counter++;
1407             }
1408         }
1409       else
1410         break;
1411     }
1412   if (err)
1413     goto out;
1414   
1415   ret = es_fseek (key_blobs, 0, SEEK_SET);
1416   if (ret)
1417     {
1418       err = gpg_error_from_errno (errno);
1419       goto out;
1420     }
1421
1422  out:
1423
1424   /* Send response.  */
1425
1426   gcry_sexp_release (key_secret);
1427   gcry_sexp_release (key_public);
1428
1429   es_write_byte (response, SSH_RESPONSE_IDENTITIES_ANSWER);
1430   if (! es_ferror (response))
1431     es_write_uint32 (response, err ? 0 : key_counter);
1432   if (! (err || es_ferror (response)))
1433     es_copy (response, key_blobs);
1434
1435   if (key_blobs)
1436     es_fclose (key_blobs);
1437   if (dir)
1438     closedir (dir);
1439
1440   free (key_directory);
1441   xfree (key_path);
1442   xfree (buffer);
1443   xfree ((void *) key_type);            /* FIXME? */
1444
1445   return bad;
1446 }
1447
1448 static gpg_error_t
1449 data_hash (unsigned char *data, size_t data_n,
1450            int md_algorithm, unsigned char *hash)
1451 {
1452   gcry_md_hash_buffer (md_algorithm, hash, data, data_n);
1453
1454   return 0;
1455 }
1456
1457 static gpg_error_t
1458 data_sign (CTRL ctrl, ssh_signature_encoder_t sig_encoder,
1459            unsigned char **sig, size_t *sig_n)
1460 {
1461   char description[] = "Please provide the passphrase for key `%c':";
1462   gpg_error_t err;
1463   gcry_sexp_t signature_sexp;
1464   estream_t stream;
1465   gcry_sexp_t valuelist;
1466   gcry_sexp_t sublist;
1467   gcry_mpi_t sig_value;
1468   unsigned char *sig_blob;
1469   size_t sig_blob_n;
1470   const char *identifier;
1471   const char *identifier_raw;
1472   size_t identifier_n;
1473   ssh_key_type_spec_t spec;
1474   int ret;
1475   unsigned int i;
1476   const char *elems;
1477   size_t elems_n;
1478   gcry_mpi_t *mpis;
1479
1480   signature_sexp = NULL;
1481   identifier = NULL;
1482   valuelist = NULL;
1483   sublist = NULL;
1484   sig_blob = NULL;
1485   sig_blob_n = 0;
1486   stream = NULL;
1487   sig_value = NULL;
1488   mpis = NULL;
1489
1490   err = agent_pksign_do (ctrl, description, &signature_sexp, 0);
1491   if (err)
1492     goto out;
1493
1494   valuelist = gcry_sexp_nth (signature_sexp, 1);
1495   if (! valuelist)
1496     {
1497       err = gpg_error (GPG_ERR_INV_SEXP);
1498       goto out;
1499     }
1500
1501   stream = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+");
1502   if (! stream)
1503     {
1504       err = gpg_error_from_errno (errno);
1505       goto out;
1506     }
1507
1508   identifier_raw = gcry_sexp_nth_data (valuelist, 0, &identifier_n);
1509   if (! identifier_raw)
1510     {
1511       err = gpg_error (GPG_ERR_INV_SEXP);
1512       goto out;
1513     }
1514
1515   identifier = make_cstring (identifier_raw, identifier_n);
1516   if (! identifier)
1517     {
1518       err = gpg_error_from_errno (errno);
1519       goto out;
1520     }
1521
1522   err = ssh_key_type_lookup (NULL, identifier, &spec);
1523   if (err)
1524     goto out;
1525
1526   err = es_write_cstring (stream, spec.ssh_identifier);
1527   if (err)
1528     goto out;
1529
1530   elems = spec.elems_signature;
1531   elems_n = strlen (elems);
1532
1533   mpis = xtrymalloc (sizeof (*mpis) * (elems_n + 1));
1534   if (! mpis)
1535     {
1536       err = gpg_error_from_errno (errno);
1537       goto out;
1538     }
1539   memset (mpis, 0, sizeof (*mpis) * (elems_n + 1));
1540
1541   for (i = 0; i < elems_n; i++)
1542     {
1543       sublist = gcry_sexp_find_token (valuelist, spec.elems_signature + i, 1);
1544       if (! sublist)
1545         {
1546           err = gpg_error (GPG_ERR_INV_SEXP);
1547           break;
1548         }
1549
1550       sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
1551       if (! sig_value)
1552         {
1553           err = gpg_error (GPG_ERR_INTERNAL); /* FIXME?  */
1554           break;
1555         }
1556       gcry_sexp_release (sublist);
1557       sublist = NULL;
1558
1559       mpis[i] = sig_value;
1560     }
1561   if (err)
1562     goto out;
1563
1564   err = (*sig_encoder) (stream, mpis);
1565   if (err)
1566     goto out;
1567
1568   sig_blob_n = es_ftell (stream);
1569   if (sig_blob_n == -1)
1570     {
1571       err = gpg_error_from_errno (errno);
1572       goto out;
1573     }
1574
1575   sig_blob = xtrymalloc (sig_blob_n);
1576   if (! sig_blob)
1577     {
1578       err = gpg_error_from_errno (errno);
1579       goto out;
1580     }
1581
1582   ret = es_fseek (stream, 0, SEEK_SET);
1583   if (ret)
1584     {
1585       err = gpg_error_from_errno (errno);
1586       goto out;
1587     }    
1588
1589   err = es_read_data (stream, sig_blob, sig_blob_n);
1590   if (err)
1591     goto out;
1592   
1593   *sig = (char *) sig_blob;
1594   *sig_n = sig_blob_n;
1595   
1596  out:
1597
1598   if (err)
1599     xfree (sig_blob);
1600
1601   if (stream)
1602     es_fclose (stream);
1603   gcry_sexp_release (valuelist);
1604   gcry_sexp_release (signature_sexp);
1605   gcry_sexp_release (sublist);
1606   mpint_list_free (mpis);
1607   xfree ((void *) identifier);
1608
1609   return err;
1610 }
1611
1612 static int
1613 ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response)
1614 {
1615   gcry_sexp_t key;
1616   ssh_key_type_spec_t spec;
1617   unsigned char hash[MAX_DIGEST_LEN];
1618   unsigned int hash_n;
1619   unsigned char key_grip[20];
1620   unsigned char *key_blob;
1621   uint32_t key_blob_size;
1622   unsigned char *data;
1623   unsigned char *sig;
1624   size_t sig_n;
1625   uint32_t data_size;
1626   uint32_t flags;
1627   const void *p;
1628   gpg_error_t err;
1629   int bad;
1630
1631   key_blob = NULL;
1632   data = NULL;
1633   sig = NULL;
1634   key = NULL;
1635   bad = 0;
1636
1637   if (DBG_COMMAND)
1638     log_debug ("[ssh-agent] sign request\n");
1639
1640   /* Receive key.  */
1641   
1642   err = es_read_string (request, 0, &key_blob, &key_blob_size);
1643   if (err)
1644     {
1645       bad = 1;
1646       goto out;
1647     }
1648
1649   err = ssh_read_key_public_from_blob (key_blob, key_blob_size, &key, &spec);
1650   if (err)
1651     {
1652       bad = 1;
1653       goto out;
1654     }
1655
1656   /* Receive data to sign.  */
1657   err = es_read_string (request, 0, &data, &data_size);
1658   if (err)
1659     {
1660       bad = 1;
1661       goto out;
1662     }
1663
1664   /* FIXME?  */
1665   err = es_read_uint32 (request, &flags);
1666   if (err)
1667     {
1668       bad = 1;
1669       goto out;
1670     }
1671
1672   /* Hash data.  */
1673   hash_n = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
1674   if (! hash_n)
1675     {
1676       err = gpg_error (GPG_ERR_INTERNAL);
1677       goto out;
1678     }
1679   err = data_hash (data, data_size, GCRY_MD_SHA1, hash);
1680   if (err)
1681     goto out;
1682
1683   /* Calculate key grip.  */
1684   p = gcry_pk_get_keygrip (key, key_grip);
1685   if (! p)
1686     {
1687       err = gpg_error (GPG_ERR_INTERNAL); /* FIXME?  */
1688       goto out;
1689     }
1690
1691   /* Sign data.  */
1692
1693   ctrl->digest.algo = GCRY_MD_SHA1;
1694   memcpy (ctrl->digest.value, hash, hash_n);
1695   ctrl->digest.valuelen = hash_n;
1696   ctrl->digest.raw_value = ! (spec.flags & SPEC_FLAG_USE_PKCS1V2);
1697   ctrl->have_keygrip = 1;
1698   memcpy (ctrl->keygrip, key_grip, 20);
1699
1700   err = data_sign (ctrl, spec.signature_encoder, &sig, &sig_n);
1701   
1702  out:
1703
1704   if (! bad)
1705     {
1706       /* Done.  */
1707       if (! err)
1708         {
1709           es_write_byte (response, SSH_RESPONSE_SIGN_RESPONSE);
1710           if (! es_ferror (response))
1711             es_write_string (response, sig, sig_n);
1712         }
1713       else
1714         es_write_byte (response, SSH_RESPONSE_FAILURE);
1715     }
1716   
1717   gcry_sexp_release (key);
1718   xfree (key_blob);
1719   xfree (data);
1720   xfree (sig);
1721
1722   return bad;
1723 }
1724
1725 static gpg_error_t
1726 get_passphrase (ctrl_t ctrl,
1727                 const char *description, size_t passphrase_n, char *passphrase)
1728 {
1729   struct pin_entry_info_s *pi;
1730   gpg_error_t err;
1731
1732   err = 0;
1733   pi = gcry_calloc_secure (1, sizeof (*pi) + passphrase_n + 1);
1734   if (! pi)
1735     {
1736       err = gpg_error (GPG_ERR_ENOMEM);
1737       goto out;
1738     }
1739
1740   pi->min_digits = 0;           /* We want a real passphrase.  */
1741   pi->max_digits = 8;
1742   pi->max_tries = 1;
1743   pi->failed_tries = 0;
1744   pi->check_cb = NULL;
1745   pi->check_cb_arg = NULL;
1746   pi->cb_errtext = NULL;
1747   pi->max_length = 100;
1748
1749   err = agent_askpin (ctrl, description, NULL, pi);
1750   if (err)
1751     goto out;
1752
1753   memcpy (passphrase, pi->pin, passphrase_n);
1754   passphrase[passphrase_n] = 0;
1755
1756  out:
1757
1758   xfree (pi);
1759   
1760   return err;
1761 }
1762
1763 static gpg_error_t
1764 ssh_key_extract_comment (gcry_sexp_t key, char **comment)
1765 {
1766   gcry_sexp_t comment_list;
1767   char *comment_new;
1768   const char *data;
1769   size_t data_n;
1770   gpg_error_t err;
1771
1772   comment_list = gcry_sexp_find_token (key, "comment", 0);
1773   if (! comment_list)
1774     {
1775       err = gpg_error (GPG_ERR_INV_SEXP);
1776       goto out;
1777     }
1778   
1779   data = gcry_sexp_nth_data (comment_list, 1, &data_n);
1780   if (! data)
1781     {
1782       err = gpg_error (GPG_ERR_INV_SEXP);
1783       goto out;
1784     }
1785
1786   comment_new = xtrymalloc (data_n + 1);
1787   if (! comment_new)
1788     {
1789       err = gpg_error_from_errno (errno);
1790       goto out;
1791     }
1792
1793   strncpy (comment_new, data, data_n);
1794   comment_new[data_n] = 0;
1795   *comment = comment_new;
1796   err = 0;
1797
1798  out:
1799
1800   gcry_sexp_release (comment_list);
1801
1802   return err;
1803 }
1804
1805 static gpg_error_t
1806 ssh_key_grip (gcry_sexp_t key, char *buffer)
1807 {
1808   gpg_error_t err;
1809   char *p;
1810
1811   /* FIXME: unsigned vs. signed.  */
1812   
1813   p = gcry_pk_get_keygrip (key, buffer);
1814   if (! p)
1815     err = gpg_error (GPG_ERR_INTERNAL); /* FIXME?  */
1816   else
1817     err = 0;
1818
1819   return err;
1820 }
1821
1822 static gpg_error_t
1823 ssh_key_to_buffer (gcry_sexp_t key, const char *passphrase,
1824                    unsigned char **buffer, size_t *buffer_n)
1825 {
1826   unsigned char *buffer_new;
1827   unsigned int buffer_new_n;
1828   gpg_error_t err;
1829
1830   err = 0;
1831   buffer_new_n = gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, NULL, 0);
1832   buffer_new = xtrymalloc (buffer_new_n);
1833   /* FIXME: secmem? */
1834   if (! buffer_new)
1835     {
1836       err = gpg_error_from_errno (errno);
1837       goto out;
1838     }
1839   
1840   gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, buffer_new, buffer_new_n);
1841   /* FIXME: guarantee?  */
1842
1843   err = agent_protect (buffer_new, passphrase, buffer, buffer_n);
1844
1845  out:
1846
1847   xfree (buffer_new);
1848
1849   return err;
1850 }
1851
1852 static gpg_error_t
1853 ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
1854 {
1855   unsigned char key_grip_raw[21];
1856   unsigned char *buffer;
1857   unsigned int buffer_n;
1858   char passphrase[100];
1859   size_t description_length;
1860   char *description;
1861   char key_grip[41];
1862   char *comment;
1863   gpg_error_t err;
1864   unsigned int i;
1865   int ret;
1866
1867   if (DBG_COMMAND)
1868     log_debug ("[ssh-agent] registering identity\n");
1869
1870   description = NULL;
1871   comment = NULL;
1872   buffer = NULL;
1873
1874   err = ssh_key_grip (key, key_grip_raw);
1875   if (err)
1876     goto out;
1877
1878   key_grip_raw[sizeof (key_grip_raw) - 1] = 0;
1879   ret = agent_key_available (key_grip_raw);
1880   if (! ret)
1881     goto out;
1882
1883   err = ssh_key_extract_comment (key, &comment);
1884   if (err)
1885     goto out;
1886
1887   description_length = 95 + (comment ? strlen (comment) : 0);
1888   description = malloc (description_length);
1889   if (! description)
1890     {
1891       err = gpg_err_code_from_errno (errno);
1892       goto out;
1893     }
1894   else
1895     sprintf (description,
1896              "Please provide the passphrase, which should be used "
1897              "for protecting the received secret key `%s':",
1898              comment ? comment : "");
1899
1900   err = get_passphrase (ctrl, description, sizeof (passphrase), passphrase);
1901   if (err)
1902     goto out;
1903
1904   err = ssh_key_to_buffer (key, passphrase, &buffer, &buffer_n);
1905   if (err)
1906     goto out;
1907
1908   err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0);
1909   if (err)
1910     goto out;
1911
1912   for (i = 0; i < 20; i++)
1913     sprintf (key_grip + 2 * i, "%02X", key_grip_raw[i]);
1914
1915   err = agent_put_cache (key_grip, passphrase, ttl);
1916   if (err)
1917     goto out;
1918
1919  out:
1920
1921   xfree (buffer);
1922   xfree (comment);
1923   xfree (description);
1924   /* FIXME: verify xfree vs free.  */
1925
1926   return err;
1927 }
1928
1929 static gpg_error_t
1930 ssh_identity_drop (gcry_sexp_t key)
1931 {
1932   unsigned char key_grip[21] = { 0 };
1933   gpg_error_t err;
1934
1935   err = ssh_key_grip (key, key_grip);
1936   if (err)
1937     goto out;
1938
1939   key_grip[sizeof (key_grip) - 1] = 0;
1940
1941   /* FIXME: What to do here - forgetting the passphrase or deleting
1942      the key from key cache?  */
1943
1944   if (DBG_COMMAND)
1945     log_debug ("[ssh-agent] dropping identity `%s'\n", key_grip);
1946
1947  out:
1948
1949   return err;
1950 }
1951
1952 static int
1953 ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response)
1954 {
1955   gpg_error_t err;
1956   gcry_sexp_t key;
1957   byte_t b;
1958   int confirm;
1959   int ttl;
1960   int bad;
1961   
1962   if (DBG_COMMAND)
1963     log_debug ("[ssh-agent] add identity\n");
1964
1965   confirm = 0;
1966   key = NULL;
1967   ttl = 0;
1968   bad = 0;
1969
1970   /* FIXME?  */
1971   err = ssh_receive_key (request, &key, 1, 1, NULL);
1972   if (err)
1973     {
1974       bad = 1;
1975       goto out;
1976     }
1977
1978   while (1)
1979     {
1980       err = es_read_byte (request, &b);
1981       if (gpg_err_code (err) == GPG_ERR_EOF)
1982         {
1983           err = 0;
1984           break;
1985         }
1986
1987       switch (b)
1988         {
1989         case SSH_OPT_CONSTRAIN_LIFETIME:
1990           {
1991             uint32_t n = 0;
1992
1993             err = es_read_uint32 (request, &n);
1994             if (! err)
1995               ttl = n;
1996             break;
1997           }
1998
1999         case SSH_OPT_CONSTRAIN_CONFIRM:
2000           {
2001             confirm = 1;
2002             break;
2003           }
2004
2005         default:
2006           /* FIXME: log/bad?  */
2007           break;
2008         }
2009     }
2010   if (err)
2011     goto out;
2012
2013   /* FIXME: are constraints used correctly?  */
2014
2015   err = ssh_identity_register (ctrl, key, ttl);
2016
2017  out:
2018
2019   gcry_sexp_release (key);
2020
2021   if (! bad)
2022     es_write_byte (response, err ? SSH_RESPONSE_FAILURE : SSH_RESPONSE_SUCCESS);
2023
2024   return bad;
2025 }
2026
2027 static int
2028 ssh_handler_remove_identity (ctrl_t ctrl, estream_t request, estream_t response)
2029 {
2030   unsigned char *key_blob;
2031   uint32_t key_blob_size;
2032   gcry_sexp_t key;
2033   gpg_error_t err;
2034   int bad;
2035
2036   /* Receive key.  */
2037
2038   if (DBG_COMMAND)
2039     log_debug ("[ssh-agent] remove identity\n");
2040
2041   key_blob = NULL;
2042   key = NULL;
2043   bad = 0;
2044   
2045   err = es_read_string (request, 0, &key_blob, &key_blob_size);
2046   if (err)
2047     {
2048       bad = 1;
2049       goto out;
2050     }
2051
2052   err = ssh_read_key_public_from_blob (key_blob, key_blob_size, &key, NULL);
2053   if (err)
2054     {
2055       bad = 1;
2056       goto out;
2057     }
2058   
2059   err = ssh_identity_drop (key);
2060
2061  out:
2062
2063   xfree (key_blob);
2064   gcry_sexp_release (key);
2065
2066   if (! bad)
2067     es_write_byte (response, err ? SSH_RESPONSE_FAILURE : SSH_RESPONSE_SUCCESS);
2068
2069   return bad;
2070 }
2071
2072 static gpg_error_t
2073 ssh_identities_remove_all (void)
2074 {
2075   gpg_error_t err;
2076
2077   if (DBG_COMMAND)
2078     log_debug ("[ssh-agent] remove all identities\n");
2079
2080   err = 0;
2081
2082   /* FIXME: shall we remove _all_ cache entries or only those
2083      registered through the ssh emulation?  */
2084   
2085   return err;
2086 }
2087
2088 static int
2089 ssh_handler_remove_all_identities (ctrl_t ctrl, estream_t request, estream_t response)
2090 {
2091   gpg_error_t err;
2092   
2093   err = ssh_identities_remove_all ();
2094   es_write_byte (response, err ? SSH_RESPONSE_FAILURE : SSH_RESPONSE_SUCCESS);
2095
2096   return 0;
2097 }
2098
2099 static gpg_error_t
2100 ssh_lock (void)
2101 {
2102   gpg_error_t err;
2103
2104   if (DBG_COMMAND)
2105     log_debug ("[ssh-agent] lock\n");
2106
2107   err = 0;
2108
2109   return err;
2110 }
2111
2112 static gpg_error_t
2113 ssh_unlock (void)
2114 {
2115   gpg_error_t err;
2116
2117   if (DBG_COMMAND)
2118     log_debug ("[ssh-agent] unlock\n");
2119
2120   err = 0;
2121
2122   return err;
2123 }
2124
2125 static int
2126 ssh_handler_lock (ctrl_t ctrl, estream_t request, estream_t response)
2127 {
2128   gpg_error_t err;
2129   
2130   err = ssh_lock ();
2131   es_write_byte (response, err ? SSH_RESPONSE_FAILURE : SSH_RESPONSE_SUCCESS);
2132
2133   return 0;
2134 }
2135
2136 static int
2137 ssh_handler_unlock (ctrl_t ctrl, estream_t request, estream_t response)
2138 {
2139   gpg_error_t err;
2140   
2141   err =  ssh_unlock ();
2142   es_write_byte (response, err ? SSH_RESPONSE_FAILURE : SSH_RESPONSE_SUCCESS);
2143
2144   return 0;
2145 }
2146
2147 \f
2148
2149 /* Associating request types with the corresponding request
2150    handlers.  */
2151
2152 static ssh_request_spec_t request_specs[] =
2153   {
2154     { SSH_REQUEST_REQUEST_IDENTITIES,    ssh_handler_request_identities },
2155     { SSH_REQUEST_SIGN_REQUEST,          ssh_handler_sign_request },
2156     { SSH_REQUEST_ADD_IDENTITY,          ssh_handler_add_identity },
2157     { SSH_REQUEST_ADD_ID_CONSTRAINED,    ssh_handler_add_identity },
2158     { SSH_REQUEST_REMOVE_IDENTITY,       ssh_handler_remove_identity },
2159     { SSH_REQUEST_REMOVE_ALL_IDENTITIES, ssh_handler_remove_all_identities },
2160     { SSH_REQUEST_LOCK,                  ssh_handler_lock },
2161     { SSH_REQUEST_UNLOCK,                ssh_handler_unlock },
2162   };
2163
2164 \f
2165
2166 static gpg_error_t
2167 ssh_request_process (ctrl_t ctrl, estream_t request, estream_t response)
2168 {
2169   byte_t request_type;
2170   gpg_error_t err;
2171   unsigned int i;
2172   int bad;
2173
2174   err = es_read_byte (request, &request_type);
2175   if (err)
2176     goto out;
2177
2178   if (DBG_COMMAND)
2179     log_debug ("[ssh-agent] request: %u\n", request_type);
2180
2181   for (i = 0; i < DIM (request_specs); i++)
2182     if (request_specs[i].type == request_type)
2183       break;
2184   if (i == DIM (request_specs))
2185     {
2186       err = es_write_byte (response, SSH_RESPONSE_FAILURE);
2187       goto out;
2188     }
2189
2190   
2191   bad = (*request_specs[i].handler) (ctrl, request, response);
2192   if (bad)
2193     err = GPG_ERR_PROTOCOL_VIOLATION;
2194
2195  out:
2196
2197   return err;
2198 }
2199
2200 void
2201 start_command_handler_ssh (int sock_client)
2202 {
2203   struct server_control_s ctrl;
2204   gpg_error_t err;
2205   estream_t stream_response;
2206   estream_t stream_request;
2207   estream_t stream_sock;
2208   unsigned char *request;
2209   uint32_t request_size;
2210   size_t size;
2211   int ret;
2212
2213   /* Setup control structure.  */
2214
2215   if (DBG_COMMAND)
2216     log_debug ("[ssh-agent] Starting command handler\n");
2217
2218   memset (&ctrl, 0, sizeof (ctrl));
2219   agent_init_default_ctrl (&ctrl);
2220   ctrl.connection_fd = sock_client;
2221
2222   stream_response = NULL;
2223   stream_request = NULL;
2224   stream_sock = NULL;
2225   request = NULL;
2226
2227   stream_sock = es_fdopen (sock_client, "r+");
2228   if (! stream_sock)
2229     {
2230       err = gpg_error_from_errno (errno);
2231       goto out;
2232     }
2233   ret = es_setvbuf (stream_sock, NULL, _IONBF, 0);
2234   if (ret)
2235     {
2236       err = gpg_error_from_errno (errno);
2237       goto out;
2238     }
2239
2240   while (1)
2241     {
2242       /* Create memory streams for request/response data.  The entire
2243          request will be stored in secure memory, since it might
2244          contain secret key material.  The response does not have to
2245          be stored in secure memory, since we never give out secret
2246          keys.  FIXME: wrong place.  */
2247       
2248       /* Retrieve request.  */
2249       err = es_read_string (stream_sock, 1, &request, &request_size);
2250       if (err)
2251         break;
2252
2253       if (DBG_COMMAND)
2254         log_debug ("[ssh-agent] Received request of length: %u\n",
2255                    request_size);
2256
2257       stream_request = es_mopen (NULL, 0, 0, 1,
2258                                  realloc_secure, gcry_free, "r+");
2259       if (! stream_request)
2260         {
2261           err = gpg_error_from_errno (errno);
2262           break;
2263         }
2264       ret = es_setvbuf (stream_request, NULL, _IONBF, 0);
2265       if (ret)
2266         {
2267           err = gpg_error_from_errno (errno);
2268           break;
2269         }
2270       err = es_write_data (stream_request, request, request_size);
2271       if (err)
2272         break;
2273       es_rewind (stream_request);
2274
2275       stream_response = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+");
2276       if (! stream_response)
2277         {
2278           err = gpg_error_from_errno (errno);
2279           break;
2280         }
2281
2282       /* Process request.  */
2283       err = ssh_request_process (&ctrl, stream_request, stream_response);
2284       if (err)
2285         break;
2286  
2287       /* Figure out size of response data.  */
2288       size = es_ftell (stream_response);
2289       err = es_fseek (stream_response, 0, SEEK_SET);
2290       if (err)
2291         break;
2292
2293       /* Write response data to socket stream.  */
2294       err = es_write_uint32 (stream_sock, size);
2295       if (err)
2296         break;
2297       err = es_copy (stream_sock, stream_response);
2298       if (err)
2299         break;
2300       
2301       err = es_fflush (stream_sock);
2302       if (err)
2303         break;
2304
2305       es_fclose (stream_request);
2306       stream_request = NULL;
2307       es_fclose (stream_response);
2308       stream_response = NULL;
2309       xfree (request);
2310       request = NULL;
2311     };
2312
2313  out:
2314
2315   /* FIXME: logging.  */
2316
2317   if (stream_sock)
2318     es_fclose (stream_sock);
2319   if (stream_request)
2320     es_fclose (stream_request);
2321   if (stream_response)
2322     es_fclose (stream_response);
2323   xfree (request);              /* FIXME?  */
2324
2325   if (DBG_COMMAND)
2326     log_debug ("[ssh-agent] Leaving ssh command handler: %s\n", gpg_strerror (err));
2327
2328   free (ctrl.display);
2329   free (ctrl.ttyname);
2330   free (ctrl.ttytype);
2331   free (ctrl.lc_ctype);
2332   free (ctrl.lc_messages);
2333 }