LCOV - code coverage report
Current view: top level - agent - command-ssh.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 1524 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 67 0.0 %

          Line data    Source code
       1             : /* command-ssh.c - gpg-agent's ssh-agent emulation layer
       2             :  * Copyright (C) 2004-2006, 2009, 2012 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2004-2006, 2009, 2012-2014 Werner Koch
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * GnuPG is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 3 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * GnuPG is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : /* Only v2 of the ssh-agent protocol is implemented.  Relevant RFCs
      22             :    are:
      23             : 
      24             :    RFC-4250 - Protocol Assigned Numbers
      25             :    RFC-4251 - Protocol Architecture
      26             :    RFC-4252 - Authentication Protocol
      27             :    RFC-4253 - Transport Layer Protocol
      28             :    RFC-5656 - ECC support
      29             : 
      30             :    The protocol for the agent is defined in OpenSSH's PROTOCL.agent
      31             :    file.
      32             :   */
      33             : 
      34             : #include <config.h>
      35             : 
      36             : #include <stdio.h>
      37             : #include <stdlib.h>
      38             : #include <string.h>
      39             : #include <errno.h>
      40             : #include <sys/types.h>
      41             : #include <sys/stat.h>
      42             : #include <assert.h>
      43             : 
      44             : #include "agent.h"
      45             : 
      46             : #include "i18n.h"
      47             : #include "../common/ssh-utils.h"
      48             : 
      49             : 
      50             : 
      51             : 
      52             : /* Request types. */
      53             : #define SSH_REQUEST_REQUEST_IDENTITIES    11
      54             : #define SSH_REQUEST_SIGN_REQUEST          13
      55             : #define SSH_REQUEST_ADD_IDENTITY          17
      56             : #define SSH_REQUEST_REMOVE_IDENTITY       18
      57             : #define SSH_REQUEST_REMOVE_ALL_IDENTITIES 19
      58             : #define SSH_REQUEST_LOCK                  22
      59             : #define SSH_REQUEST_UNLOCK                23
      60             : #define SSH_REQUEST_ADD_ID_CONSTRAINED    25
      61             : 
      62             : /* Options. */
      63             : #define SSH_OPT_CONSTRAIN_LIFETIME         1
      64             : #define SSH_OPT_CONSTRAIN_CONFIRM          2
      65             : 
      66             : /* Response types. */
      67             : #define SSH_RESPONSE_SUCCESS               6
      68             : #define SSH_RESPONSE_FAILURE               5
      69             : #define SSH_RESPONSE_IDENTITIES_ANSWER    12
      70             : #define SSH_RESPONSE_SIGN_RESPONSE        14
      71             : 
      72             : /* Other constants.  */
      73             : #define SSH_DSA_SIGNATURE_PADDING 20
      74             : #define SSH_DSA_SIGNATURE_ELEMS    2
      75             : #define SPEC_FLAG_USE_PKCS1V2 (1 << 0)
      76             : #define SPEC_FLAG_IS_ECDSA    (1 << 1)
      77             : #define SPEC_FLAG_IS_EdDSA    (1 << 2)  /*(lowercase 'd' on purpose.)*/
      78             : 
      79             : /* The name of the control file.  */
      80             : #define SSH_CONTROL_FILE_NAME "sshcontrol"
      81             : 
      82             : /* The blurb we put into the header of a newly created control file.  */
      83             : static const char sshcontrolblurb[] =
      84             : "# List of allowed ssh keys.  Only keys present in this file are used\n"
      85             : "# in the SSH protocol.  The ssh-add tool may add new entries to this\n"
      86             : "# file to enable them; you may also add them manually.  Comment\n"
      87             : "# lines, like this one, as well as empty lines are ignored.  Lines do\n"
      88             : "# have a certain length limit but this is not serious limitation as\n"
      89             : "# the format of the entries is fixed and checked by gpg-agent. A\n"
      90             : "# non-comment line starts with optional white spaces, followed by the\n"
      91             : "# keygrip of the key given as 40 hex digits, optionally followed by a\n"
      92             : "# caching TTL in seconds, and another optional field for arbitrary\n"
      93             : "# flags.   Prepend the keygrip with an '!' mark to disable it.\n"
      94             : "\n";
      95             : 
      96             : 
      97             : /* Macros.  */
      98             : 
      99             : /* Return a new uint32 with b0 being the most significant byte and b3
     100             :    being the least significant byte.  */
     101             : #define uint32_construct(b0, b1, b2, b3) \
     102             :   ((b0 << 24) | (b1 << 16) | (b2 << 8) | b3)
     103             : 
     104             : 
     105             : 
     106             : 
     107             : /*
     108             :  * Basic types.
     109             :  */
     110             : 
     111             : /* Type for a request handler.  */
     112             : typedef gpg_error_t (*ssh_request_handler_t) (ctrl_t ctrl,
     113             :                                               estream_t request,
     114             :                                               estream_t response);
     115             : 
     116             : 
     117             : struct ssh_key_type_spec;
     118             : typedef struct ssh_key_type_spec ssh_key_type_spec_t;
     119             : 
     120             : /* Type, which is used for associating request handlers with the
     121             :    appropriate request IDs.  */
     122             : typedef struct ssh_request_spec
     123             : {
     124             :   unsigned char type;
     125             :   ssh_request_handler_t handler;
     126             :   const char *identifier;
     127             :   unsigned int secret_input;
     128             : } ssh_request_spec_t;
     129             : 
     130             : /* Type for "key modifier functions", which are necessary since
     131             :    OpenSSH and GnuPG treat key material slightly different.  A key
     132             :    modifier is called right after a new key identity has been received
     133             :    in order to "sanitize" the material.  */
     134             : typedef gpg_error_t (*ssh_key_modifier_t) (const char *elems,
     135             :                                            gcry_mpi_t *mpis);
     136             : 
     137             : /* The encoding of a generated signature is dependent on the
     138             :    algorithm; therefore algorithm specific signature encoding
     139             :    functions are necessary.  */
     140             : typedef gpg_error_t (*ssh_signature_encoder_t) (ssh_key_type_spec_t *spec,
     141             :                                                 estream_t signature_blob,
     142             :                                                 gcry_sexp_t sig);
     143             : 
     144             : /* Type, which is used for boundling all the algorithm specific
     145             :    information together in a single object.  */
     146             : struct ssh_key_type_spec
     147             : {
     148             :   /* Algorithm identifier as used by OpenSSH.  */
     149             :   const char *ssh_identifier;
     150             : 
     151             :   /* Human readable name of the algorithm.  */
     152             :   const char *name;
     153             : 
     154             :   /* Algorithm identifier as used by GnuPG.  */
     155             :   const char *identifier;
     156             : 
     157             :   /* List of MPI names for secret keys; order matches the one of the
     158             :      agent protocol.  */
     159             :   const char *elems_key_secret;
     160             : 
     161             :   /* List of MPI names for public keys; order matches the one of the
     162             :      agent protocol.  */
     163             :   const char *elems_key_public;
     164             : 
     165             :   /* List of MPI names for signature data.  */
     166             :   const char *elems_signature;
     167             : 
     168             :   /* List of MPI names for secret keys; order matches the one, which
     169             :      is required by gpg-agent's key access layer.  */
     170             :   const char *elems_sexp_order;
     171             : 
     172             :   /* Key modifier function.  Key modifier functions are necessary in
     173             :      order to fix any inconsistencies between the representation of
     174             :      keys on the SSH and on the GnuPG side.  */
     175             :   ssh_key_modifier_t key_modifier;
     176             : 
     177             :   /* Signature encoder function.  Signature encoder functions are
     178             :      necessary since the encoding of signatures depends on the used
     179             :      algorithm.  */
     180             :   ssh_signature_encoder_t signature_encoder;
     181             : 
     182             :   /* The name of the ECC curve or NULL.  */
     183             :   const char *curve_name;
     184             : 
     185             :   /* The hash algorithm to be used with this key.  0 for using the
     186             :      default.  */
     187             :   int hash_algo;
     188             : 
     189             :   /* Misc flags.  */
     190             :   unsigned int flags;
     191             : };
     192             : 
     193             : 
     194             : /* Definition of an object to access the sshcontrol file.  */
     195             : struct ssh_control_file_s
     196             : {
     197             :   char *fname;  /* Name of the file.  */
     198             :   FILE *fp;     /* This is never NULL. */
     199             :   int lnr;      /* The current line number.  */
     200             :   struct {
     201             :     int valid;           /* True if the data of this structure is valid.  */
     202             :     int disabled;        /* The item is disabled.  */
     203             :     int ttl;             /* The TTL of the item.   */
     204             :     int confirm;         /* The confirm flag is set.  */
     205             :     char hexgrip[40+1];  /* The hexgrip of the item (uppercase).  */
     206             :   } item;
     207             : };
     208             : 
     209             : 
     210             : /* Prototypes.  */
     211             : static gpg_error_t ssh_handler_request_identities (ctrl_t ctrl,
     212             :                                                    estream_t request,
     213             :                                                    estream_t response);
     214             : static gpg_error_t ssh_handler_sign_request (ctrl_t ctrl,
     215             :                                              estream_t request,
     216             :                                              estream_t response);
     217             : static gpg_error_t ssh_handler_add_identity (ctrl_t ctrl,
     218             :                                              estream_t request,
     219             :                                              estream_t response);
     220             : static gpg_error_t ssh_handler_remove_identity (ctrl_t ctrl,
     221             :                                                 estream_t request,
     222             :                                                 estream_t response);
     223             : static gpg_error_t ssh_handler_remove_all_identities (ctrl_t ctrl,
     224             :                                                       estream_t request,
     225             :                                                       estream_t response);
     226             : static gpg_error_t ssh_handler_lock (ctrl_t ctrl,
     227             :                                      estream_t request,
     228             :                                      estream_t response);
     229             : static gpg_error_t ssh_handler_unlock (ctrl_t ctrl,
     230             :                                        estream_t request,
     231             :                                        estream_t response);
     232             : 
     233             : static gpg_error_t ssh_key_modifier_rsa (const char *elems, gcry_mpi_t *mpis);
     234             : static gpg_error_t ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec,
     235             :                                               estream_t signature_blob,
     236             :                                               gcry_sexp_t signature);
     237             : static gpg_error_t ssh_signature_encoder_dsa (ssh_key_type_spec_t *spec,
     238             :                                               estream_t signature_blob,
     239             :                                               gcry_sexp_t signature);
     240             : static gpg_error_t ssh_signature_encoder_ecdsa (ssh_key_type_spec_t *spec,
     241             :                                                 estream_t signature_blob,
     242             :                                                 gcry_sexp_t signature);
     243             : static gpg_error_t ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec,
     244             :                                                 estream_t signature_blob,
     245             :                                                 gcry_sexp_t signature);
     246             : static gpg_error_t ssh_key_extract_comment (gcry_sexp_t key, char **comment);
     247             : 
     248             : 
     249             : 
     250             : /* Global variables.  */
     251             : 
     252             : 
     253             : /* Associating request types with the corresponding request
     254             :    handlers.  */
     255             : 
     256             : static ssh_request_spec_t request_specs[] =
     257             :   {
     258             : #define REQUEST_SPEC_DEFINE(id, name, secret_input) \
     259             :   { SSH_REQUEST_##id, ssh_handler_##name, #name, secret_input }
     260             : 
     261             :     REQUEST_SPEC_DEFINE (REQUEST_IDENTITIES,    request_identities,    1),
     262             :     REQUEST_SPEC_DEFINE (SIGN_REQUEST,          sign_request,          0),
     263             :     REQUEST_SPEC_DEFINE (ADD_IDENTITY,          add_identity,          1),
     264             :     REQUEST_SPEC_DEFINE (ADD_ID_CONSTRAINED,    add_identity,          1),
     265             :     REQUEST_SPEC_DEFINE (REMOVE_IDENTITY,       remove_identity,       0),
     266             :     REQUEST_SPEC_DEFINE (REMOVE_ALL_IDENTITIES, remove_all_identities, 0),
     267             :     REQUEST_SPEC_DEFINE (LOCK,                  lock,                  0),
     268             :     REQUEST_SPEC_DEFINE (UNLOCK,                unlock,                0)
     269             : #undef REQUEST_SPEC_DEFINE
     270             :   };
     271             : 
     272             : 
     273             : /* Table holding key type specifications.  */
     274             : static ssh_key_type_spec_t ssh_key_types[] =
     275             :   {
     276             :     {
     277             :       "ssh-ed25519", "Ed25519", "ecc", "qd",  "q", "rs", "qd",
     278             :       NULL,                 ssh_signature_encoder_eddsa,
     279             :       "Ed25519", 0,               SPEC_FLAG_IS_EdDSA
     280             :     },
     281             :     {
     282             :       "ssh-rsa", "RSA", "rsa", "nedupq", "en",   "s",  "nedpqu",
     283             :       ssh_key_modifier_rsa, ssh_signature_encoder_rsa,
     284             :       NULL, 0,                    SPEC_FLAG_USE_PKCS1V2
     285             :     },
     286             :     {
     287             :       "ssh-dss", "DSA", "dsa", "pqgyx",  "pqgy", "rs", "pqgyx",
     288             :       NULL,                 ssh_signature_encoder_dsa,
     289             :       NULL, 0, 0
     290             :     },
     291             :     {
     292             :       "ecdsa-sha2-nistp256", "ECDSA", "ecdsa", "qd",  "q", "rs", "qd",
     293             :       NULL,                 ssh_signature_encoder_ecdsa,
     294             :       "nistp256", GCRY_MD_SHA256, SPEC_FLAG_IS_ECDSA
     295             :     },
     296             :     {
     297             :       "ecdsa-sha2-nistp384", "ECDSA", "ecdsa", "qd",  "q", "rs", "qd",
     298             :       NULL,                 ssh_signature_encoder_ecdsa,
     299             :       "nistp384", GCRY_MD_SHA384, SPEC_FLAG_IS_ECDSA
     300             :     },
     301             :     {
     302             :       "ecdsa-sha2-nistp521", "ECDSA", "ecdsa", "qd",  "q", "rs", "qd",
     303             :       NULL,                 ssh_signature_encoder_ecdsa,
     304             :       "nistp521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA
     305             :     }
     306             :   };
     307             : 
     308             : 
     309             : 
     310             : 
     311             : 
     312             : /*
     313             :    General utility functions.
     314             :  */
     315             : 
     316             : /* A secure realloc, i.e. it makes sure to allocate secure memory if A
     317             :    is NULL.  This is required because the standard gcry_realloc does
     318             :    not know whether to allocate secure or normal if NULL is passed as
     319             :    existing buffer.  */
     320             : static void *
     321           0 : realloc_secure (void *a, size_t n)
     322             : {
     323             :   void *p;
     324             : 
     325           0 :   if (a)
     326           0 :     p = gcry_realloc (a, n);
     327             :   else
     328           0 :     p = gcry_malloc_secure (n);
     329             : 
     330           0 :   return p;
     331             : }
     332             : 
     333             : 
     334             : /* Create and return a new C-string from DATA/DATA_N (i.e.: add
     335             :    NUL-termination); return NULL on OOM.  */
     336             : static char *
     337           0 : make_cstring (const char *data, size_t data_n)
     338             : {
     339             :   char *s;
     340             : 
     341           0 :   s = xtrymalloc (data_n + 1);
     342           0 :   if (s)
     343             :     {
     344           0 :       memcpy (s, data, data_n);
     345           0 :       s[data_n] = 0;
     346             :     }
     347             : 
     348           0 :   return s;
     349             : }
     350             : 
     351             : /* Lookup the ssh-identifier for the ECC curve CURVE_NAME.  Returns
     352             :    NULL if not found.  */
     353             : static const char *
     354           0 : ssh_identifier_from_curve_name (const char *curve_name)
     355             : {
     356             :   int i;
     357             : 
     358           0 :   for (i = 0; i < DIM (ssh_key_types); i++)
     359           0 :     if (ssh_key_types[i].curve_name
     360           0 :         && !strcmp (ssh_key_types[i].curve_name, curve_name))
     361           0 :       return ssh_key_types[i].ssh_identifier;
     362             : 
     363           0 :   return NULL;
     364             : }
     365             : 
     366             : 
     367             : /*
     368             :    Primitive I/O functions.
     369             :  */
     370             : 
     371             : 
     372             : /* Read a byte from STREAM, store it in B.  */
     373             : static gpg_error_t
     374           0 : stream_read_byte (estream_t stream, unsigned char *b)
     375             : {
     376             :   gpg_error_t err;
     377             :   int ret;
     378             : 
     379           0 :   ret = es_fgetc (stream);
     380           0 :   if (ret == EOF)
     381             :     {
     382           0 :       if (es_ferror (stream))
     383           0 :         err = gpg_error_from_syserror ();
     384             :       else
     385           0 :         err = gpg_error (GPG_ERR_EOF);
     386           0 :       *b = 0;
     387             :     }
     388             :   else
     389             :     {
     390           0 :       *b = ret & 0xFF;
     391           0 :       err = 0;
     392             :     }
     393             : 
     394           0 :   return err;
     395             : }
     396             : 
     397             : /* Write the byte contained in B to STREAM.  */
     398             : static gpg_error_t
     399           0 : stream_write_byte (estream_t stream, unsigned char b)
     400             : {
     401             :   gpg_error_t err;
     402             :   int ret;
     403             : 
     404           0 :   ret = es_fputc (b, stream);
     405           0 :   if (ret == EOF)
     406           0 :     err = gpg_error_from_syserror ();
     407             :   else
     408           0 :     err = 0;
     409             : 
     410           0 :   return err;
     411             : }
     412             : 
     413             : 
     414             : /* Read a uint32 from STREAM, store it in UINT32.  */
     415             : static gpg_error_t
     416           0 : stream_read_uint32 (estream_t stream, u32 *uint32)
     417             : {
     418             :   unsigned char buffer[4];
     419             :   size_t bytes_read;
     420             :   gpg_error_t err;
     421             :   int ret;
     422             : 
     423           0 :   ret = es_read (stream, buffer, sizeof (buffer), &bytes_read);
     424           0 :   if (ret)
     425           0 :     err = gpg_error_from_syserror ();
     426             :   else
     427             :     {
     428           0 :       if (bytes_read != sizeof (buffer))
     429           0 :         err = gpg_error (GPG_ERR_EOF);
     430             :       else
     431             :         {
     432             :           u32 n;
     433             : 
     434           0 :           n = uint32_construct (buffer[0], buffer[1], buffer[2], buffer[3]);
     435           0 :           *uint32 = n;
     436           0 :           err = 0;
     437             :         }
     438             :     }
     439             : 
     440           0 :   return err;
     441             : }
     442             : 
     443             : /* Write the uint32 contained in UINT32 to STREAM.  */
     444             : static gpg_error_t
     445           0 : stream_write_uint32 (estream_t stream, u32 uint32)
     446             : {
     447             :   unsigned char buffer[4];
     448             :   gpg_error_t err;
     449             :   int ret;
     450             : 
     451           0 :   buffer[0] = uint32 >> 24;
     452           0 :   buffer[1] = uint32 >> 16;
     453           0 :   buffer[2] = uint32 >>  8;
     454           0 :   buffer[3] = uint32 >>  0;
     455             : 
     456           0 :   ret = es_write (stream, buffer, sizeof (buffer), NULL);
     457           0 :   if (ret)
     458           0 :     err = gpg_error_from_syserror ();
     459             :   else
     460           0 :     err = 0;
     461             : 
     462           0 :   return err;
     463             : }
     464             : 
     465             : /* Read SIZE bytes from STREAM into BUFFER.  */
     466             : static gpg_error_t
     467           0 : stream_read_data (estream_t stream, unsigned char *buffer, size_t size)
     468             : {
     469             :   gpg_error_t err;
     470             :   size_t bytes_read;
     471             :   int ret;
     472             : 
     473           0 :   ret = es_read (stream, buffer, size, &bytes_read);
     474           0 :   if (ret)
     475           0 :     err = gpg_error_from_syserror ();
     476             :   else
     477             :     {
     478           0 :       if (bytes_read != size)
     479           0 :         err = gpg_error (GPG_ERR_EOF);
     480             :       else
     481           0 :         err = 0;
     482             :     }
     483             : 
     484           0 :   return err;
     485             : }
     486             : 
     487             : /* Skip over SIZE bytes from STREAM.  */
     488             : static gpg_error_t
     489           0 : stream_read_skip (estream_t stream, size_t size)
     490             : {
     491             :   char buffer[128];
     492             :   size_t bytes_to_read, bytes_read;
     493             :   int ret;
     494             : 
     495             :   do
     496             :     {
     497           0 :       bytes_to_read = size;
     498           0 :       if (bytes_to_read > sizeof buffer)
     499           0 :         bytes_to_read = sizeof buffer;
     500             : 
     501           0 :       ret = es_read (stream, buffer, bytes_to_read, &bytes_read);
     502           0 :       if (ret)
     503           0 :         return gpg_error_from_syserror ();
     504           0 :       else if (bytes_read != bytes_to_read)
     505           0 :         return gpg_error (GPG_ERR_EOF);
     506             :       else
     507           0 :         size -= bytes_to_read;
     508             :     }
     509           0 :   while (size);
     510             : 
     511           0 :   return 0;
     512             : }
     513             : 
     514             : 
     515             : /* Write SIZE bytes from BUFFER to STREAM.  */
     516             : static gpg_error_t
     517           0 : stream_write_data (estream_t stream, const unsigned char *buffer, size_t size)
     518             : {
     519             :   gpg_error_t err;
     520             :   int ret;
     521             : 
     522           0 :   ret = es_write (stream, buffer, size, NULL);
     523           0 :   if (ret)
     524           0 :     err = gpg_error_from_syserror ();
     525             :   else
     526           0 :     err = 0;
     527             : 
     528           0 :   return err;
     529             : }
     530             : 
     531             : /* Read a binary string from STREAM into STRING, store size of string
     532             :    in STRING_SIZE.  Append a hidden nul so that the result may
     533             :    directly be used as a C string.  Depending on SECURE use secure
     534             :    memory for STRING.  */
     535             : static gpg_error_t
     536           0 : stream_read_string (estream_t stream, unsigned int secure,
     537             :                     unsigned char **string, u32 *string_size)
     538             : {
     539             :   gpg_error_t err;
     540           0 :   unsigned char *buffer = NULL;
     541           0 :   u32 length = 0;
     542             : 
     543           0 :   if (string_size)
     544           0 :     *string_size = 0;
     545             : 
     546             :   /* Read string length.  */
     547           0 :   err = stream_read_uint32 (stream, &length);
     548           0 :   if (err)
     549           0 :     goto out;
     550             : 
     551             :   /* Allocate space.  */
     552           0 :   if (secure)
     553           0 :     buffer = xtrymalloc_secure (length + 1);
     554             :   else
     555           0 :     buffer = xtrymalloc (length + 1);
     556           0 :   if (! buffer)
     557             :     {
     558           0 :       err = gpg_error_from_syserror ();
     559           0 :       goto out;
     560             :     }
     561             : 
     562             :   /* Read data.  */
     563           0 :   err = stream_read_data (stream, buffer, length);
     564           0 :   if (err)
     565           0 :     goto out;
     566             : 
     567             :   /* Finalize string object.  */
     568           0 :   buffer[length] = 0;
     569           0 :   *string = buffer;
     570           0 :   if (string_size)
     571           0 :     *string_size = length;
     572             : 
     573             :  out:
     574             : 
     575           0 :   if (err)
     576           0 :     xfree (buffer);
     577             : 
     578           0 :   return err;
     579             : }
     580             : 
     581             : 
     582             : /* Read a binary string from STREAM and store it as an opaque MPI at
     583             :    R_MPI, adding 0x40 (this is the prefix for EdDSA key in OpenPGP).
     584             :    Depending on SECURE use secure memory.  If the string is too large
     585             :    for key material return an error.  */
     586             : static gpg_error_t
     587           0 : stream_read_blob (estream_t stream, unsigned int secure, gcry_mpi_t *r_mpi)
     588             : {
     589             :   gpg_error_t err;
     590           0 :   unsigned char *buffer = NULL;
     591           0 :   u32 length = 0;
     592             : 
     593           0 :   *r_mpi = NULL;
     594             : 
     595             :   /* Read string length.  */
     596           0 :   err = stream_read_uint32 (stream, &length);
     597           0 :   if (err)
     598           0 :     goto leave;
     599             : 
     600             :   /* To avoid excessive use of secure memory we check that an MPI is
     601             :      not too large. */
     602           0 :   if (length > (4096/8) + 8)
     603             :     {
     604           0 :       log_error (_("ssh keys greater than %d bits are not supported\n"), 4096);
     605           0 :       err = GPG_ERR_TOO_LARGE;
     606           0 :       goto leave;
     607             :     }
     608             : 
     609             :   /* Allocate space.  */
     610           0 :   if (secure)
     611           0 :     buffer = xtrymalloc_secure (length+1);
     612             :   else
     613           0 :     buffer = xtrymalloc (length+1);
     614           0 :   if (!buffer)
     615             :     {
     616           0 :       err = gpg_error_from_syserror ();
     617           0 :       goto leave;
     618             :     }
     619             : 
     620             :   /* Read data.  */
     621           0 :   err = stream_read_data (stream, buffer + 1, length);
     622           0 :   if (err)
     623           0 :     goto leave;
     624             : 
     625           0 :   buffer[0] = 0x40;
     626           0 :   *r_mpi = gcry_mpi_set_opaque (NULL, buffer, 8*(length+1));
     627           0 :   buffer = NULL;
     628             : 
     629             :  leave:
     630           0 :   xfree (buffer);
     631           0 :   return err;
     632             : }
     633             : 
     634             : 
     635             : /* Read a C-string from STREAM, store copy in STRING.  */
     636             : static gpg_error_t
     637           0 : stream_read_cstring (estream_t stream, char **string)
     638             : {
     639             :   gpg_error_t err;
     640             :   unsigned char *buffer;
     641             : 
     642           0 :   err = stream_read_string (stream, 0, &buffer, NULL);
     643           0 :   if (!err)
     644           0 :     *string = (char *)buffer;
     645           0 :   return err;
     646             : }
     647             : 
     648             : 
     649             : /* Write a binary string from STRING of size STRING_N to STREAM.  */
     650             : static gpg_error_t
     651           0 : stream_write_string (estream_t stream,
     652             :                      const unsigned char *string, u32 string_n)
     653             : {
     654             :   gpg_error_t err;
     655             : 
     656           0 :   err = stream_write_uint32 (stream, string_n);
     657           0 :   if (err)
     658           0 :     goto out;
     659             : 
     660           0 :   err = stream_write_data (stream, string, string_n);
     661             : 
     662             :  out:
     663             : 
     664           0 :   return err;
     665             : }
     666             : 
     667             : /* Write a C-string from STRING to STREAM.  */
     668             : static gpg_error_t
     669           0 : stream_write_cstring (estream_t stream, const char *string)
     670             : {
     671             :   gpg_error_t err;
     672             : 
     673           0 :   err = stream_write_string (stream,
     674           0 :                              (const unsigned char *) string, strlen (string));
     675             : 
     676           0 :   return err;
     677             : }
     678             : 
     679             : /* Read an MPI from STREAM, store it in MPINT.  Depending on SECURE
     680             :    use secure memory.  */
     681             : static gpg_error_t
     682           0 : stream_read_mpi (estream_t stream, unsigned int secure, gcry_mpi_t *mpint)
     683             : {
     684             :   unsigned char *mpi_data;
     685             :   u32 mpi_data_size;
     686             :   gpg_error_t err;
     687             :   gcry_mpi_t mpi;
     688             : 
     689           0 :   mpi_data = NULL;
     690             : 
     691           0 :   err = stream_read_string (stream, secure, &mpi_data, &mpi_data_size);
     692           0 :   if (err)
     693           0 :     goto out;
     694             : 
     695             :   /* To avoid excessive use of secure memory we check that an MPI is
     696             :      not too large. */
     697           0 :   if (mpi_data_size > 520)
     698             :     {
     699           0 :       log_error (_("ssh keys greater than %d bits are not supported\n"), 4096);
     700           0 :       err = GPG_ERR_TOO_LARGE;
     701           0 :       goto out;
     702             :     }
     703             : 
     704           0 :   err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_STD, mpi_data, mpi_data_size, NULL);
     705           0 :   if (err)
     706           0 :     goto out;
     707             : 
     708           0 :   *mpint = mpi;
     709             : 
     710             :  out:
     711             : 
     712           0 :   xfree (mpi_data);
     713             : 
     714           0 :   return err;
     715             : }
     716             : 
     717             : /* Write the MPI contained in MPINT to STREAM.  */
     718             : static gpg_error_t
     719           0 : stream_write_mpi (estream_t stream, gcry_mpi_t mpint)
     720             : {
     721             :   unsigned char *mpi_buffer;
     722             :   size_t mpi_buffer_n;
     723             :   gpg_error_t err;
     724             : 
     725           0 :   mpi_buffer = NULL;
     726             : 
     727           0 :   err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &mpi_buffer, &mpi_buffer_n, mpint);
     728           0 :   if (err)
     729           0 :     goto out;
     730             : 
     731           0 :   err = stream_write_string (stream, mpi_buffer, mpi_buffer_n);
     732             : 
     733             :  out:
     734             : 
     735           0 :   xfree (mpi_buffer);
     736             : 
     737           0 :   return err;
     738             : }
     739             : 
     740             : 
     741             : /* Copy data from SRC to DST until EOF is reached.  */
     742             : static gpg_error_t
     743           0 : stream_copy (estream_t dst, estream_t src)
     744             : {
     745             :   char buffer[BUFSIZ];
     746             :   size_t bytes_read;
     747             :   gpg_error_t err;
     748             :   int ret;
     749             : 
     750           0 :   err = 0;
     751             :   while (1)
     752             :     {
     753           0 :       ret = es_read (src, buffer, sizeof (buffer), &bytes_read);
     754           0 :       if (ret || (! bytes_read))
     755             :         {
     756           0 :           if (ret)
     757           0 :             err = gpg_error_from_syserror ();
     758           0 :           break;
     759             :         }
     760           0 :       ret = es_write (dst, buffer, bytes_read, NULL);
     761           0 :       if (ret)
     762             :         {
     763           0 :           err = gpg_error_from_syserror ();
     764           0 :           break;
     765             :         }
     766           0 :     }
     767             : 
     768           0 :   return err;
     769             : }
     770             : 
     771             : 
     772             : /* Read the content of the file specified by FILENAME into a newly
     773             :    create buffer, which is to be stored in BUFFER; store length of
     774             :    buffer in BUFFER_N.  */
     775             : static gpg_error_t
     776           0 : file_to_buffer (const char *filename, unsigned char **buffer, size_t *buffer_n)
     777             : {
     778             :   unsigned char *buffer_new;
     779             :   struct stat statbuf;
     780             :   estream_t stream;
     781             :   gpg_error_t err;
     782             :   int ret;
     783             : 
     784           0 :   *buffer = NULL;
     785           0 :   *buffer_n = 0;
     786             : 
     787           0 :   buffer_new = NULL;
     788           0 :   err = 0;
     789             : 
     790           0 :   stream = es_fopen (filename, "rb");
     791           0 :   if (! stream)
     792             :     {
     793           0 :       err = gpg_error_from_syserror ();
     794           0 :       goto out;
     795             :     }
     796             : 
     797           0 :   ret = fstat (es_fileno (stream), &statbuf);
     798           0 :   if (ret)
     799             :     {
     800           0 :       err = gpg_error_from_syserror ();
     801           0 :       goto out;
     802             :     }
     803             : 
     804           0 :   buffer_new = xtrymalloc (statbuf.st_size);
     805           0 :   if (! buffer_new)
     806             :     {
     807           0 :       err = gpg_error_from_syserror ();
     808           0 :       goto out;
     809             :     }
     810             : 
     811           0 :   err = stream_read_data (stream, buffer_new, statbuf.st_size);
     812           0 :   if (err)
     813           0 :     goto out;
     814             : 
     815           0 :   *buffer = buffer_new;
     816           0 :   *buffer_n = statbuf.st_size;
     817             : 
     818             :  out:
     819             : 
     820           0 :   if (stream)
     821           0 :     es_fclose (stream);
     822             : 
     823           0 :   if (err)
     824           0 :     xfree (buffer_new);
     825             : 
     826           0 :   return err;
     827             : }
     828             : 
     829             : 
     830             : 
     831             : 
     832             : /* Open the ssh control file and create it if not available.  With
     833             :    APPEND passed as true the file will be opened in append mode,
     834             :    otherwise in read only mode.  On success 0 is returned and a new
     835             :    control file object stored at R_CF.  On error an error code is
     836             :    returned and NULL is stored at R_CF.  */
     837             : static gpg_error_t
     838           0 : open_control_file (ssh_control_file_t *r_cf, int append)
     839             : {
     840             :   gpg_error_t err;
     841             :   ssh_control_file_t cf;
     842             : 
     843           0 :   cf = xtrycalloc (1, sizeof *cf);
     844           0 :   if (!cf)
     845             :     {
     846           0 :       err = gpg_error_from_syserror ();
     847           0 :       goto leave;
     848             :     }
     849             : 
     850             :   /* Note: As soon as we start to use non blocking functions here
     851             :      (i.e. where Pth might switch threads) we need to employ a
     852             :      mutex.  */
     853           0 :   cf->fname = make_filename_try (opt.homedir, SSH_CONTROL_FILE_NAME, NULL);
     854           0 :   if (!cf->fname)
     855             :     {
     856           0 :       err = gpg_error_from_syserror ();
     857           0 :       goto leave;
     858             :     }
     859             :   /* FIXME: With "a+" we are not able to check whether this will
     860             :      be created and thus the blurb needs to be written first.  */
     861           0 :   cf->fp = fopen (cf->fname, append? "a+":"r");
     862           0 :   if (!cf->fp && errno == ENOENT)
     863             :     {
     864           0 :       estream_t stream = es_fopen (cf->fname, "wx,mode=-rw-r");
     865           0 :       if (!stream)
     866             :         {
     867           0 :           err = gpg_error_from_syserror ();
     868           0 :           log_error (_("can't create '%s': %s\n"),
     869             :                      cf->fname, gpg_strerror (err));
     870           0 :           goto leave;
     871             :         }
     872           0 :       es_fputs (sshcontrolblurb, stream);
     873           0 :       es_fclose (stream);
     874           0 :       cf->fp = fopen (cf->fname, append? "a+":"r");
     875             :     }
     876             : 
     877           0 :   if (!cf->fp)
     878             :     {
     879           0 :       err = gpg_error_from_syserror ();
     880           0 :       log_error (_("can't open '%s': %s\n"),
     881             :                  cf->fname, gpg_strerror (err));
     882           0 :       goto leave;
     883             :     }
     884             : 
     885           0 :   err = 0;
     886             : 
     887             :  leave:
     888           0 :   if (err && cf)
     889             :     {
     890           0 :       if (cf->fp)
     891           0 :         fclose (cf->fp);
     892           0 :       xfree (cf->fname);
     893           0 :       xfree (cf);
     894             :     }
     895             :   else
     896           0 :     *r_cf = cf;
     897             : 
     898           0 :   return err;
     899             : }
     900             : 
     901             : 
     902             : static void
     903           0 : rewind_control_file (ssh_control_file_t cf)
     904             : {
     905           0 :   fseek (cf->fp, 0, SEEK_SET);
     906           0 :   cf->lnr = 0;
     907           0 :   clearerr (cf->fp);
     908           0 : }
     909             : 
     910             : 
     911             : static void
     912           0 : close_control_file (ssh_control_file_t cf)
     913             : {
     914           0 :   if (!cf)
     915           0 :     return;
     916           0 :   fclose (cf->fp);
     917           0 :   xfree (cf->fname);
     918           0 :   xfree (cf);
     919             : }
     920             : 
     921             : 
     922             : 
     923             : /* Read the next line from the control file and store the data in CF.
     924             :    Returns 0 on success, GPG_ERR_EOF on EOF, or other error codes. */
     925             : static gpg_error_t
     926           0 : read_control_file_item (ssh_control_file_t cf)
     927             : {
     928             :   int c, i, n;
     929             :   char *p, *pend, line[256];
     930           0 :   long ttl = 0;
     931             : 
     932           0 :   cf->item.valid = 0;
     933           0 :   clearerr (cf->fp);
     934             : 
     935             :   do
     936             :     {
     937           0 :       if (!fgets (line, DIM(line)-1, cf->fp) )
     938             :         {
     939           0 :           if (feof (cf->fp))
     940           0 :             return gpg_error (GPG_ERR_EOF);
     941           0 :           return gpg_error_from_syserror ();
     942             :         }
     943           0 :       cf->lnr++;
     944             : 
     945           0 :       if (!*line || line[strlen(line)-1] != '\n')
     946             :         {
     947             :           /* Eat until end of line */
     948           0 :           while ( (c=getc (cf->fp)) != EOF && c != '\n')
     949             :             ;
     950           0 :           return gpg_error (*line? GPG_ERR_LINE_TOO_LONG
     951             :                                  : GPG_ERR_INCOMPLETE_LINE);
     952             :         }
     953             : 
     954             :       /* Allow for empty lines and spaces */
     955           0 :       for (p=line; spacep (p); p++)
     956             :         ;
     957             :     }
     958           0 :   while (!*p || *p == '\n' || *p == '#');
     959             : 
     960           0 :   cf->item.disabled = 0;
     961           0 :   if (*p == '!')
     962             :     {
     963           0 :       cf->item.disabled = 1;
     964           0 :       for (p++; spacep (p); p++)
     965             :         ;
     966             :     }
     967             : 
     968           0 :   for (i=0; hexdigitp (p) && i < 40; p++, i++)
     969           0 :     cf->item.hexgrip[i] = (*p >= 'a'? (*p & 0xdf): *p);
     970           0 :   cf->item.hexgrip[i] = 0;
     971           0 :   if (i != 40 || !(spacep (p) || *p == '\n'))
     972             :     {
     973           0 :       log_error ("%s:%d: invalid formatted line\n", cf->fname, cf->lnr);
     974           0 :       return gpg_error (GPG_ERR_BAD_DATA);
     975             :     }
     976             : 
     977           0 :   ttl = strtol (p, &pend, 10);
     978           0 :   p = pend;
     979           0 :   if (!(spacep (p) || *p == '\n') || (int)ttl < -1)
     980             :     {
     981           0 :       log_error ("%s:%d: invalid TTL value; assuming 0\n", cf->fname, cf->lnr);
     982           0 :       cf->item.ttl = 0;
     983             :     }
     984           0 :   cf->item.ttl = ttl;
     985             : 
     986             :   /* Now check for key-value pairs of the form NAME[=VALUE]. */
     987           0 :   cf->item.confirm = 0;
     988           0 :   while (*p)
     989             :     {
     990           0 :       for (; spacep (p) && *p != '\n'; p++)
     991             :         ;
     992           0 :       if (!*p || *p == '\n')
     993             :         break;
     994           0 :       n = strcspn (p, "= \t\n");
     995           0 :       if (p[n] == '=')
     996             :         {
     997           0 :           log_error ("%s:%d: assigning a value to a flag is not yet supported; "
     998             :                      "flag ignored\n", cf->fname, cf->lnr);
     999           0 :           p++;
    1000             :         }
    1001           0 :       else if (n == 7 && !memcmp (p, "confirm", 7))
    1002             :         {
    1003           0 :           cf->item.confirm = 1;
    1004             :         }
    1005             :       else
    1006           0 :         log_error ("%s:%d: invalid flag '%.*s'; ignored\n",
    1007             :                    cf->fname, cf->lnr, n, p);
    1008           0 :       p += n;
    1009             :     }
    1010             : 
    1011             :   /* log_debug ("%s:%d: grip=%s ttl=%d%s%s\n", */
    1012             :   /*            cf->fname, cf->lnr, */
    1013             :   /*            cf->item.hexgrip, cf->item.ttl, */
    1014             :   /*            cf->item.disabled? " disabled":"", */
    1015             :   /*            cf->item.confirm? " confirm":""); */
    1016             : 
    1017           0 :   cf->item.valid = 1;
    1018           0 :   return 0; /* Okay: valid entry found.  */
    1019             : }
    1020             : 
    1021             : 
    1022             : 
    1023             : /* Search the control file CF from the beginning until a matching
    1024             :    HEXGRIP is found; return success in this case and store true at
    1025             :    DISABLED if the found key has been disabled.  If R_TTL is not NULL
    1026             :    a specified TTL for that key is stored there.  If R_CONFIRM is not
    1027             :    NULL it is set to 1 if the key has the confirm flag set. */
    1028             : static gpg_error_t
    1029           0 : search_control_file (ssh_control_file_t cf, const char *hexgrip,
    1030             :                      int *r_disabled, int *r_ttl, int *r_confirm)
    1031             : {
    1032             :   gpg_error_t err;
    1033             : 
    1034           0 :   assert (strlen (hexgrip) == 40 );
    1035             : 
    1036           0 :   if (r_disabled)
    1037           0 :     *r_disabled = 0;
    1038           0 :   if (r_ttl)
    1039           0 :     *r_ttl = 0;
    1040           0 :   if (r_confirm)
    1041           0 :     *r_confirm = 0;
    1042             : 
    1043           0 :   rewind_control_file (cf);
    1044           0 :   while (!(err=read_control_file_item (cf)))
    1045             :     {
    1046           0 :       if (!cf->item.valid)
    1047           0 :         continue; /* Should not happen.  */
    1048           0 :       if (!strcmp (hexgrip, cf->item.hexgrip))
    1049           0 :         break;
    1050             :     }
    1051           0 :   if (!err)
    1052             :     {
    1053           0 :       if (r_disabled)
    1054           0 :         *r_disabled = cf->item.disabled;
    1055           0 :       if (r_ttl)
    1056           0 :         *r_ttl = cf->item.ttl;
    1057           0 :       if (r_confirm)
    1058           0 :         *r_confirm = cf->item.confirm;
    1059             :     }
    1060           0 :   return err;
    1061             : }
    1062             : 
    1063             : 
    1064             : 
    1065             : /* Add an entry to the control file to mark the key with the keygrip
    1066             :    HEXGRIP as usable for SSH; i.e. it will be returned when ssh asks
    1067             :    for it.  FMTFPR is the fingerprint string.  This function is in
    1068             :    general used to add a key received through the ssh-add function.
    1069             :    We can assume that the user wants to allow ssh using this key. */
    1070             : static gpg_error_t
    1071           0 : add_control_entry (ctrl_t ctrl, ssh_key_type_spec_t *spec,
    1072             :                    const char *hexgrip, const char *fmtfpr,
    1073             :                    int ttl, int confirm)
    1074             : {
    1075             :   gpg_error_t err;
    1076             :   ssh_control_file_t cf;
    1077             :   int disabled;
    1078             : 
    1079             :   (void)ctrl;
    1080             : 
    1081           0 :   err = open_control_file (&cf, 1);
    1082           0 :   if (err)
    1083           0 :     return err;
    1084             : 
    1085           0 :   err = search_control_file (cf, hexgrip, &disabled, NULL, NULL);
    1086           0 :   if (err && gpg_err_code(err) == GPG_ERR_EOF)
    1087             :     {
    1088             :       struct tm *tp;
    1089           0 :       time_t atime = time (NULL);
    1090             : 
    1091             :       /* Not yet in the file - add it. Because the file has been
    1092             :          opened in append mode, we simply need to write to it.  */
    1093           0 :       tp = localtime (&atime);
    1094           0 :       fprintf (cf->fp,
    1095             :                ("# %s key added on: %04d-%02d-%02d %02d:%02d:%02d\n"
    1096             :                 "# MD5 Fingerprint:  %s\n"
    1097             :                 "%s %d%s\n"),
    1098             :                spec->name,
    1099           0 :                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
    1100             :                tp->tm_hour, tp->tm_min, tp->tm_sec,
    1101             :                fmtfpr, hexgrip, ttl, confirm? " confirm":"");
    1102             : 
    1103             :     }
    1104           0 :   close_control_file (cf);
    1105           0 :   return 0;
    1106             : }
    1107             : 
    1108             : 
    1109             : /* Scan the sshcontrol file and return the TTL.  */
    1110             : static int
    1111           0 : ttl_from_sshcontrol (const char *hexgrip)
    1112             : {
    1113             :   ssh_control_file_t cf;
    1114             :   int disabled, ttl;
    1115             : 
    1116           0 :   if (!hexgrip || strlen (hexgrip) != 40)
    1117           0 :     return 0;  /* Wrong input: Use global default.  */
    1118             : 
    1119           0 :   if (open_control_file (&cf, 0))
    1120           0 :     return 0; /* Error: Use the global default TTL.  */
    1121             : 
    1122           0 :   if (search_control_file (cf, hexgrip, &disabled, &ttl, NULL)
    1123           0 :       || disabled)
    1124           0 :     ttl = 0;  /* Use the global default if not found or disabled.  */
    1125             : 
    1126           0 :   close_control_file (cf);
    1127             : 
    1128           0 :   return ttl;
    1129             : }
    1130             : 
    1131             : 
    1132             : /* Scan the sshcontrol file and return the confirm flag.  */
    1133             : static int
    1134           0 : confirm_flag_from_sshcontrol (const char *hexgrip)
    1135             : {
    1136             :   ssh_control_file_t cf;
    1137             :   int disabled, confirm;
    1138             : 
    1139           0 :   if (!hexgrip || strlen (hexgrip) != 40)
    1140           0 :     return 1;  /* Wrong input: Better ask for confirmation.  */
    1141             : 
    1142           0 :   if (open_control_file (&cf, 0))
    1143           0 :     return 1; /* Error: Better ask for confirmation.  */
    1144             : 
    1145           0 :   if (search_control_file (cf, hexgrip, &disabled, NULL, &confirm)
    1146           0 :       || disabled)
    1147           0 :     confirm = 0;  /* If not found or disabled, there is no reason to
    1148             :                      ask for confirmation.  */
    1149             : 
    1150           0 :   close_control_file (cf);
    1151             : 
    1152           0 :   return confirm;
    1153             : }
    1154             : 
    1155             : 
    1156             : 
    1157             : 
    1158             : /* Open the ssh control file for reading.  This is a public version of
    1159             :    open_control_file.  The caller must use ssh_close_control_file to
    1160             :    release the retruned handle.  */
    1161             : ssh_control_file_t
    1162           0 : ssh_open_control_file (void)
    1163             : {
    1164             :   ssh_control_file_t cf;
    1165             : 
    1166             :   /* Then look at all the registered and non-disabled keys. */
    1167           0 :   if (open_control_file (&cf, 0))
    1168           0 :     return NULL;
    1169           0 :   return cf;
    1170             : }
    1171             : 
    1172             : /* Close an ssh control file handle.  This is the public version of
    1173             :    close_control_file.  CF may be NULL.  */
    1174             : void
    1175           0 : ssh_close_control_file (ssh_control_file_t cf)
    1176             : {
    1177           0 :   close_control_file (cf);
    1178           0 : }
    1179             : 
    1180             : /* Read the next item from the ssh control file.  The function returns
    1181             :    0 if a item was read, GPG_ERR_EOF on eof or another error value.
    1182             :    R_HEXGRIP shall either be null or a BUFFER of at least 41 byte.
    1183             :    R_DISABLED, R_TTLm and R_CONFIRM return flags from the control
    1184             :    file; they are only set on success. */
    1185             : gpg_error_t
    1186           0 : ssh_read_control_file (ssh_control_file_t cf,
    1187             :                        char *r_hexgrip,
    1188             :                        int *r_disabled, int *r_ttl, int *r_confirm)
    1189             : {
    1190             :   gpg_error_t err;
    1191             : 
    1192             :   do
    1193           0 :     err = read_control_file_item (cf);
    1194           0 :   while (!err && !cf->item.valid);
    1195           0 :   if (!err)
    1196             :     {
    1197           0 :       if (r_hexgrip)
    1198           0 :         strcpy (r_hexgrip, cf->item.hexgrip);
    1199           0 :       if (r_disabled)
    1200           0 :         *r_disabled = cf->item.disabled;
    1201           0 :       if (r_ttl)
    1202           0 :         *r_ttl = cf->item.ttl;
    1203           0 :       if (r_confirm)
    1204           0 :         *r_confirm = cf->item.confirm;
    1205             :     }
    1206           0 :   return err;
    1207             : }
    1208             : 
    1209             : 
    1210             : /* Search for a key with HEXGRIP in sshcontrol and return all
    1211             :    info.  */
    1212             : gpg_error_t
    1213           0 : ssh_search_control_file (ssh_control_file_t cf,
    1214             :                          const char *hexgrip,
    1215             :                          int *r_disabled, int *r_ttl, int *r_confirm)
    1216             : {
    1217             :   gpg_error_t err;
    1218             :   int i;
    1219             :   const char *s;
    1220             :   char uphexgrip[41];
    1221             : 
    1222             :   /* We need to make sure that HEXGRIP is all uppercase.  The easiest
    1223             :      way to do this and also check its length is by copying to a
    1224             :      second buffer. */
    1225           0 :   for (i=0, s=hexgrip; i < 40 && *s; s++, i++)
    1226           0 :     uphexgrip[i] = *s >= 'a'? (*s & 0xdf): *s;
    1227           0 :   uphexgrip[i] = 0;
    1228           0 :   if (i != 40)
    1229           0 :     err = gpg_error (GPG_ERR_INV_LENGTH);
    1230             :   else
    1231           0 :     err = search_control_file (cf, uphexgrip, r_disabled, r_ttl, r_confirm);
    1232           0 :   if (gpg_err_code (err) == GPG_ERR_EOF)
    1233           0 :     err = gpg_error (GPG_ERR_NOT_FOUND);
    1234           0 :   return err;
    1235             : }
    1236             : 
    1237             : 
    1238             : 
    1239             : 
    1240             : /*
    1241             : 
    1242             :   MPI lists.
    1243             : 
    1244             :  */
    1245             : 
    1246             : /* Free the list of MPIs MPI_LIST.  */
    1247             : static void
    1248           0 : mpint_list_free (gcry_mpi_t *mpi_list)
    1249             : {
    1250           0 :   if (mpi_list)
    1251             :     {
    1252             :       unsigned int i;
    1253             : 
    1254           0 :       for (i = 0; mpi_list[i]; i++)
    1255           0 :         gcry_mpi_release (mpi_list[i]);
    1256           0 :       xfree (mpi_list);
    1257             :     }
    1258           0 : }
    1259             : 
    1260             : /* Receive key material MPIs from STREAM according to KEY_SPEC;
    1261             :    depending on SECRET expect a public key or secret key.  The newly
    1262             :    allocated list of MPIs is stored in MPI_LIST.  Returns usual error
    1263             :    code.  */
    1264             : static gpg_error_t
    1265           0 : ssh_receive_mpint_list (estream_t stream, int secret,
    1266             :                         ssh_key_type_spec_t key_spec, gcry_mpi_t **mpi_list)
    1267             : {
    1268             :   const char *elems_public;
    1269             :   unsigned int elems_n;
    1270             :   const char *elems;
    1271             :   int elem_is_secret;
    1272             :   gcry_mpi_t *mpis;
    1273             :   gpg_error_t err;
    1274             :   unsigned int i;
    1275             : 
    1276           0 :   mpis = NULL;
    1277           0 :   err = 0;
    1278             : 
    1279           0 :   if (secret)
    1280           0 :     elems = key_spec.elems_key_secret;
    1281             :   else
    1282           0 :     elems = key_spec.elems_key_public;
    1283           0 :   elems_n = strlen (elems);
    1284             : 
    1285           0 :   elems_public = key_spec.elems_key_public;
    1286             : 
    1287           0 :   mpis = xtrycalloc (elems_n + 1, sizeof *mpis );
    1288           0 :   if (!mpis)
    1289             :     {
    1290           0 :       err = gpg_error_from_syserror ();
    1291           0 :       goto out;
    1292             :     }
    1293             : 
    1294           0 :   elem_is_secret = 0;
    1295           0 :   for (i = 0; i < elems_n; i++)
    1296             :     {
    1297           0 :       if (secret)
    1298           0 :         elem_is_secret = ! strchr (elems_public, elems[i]);
    1299           0 :       err = stream_read_mpi (stream, elem_is_secret, &mpis[i]);
    1300           0 :       if (err)
    1301           0 :         break;
    1302             :     }
    1303           0 :   if (err)
    1304           0 :     goto out;
    1305             : 
    1306           0 :   *mpi_list = mpis;
    1307             : 
    1308             :  out:
    1309             : 
    1310           0 :   if (err)
    1311           0 :     mpint_list_free (mpis);
    1312             : 
    1313           0 :   return err;
    1314             : }
    1315             : 
    1316             : 
    1317             : 
    1318             : /* Key modifier function for RSA.  */
    1319             : static gpg_error_t
    1320           0 : ssh_key_modifier_rsa (const char *elems, gcry_mpi_t *mpis)
    1321             : {
    1322             :   gcry_mpi_t p;
    1323             :   gcry_mpi_t q;
    1324             :   gcry_mpi_t u;
    1325             : 
    1326           0 :   if (strcmp (elems, "nedupq"))
    1327             :     /* Modifying only necessary for secret keys.  */
    1328           0 :     goto out;
    1329             : 
    1330           0 :   u = mpis[3];
    1331           0 :   p = mpis[4];
    1332           0 :   q = mpis[5];
    1333             : 
    1334           0 :   if (gcry_mpi_cmp (p, q) > 0)
    1335             :     {
    1336             :       /* P shall be smaller then Q!  Swap primes.  iqmp becomes u.  */
    1337             :       gcry_mpi_t tmp;
    1338             : 
    1339           0 :       tmp = mpis[4];
    1340           0 :       mpis[4] = mpis[5];
    1341           0 :       mpis[5] = tmp;
    1342             :     }
    1343             :   else
    1344             :     /* U needs to be recomputed.  */
    1345           0 :     gcry_mpi_invm (u, p, q);
    1346             : 
    1347             :  out:
    1348             : 
    1349           0 :   return 0;
    1350             : }
    1351             : 
    1352             : /* Signature encoder function for RSA.  */
    1353             : static gpg_error_t
    1354           0 : ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec,
    1355             :                            estream_t signature_blob,
    1356             :                            gcry_sexp_t s_signature)
    1357             : {
    1358           0 :   gpg_error_t err = 0;
    1359           0 :   gcry_sexp_t valuelist = NULL;
    1360           0 :   gcry_sexp_t sublist = NULL;
    1361           0 :   gcry_mpi_t sig_value = NULL;
    1362           0 :   gcry_mpi_t *mpis = NULL;
    1363             :   const char *elems;
    1364             :   size_t elems_n;
    1365             :   int i;
    1366             : 
    1367             :   unsigned char *data;
    1368             :   size_t data_n;
    1369             :   gcry_mpi_t s;
    1370             : 
    1371           0 :   valuelist = gcry_sexp_nth (s_signature, 1);
    1372           0 :   if (!valuelist)
    1373             :     {
    1374           0 :       err = gpg_error (GPG_ERR_INV_SEXP);
    1375           0 :       goto out;
    1376             :     }
    1377             : 
    1378           0 :   elems = spec->elems_signature;
    1379           0 :   elems_n = strlen (elems);
    1380             : 
    1381           0 :   mpis = xtrycalloc (elems_n + 1, sizeof *mpis);
    1382           0 :   if (!mpis)
    1383             :     {
    1384           0 :       err = gpg_error_from_syserror ();
    1385           0 :       goto out;
    1386             :     }
    1387             : 
    1388           0 :   for (i = 0; i < elems_n; i++)
    1389             :     {
    1390           0 :       sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
    1391           0 :       if (!sublist)
    1392             :         {
    1393           0 :           err = gpg_error (GPG_ERR_INV_SEXP);
    1394           0 :           break;
    1395             :         }
    1396             : 
    1397           0 :       sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
    1398           0 :       if (!sig_value)
    1399             :         {
    1400           0 :           err = gpg_error (GPG_ERR_INTERNAL); /* FIXME?  */
    1401           0 :           break;
    1402             :         }
    1403           0 :       gcry_sexp_release (sublist);
    1404           0 :       sublist = NULL;
    1405             : 
    1406           0 :       mpis[i] = sig_value;
    1407             :     }
    1408           0 :   if (err)
    1409           0 :     goto out;
    1410             : 
    1411             :   /* RSA specific */
    1412           0 :   s = mpis[0];
    1413             : 
    1414           0 :   err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &data, &data_n, s);
    1415           0 :   if (err)
    1416           0 :     goto out;
    1417             : 
    1418           0 :   err = stream_write_string (signature_blob, data, data_n);
    1419           0 :   xfree (data);
    1420             : 
    1421             :  out:
    1422           0 :   gcry_sexp_release (valuelist);
    1423           0 :   gcry_sexp_release (sublist);
    1424           0 :   mpint_list_free (mpis);
    1425           0 :   return err;
    1426             : }
    1427             : 
    1428             : 
    1429             : /* Signature encoder function for DSA.  */
    1430             : static gpg_error_t
    1431           0 : ssh_signature_encoder_dsa (ssh_key_type_spec_t *spec,
    1432             :                            estream_t signature_blob,
    1433             :                            gcry_sexp_t s_signature)
    1434             : {
    1435           0 :   gpg_error_t err = 0;
    1436           0 :   gcry_sexp_t valuelist = NULL;
    1437           0 :   gcry_sexp_t sublist = NULL;
    1438           0 :   gcry_mpi_t sig_value = NULL;
    1439           0 :   gcry_mpi_t *mpis = NULL;
    1440             :   const char *elems;
    1441             :   size_t elems_n;
    1442             :   int i;
    1443             : 
    1444             :   unsigned char buffer[SSH_DSA_SIGNATURE_PADDING * SSH_DSA_SIGNATURE_ELEMS];
    1445           0 :   unsigned char *data = NULL;
    1446             :   size_t data_n;
    1447             : 
    1448           0 :   valuelist = gcry_sexp_nth (s_signature, 1);
    1449           0 :   if (!valuelist)
    1450             :     {
    1451           0 :       err = gpg_error (GPG_ERR_INV_SEXP);
    1452           0 :       goto out;
    1453             :     }
    1454             : 
    1455           0 :   elems = spec->elems_signature;
    1456           0 :   elems_n = strlen (elems);
    1457             : 
    1458           0 :   mpis = xtrycalloc (elems_n + 1, sizeof *mpis);
    1459           0 :   if (!mpis)
    1460             :     {
    1461           0 :       err = gpg_error_from_syserror ();
    1462           0 :       goto out;
    1463             :     }
    1464             : 
    1465           0 :   for (i = 0; i < elems_n; i++)
    1466             :     {
    1467           0 :       sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
    1468           0 :       if (!sublist)
    1469             :         {
    1470           0 :           err = gpg_error (GPG_ERR_INV_SEXP);
    1471           0 :           break;
    1472             :         }
    1473             : 
    1474           0 :       sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
    1475           0 :       if (!sig_value)
    1476             :         {
    1477           0 :           err = gpg_error (GPG_ERR_INTERNAL); /* FIXME?  */
    1478           0 :           break;
    1479             :         }
    1480           0 :       gcry_sexp_release (sublist);
    1481           0 :       sublist = NULL;
    1482             : 
    1483           0 :       mpis[i] = sig_value;
    1484             :     }
    1485           0 :   if (err)
    1486           0 :     goto out;
    1487             : 
    1488             :   /* DSA specific code.  */
    1489             : 
    1490             :   /* FIXME: Why this complicated code?  Why collecting boths mpis in a
    1491             :      buffer instead of writing them out one after the other?  */
    1492           0 :   for (i = 0; i < 2; i++)
    1493             :     {
    1494           0 :       err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &data, &data_n, mpis[i]);
    1495           0 :       if (err)
    1496           0 :         break;
    1497             : 
    1498           0 :       if (data_n > SSH_DSA_SIGNATURE_PADDING)
    1499             :         {
    1500           0 :           err = gpg_error (GPG_ERR_INTERNAL); /* FIXME?  */
    1501           0 :           break;
    1502             :         }
    1503             : 
    1504           0 :       memset (buffer + (i * SSH_DSA_SIGNATURE_PADDING), 0,
    1505             :               SSH_DSA_SIGNATURE_PADDING - data_n);
    1506           0 :       memcpy (buffer + (i * SSH_DSA_SIGNATURE_PADDING)
    1507           0 :               + (SSH_DSA_SIGNATURE_PADDING - data_n), data, data_n);
    1508             : 
    1509           0 :       xfree (data);
    1510           0 :       data = NULL;
    1511             :     }
    1512           0 :   if (err)
    1513           0 :     goto out;
    1514             : 
    1515           0 :   err = stream_write_string (signature_blob, buffer, sizeof (buffer));
    1516             : 
    1517             :  out:
    1518           0 :   xfree (data);
    1519           0 :   gcry_sexp_release (valuelist);
    1520           0 :   gcry_sexp_release (sublist);
    1521           0 :   mpint_list_free (mpis);
    1522           0 :   return err;
    1523             : }
    1524             : 
    1525             : 
    1526             : /* Signature encoder function for ECDSA.  */
    1527             : static gpg_error_t
    1528           0 : ssh_signature_encoder_ecdsa (ssh_key_type_spec_t *spec,
    1529             :                              estream_t stream, gcry_sexp_t s_signature)
    1530             : {
    1531           0 :   gpg_error_t err = 0;
    1532           0 :   gcry_sexp_t valuelist = NULL;
    1533           0 :   gcry_sexp_t sublist = NULL;
    1534           0 :   gcry_mpi_t sig_value = NULL;
    1535           0 :   gcry_mpi_t *mpis = NULL;
    1536             :   const char *elems;
    1537             :   size_t elems_n;
    1538             :   int i;
    1539             : 
    1540           0 :   unsigned char *data[2] = {NULL, NULL};
    1541             :   size_t data_n[2];
    1542             :   size_t innerlen;
    1543             : 
    1544           0 :   valuelist = gcry_sexp_nth (s_signature, 1);
    1545           0 :   if (!valuelist)
    1546             :     {
    1547           0 :       err = gpg_error (GPG_ERR_INV_SEXP);
    1548           0 :       goto out;
    1549             :     }
    1550             : 
    1551           0 :   elems = spec->elems_signature;
    1552           0 :   elems_n = strlen (elems);
    1553             : 
    1554           0 :   mpis = xtrycalloc (elems_n + 1, sizeof *mpis);
    1555           0 :   if (!mpis)
    1556             :     {
    1557           0 :       err = gpg_error_from_syserror ();
    1558           0 :       goto out;
    1559             :     }
    1560             : 
    1561           0 :   for (i = 0; i < elems_n; i++)
    1562             :     {
    1563           0 :       sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
    1564           0 :       if (!sublist)
    1565             :         {
    1566           0 :           err = gpg_error (GPG_ERR_INV_SEXP);
    1567           0 :           break;
    1568             :         }
    1569             : 
    1570           0 :       sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
    1571           0 :       if (!sig_value)
    1572             :         {
    1573           0 :           err = gpg_error (GPG_ERR_INTERNAL); /* FIXME?  */
    1574           0 :           break;
    1575             :         }
    1576           0 :       gcry_sexp_release (sublist);
    1577           0 :       sublist = NULL;
    1578             : 
    1579           0 :       mpis[i] = sig_value;
    1580             :     }
    1581           0 :   if (err)
    1582           0 :     goto out;
    1583             : 
    1584             :   /* ECDSA specific */
    1585             : 
    1586           0 :   innerlen = 0;
    1587           0 :   for (i = 0; i < DIM(data); i++)
    1588             :     {
    1589           0 :       err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &data[i], &data_n[i], mpis[i]);
    1590           0 :       if (err)
    1591           0 :         goto out;
    1592           0 :       innerlen += 4 + data_n[i];
    1593             :     }
    1594             : 
    1595           0 :   err = stream_write_uint32 (stream, innerlen);
    1596           0 :   if (err)
    1597           0 :     goto out;
    1598             : 
    1599           0 :   for (i = 0; i < DIM(data); i++)
    1600             :     {
    1601           0 :       err = stream_write_string (stream, data[i], data_n[i]);
    1602           0 :       if (err)
    1603           0 :         goto out;
    1604             :     }
    1605             : 
    1606             :  out:
    1607           0 :   for (i = 0; i < DIM(data); i++)
    1608           0 :     xfree (data[i]);
    1609           0 :   gcry_sexp_release (valuelist);
    1610           0 :   gcry_sexp_release (sublist);
    1611           0 :   mpint_list_free (mpis);
    1612           0 :   return err;
    1613             : }
    1614             : 
    1615             : 
    1616             : /* Signature encoder function for EdDSA.  */
    1617             : static gpg_error_t
    1618           0 : ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec,
    1619             :                              estream_t stream, gcry_sexp_t s_signature)
    1620             : {
    1621           0 :   gpg_error_t err = 0;
    1622           0 :   gcry_sexp_t valuelist = NULL;
    1623           0 :   gcry_sexp_t sublist = NULL;
    1624             :   const char *elems;
    1625             :   size_t elems_n;
    1626             :   int i;
    1627             : 
    1628           0 :   unsigned char *data[2] = {NULL, NULL};
    1629             :   size_t data_n[2];
    1630           0 :   size_t totallen = 0;
    1631             : 
    1632           0 :   valuelist = gcry_sexp_nth (s_signature, 1);
    1633           0 :   if (!valuelist)
    1634             :     {
    1635           0 :       err = gpg_error (GPG_ERR_INV_SEXP);
    1636           0 :       goto out;
    1637             :     }
    1638             : 
    1639           0 :   elems = spec->elems_signature;
    1640           0 :   elems_n = strlen (elems);
    1641             : 
    1642           0 :   if (elems_n != DIM(data))
    1643             :     {
    1644           0 :       err = gpg_error (GPG_ERR_INV_SEXP);
    1645           0 :       goto out;
    1646             :     }
    1647             : 
    1648           0 :   for (i = 0; i < DIM(data); i++)
    1649             :     {
    1650           0 :       sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
    1651           0 :       if (!sublist)
    1652             :         {
    1653           0 :           err = gpg_error (GPG_ERR_INV_SEXP);
    1654           0 :           break;
    1655             :         }
    1656             : 
    1657           0 :       data[i] = gcry_sexp_nth_buffer (sublist, 1, &data_n[i]);
    1658           0 :       if (!data[i])
    1659             :         {
    1660           0 :           err = gpg_error (GPG_ERR_INTERNAL); /* FIXME?  */
    1661           0 :           break;
    1662             :         }
    1663           0 :       totallen += data_n[i];
    1664           0 :       gcry_sexp_release (sublist);
    1665           0 :       sublist = NULL;
    1666             :     }
    1667           0 :   if (err)
    1668           0 :     goto out;
    1669             : 
    1670           0 :   err = stream_write_uint32 (stream, totallen);
    1671           0 :   if (err)
    1672           0 :     goto out;
    1673             : 
    1674           0 :   for (i = 0; i < DIM(data); i++)
    1675             :     {
    1676           0 :       err = stream_write_data (stream, data[i], data_n[i]);
    1677           0 :       if (err)
    1678           0 :         goto out;
    1679             :     }
    1680             : 
    1681             :  out:
    1682           0 :   for (i = 0; i < DIM(data); i++)
    1683           0 :     xfree (data[i]);
    1684           0 :   gcry_sexp_release (valuelist);
    1685           0 :   gcry_sexp_release (sublist);
    1686           0 :   return err;
    1687             : }
    1688             : 
    1689             : 
    1690             : /*
    1691             :    S-Expressions.
    1692             :  */
    1693             : 
    1694             : 
    1695             : /* This function constructs a new S-Expression for the key identified
    1696             :    by the KEY_SPEC, SECRET, CURVE_NAME, MPIS, and COMMENT, which is to
    1697             :    be stored at R_SEXP.  Returns an error code.  */
    1698             : static gpg_error_t
    1699           0 : sexp_key_construct (gcry_sexp_t *r_sexp,
    1700             :                     ssh_key_type_spec_t key_spec, int secret,
    1701             :                     const char *curve_name, gcry_mpi_t *mpis,
    1702             :                     const char *comment)
    1703             : {
    1704             :   gpg_error_t err;
    1705           0 :   gcry_sexp_t sexp_new = NULL;
    1706           0 :   void *formatbuf = NULL;
    1707           0 :   void **arg_list = NULL;
    1708           0 :   estream_t format = NULL;
    1709             : 
    1710             : 
    1711           0 :   if ((key_spec.flags & SPEC_FLAG_IS_EdDSA))
    1712             :     {
    1713             :       /* It is much easier and more readable to use a separate code
    1714             :          path for EdDSA.  */
    1715           0 :       if (!curve_name)
    1716           0 :         err = gpg_error (GPG_ERR_INV_CURVE);
    1717           0 :       else if (!mpis[0] || !gcry_mpi_get_flag (mpis[0], GCRYMPI_FLAG_OPAQUE))
    1718           0 :         err = gpg_error (GPG_ERR_BAD_PUBKEY);
    1719           0 :       else if (secret
    1720           0 :                && (!mpis[1]
    1721           0 :                    || !gcry_mpi_get_flag (mpis[1], GCRYMPI_FLAG_OPAQUE)))
    1722           0 :         err = gpg_error (GPG_ERR_BAD_SECKEY);
    1723           0 :       else if (secret)
    1724           0 :         err = gcry_sexp_build (&sexp_new, NULL,
    1725             :                                "(private-key(ecc(curve %s)"
    1726             :                                "(flags eddsa)(q %m)(d %m))"
    1727             :                                "(comment%s))",
    1728             :                                curve_name,
    1729           0 :                                mpis[0], mpis[1],
    1730           0 :                                comment? comment:"");
    1731             :       else
    1732           0 :         err = gcry_sexp_build (&sexp_new, NULL,
    1733             :                                "(public-key(ecc(curve %s)"
    1734             :                                "(flags eddsa)(q %m))"
    1735             :                                "(comment%s))",
    1736             :                                curve_name,
    1737             :                                mpis[0],
    1738           0 :                                comment? comment:"");
    1739             :     }
    1740             :   else
    1741             :     {
    1742           0 :       const char *key_identifier[] = { "public-key", "private-key" };
    1743             :       int arg_idx;
    1744             :       const char *elems;
    1745             :       size_t elems_n;
    1746             :       unsigned int i, j;
    1747             : 
    1748           0 :       if (secret)
    1749           0 :         elems = key_spec.elems_sexp_order;
    1750             :       else
    1751           0 :         elems = key_spec.elems_key_public;
    1752           0 :       elems_n = strlen (elems);
    1753             : 
    1754           0 :       format = es_fopenmem (0, "a+b");
    1755           0 :       if (!format)
    1756             :         {
    1757           0 :           err = gpg_error_from_syserror ();
    1758           0 :           goto out;
    1759             :         }
    1760             : 
    1761             :       /* Key identifier, algorithm identifier, mpis, comment, and a NULL
    1762             :          as a safeguard. */
    1763           0 :       arg_list = xtrymalloc (sizeof (*arg_list) * (2 + 1 + elems_n + 1 + 1));
    1764           0 :       if (!arg_list)
    1765             :         {
    1766           0 :           err = gpg_error_from_syserror ();
    1767           0 :           goto out;
    1768             :         }
    1769           0 :       arg_idx = 0;
    1770             : 
    1771           0 :       es_fputs ("(%s(%s", format);
    1772           0 :       arg_list[arg_idx++] = &key_identifier[secret];
    1773           0 :       arg_list[arg_idx++] = &key_spec.identifier;
    1774           0 :       if (curve_name)
    1775             :         {
    1776           0 :           es_fputs ("(curve%s)", format);
    1777           0 :           arg_list[arg_idx++] = &curve_name;
    1778             :         }
    1779             : 
    1780           0 :       for (i = 0; i < elems_n; i++)
    1781             :         {
    1782           0 :           es_fprintf (format, "(%c%%m)", elems[i]);
    1783           0 :           if (secret)
    1784             :             {
    1785           0 :               for (j = 0; j < elems_n; j++)
    1786           0 :                 if (key_spec.elems_key_secret[j] == elems[i])
    1787           0 :                   break;
    1788             :             }
    1789             :           else
    1790           0 :             j = i;
    1791           0 :           arg_list[arg_idx++] = &mpis[j];
    1792             :         }
    1793           0 :       es_fputs (")(comment%s))", format);
    1794           0 :       arg_list[arg_idx++] = &comment;
    1795           0 :       arg_list[arg_idx] = NULL;
    1796             : 
    1797           0 :       es_putc (0, format);
    1798           0 :       if (es_ferror (format))
    1799             :         {
    1800           0 :           err = gpg_error_from_syserror ();
    1801           0 :           goto out;
    1802             :         }
    1803           0 :       if (es_fclose_snatch (format, &formatbuf, NULL))
    1804             :         {
    1805           0 :           err = gpg_error_from_syserror ();
    1806           0 :           goto out;
    1807             :         }
    1808           0 :       format = NULL;
    1809             : 
    1810           0 :       err = gcry_sexp_build_array (&sexp_new, NULL, formatbuf, arg_list);
    1811             :     }
    1812             : 
    1813           0 :   if (!err)
    1814           0 :     *r_sexp = sexp_new;
    1815             : 
    1816             :  out:
    1817           0 :   es_fclose (format);
    1818           0 :   xfree (arg_list);
    1819           0 :   xfree (formatbuf);
    1820             : 
    1821           0 :   return err;
    1822             : }
    1823             : 
    1824             : 
    1825             : /* This function extracts the key from the s-expression SEXP according
    1826             :    to KEY_SPEC and stores it in ssh format at (R_BLOB, R_BLOBLEN).  If
    1827             :    WITH_SECRET is true, the secret key parts are also extracted if
    1828             :    possible.  Returns 0 on success or an error code.  Note that data
    1829             :    stored at R_BLOB must be freed using es_free!  */
    1830             : static gpg_error_t
    1831           0 : ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
    1832             :                  ssh_key_type_spec_t key_spec,
    1833             :                  void **r_blob, size_t *r_blob_size)
    1834             : {
    1835           0 :   gpg_error_t err = 0;
    1836           0 :   gcry_sexp_t value_list = NULL;
    1837           0 :   gcry_sexp_t value_pair = NULL;
    1838           0 :   char *curve_name = NULL;
    1839           0 :   estream_t stream = NULL;
    1840           0 :   void *blob = NULL;
    1841             :   size_t blob_size;
    1842             :   const char *elems, *p_elems;
    1843             :   const char *data;
    1844             :   size_t datalen;
    1845             : 
    1846           0 :   *r_blob = NULL;
    1847           0 :   *r_blob_size = 0;
    1848             : 
    1849           0 :   stream = es_fopenmem (0, "r+b");
    1850           0 :   if (!stream)
    1851             :     {
    1852           0 :       err = gpg_error_from_syserror ();
    1853           0 :       goto out;
    1854             :     }
    1855             : 
    1856             :   /* Get the type of the key extpression.  */
    1857           0 :   data = gcry_sexp_nth_data (sexp, 0, &datalen);
    1858           0 :   if (!data)
    1859             :     {
    1860           0 :       err = gpg_error (GPG_ERR_INV_SEXP);
    1861           0 :       goto out;
    1862             :     }
    1863             : 
    1864           0 :   if ((datalen == 10 && !strncmp (data, "public-key", 10))
    1865           0 :       || (datalen == 21 && !strncmp (data, "protected-private-key", 21))
    1866           0 :       || (datalen == 20 && !strncmp (data, "shadowed-private-key", 20)))
    1867           0 :     elems = key_spec.elems_key_public;
    1868           0 :   else if (datalen == 11 && !strncmp (data, "private-key", 11))
    1869           0 :     elems = with_secret? key_spec.elems_key_secret : key_spec.elems_key_public;
    1870             :   else
    1871             :     {
    1872           0 :       err = gpg_error (GPG_ERR_INV_SEXP);
    1873           0 :       goto out;
    1874             :     }
    1875             : 
    1876             :   /* Get the algorithm identifier.  */
    1877           0 :   value_list = gcry_sexp_find_token (sexp, key_spec.identifier, 0);
    1878           0 :   if (!value_list)
    1879             :     {
    1880           0 :       err = gpg_error (GPG_ERR_INV_SEXP);
    1881           0 :       goto out;
    1882             :     }
    1883             : 
    1884             :   /* Write the ssh algorithm identifier.  */
    1885           0 :   if ((key_spec.flags & SPEC_FLAG_IS_ECDSA))
    1886             :     {
    1887             :       /* Parse the "curve" parameter.  We currently expect the curve
    1888             :          name for ECC and not the parameters of the curve.  This can
    1889             :          easily be changed but then we need to find the curve name
    1890             :          from the parameters using gcry_pk_get_curve.  */
    1891             :       const char *mapped;
    1892             :       const char *sshname;
    1893             : 
    1894           0 :       gcry_sexp_release (value_pair);
    1895           0 :       value_pair = gcry_sexp_find_token (value_list, "curve", 5);
    1896           0 :       if (!value_pair)
    1897             :         {
    1898           0 :           err = gpg_error (GPG_ERR_INV_CURVE);
    1899           0 :           goto out;
    1900             :         }
    1901           0 :       curve_name = gcry_sexp_nth_string (value_pair, 1);
    1902           0 :       if (!curve_name)
    1903             :         {
    1904           0 :           err = gpg_error (GPG_ERR_INV_CURVE); /* (Or out of core.)  */
    1905           0 :           goto out;
    1906             :         }
    1907             : 
    1908             :       /* Fixme: The mapping should be done by using gcry_pk_get_curve
    1909             :          et al to iterate over all name aliases.  */
    1910           0 :       if (!strcmp (curve_name, "NIST P-256"))
    1911           0 :         mapped = "nistp256";
    1912           0 :       else if (!strcmp (curve_name, "NIST P-384"))
    1913           0 :         mapped = "nistp384";
    1914           0 :       else if (!strcmp (curve_name, "NIST P-521"))
    1915           0 :         mapped = "nistp521";
    1916             :       else
    1917           0 :         mapped = NULL;
    1918           0 :       if (mapped)
    1919             :         {
    1920           0 :           xfree (curve_name);
    1921           0 :           curve_name = xtrystrdup (mapped);
    1922           0 :           if (!curve_name)
    1923             :             {
    1924           0 :               err = gpg_error_from_syserror ();
    1925           0 :               goto out;
    1926             :             }
    1927             :         }
    1928             : 
    1929           0 :       sshname = ssh_identifier_from_curve_name (curve_name);
    1930           0 :       if (!sshname)
    1931             :         {
    1932           0 :           err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
    1933           0 :           goto out;
    1934             :         }
    1935           0 :       err = stream_write_cstring (stream, sshname);
    1936           0 :       if (err)
    1937           0 :         goto out;
    1938           0 :       err = stream_write_cstring (stream, curve_name);
    1939           0 :       if (err)
    1940           0 :         goto out;
    1941             :     }
    1942             :   else
    1943             :     {
    1944             :       /* Note: This is also used for EdDSA.  */
    1945           0 :       err = stream_write_cstring (stream, key_spec.ssh_identifier);
    1946           0 :       if (err)
    1947           0 :         goto out;
    1948             :     }
    1949             : 
    1950             :   /* Write the parameters.  */
    1951           0 :   for (p_elems = elems; *p_elems; p_elems++)
    1952             :     {
    1953           0 :       gcry_sexp_release (value_pair);
    1954           0 :       value_pair = gcry_sexp_find_token (value_list, p_elems, 1);
    1955           0 :       if (!value_pair)
    1956             :         {
    1957           0 :           err = gpg_error (GPG_ERR_INV_SEXP);
    1958           0 :           goto out;
    1959             :         }
    1960           0 :       if ((key_spec.flags & SPEC_FLAG_IS_EdDSA))
    1961             :         {
    1962             : 
    1963           0 :           data = gcry_sexp_nth_data (value_pair, 1, &datalen);
    1964           0 :           if (!data)
    1965             :             {
    1966           0 :               err = gpg_error (GPG_ERR_INV_SEXP);
    1967           0 :               goto out;
    1968             :             }
    1969           0 :           if (*p_elems == 'q' && datalen)
    1970             :             { /* Remove the prefix 0x40.  */
    1971           0 :               data++;
    1972           0 :               datalen--;
    1973             :             }
    1974           0 :           err = stream_write_string (stream, data, datalen);
    1975           0 :           if (err)
    1976           0 :             goto out;
    1977             :         }
    1978             :       else
    1979             :         {
    1980             :           gcry_mpi_t mpi;
    1981             : 
    1982             :           /* Note that we need to use STD format; i.e. prepend a 0x00
    1983             :              to indicate a positive number if the high bit is set. */
    1984           0 :           mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_STD);
    1985           0 :           if (!mpi)
    1986             :             {
    1987           0 :               err = gpg_error (GPG_ERR_INV_SEXP);
    1988           0 :               goto out;
    1989             :             }
    1990           0 :           err = stream_write_mpi (stream, mpi);
    1991           0 :           gcry_mpi_release (mpi);
    1992           0 :           if (err)
    1993           0 :             goto out;
    1994             :         }
    1995             :     }
    1996             : 
    1997           0 :   if (es_fclose_snatch (stream, &blob, &blob_size))
    1998             :     {
    1999           0 :       err = gpg_error_from_syserror ();
    2000           0 :       goto out;
    2001             :     }
    2002           0 :   stream = NULL;
    2003             : 
    2004           0 :   *r_blob = blob;
    2005           0 :   blob = NULL;
    2006           0 :   *r_blob_size = blob_size;
    2007             : 
    2008             :  out:
    2009           0 :   gcry_sexp_release (value_list);
    2010           0 :   gcry_sexp_release (value_pair);
    2011           0 :   xfree (curve_name);
    2012           0 :   es_fclose (stream);
    2013           0 :   es_free (blob);
    2014             : 
    2015           0 :   return err;
    2016             : }
    2017             : 
    2018             : /* Extract the car from SEXP, and create a newly created C-string
    2019             :    which is to be stored in IDENTIFIER.  */
    2020             : static gpg_error_t
    2021           0 : sexp_extract_identifier (gcry_sexp_t sexp, char **identifier)
    2022             : {
    2023             :   char *identifier_new;
    2024             :   gcry_sexp_t sublist;
    2025             :   const char *data;
    2026             :   size_t data_n;
    2027             :   gpg_error_t err;
    2028             : 
    2029           0 :   identifier_new = NULL;
    2030           0 :   err = 0;
    2031             : 
    2032           0 :   sublist = gcry_sexp_nth (sexp, 1);
    2033           0 :   if (! sublist)
    2034             :     {
    2035           0 :       err = gpg_error (GPG_ERR_INV_SEXP);
    2036           0 :       goto out;
    2037             :     }
    2038             : 
    2039           0 :   data = gcry_sexp_nth_data (sublist, 0, &data_n);
    2040           0 :   if (! data)
    2041             :     {
    2042           0 :       err = gpg_error (GPG_ERR_INV_SEXP);
    2043           0 :       goto out;
    2044             :     }
    2045             : 
    2046           0 :   identifier_new = make_cstring (data, data_n);
    2047           0 :   if (! identifier_new)
    2048             :     {
    2049           0 :       err = gpg_err_code_from_errno (errno);
    2050           0 :       goto out;
    2051             :     }
    2052             : 
    2053           0 :   *identifier = identifier_new;
    2054             : 
    2055             :  out:
    2056             : 
    2057           0 :   gcry_sexp_release (sublist);
    2058             : 
    2059           0 :   return err;
    2060             : }
    2061             : 
    2062             : 
    2063             : 
    2064             : /*
    2065             : 
    2066             :   Key I/O.
    2067             : 
    2068             : */
    2069             : 
    2070             : /* Search for a key specification entry.  If SSH_NAME is not NULL,
    2071             :    search for an entry whose "ssh_name" is equal to SSH_NAME;
    2072             :    otherwise, search for an entry whose "name" is equal to NAME.
    2073             :    Store found entry in SPEC on success, return error otherwise.  */
    2074             : static gpg_error_t
    2075           0 : ssh_key_type_lookup (const char *ssh_name, const char *name,
    2076             :                      ssh_key_type_spec_t *spec)
    2077             : {
    2078             :   gpg_error_t err;
    2079             :   unsigned int i;
    2080             : 
    2081             :   /* FIXME: Although this sees to work, it not be correct if the
    2082             :      lookup is done via name which might be "ecc" but actually it need
    2083             :      to check the flags to see whether it is eddsa or ecdsa.  Maybe
    2084             :      the entire parameter controlled logic is too complicated and we
    2085             :      would do better by just switching on the ssh_name.  */
    2086           0 :   for (i = 0; i < DIM (ssh_key_types); i++)
    2087           0 :     if ((ssh_name && (! strcmp (ssh_name, ssh_key_types[i].ssh_identifier)))
    2088           0 :         || (name && (! strcmp (name, ssh_key_types[i].identifier))))
    2089             :       break;
    2090             : 
    2091           0 :   if (i == DIM (ssh_key_types))
    2092           0 :     err = gpg_error (GPG_ERR_NOT_FOUND);
    2093             :   else
    2094             :     {
    2095           0 :       *spec = ssh_key_types[i];
    2096           0 :       err = 0;
    2097             :     }
    2098             : 
    2099           0 :   return err;
    2100             : }
    2101             : 
    2102             : 
    2103             : /* Receive a key from STREAM, according to the key specification given
    2104             :    as KEY_SPEC.  Depending on SECRET, receive a secret or a public
    2105             :    key.  If READ_COMMENT is true, receive a comment string as well.
    2106             :    Constructs a new S-Expression from received data and stores it in
    2107             :    KEY_NEW.  Returns zero on success or an error code.  */
    2108             : static gpg_error_t
    2109           0 : ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret,
    2110             :                  int read_comment, ssh_key_type_spec_t *key_spec)
    2111             : {
    2112             :   gpg_error_t err;
    2113           0 :   char *key_type = NULL;
    2114           0 :   char *comment = NULL;
    2115           0 :   gcry_sexp_t key = NULL;
    2116             :   ssh_key_type_spec_t spec;
    2117           0 :   gcry_mpi_t *mpi_list = NULL;
    2118             :   const char *elems;
    2119           0 :   char *curve_name = NULL;
    2120             : 
    2121             : 
    2122           0 :   err = stream_read_cstring (stream, &key_type);
    2123           0 :   if (err)
    2124           0 :     goto out;
    2125             : 
    2126           0 :   err = ssh_key_type_lookup (key_type, NULL, &spec);
    2127           0 :   if (err)
    2128           0 :     goto out;
    2129             : 
    2130           0 :   if ((spec.flags & SPEC_FLAG_IS_EdDSA))
    2131             :     {
    2132             :       /* The format of an EdDSA key is:
    2133             :        *   string       key_type ("ssh-ed25519")
    2134             :        *   string       public_key
    2135             :        *   string       private_key
    2136             :        *
    2137             :        * Note that the private key is the concatenation of the private
    2138             :        * key with the public key.  Thus theres are 64 bytes; however
    2139             :        * we only want the real 32 byte private key - Libgcrypt expects
    2140             :        * this.
    2141             :        */
    2142           0 :       mpi_list = xtrycalloc (3, sizeof *mpi_list);
    2143           0 :       if (!mpi_list)
    2144             :         {
    2145           0 :           err = gpg_error_from_syserror ();
    2146           0 :           goto out;
    2147             :         }
    2148             : 
    2149           0 :       err = stream_read_blob (stream, 0, &mpi_list[0]);
    2150           0 :       if (err)
    2151           0 :         goto out;
    2152           0 :       if (secret)
    2153             :         {
    2154           0 :           u32 len = 0;
    2155             :           unsigned char *buffer;
    2156             : 
    2157             :           /* Read string length.  */
    2158           0 :           err = stream_read_uint32 (stream, &len);
    2159           0 :           if (err)
    2160           0 :             goto out;
    2161           0 :           if (len != 32 && len != 64)
    2162             :             {
    2163           0 :               err = gpg_error (GPG_ERR_BAD_SECKEY);
    2164           0 :               goto out;
    2165             :             }
    2166           0 :           buffer = xtrymalloc_secure (32);
    2167           0 :           if (!buffer)
    2168             :             {
    2169           0 :               err = gpg_error_from_syserror ();
    2170           0 :               goto out;
    2171             :             }
    2172           0 :           err = stream_read_data (stream, buffer, 32);
    2173           0 :           if (err)
    2174             :             {
    2175           0 :               xfree (buffer);
    2176           0 :               goto out;
    2177             :             }
    2178           0 :           mpi_list[1] = gcry_mpi_set_opaque (NULL, buffer, 8*32);
    2179           0 :           buffer = NULL;
    2180           0 :           if (len == 64)
    2181             :             {
    2182           0 :               err = stream_read_skip (stream, 32);
    2183           0 :               if (err)
    2184           0 :                 goto out;
    2185             :             }
    2186             :         }
    2187             :     }
    2188           0 :   else if ((spec.flags & SPEC_FLAG_IS_ECDSA))
    2189             :     {
    2190             :       /* The format of an ECDSA key is:
    2191             :        *   string       key_type ("ecdsa-sha2-nistp256" |
    2192             :        *                          "ecdsa-sha2-nistp384" |
    2193             :        *                          "ecdsa-sha2-nistp521" )
    2194             :        *   string       ecdsa_curve_name
    2195             :        *   string       ecdsa_public_key
    2196             :        *   mpint        ecdsa_private
    2197             :        *
    2198             :        * Note that we use the mpint reader instead of the string
    2199             :        * reader for ecsa_public_key.
    2200             :        */
    2201             :       unsigned char *buffer;
    2202             :       const char *mapped;
    2203             : 
    2204           0 :       err = stream_read_string (stream, 0, &buffer, NULL);
    2205           0 :       if (err)
    2206           0 :         goto out;
    2207           0 :       curve_name = buffer;
    2208             :       /* Fixme: Check that curve_name matches the keytype.  */
    2209             :       /* Because Libgcrypt < 1.6 has no support for the "nistpNNN"
    2210             :          curve names, we need to translate them here to Libgcrypt's
    2211             :          native names.  */
    2212           0 :       if (!strcmp (curve_name, "nistp256"))
    2213           0 :         mapped = "NIST P-256";
    2214           0 :       else if (!strcmp (curve_name, "nistp384"))
    2215           0 :         mapped = "NIST P-384";
    2216           0 :       else if (!strcmp (curve_name, "nistp521"))
    2217           0 :         mapped = "NIST P-521";
    2218             :       else
    2219           0 :         mapped = NULL;
    2220           0 :       if (mapped)
    2221             :         {
    2222           0 :           xfree (curve_name);
    2223           0 :           curve_name = xtrystrdup (mapped);
    2224           0 :           if (!curve_name)
    2225             :             {
    2226           0 :               err = gpg_error_from_syserror ();
    2227           0 :               goto out;
    2228             :             }
    2229             :         }
    2230             : 
    2231           0 :       err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list);
    2232           0 :       if (err)
    2233           0 :         goto out;
    2234             :     }
    2235             :   else
    2236             :     {
    2237           0 :       err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list);
    2238           0 :       if (err)
    2239           0 :         goto out;
    2240             :     }
    2241             : 
    2242           0 :   if (read_comment)
    2243             :     {
    2244           0 :       err = stream_read_cstring (stream, &comment);
    2245           0 :       if (err)
    2246           0 :         goto out;
    2247             :     }
    2248             : 
    2249           0 :   if (secret)
    2250           0 :     elems = spec.elems_key_secret;
    2251             :   else
    2252           0 :     elems = spec.elems_key_public;
    2253             : 
    2254           0 :   if (spec.key_modifier)
    2255             :     {
    2256           0 :       err = (*spec.key_modifier) (elems, mpi_list);
    2257           0 :       if (err)
    2258           0 :         goto out;
    2259             :     }
    2260             : 
    2261           0 :   if ((spec.flags & SPEC_FLAG_IS_EdDSA))
    2262             :     {
    2263           0 :       if (secret)
    2264             :         {
    2265           0 :           err = gcry_sexp_build (&key, NULL,
    2266             :                                  "(private-key(ecc(curve \"Ed25519\")"
    2267             :                                  "(flags eddsa)(q %m)(d %m))"
    2268             :                                  "(comment%s))",
    2269           0 :                                  mpi_list[0], mpi_list[1],
    2270           0 :                                  comment? comment:"");
    2271             :         }
    2272             :       else
    2273             :         {
    2274           0 :           err = gcry_sexp_build (&key, NULL,
    2275             :                                  "(public-key(ecc(curve \"Ed25519\")"
    2276             :                                  "(flags eddsa)(q %m))"
    2277             :                                  "(comment%s))",
    2278             :                                  mpi_list[0],
    2279           0 :                                  comment? comment:"");
    2280             :         }
    2281             :     }
    2282             :   else
    2283             :     {
    2284           0 :       err = sexp_key_construct (&key, spec, secret, curve_name, mpi_list,
    2285           0 :                                 comment? comment:"");
    2286           0 :       if (err)
    2287           0 :         goto out;
    2288             :     }
    2289             : 
    2290           0 :   if (key_spec)
    2291           0 :     *key_spec = spec;
    2292           0 :   *key_new = key;
    2293             : 
    2294             :  out:
    2295           0 :   mpint_list_free (mpi_list);
    2296           0 :   xfree (curve_name);
    2297           0 :   xfree (key_type);
    2298           0 :   xfree (comment);
    2299             : 
    2300           0 :   return err;
    2301             : }
    2302             : 
    2303             : 
    2304             : /* Write the public key from KEY to STREAM in SSH key format.  If
    2305             :    OVERRIDE_COMMENT is not NULL, it will be used instead of the
    2306             :    comment stored in the key.  */
    2307             : static gpg_error_t
    2308           0 : ssh_send_key_public (estream_t stream, gcry_sexp_t key,
    2309             :                      const char *override_comment)
    2310             : {
    2311             :   ssh_key_type_spec_t spec;
    2312           0 :   char *key_type = NULL;
    2313           0 :   char *comment = NULL;
    2314           0 :   void *blob = NULL;
    2315             :   size_t bloblen;
    2316             :   gpg_error_t err;
    2317             : 
    2318           0 :   err = sexp_extract_identifier (key, &key_type);
    2319           0 :   if (err)
    2320           0 :     goto out;
    2321             : 
    2322           0 :   err = ssh_key_type_lookup (NULL, key_type, &spec);
    2323           0 :   if (err)
    2324           0 :     goto out;
    2325             : 
    2326           0 :   err = ssh_key_to_blob (key, 0, spec, &blob, &bloblen);
    2327           0 :   if (err)
    2328           0 :     goto out;
    2329             : 
    2330           0 :   err = stream_write_string (stream, blob, bloblen);
    2331           0 :   if (err)
    2332           0 :     goto out;
    2333             : 
    2334           0 :   if (override_comment)
    2335           0 :     err = stream_write_cstring (stream, override_comment);
    2336             :   else
    2337             :     {
    2338           0 :       err = ssh_key_extract_comment (key, &comment);
    2339           0 :       if (err)
    2340           0 :         err = stream_write_cstring (stream, "(none)");
    2341             :       else
    2342           0 :         err = stream_write_cstring (stream, comment);
    2343             :     }
    2344           0 :   if (err)
    2345           0 :     goto out;
    2346             : 
    2347             :  out:
    2348           0 :   xfree (key_type);
    2349           0 :   xfree (comment);
    2350           0 :   es_free (blob);
    2351             : 
    2352           0 :   return err;
    2353             : }
    2354             : 
    2355             : 
    2356             : /* Read a public key out of BLOB/BLOB_SIZE according to the key
    2357             :    specification given as KEY_SPEC, storing the new key in KEY_PUBLIC.
    2358             :    Returns zero on success or an error code.  */
    2359             : static gpg_error_t
    2360           0 : ssh_read_key_public_from_blob (unsigned char *blob, size_t blob_size,
    2361             :                                gcry_sexp_t *key_public,
    2362             :                                ssh_key_type_spec_t *key_spec)
    2363             : {
    2364             :   gpg_error_t err;
    2365             :   estream_t blob_stream;
    2366             : 
    2367           0 :   blob_stream = es_fopenmem (0, "r+b");
    2368           0 :   if (!blob_stream)
    2369             :     {
    2370           0 :       err = gpg_error_from_syserror ();
    2371           0 :       goto out;
    2372             :     }
    2373             : 
    2374           0 :   err = stream_write_data (blob_stream, blob, blob_size);
    2375           0 :   if (err)
    2376           0 :     goto out;
    2377             : 
    2378           0 :   err = es_fseek (blob_stream, 0, SEEK_SET);
    2379           0 :   if (err)
    2380           0 :     goto out;
    2381             : 
    2382           0 :   err = ssh_receive_key (blob_stream, key_public, 0, 0, key_spec);
    2383             : 
    2384             :  out:
    2385           0 :   es_fclose (blob_stream);
    2386           0 :   return err;
    2387             : }
    2388             : 
    2389             : 
    2390             : 
    2391             : /* This function calculates the key grip for the key contained in the
    2392             :    S-Expression KEY and writes it to BUFFER, which must be large
    2393             :    enough to hold it.  Returns usual error code.  */
    2394             : static gpg_error_t
    2395           0 : ssh_key_grip (gcry_sexp_t key, unsigned char *buffer)
    2396             : {
    2397           0 :   if (!gcry_pk_get_keygrip (key, buffer))
    2398             :     {
    2399           0 :       gpg_error_t err = gcry_pk_testkey (key);
    2400           0 :       return err? err : gpg_error (GPG_ERR_INTERNAL);
    2401             :     }
    2402             : 
    2403           0 :   return 0;
    2404             : }
    2405             : 
    2406             : 
    2407             : /* Check whether a smartcard is available and whether it has a usable
    2408             :    key.  Store a copy of that key at R_PK and return 0.  If no key is
    2409             :    available store NULL at R_PK and return an error code.  If CARDSN
    2410             :    is not NULL, a string with the serial number of the card will be
    2411             :    a malloced and stored there. */
    2412             : static gpg_error_t
    2413           0 : card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn)
    2414             : {
    2415             :   gpg_error_t err;
    2416             :   char *authkeyid;
    2417           0 :   char *serialno = NULL;
    2418             :   unsigned char *pkbuf;
    2419             :   size_t pkbuflen;
    2420             :   gcry_sexp_t s_pk;
    2421             :   unsigned char grip[20];
    2422             : 
    2423           0 :   *r_pk = NULL;
    2424           0 :   if (cardsn)
    2425           0 :     *cardsn = NULL;
    2426             : 
    2427             :   /* First see whether a card is available and whether the application
    2428             :      is supported.  */
    2429           0 :   err = agent_card_getattr (ctrl, "$AUTHKEYID", &authkeyid);
    2430           0 :   if ( gpg_err_code (err) == GPG_ERR_CARD_REMOVED )
    2431             :     {
    2432             :       /* Ask for the serial number to reset the card.  */
    2433           0 :       err = agent_card_serialno (ctrl, &serialno);
    2434           0 :       if (err)
    2435             :         {
    2436           0 :           if (opt.verbose)
    2437           0 :             log_info (_("error getting serial number of card: %s\n"),
    2438             :                       gpg_strerror (err));
    2439           0 :           return err;
    2440             :         }
    2441           0 :       log_info (_("detected card with S/N: %s\n"), serialno);
    2442           0 :       err = agent_card_getattr (ctrl, "$AUTHKEYID", &authkeyid);
    2443             :     }
    2444           0 :   if (err)
    2445             :     {
    2446           0 :       log_error (_("no authentication key for ssh on card: %s\n"),
    2447             :                  gpg_strerror (err));
    2448           0 :       xfree (serialno);
    2449           0 :       return err;
    2450             :     }
    2451             : 
    2452             :   /* Get the S/N if we don't have it yet.  Use the fast getattr method.  */
    2453           0 :   if (!serialno && (err = agent_card_getattr (ctrl, "SERIALNO", &serialno)) )
    2454             :     {
    2455           0 :       log_error (_("error getting serial number of card: %s\n"),
    2456             :                  gpg_strerror (err));
    2457           0 :       xfree (authkeyid);
    2458           0 :       return err;
    2459             :     }
    2460             : 
    2461             :   /* Read the public key.  */
    2462           0 :   err = agent_card_readkey (ctrl, authkeyid, &pkbuf);
    2463           0 :   if (err)
    2464             :     {
    2465           0 :       if (opt.verbose)
    2466           0 :         log_info (_("no suitable card key found: %s\n"), gpg_strerror (err));
    2467           0 :       xfree (serialno);
    2468           0 :       xfree (authkeyid);
    2469           0 :       return err;
    2470             :     }
    2471             : 
    2472           0 :   pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
    2473           0 :   err = gcry_sexp_sscan (&s_pk, NULL, (char*)pkbuf, pkbuflen);
    2474           0 :   if (err)
    2475             :     {
    2476           0 :       log_error ("failed to build S-Exp from received card key: %s\n",
    2477             :                  gpg_strerror (err));
    2478           0 :       xfree (pkbuf);
    2479           0 :       xfree (serialno);
    2480           0 :       xfree (authkeyid);
    2481           0 :       return err;
    2482             :     }
    2483             : 
    2484           0 :   err = ssh_key_grip (s_pk, grip);
    2485           0 :   if (err)
    2486             :     {
    2487           0 :       log_debug ("error computing keygrip from received card key: %s\n",
    2488             :                  gcry_strerror (err));
    2489           0 :       xfree (pkbuf);
    2490           0 :       gcry_sexp_release (s_pk);
    2491           0 :       xfree (serialno);
    2492           0 :       xfree (authkeyid);
    2493           0 :       return err;
    2494             :     }
    2495             : 
    2496           0 :   if ( agent_key_available (grip) )
    2497             :     {
    2498             :       /* (Shadow)-key is not available in our key storage.  */
    2499             :       unsigned char *shadow_info;
    2500             :       unsigned char *tmp;
    2501             : 
    2502           0 :       shadow_info = make_shadow_info (serialno, authkeyid);
    2503           0 :       if (!shadow_info)
    2504             :         {
    2505           0 :           err = gpg_error_from_syserror ();
    2506           0 :           xfree (pkbuf);
    2507           0 :           gcry_sexp_release (s_pk);
    2508           0 :           xfree (serialno);
    2509           0 :           xfree (authkeyid);
    2510           0 :           return err;
    2511             :         }
    2512           0 :       err = agent_shadow_key (pkbuf, shadow_info, &tmp);
    2513           0 :       xfree (shadow_info);
    2514           0 :       if (err)
    2515             :         {
    2516           0 :           log_error (_("shadowing the key failed: %s\n"), gpg_strerror (err));
    2517           0 :           xfree (pkbuf);
    2518           0 :           gcry_sexp_release (s_pk);
    2519           0 :           xfree (serialno);
    2520           0 :           xfree (authkeyid);
    2521           0 :           return err;
    2522             :         }
    2523           0 :       xfree (pkbuf);
    2524           0 :       pkbuf = tmp;
    2525           0 :       pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
    2526           0 :       assert (pkbuflen);
    2527             : 
    2528           0 :       err = agent_write_private_key (grip, pkbuf, pkbuflen, 0);
    2529           0 :       if (err)
    2530             :         {
    2531           0 :           log_error (_("error writing key: %s\n"), gpg_strerror (err));
    2532           0 :           xfree (pkbuf);
    2533           0 :           gcry_sexp_release (s_pk);
    2534           0 :           xfree (serialno);
    2535           0 :           xfree (authkeyid);
    2536           0 :           return err;
    2537             :         }
    2538             :     }
    2539             : 
    2540           0 :   if (cardsn)
    2541             :     {
    2542             :       char *dispsn;
    2543             : 
    2544             :       /* If the card handler is able to return a short serialnumber,
    2545             :          use that one, else use the complete serialno. */
    2546           0 :       if (!agent_card_getattr (ctrl, "$DISPSERIALNO", &dispsn))
    2547             :         {
    2548           0 :           *cardsn = xtryasprintf ("cardno:%s", dispsn);
    2549           0 :           xfree (dispsn);
    2550             :         }
    2551             :       else
    2552           0 :         *cardsn = xtryasprintf ("cardno:%s", serialno);
    2553           0 :       if (!*cardsn)
    2554             :         {
    2555           0 :           err = gpg_error_from_syserror ();
    2556           0 :           xfree (pkbuf);
    2557           0 :           gcry_sexp_release (s_pk);
    2558           0 :           xfree (serialno);
    2559           0 :           xfree (authkeyid);
    2560           0 :           return err;
    2561             :         }
    2562             :     }
    2563             : 
    2564           0 :   xfree (pkbuf);
    2565           0 :   xfree (serialno);
    2566           0 :   xfree (authkeyid);
    2567           0 :   *r_pk = s_pk;
    2568           0 :   return 0;
    2569             : }
    2570             : 
    2571             : 
    2572             : 
    2573             : 
    2574             : /*
    2575             : 
    2576             :   Request handler.  Each handler is provided with a CTRL context, a
    2577             :   REQUEST object and a RESPONSE object.  The actual request is to be
    2578             :   read from REQUEST, the response needs to be written to RESPONSE.
    2579             : 
    2580             : */
    2581             : 
    2582             : 
    2583             : /* Handler for the "request_identities" command.  */
    2584             : static gpg_error_t
    2585           0 : ssh_handler_request_identities (ctrl_t ctrl,
    2586             :                                 estream_t request, estream_t response)
    2587             : {
    2588             :   ssh_key_type_spec_t spec;
    2589           0 :   char *key_fname = NULL;
    2590             :   char *fnameptr;
    2591             :   u32 key_counter;
    2592             :   estream_t key_blobs;
    2593             :   gcry_sexp_t key_secret;
    2594             :   gcry_sexp_t key_public;
    2595             :   gpg_error_t err;
    2596             :   int ret;
    2597           0 :   ssh_control_file_t cf = NULL;
    2598             :   char *cardsn;
    2599             :   gpg_error_t ret_err;
    2600             : 
    2601             :   (void)request;
    2602             : 
    2603             :   /* Prepare buffer stream.  */
    2604             : 
    2605           0 :   key_secret = NULL;
    2606           0 :   key_public = NULL;
    2607           0 :   key_counter = 0;
    2608           0 :   err = 0;
    2609             : 
    2610           0 :   key_blobs = es_fopenmem (0, "r+b");
    2611           0 :   if (! key_blobs)
    2612             :     {
    2613           0 :       err = gpg_error_from_syserror ();
    2614           0 :       goto out;
    2615             :     }
    2616             : 
    2617             :   /* First check whether a key is currently available in the card
    2618             :      reader - this should be allowed even without being listed in
    2619             :      sshcontrol. */
    2620             : 
    2621           0 :   if (!opt.disable_scdaemon
    2622           0 :       && !card_key_available (ctrl, &key_public, &cardsn))
    2623             :     {
    2624           0 :       err = ssh_send_key_public (key_blobs, key_public, cardsn);
    2625           0 :       gcry_sexp_release (key_public);
    2626           0 :       key_public = NULL;
    2627           0 :       xfree (cardsn);
    2628           0 :       if (err)
    2629           0 :         goto out;
    2630             : 
    2631           0 :       key_counter++;
    2632             :     }
    2633             : 
    2634             : 
    2635             :   /* Prepare buffer for key name construction.  */
    2636             :   {
    2637             :     char *dname;
    2638             : 
    2639           0 :     dname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, NULL);
    2640           0 :     if (!dname)
    2641             :       {
    2642           0 :         err = gpg_err_code_from_syserror ();
    2643           0 :         goto out;
    2644             :       }
    2645             : 
    2646           0 :     key_fname = xtrymalloc (strlen (dname) + 1 + 40 + 4 + 1);
    2647           0 :     if (!key_fname)
    2648             :       {
    2649           0 :         err = gpg_err_code_from_syserror ();
    2650           0 :         xfree (dname);
    2651           0 :         goto out;
    2652             :       }
    2653           0 :     fnameptr = stpcpy (stpcpy (key_fname, dname), "/");
    2654           0 :     xfree (dname);
    2655             :   }
    2656             : 
    2657             :   /* Then look at all the registered and non-disabled keys. */
    2658           0 :   err = open_control_file (&cf, 0);
    2659           0 :   if (err)
    2660           0 :     goto out;
    2661             : 
    2662           0 :   while (!read_control_file_item (cf))
    2663             :     {
    2664           0 :       if (!cf->item.valid)
    2665           0 :         continue; /* Should not happen.  */
    2666           0 :       if (cf->item.disabled)
    2667           0 :         continue;
    2668           0 :       assert (strlen (cf->item.hexgrip) == 40);
    2669             : 
    2670           0 :       stpcpy (stpcpy (fnameptr, cf->item.hexgrip), ".key");
    2671             : 
    2672             :       /* Read file content.  */
    2673             :       {
    2674             :         unsigned char *buffer;
    2675             :         size_t buffer_n;
    2676             : 
    2677           0 :         err = file_to_buffer (key_fname, &buffer, &buffer_n);
    2678           0 :         if (err)
    2679             :           {
    2680           0 :             log_error ("%s:%d: key '%s' skipped: %s\n",
    2681           0 :                        cf->fname, cf->lnr, cf->item.hexgrip,
    2682             :                        gpg_strerror (err));
    2683           0 :             continue;
    2684             :           }
    2685             : 
    2686           0 :         err = gcry_sexp_sscan (&key_secret, NULL, (char*)buffer, buffer_n);
    2687           0 :         xfree (buffer);
    2688           0 :         if (err)
    2689           0 :           goto out;
    2690             :       }
    2691             : 
    2692             :       {
    2693           0 :         char *key_type = NULL;
    2694             : 
    2695           0 :         err = sexp_extract_identifier (key_secret, &key_type);
    2696           0 :         if (err)
    2697           0 :           goto out;
    2698             : 
    2699           0 :         err = ssh_key_type_lookup (NULL, key_type, &spec);
    2700           0 :         xfree (key_type);
    2701           0 :         if (err)
    2702           0 :           goto out;
    2703             :       }
    2704             : 
    2705           0 :       err = ssh_send_key_public (key_blobs, key_secret, NULL);
    2706           0 :       if (err)
    2707           0 :         goto out;
    2708           0 :       gcry_sexp_release (key_secret);
    2709           0 :       key_secret = NULL;
    2710             : 
    2711           0 :       key_counter++;
    2712             :     }
    2713           0 :   err = 0;
    2714             : 
    2715           0 :   ret = es_fseek (key_blobs, 0, SEEK_SET);
    2716           0 :   if (ret)
    2717             :     {
    2718           0 :       err = gpg_error_from_syserror ();
    2719           0 :       goto out;
    2720             :     }
    2721             : 
    2722             :  out:
    2723             :   /* Send response.  */
    2724             : 
    2725           0 :   gcry_sexp_release (key_secret);
    2726           0 :   gcry_sexp_release (key_public);
    2727             : 
    2728           0 :   if (!err)
    2729             :     {
    2730           0 :       ret_err = stream_write_byte (response, SSH_RESPONSE_IDENTITIES_ANSWER);
    2731           0 :       if (!ret_err)
    2732           0 :         ret_err = stream_write_uint32 (response, key_counter);
    2733           0 :       if (!ret_err)
    2734           0 :         ret_err = stream_copy (response, key_blobs);
    2735             :     }
    2736             :   else
    2737             :     {
    2738           0 :       ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
    2739             :     }
    2740             : 
    2741           0 :   es_fclose (key_blobs);
    2742           0 :   close_control_file (cf);
    2743           0 :   xfree (key_fname);
    2744             : 
    2745           0 :   return ret_err;
    2746             : }
    2747             : 
    2748             : 
    2749             : /* This function hashes the data contained in DATA of size DATA_N
    2750             :    according to the message digest algorithm specified by MD_ALGORITHM
    2751             :    and writes the message digest to HASH, which needs to large enough
    2752             :    for the digest.  */
    2753             : static gpg_error_t
    2754           0 : data_hash (unsigned char *data, size_t data_n,
    2755             :            int md_algorithm, unsigned char *hash)
    2756             : {
    2757           0 :   gcry_md_hash_buffer (md_algorithm, hash, data, data_n);
    2758             : 
    2759           0 :   return 0;
    2760             : }
    2761             : 
    2762             : 
    2763             : /* This function signs the data described by CTRL. If HASH is is not
    2764             :    NULL, (HASH,HASHLEN) overrides the hash stored in CTRL.  This is to
    2765             :    allow the use of signature algorithms that implement the hashing
    2766             :    internally (e.g. Ed25519).  On success the created signature is
    2767             :    stored in ssh format at R_SIG and it's size at R_SIGLEN; the caller
    2768             :    must use es_free to releaase this memory.  */
    2769             : static gpg_error_t
    2770           0 : data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec,
    2771             :            const void *hash, size_t hashlen,
    2772             :            unsigned char **r_sig, size_t *r_siglen)
    2773             : {
    2774             :   gpg_error_t err;
    2775           0 :   gcry_sexp_t signature_sexp = NULL;
    2776           0 :   estream_t stream = NULL;
    2777           0 :   void *blob = NULL;
    2778             :   size_t bloblen;
    2779             :   char hexgrip[40+1];
    2780             : 
    2781           0 :   *r_sig = NULL;
    2782           0 :   *r_siglen = 0;
    2783             : 
    2784             :   /* Quick check to see whether we have a valid keygrip and convert it
    2785             :      to hex.  */
    2786           0 :   if (!ctrl->have_keygrip)
    2787             :     {
    2788           0 :       err = gpg_error (GPG_ERR_NO_SECKEY);
    2789           0 :       goto out;
    2790             :     }
    2791           0 :   bin2hex (ctrl->keygrip, 20, hexgrip);
    2792             : 
    2793             :   /* Ask for confirmation if needed.  */
    2794           0 :   if (confirm_flag_from_sshcontrol (hexgrip))
    2795             :     {
    2796             :       gcry_sexp_t key;
    2797             :       char *fpr, *prompt;
    2798           0 :       char *comment = NULL;
    2799             : 
    2800           0 :       err = agent_raw_key_from_file (ctrl, ctrl->keygrip, &key);
    2801           0 :       if (err)
    2802           0 :         goto out;
    2803           0 :       err = ssh_get_fingerprint_string (key, &fpr);
    2804           0 :       if (!err)
    2805             :         {
    2806           0 :           gcry_sexp_t tmpsxp = gcry_sexp_find_token (key, "comment", 0);
    2807           0 :           if (tmpsxp)
    2808           0 :             comment = gcry_sexp_nth_string (tmpsxp, 1);
    2809           0 :           gcry_sexp_release (tmpsxp);
    2810             :         }
    2811           0 :       gcry_sexp_release (key);
    2812           0 :       if (err)
    2813           0 :         goto out;
    2814           0 :       prompt = xtryasprintf (L_("An ssh process requested the use of key%%0A"
    2815             :                                 "  %s%%0A"
    2816             :                                 "  (%s)%%0A"
    2817             :                                 "Do you want to allow this?"),
    2818             :                              fpr, comment? comment:"");
    2819           0 :       xfree (fpr);
    2820           0 :       gcry_free (comment);
    2821           0 :       err = agent_get_confirmation (ctrl, prompt, L_("Allow"), L_("Deny"), 0);
    2822           0 :       xfree (prompt);
    2823           0 :       if (err)
    2824           0 :         goto out;
    2825             :     }
    2826             : 
    2827             :   /* Create signature.  */
    2828           0 :   ctrl->use_auth_call = 1;
    2829           0 :   err = agent_pksign_do (ctrl, NULL,
    2830             :                          L_("Please enter the passphrase "
    2831             :                             "for the ssh key%%0A  %F%%0A  (%c)"),
    2832             :                          &signature_sexp,
    2833             :                          CACHE_MODE_SSH, ttl_from_sshcontrol,
    2834             :                          hash, hashlen);
    2835           0 :   ctrl->use_auth_call = 0;
    2836           0 :   if (err)
    2837           0 :     goto out;
    2838             : 
    2839           0 :   stream = es_fopenmem (0, "r+b");
    2840           0 :   if (!stream)
    2841             :     {
    2842           0 :       err = gpg_error_from_syserror ();
    2843           0 :       goto out;
    2844             :     }
    2845             : 
    2846           0 :   err = stream_write_cstring (stream, spec->ssh_identifier);
    2847           0 :   if (err)
    2848           0 :     goto out;
    2849             : 
    2850           0 :   err = spec->signature_encoder (spec, stream, signature_sexp);
    2851           0 :   if (err)
    2852           0 :     goto out;
    2853             : 
    2854           0 :   err = es_fclose_snatch (stream, &blob, &bloblen);
    2855           0 :   if (err)
    2856           0 :     goto out;
    2857           0 :   stream = NULL;
    2858             : 
    2859           0 :   *r_sig = blob; blob = NULL;
    2860           0 :   *r_siglen = bloblen;
    2861             : 
    2862             :  out:
    2863           0 :   xfree (blob);
    2864           0 :   es_fclose (stream);
    2865           0 :   gcry_sexp_release (signature_sexp);
    2866             : 
    2867           0 :   return err;
    2868             : }
    2869             : 
    2870             : 
    2871             : /* Handler for the "sign_request" command.  */
    2872             : static gpg_error_t
    2873           0 : ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response)
    2874             : {
    2875           0 :   gcry_sexp_t key = NULL;
    2876             :   ssh_key_type_spec_t spec;
    2877             :   unsigned char hash[MAX_DIGEST_LEN];
    2878             :   unsigned int hash_n;
    2879             :   unsigned char key_grip[20];
    2880           0 :   unsigned char *key_blob = NULL;
    2881             :   u32 key_blob_size;
    2882           0 :   unsigned char *data = NULL;
    2883           0 :   unsigned char *sig = NULL;
    2884             :   size_t sig_n;
    2885             :   u32 data_size;
    2886             :   u32 flags;
    2887             :   gpg_error_t err;
    2888             :   gpg_error_t ret_err;
    2889             :   int hash_algo;
    2890             : 
    2891             :   /* Receive key.  */
    2892             : 
    2893           0 :   err = stream_read_string (request, 0, &key_blob, &key_blob_size);
    2894           0 :   if (err)
    2895           0 :     goto out;
    2896             : 
    2897           0 :   err = ssh_read_key_public_from_blob (key_blob, key_blob_size, &key, &spec);
    2898           0 :   if (err)
    2899           0 :     goto out;
    2900             : 
    2901             :   /* Receive data to sign.  */
    2902           0 :   err = stream_read_string (request, 0, &data, &data_size);
    2903           0 :   if (err)
    2904           0 :     goto out;
    2905             : 
    2906             :   /* FIXME?  */
    2907           0 :   err = stream_read_uint32 (request, &flags);
    2908           0 :   if (err)
    2909           0 :     goto out;
    2910             : 
    2911           0 :   hash_algo = spec.hash_algo;
    2912           0 :   if (!hash_algo)
    2913           0 :     hash_algo = GCRY_MD_SHA1;  /* Use the default.  */
    2914           0 :   ctrl->digest.algo = hash_algo;
    2915           0 :   if ((spec.flags & SPEC_FLAG_USE_PKCS1V2))
    2916           0 :     ctrl->digest.raw_value = 0;
    2917             :   else
    2918           0 :     ctrl->digest.raw_value = 1;
    2919             : 
    2920             :   /* Calculate key grip.  */
    2921           0 :   err = ssh_key_grip (key, key_grip);
    2922           0 :   if (err)
    2923           0 :     goto out;
    2924           0 :   ctrl->have_keygrip = 1;
    2925           0 :   memcpy (ctrl->keygrip, key_grip, 20);
    2926             : 
    2927             :   /* Hash data unless we use EdDSA.  */
    2928           0 :   if ((spec.flags & SPEC_FLAG_IS_EdDSA))
    2929             :     {
    2930           0 :       ctrl->digest.valuelen = 0;
    2931             :     }
    2932             :   else
    2933             :     {
    2934           0 :       hash_n = gcry_md_get_algo_dlen (hash_algo);
    2935           0 :       if (!hash_n)
    2936             :         {
    2937           0 :           err = gpg_error (GPG_ERR_INTERNAL);
    2938           0 :           goto out;
    2939             :         }
    2940           0 :       err = data_hash (data, data_size, hash_algo, hash);
    2941           0 :       if (err)
    2942           0 :         goto out;
    2943           0 :       memcpy (ctrl->digest.value, hash, hash_n);
    2944           0 :       ctrl->digest.valuelen = hash_n;
    2945             :     }
    2946             : 
    2947             :   /* Sign data.  */
    2948           0 :   if ((spec.flags & SPEC_FLAG_IS_EdDSA))
    2949           0 :     err = data_sign (ctrl, &spec, data, data_size, &sig, &sig_n);
    2950             :   else
    2951           0 :     err = data_sign (ctrl, &spec, NULL, 0, &sig, &sig_n);
    2952             : 
    2953             :  out:
    2954             :   /* Done.  */
    2955           0 :   if (!err)
    2956             :     {
    2957           0 :       ret_err = stream_write_byte (response, SSH_RESPONSE_SIGN_RESPONSE);
    2958           0 :       if (ret_err)
    2959           0 :         goto leave;
    2960           0 :       ret_err = stream_write_string (response, sig, sig_n);
    2961           0 :       if (ret_err)
    2962           0 :         goto leave;
    2963             :     }
    2964             :   else
    2965             :     {
    2966           0 :       log_error ("ssh sign request failed: %s <%s>\n",
    2967             :                  gpg_strerror (err), gpg_strsource (err));
    2968           0 :       ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
    2969           0 :       if (ret_err)
    2970           0 :         goto leave;
    2971             :     }
    2972             : 
    2973             :  leave:
    2974             : 
    2975           0 :   gcry_sexp_release (key);
    2976           0 :   xfree (key_blob);
    2977           0 :   xfree (data);
    2978           0 :   es_free (sig);
    2979             : 
    2980           0 :   return ret_err;
    2981             : }
    2982             : 
    2983             : 
    2984             : /* This function extracts the comment contained in the key
    2985             :    s-expression KEY and stores a copy in COMMENT.  Returns usual error
    2986             :    code.  */
    2987             : static gpg_error_t
    2988           0 : ssh_key_extract_comment (gcry_sexp_t key, char **r_comment)
    2989             : {
    2990             :   gcry_sexp_t comment_list;
    2991             : 
    2992           0 :   *r_comment = NULL;
    2993             : 
    2994           0 :   comment_list = gcry_sexp_find_token (key, "comment", 0);
    2995           0 :   if (!comment_list)
    2996           0 :     return gpg_error (GPG_ERR_INV_SEXP);
    2997             : 
    2998           0 :   *r_comment = gcry_sexp_nth_string (comment_list, 1);
    2999           0 :   gcry_sexp_release (comment_list);
    3000           0 :   if (!*r_comment)
    3001           0 :     return gpg_error (GPG_ERR_INV_SEXP);
    3002             : 
    3003           0 :   return 0;
    3004             : }
    3005             : 
    3006             : 
    3007             : /* This function converts the key contained in the S-Expression KEY
    3008             :    into a buffer, which is protected by the passphrase PASSPHRASE.
    3009             :    Returns usual error code.  */
    3010             : static gpg_error_t
    3011           0 : ssh_key_to_protected_buffer (gcry_sexp_t key, const char *passphrase,
    3012             :                              unsigned char **buffer, size_t *buffer_n)
    3013             : {
    3014             :   unsigned char *buffer_new;
    3015             :   unsigned int buffer_new_n;
    3016             :   gpg_error_t err;
    3017             : 
    3018           0 :   err = 0;
    3019           0 :   buffer_new_n = gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, NULL, 0);
    3020           0 :   buffer_new = xtrymalloc_secure (buffer_new_n);
    3021           0 :   if (! buffer_new)
    3022             :     {
    3023           0 :       err = gpg_error_from_syserror ();
    3024           0 :       goto out;
    3025             :     }
    3026             : 
    3027           0 :   gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, buffer_new, buffer_new_n);
    3028             :   /* FIXME: guarantee?  */
    3029             : 
    3030           0 :   err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0);
    3031             : 
    3032             :  out:
    3033             : 
    3034           0 :   xfree (buffer_new);
    3035             : 
    3036           0 :   return err;
    3037             : }
    3038             : 
    3039             : 
    3040             : 
    3041             : /* Callback function to compare the first entered PIN with the one
    3042             :    currently being entered. */
    3043             : static gpg_error_t
    3044           0 : reenter_compare_cb (struct pin_entry_info_s *pi)
    3045             : {
    3046           0 :   const char *pin1 = pi->check_cb_arg;
    3047             : 
    3048           0 :   if (!strcmp (pin1, pi->pin))
    3049           0 :     return 0; /* okay */
    3050           0 :   return gpg_error (GPG_ERR_BAD_PASSPHRASE);
    3051             : }
    3052             : 
    3053             : 
    3054             : /* Store the ssh KEY into our local key storage and protect it after
    3055             :    asking for a passphrase.  Cache that passphrase.  TTL is the
    3056             :    maximum caching time for that key.  If the key already exists in
    3057             :    our key storage, don't do anything.  When entering a new key also
    3058             :    add an entry to the sshcontrol file.  */
    3059             : static gpg_error_t
    3060           0 : ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
    3061             :                        gcry_sexp_t key, int ttl, int confirm)
    3062             : {
    3063             :   gpg_error_t err;
    3064             :   unsigned char key_grip_raw[20];
    3065             :   char key_grip[41];
    3066           0 :   unsigned char *buffer = NULL;
    3067             :   size_t buffer_n;
    3068           0 :   char *description = NULL;
    3069           0 :   const char *description2 = L_("Please re-enter this passphrase");
    3070           0 :   char *comment = NULL;
    3071           0 :   char *key_fpr = NULL;
    3072           0 :   const char *initial_errtext = NULL;
    3073           0 :   struct pin_entry_info_s *pi = NULL;
    3074           0 :   struct pin_entry_info_s *pi2 = NULL;
    3075             : 
    3076           0 :   err = ssh_key_grip (key, key_grip_raw);
    3077           0 :   if (err)
    3078           0 :     goto out;
    3079             : 
    3080             :   /* Check whether the key is already in our key storage.  Don't do
    3081             :      anything then.  */
    3082           0 :   if ( !agent_key_available (key_grip_raw) )
    3083           0 :     goto out; /* Yes, key is available.  */
    3084             : 
    3085           0 :   err = ssh_get_fingerprint_string (key, &key_fpr);
    3086           0 :   if (err)
    3087           0 :     goto out;
    3088             : 
    3089           0 :   err = ssh_key_extract_comment (key, &comment);
    3090           0 :   if (err)
    3091           0 :     goto out;
    3092             : 
    3093           0 :   if ( asprintf (&description,
    3094             :                  L_("Please enter a passphrase to protect"
    3095             :                     " the received secret key%%0A"
    3096             :                     "   %s%%0A"
    3097             :                     "   %s%%0A"
    3098             :                     "within gpg-agent's key storage"),
    3099           0 :                  key_fpr, comment ? comment : "") < 0)
    3100             :     {
    3101           0 :       err = gpg_error_from_syserror ();
    3102           0 :       goto out;
    3103             :     }
    3104             : 
    3105           0 :   pi = gcry_calloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1);
    3106           0 :   if (!pi)
    3107             :     {
    3108           0 :       err = gpg_error_from_syserror ();
    3109           0 :       goto out;
    3110             :     }
    3111           0 :   pi2 = gcry_calloc_secure (1, sizeof (*pi2) + MAX_PASSPHRASE_LEN + 1);
    3112           0 :   if (!pi2)
    3113             :     {
    3114           0 :       err = gpg_error_from_syserror ();
    3115           0 :       goto out;
    3116             :     }
    3117           0 :   pi->max_length = MAX_PASSPHRASE_LEN + 1;
    3118           0 :   pi->max_tries = 1;
    3119           0 :   pi->with_repeat = 1;
    3120           0 :   pi2->max_length = MAX_PASSPHRASE_LEN + 1;
    3121           0 :   pi2->max_tries = 1;
    3122           0 :   pi2->check_cb = reenter_compare_cb;
    3123           0 :   pi2->check_cb_arg = pi->pin;
    3124             : 
    3125             :  next_try:
    3126           0 :   err = agent_askpin (ctrl, description, NULL, initial_errtext, pi, NULL, 0);
    3127           0 :   initial_errtext = NULL;
    3128           0 :   if (err)
    3129           0 :     goto out;
    3130             : 
    3131             :   /* Unless the passphrase is empty or the pinentry told us that
    3132             :      it already did the repetition check, ask to confirm it.  */
    3133           0 :   if (*pi->pin && !pi->repeat_okay)
    3134             :     {
    3135           0 :       err = agent_askpin (ctrl, description2, NULL, NULL, pi2, NULL, 0);
    3136           0 :       if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE)
    3137             :         { /* The re-entered one did not match and the user did not
    3138             :              hit cancel. */
    3139           0 :           initial_errtext = L_("does not match - try again");
    3140           0 :           goto next_try;
    3141             :         }
    3142             :     }
    3143             : 
    3144           0 :   err = ssh_key_to_protected_buffer (key, pi->pin, &buffer, &buffer_n);
    3145           0 :   if (err)
    3146           0 :     goto out;
    3147             : 
    3148             :   /* Store this key to our key storage.  */
    3149           0 :   err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0);
    3150           0 :   if (err)
    3151           0 :     goto out;
    3152             : 
    3153             :   /* Cache this passphrase. */
    3154           0 :   bin2hex (key_grip_raw, 20, key_grip);
    3155           0 :   err = agent_put_cache (key_grip, CACHE_MODE_SSH, pi->pin, ttl);
    3156           0 :   if (err)
    3157           0 :     goto out;
    3158             : 
    3159             :   /* And add an entry to the sshcontrol file.  */
    3160           0 :   err = add_control_entry (ctrl, spec, key_grip, key_fpr, ttl, confirm);
    3161             : 
    3162             : 
    3163             :  out:
    3164           0 :   if (pi2 && pi2->max_length)
    3165           0 :     wipememory (pi2->pin, pi2->max_length);
    3166           0 :   xfree (pi2);
    3167           0 :   if (pi && pi->max_length)
    3168           0 :     wipememory (pi->pin, pi->max_length);
    3169           0 :   xfree (pi);
    3170           0 :   xfree (buffer);
    3171           0 :   xfree (comment);
    3172           0 :   xfree (key_fpr);
    3173           0 :   xfree (description);
    3174             : 
    3175           0 :   return err;
    3176             : }
    3177             : 
    3178             : 
    3179             : /* This function removes the key contained in the S-Expression KEY
    3180             :    from the local key storage, in case it exists there.  Returns usual
    3181             :    error code.  FIXME: this function is a stub.  */
    3182             : static gpg_error_t
    3183           0 : ssh_identity_drop (gcry_sexp_t key)
    3184             : {
    3185           0 :   unsigned char key_grip[21] = { 0 };
    3186             :   gpg_error_t err;
    3187             : 
    3188           0 :   err = ssh_key_grip (key, key_grip);
    3189           0 :   if (err)
    3190           0 :     goto out;
    3191             : 
    3192           0 :   key_grip[sizeof (key_grip) - 1] = 0;
    3193             : 
    3194             :   /* FIXME: What to do here - forgetting the passphrase or deleting
    3195             :      the key from key cache?  */
    3196             : 
    3197             :  out:
    3198             : 
    3199           0 :   return err;
    3200             : }
    3201             : 
    3202             : /* Handler for the "add_identity" command.  */
    3203             : static gpg_error_t
    3204           0 : ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response)
    3205             : {
    3206             :   gpg_error_t ret_err;
    3207             :   ssh_key_type_spec_t spec;
    3208             :   gpg_error_t err;
    3209             :   gcry_sexp_t key;
    3210             :   unsigned char b;
    3211             :   int confirm;
    3212             :   int ttl;
    3213             : 
    3214           0 :   confirm = 0;
    3215           0 :   key = NULL;
    3216           0 :   ttl = 0;
    3217             : 
    3218             :   /* FIXME?  */
    3219           0 :   err = ssh_receive_key (request, &key, 1, 1, &spec);
    3220           0 :   if (err)
    3221           0 :     goto out;
    3222             : 
    3223             :   while (1)
    3224             :     {
    3225           0 :       err = stream_read_byte (request, &b);
    3226           0 :       if (gpg_err_code (err) == GPG_ERR_EOF)
    3227             :         {
    3228           0 :           err = 0;
    3229           0 :           break;
    3230             :         }
    3231             : 
    3232           0 :       switch (b)
    3233             :         {
    3234             :         case SSH_OPT_CONSTRAIN_LIFETIME:
    3235             :           {
    3236           0 :             u32 n = 0;
    3237             : 
    3238           0 :             err = stream_read_uint32 (request, &n);
    3239           0 :             if (! err)
    3240           0 :               ttl = n;
    3241           0 :             break;
    3242             :           }
    3243             : 
    3244             :         case SSH_OPT_CONSTRAIN_CONFIRM:
    3245             :           {
    3246           0 :             confirm = 1;
    3247           0 :             break;
    3248             :           }
    3249             : 
    3250             :         default:
    3251             :           /* FIXME: log/bad?  */
    3252           0 :           break;
    3253             :         }
    3254           0 :     }
    3255           0 :   if (err)
    3256           0 :     goto out;
    3257             : 
    3258           0 :   err = ssh_identity_register (ctrl, &spec, key, ttl, confirm);
    3259             : 
    3260             :  out:
    3261             : 
    3262           0 :   gcry_sexp_release (key);
    3263             : 
    3264           0 :   if (! err)
    3265           0 :     ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
    3266             :   else
    3267           0 :     ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
    3268             : 
    3269           0 :   return ret_err;
    3270             : }
    3271             : 
    3272             : /* Handler for the "remove_identity" command.  */
    3273             : static gpg_error_t
    3274           0 : ssh_handler_remove_identity (ctrl_t ctrl,
    3275             :                              estream_t request, estream_t response)
    3276             : {
    3277             :   unsigned char *key_blob;
    3278             :   u32 key_blob_size;
    3279             :   gcry_sexp_t key;
    3280             :   gpg_error_t ret_err;
    3281             :   gpg_error_t err;
    3282             : 
    3283             :   (void)ctrl;
    3284             : 
    3285             :   /* Receive key.  */
    3286             : 
    3287           0 :   key_blob = NULL;
    3288           0 :   key = NULL;
    3289             : 
    3290           0 :   err = stream_read_string (request, 0, &key_blob, &key_blob_size);
    3291           0 :   if (err)
    3292           0 :     goto out;
    3293             : 
    3294           0 :   err = ssh_read_key_public_from_blob (key_blob, key_blob_size, &key, NULL);
    3295           0 :   if (err)
    3296           0 :     goto out;
    3297             : 
    3298           0 :   err = ssh_identity_drop (key);
    3299             : 
    3300             :  out:
    3301             : 
    3302           0 :   xfree (key_blob);
    3303           0 :   gcry_sexp_release (key);
    3304             : 
    3305           0 :   if (! err)
    3306           0 :     ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
    3307             :   else
    3308           0 :     ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
    3309             : 
    3310           0 :   return ret_err;
    3311             : }
    3312             : 
    3313             : /* FIXME: stub function.  Actually useful?  */
    3314             : static gpg_error_t
    3315           0 : ssh_identities_remove_all (void)
    3316             : {
    3317             :   gpg_error_t err;
    3318             : 
    3319           0 :   err = 0;
    3320             : 
    3321             :   /* FIXME: shall we remove _all_ cache entries or only those
    3322             :      registered through the ssh emulation?  */
    3323             : 
    3324           0 :   return err;
    3325             : }
    3326             : 
    3327             : /* Handler for the "remove_all_identities" command.  */
    3328             : static gpg_error_t
    3329           0 : ssh_handler_remove_all_identities (ctrl_t ctrl,
    3330             :                                    estream_t request, estream_t response)
    3331             : {
    3332             :   gpg_error_t ret_err;
    3333             :   gpg_error_t err;
    3334             : 
    3335             :   (void)ctrl;
    3336             :   (void)request;
    3337             : 
    3338           0 :   err = ssh_identities_remove_all ();
    3339             : 
    3340           0 :   if (! err)
    3341           0 :     ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
    3342             :   else
    3343           0 :     ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
    3344             : 
    3345           0 :   return ret_err;
    3346             : }
    3347             : 
    3348             : /* Lock agent?  FIXME: stub function.  */
    3349             : static gpg_error_t
    3350           0 : ssh_lock (void)
    3351             : {
    3352             :   gpg_error_t err;
    3353             : 
    3354             :   /* FIXME */
    3355           0 :   log_error ("ssh-agent's lock command is not implemented\n");
    3356           0 :   err = 0;
    3357             : 
    3358           0 :   return err;
    3359             : }
    3360             : 
    3361             : /* Unock agent?  FIXME: stub function.  */
    3362             : static gpg_error_t
    3363           0 : ssh_unlock (void)
    3364             : {
    3365             :   gpg_error_t err;
    3366             : 
    3367           0 :   log_error ("ssh-agent's unlock command is not implemented\n");
    3368           0 :   err = 0;
    3369             : 
    3370           0 :   return err;
    3371             : }
    3372             : 
    3373             : /* Handler for the "lock" command.  */
    3374             : static gpg_error_t
    3375           0 : ssh_handler_lock (ctrl_t ctrl, estream_t request, estream_t response)
    3376             : {
    3377             :   gpg_error_t ret_err;
    3378             :   gpg_error_t err;
    3379             : 
    3380             :   (void)ctrl;
    3381             :   (void)request;
    3382             : 
    3383           0 :   err = ssh_lock ();
    3384             : 
    3385           0 :   if (! err)
    3386           0 :     ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
    3387             :   else
    3388           0 :     ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
    3389             : 
    3390           0 :   return ret_err;
    3391             : }
    3392             : 
    3393             : /* Handler for the "unlock" command.  */
    3394             : static gpg_error_t
    3395           0 : ssh_handler_unlock (ctrl_t ctrl, estream_t request, estream_t response)
    3396             : {
    3397             :   gpg_error_t ret_err;
    3398             :   gpg_error_t err;
    3399             : 
    3400             :   (void)ctrl;
    3401             :   (void)request;
    3402             : 
    3403           0 :   err = ssh_unlock ();
    3404             : 
    3405           0 :   if (! err)
    3406           0 :     ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
    3407             :   else
    3408           0 :     ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
    3409             : 
    3410           0 :   return ret_err;
    3411             : }
    3412             : 
    3413             : 
    3414             : 
    3415             : /* Return the request specification for the request identified by TYPE
    3416             :    or NULL in case the requested request specification could not be
    3417             :    found.  */
    3418             : static ssh_request_spec_t *
    3419           0 : request_spec_lookup (int type)
    3420             : {
    3421             :   ssh_request_spec_t *spec;
    3422             :   unsigned int i;
    3423             : 
    3424           0 :   for (i = 0; i < DIM (request_specs); i++)
    3425           0 :     if (request_specs[i].type == type)
    3426           0 :       break;
    3427           0 :   if (i == DIM (request_specs))
    3428             :     {
    3429           0 :       if (opt.verbose)
    3430           0 :         log_info ("ssh request %u is not supported\n", type);
    3431           0 :       spec = NULL;
    3432             :     }
    3433             :   else
    3434           0 :     spec = request_specs + i;
    3435             : 
    3436           0 :   return spec;
    3437             : }
    3438             : 
    3439             : /* Process a single request.  The request is read from and the
    3440             :    response is written to STREAM_SOCK.  Uses CTRL as context.  Returns
    3441             :    zero in case of success, non zero in case of failure.  */
    3442             : static int
    3443           0 : ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
    3444             : {
    3445             :   ssh_request_spec_t *spec;
    3446           0 :   estream_t response = NULL;
    3447           0 :   estream_t request = NULL;
    3448             :   unsigned char request_type;
    3449             :   gpg_error_t err;
    3450           0 :   int send_err = 0;
    3451             :   int ret;
    3452           0 :   unsigned char *request_data = NULL;
    3453             :   u32 request_data_size;
    3454             :   u32 response_size;
    3455             : 
    3456             :   /* Create memory streams for request/response data.  The entire
    3457             :      request will be stored in secure memory, since it might contain
    3458             :      secret key material.  The response does not have to be stored in
    3459             :      secure memory, since we never give out secret keys.
    3460             : 
    3461             :      Note: we only have little secure memory, but there is NO
    3462             :      possibility of DoS here; only trusted clients are allowed to
    3463             :      connect to the agent.  What could happen is that the agent
    3464             :      returns out-of-secure-memory errors on requests in case the
    3465             :      agent's owner floods his own agent with many large messages.
    3466             :      -moritz */
    3467             : 
    3468             :   /* Retrieve request.  */
    3469           0 :   err = stream_read_string (stream_sock, 1, &request_data, &request_data_size);
    3470           0 :   if (err)
    3471           0 :     goto out;
    3472             : 
    3473           0 :   if (opt.verbose > 1)
    3474           0 :     log_info ("received ssh request of length %u\n",
    3475             :               (unsigned int)request_data_size);
    3476             : 
    3477           0 :   if (! request_data_size)
    3478             :     {
    3479           0 :       send_err = 1;
    3480           0 :       goto out;
    3481             :       /* Broken request; FIXME.  */
    3482             :     }
    3483             : 
    3484           0 :   request_type = request_data[0];
    3485           0 :   spec = request_spec_lookup (request_type);
    3486           0 :   if (! spec)
    3487             :     {
    3488           0 :       send_err = 1;
    3489           0 :       goto out;
    3490             :       /* Unknown request; FIXME.  */
    3491             :     }
    3492             : 
    3493           0 :   if (spec->secret_input)
    3494           0 :     request = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+b");
    3495             :   else
    3496           0 :     request = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+b");
    3497           0 :   if (! request)
    3498             :     {
    3499           0 :       err = gpg_error_from_syserror ();
    3500           0 :       goto out;
    3501             :     }
    3502           0 :   ret = es_setvbuf (request, NULL, _IONBF, 0);
    3503           0 :   if (ret)
    3504             :     {
    3505           0 :       err = gpg_error_from_syserror ();
    3506           0 :       goto out;
    3507             :     }
    3508           0 :   err = stream_write_data (request, request_data + 1, request_data_size - 1);
    3509           0 :   if (err)
    3510           0 :     goto out;
    3511           0 :   es_rewind (request);
    3512             : 
    3513           0 :   response = es_fopenmem (0, "r+b");
    3514           0 :   if (! response)
    3515             :     {
    3516           0 :       err = gpg_error_from_syserror ();
    3517           0 :       goto out;
    3518             :     }
    3519             : 
    3520           0 :   if (opt.verbose)
    3521           0 :     log_info ("ssh request handler for %s (%u) started\n",
    3522           0 :                spec->identifier, spec->type);
    3523             : 
    3524           0 :   err = (*spec->handler) (ctrl, request, response);
    3525             : 
    3526           0 :   if (opt.verbose)
    3527             :     {
    3528           0 :       if (err)
    3529           0 :         log_info ("ssh request handler for %s (%u) failed: %s\n",
    3530           0 :                   spec->identifier, spec->type, gpg_strerror (err));
    3531             :       else
    3532           0 :         log_info ("ssh request handler for %s (%u) ready\n",
    3533           0 :                   spec->identifier, spec->type);
    3534             :     }
    3535             : 
    3536           0 :   if (err)
    3537             :     {
    3538           0 :       send_err = 1;
    3539           0 :       goto out;
    3540             :     }
    3541             : 
    3542           0 :   response_size = es_ftell (response);
    3543           0 :   if (opt.verbose > 1)
    3544           0 :     log_info ("sending ssh response of length %u\n",
    3545             :               (unsigned int)response_size);
    3546             : 
    3547           0 :   err = es_fseek (response, 0, SEEK_SET);
    3548           0 :   if (err)
    3549             :     {
    3550           0 :       send_err = 1;
    3551           0 :       goto out;
    3552             :     }
    3553             : 
    3554           0 :   err = stream_write_uint32 (stream_sock, response_size);
    3555           0 :   if (err)
    3556             :     {
    3557           0 :       send_err = 1;
    3558           0 :       goto out;
    3559             :     }
    3560             : 
    3561           0 :   err = stream_copy (stream_sock, response);
    3562           0 :   if (err)
    3563           0 :     goto out;
    3564             : 
    3565           0 :   err = es_fflush (stream_sock);
    3566           0 :   if (err)
    3567           0 :     goto out;
    3568             : 
    3569             :  out:
    3570             : 
    3571           0 :   if (err && es_feof (stream_sock))
    3572           0 :     log_error ("error occured while processing request: %s\n",
    3573             :                gpg_strerror (err));
    3574             : 
    3575           0 :   if (send_err)
    3576             :     {
    3577           0 :       if (opt.verbose > 1)
    3578           0 :         log_info ("sending ssh error response\n");
    3579           0 :       err = stream_write_uint32 (stream_sock, 1);
    3580           0 :       if (err)
    3581           0 :         goto leave;
    3582           0 :       err = stream_write_byte (stream_sock, SSH_RESPONSE_FAILURE);
    3583           0 :       if (err)
    3584           0 :         goto leave;
    3585             :     }
    3586             : 
    3587             :  leave:
    3588             : 
    3589           0 :   es_fclose (request);
    3590           0 :   es_fclose (response);
    3591           0 :   xfree (request_data);
    3592             : 
    3593           0 :   return !!err;
    3594             : }
    3595             : 
    3596             : 
    3597             : /* Start serving client on SOCK_CLIENT.  */
    3598             : void
    3599           0 : start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
    3600             : {
    3601           0 :   estream_t stream_sock = NULL;
    3602             :   gpg_error_t err;
    3603             :   int ret;
    3604             : 
    3605           0 :   err = agent_copy_startup_env (ctrl);
    3606           0 :   if (err)
    3607           0 :     goto out;
    3608             : 
    3609             :   /* Create stream from socket.  */
    3610           0 :   stream_sock = es_fdopen (FD2INT(sock_client), "r+");
    3611           0 :   if (!stream_sock)
    3612             :     {
    3613           0 :       err = gpg_error_from_syserror ();
    3614           0 :       log_error (_("failed to create stream from socket: %s\n"),
    3615             :                  gpg_strerror (err));
    3616           0 :       goto out;
    3617             :     }
    3618             :   /* We have to disable the estream buffering, because the estream
    3619             :      core doesn't know about secure memory.  */
    3620           0 :   ret = es_setvbuf (stream_sock, NULL, _IONBF, 0);
    3621           0 :   if (ret)
    3622             :     {
    3623           0 :       err = gpg_error_from_syserror ();
    3624           0 :       log_error ("failed to disable buffering "
    3625             :                  "on socket stream: %s\n", gpg_strerror (err));
    3626           0 :       goto out;
    3627             :     }
    3628             : 
    3629             :   /* Main processing loop. */
    3630           0 :   while ( !ssh_request_process (ctrl, stream_sock) )
    3631             :     {
    3632             :       /* Check wether we have reached EOF before trying to read
    3633             :          another request.  */
    3634             :       int c;
    3635             : 
    3636           0 :       c = es_fgetc (stream_sock);
    3637           0 :       if (c == EOF)
    3638           0 :         break;
    3639           0 :       es_ungetc (c, stream_sock);
    3640             :     }
    3641             : 
    3642             :   /* Reset the SCD in case it has been used. */
    3643           0 :   agent_reset_scd (ctrl);
    3644             : 
    3645             : 
    3646             :  out:
    3647           0 :   if (stream_sock)
    3648           0 :     es_fclose (stream_sock);
    3649           0 : }
    3650             : 
    3651             : 
    3652             : #ifdef HAVE_W32_SYSTEM
    3653             : /* Serve one ssh-agent request.  This is used for the Putty support.
    3654             :    REQUEST is the the mmapped memory which may be accessed up to a
    3655             :    length of MAXREQLEN.  Returns 0 on success which also indicates
    3656             :    that a valid SSH response message is now in REQUEST.  */
    3657             : int
    3658             : serve_mmapped_ssh_request (ctrl_t ctrl,
    3659             :                            unsigned char *request, size_t maxreqlen)
    3660             : {
    3661             :   gpg_error_t err;
    3662             :   int send_err = 0;
    3663             :   int valid_response = 0;
    3664             :   ssh_request_spec_t *spec;
    3665             :   u32 msglen;
    3666             :   estream_t request_stream, response_stream;
    3667             : 
    3668             :   if (agent_copy_startup_env (ctrl))
    3669             :     goto leave; /* Error setting up the environment.  */
    3670             : 
    3671             :   if (maxreqlen < 5)
    3672             :     goto leave; /* Caller error.  */
    3673             : 
    3674             :   msglen = uint32_construct (request[0], request[1], request[2], request[3]);
    3675             :   if (msglen < 1 || msglen > maxreqlen - 4)
    3676             :     {
    3677             :       log_error ("ssh message len (%u) out of range", (unsigned int)msglen);
    3678             :       goto leave;
    3679             :     }
    3680             : 
    3681             :   spec = request_spec_lookup (request[4]);
    3682             :   if (!spec)
    3683             :     {
    3684             :       send_err = 1;  /* Unknown request type.  */
    3685             :       goto leave;
    3686             :     }
    3687             : 
    3688             :   /* Create a stream object with the data part of the request.  */
    3689             :   if (spec->secret_input)
    3690             :     request_stream = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+");
    3691             :   else
    3692             :     request_stream = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+");
    3693             :   if (!request_stream)
    3694             :     {
    3695             :       err = gpg_error_from_syserror ();
    3696             :       goto leave;
    3697             :     }
    3698             :   /* We have to disable the estream buffering, because the estream
    3699             :      core doesn't know about secure memory.  */
    3700             :   if (es_setvbuf (request_stream, NULL, _IONBF, 0))
    3701             :     {
    3702             :       err = gpg_error_from_syserror ();
    3703             :       goto leave;
    3704             :     }
    3705             :   /* Copy the request to the stream but omit the request type.  */
    3706             :   err = stream_write_data (request_stream, request + 5, msglen - 1);
    3707             :   if (err)
    3708             :     goto leave;
    3709             :   es_rewind (request_stream);
    3710             : 
    3711             :   response_stream = es_fopenmem (0, "r+b");
    3712             :   if (!response_stream)
    3713             :     {
    3714             :       err = gpg_error_from_syserror ();
    3715             :       goto leave;
    3716             :     }
    3717             : 
    3718             :   if (opt.verbose)
    3719             :     log_info ("ssh request handler for %s (%u) started\n",
    3720             :                spec->identifier, spec->type);
    3721             : 
    3722             :   err = (*spec->handler) (ctrl, request_stream, response_stream);
    3723             : 
    3724             :   if (opt.verbose)
    3725             :     {
    3726             :       if (err)
    3727             :         log_info ("ssh request handler for %s (%u) failed: %s\n",
    3728             :                   spec->identifier, spec->type, gpg_strerror (err));
    3729             :       else
    3730             :         log_info ("ssh request handler for %s (%u) ready\n",
    3731             :                   spec->identifier, spec->type);
    3732             :     }
    3733             : 
    3734             :   es_fclose (request_stream);
    3735             :   request_stream = NULL;
    3736             : 
    3737             :   if (err)
    3738             :     {
    3739             :       send_err = 1;
    3740             :       goto leave;
    3741             :     }
    3742             : 
    3743             :   /* Put the response back into the mmapped buffer.  */
    3744             :   {
    3745             :     void *response_data;
    3746             :     size_t response_size;
    3747             : 
    3748             :     /* NB: In contrast to the request-stream, the response stream
    3749             :        includes the the message type byte.  */
    3750             :     if (es_fclose_snatch (response_stream, &response_data, &response_size))
    3751             :       {
    3752             :         log_error ("snatching ssh response failed: %s",
    3753             :                    gpg_strerror (gpg_error_from_syserror ()));
    3754             :         send_err = 1; /* Ooops.  */
    3755             :         goto leave;
    3756             :       }
    3757             : 
    3758             :     if (opt.verbose > 1)
    3759             :       log_info ("sending ssh response of length %u\n",
    3760             :                 (unsigned int)response_size);
    3761             :     if (response_size > maxreqlen - 4)
    3762             :       {
    3763             :         log_error ("invalid length of the ssh response: %s",
    3764             :                    gpg_strerror (GPG_ERR_INTERNAL));
    3765             :         es_free (response_data);
    3766             :         send_err = 1;
    3767             :         goto leave;
    3768             :       }
    3769             : 
    3770             :     request[0] = response_size >> 24;
    3771             :     request[1] = response_size >> 16;
    3772             :     request[2] = response_size >>  8;
    3773             :     request[3] = response_size >>  0;
    3774             :     memcpy (request+4, response_data, response_size);
    3775             :     es_free (response_data);
    3776             :     valid_response = 1;
    3777             :   }
    3778             : 
    3779             :  leave:
    3780             :   if (send_err)
    3781             :     {
    3782             :       request[0] = 0;
    3783             :       request[1] = 0;
    3784             :       request[2] = 0;
    3785             :       request[3] = 1;
    3786             :       request[4] = SSH_RESPONSE_FAILURE;
    3787             :       valid_response = 1;
    3788             :     }
    3789             : 
    3790             :   /* Reset the SCD in case it has been used. */
    3791             :   agent_reset_scd (ctrl);
    3792             : 
    3793             :   return valid_response? 0 : -1;
    3794             : }
    3795             : #endif /*HAVE_W32_SYSTEM*/

Generated by: LCOV version 1.11