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