LCOV - code coverage report
Current view: top level - agent - command-ssh.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 676 1461 46.3 %
Date: 2016-11-29 15:00:56 Functions: 43 64 67.2 %

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

Generated by: LCOV version 1.11