LCOV - code coverage report
Current view: top level - common - ssh-utils.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 102 130 78.5 %
Date: 2015-11-05 17:10:59 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /* ssh-utils.c - Secure Shell helper functions
       2             :  * Copyright (C) 2011 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * This file is free software; you can redistribute it and/or modify
       7             :  * it under the terms of either
       8             :  *
       9             :  *   - the GNU Lesser General Public License as published by the Free
      10             :  *     Software Foundation; either version 3 of the License, or (at
      11             :  *     your option) any later version.
      12             :  *
      13             :  * or
      14             :  *
      15             :  *   - the GNU General Public License as published by the Free
      16             :  *     Software Foundation; either version 2 of the License, or (at
      17             :  *     your option) any later version.
      18             :  *
      19             :  * or both in parallel, as here.
      20             :  *
      21             :  * This file is distributed in the hope that it will be useful,
      22             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      23             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      24             :  * GNU General Public License for more details.
      25             :  *
      26             :  * You should have received a copy of the GNU General Public License
      27             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      28             :  */
      29             : 
      30             : #include <config.h>
      31             : #include <stdlib.h>
      32             : #include <errno.h>
      33             : #include <ctype.h>
      34             : #include <assert.h>
      35             : 
      36             : #include "util.h"
      37             : #include "ssh-utils.h"
      38             : 
      39             : 
      40             : /* Return true if KEYPARMS holds an EdDSA key.  */
      41             : static int
      42           4 : is_eddsa (gcry_sexp_t keyparms)
      43             : {
      44           4 :   int result = 0;
      45             :   gcry_sexp_t list;
      46             :   const char *s;
      47             :   size_t n;
      48             :   int i;
      49             : 
      50           4 :   list = gcry_sexp_find_token (keyparms, "flags", 0);
      51           4 :   for (i = list ? gcry_sexp_length (list)-1 : 0; i > 0; i--)
      52             :     {
      53           1 :       s = gcry_sexp_nth_data (list, i, &n);
      54           1 :       if (!s)
      55           0 :         continue; /* Not a data element. */
      56             : 
      57           1 :       if (n == 5 && !memcmp (s, "eddsa", 5))
      58             :         {
      59           1 :           result = 1;
      60           1 :           break;
      61             :         }
      62             :     }
      63           4 :   gcry_sexp_release (list);
      64           4 :   return result;
      65             : }
      66             : 
      67             : 
      68             : /* Return the Secure Shell type fingerprint for KEY.  The length of
      69             :    the fingerprint is returned at R_LEN and the fingerprint itself at
      70             :    R_FPR.  In case of a error code is returned and NULL stored at
      71             :    R_FPR.  */
      72             : static gpg_error_t
      73           6 : get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string)
      74             : {
      75             :   gpg_error_t err;
      76           6 :   gcry_sexp_t list = NULL;
      77           6 :   gcry_sexp_t l2 = NULL;
      78             :   const char *s;
      79           6 :   char *name = NULL;
      80             :   int idx;
      81             :   const char *elems;
      82           6 :   gcry_md_hd_t md = NULL;
      83           6 :   int blobmode = 0;
      84             : 
      85           6 :   *r_fpr = NULL;
      86           6 :   *r_len = 0;
      87             : 
      88             :   /* Check that the first element is valid. */
      89           6 :   list = gcry_sexp_find_token (key, "public-key", 0);
      90           6 :   if (!list)
      91           6 :     list = gcry_sexp_find_token (key, "private-key", 0);
      92           6 :   if (!list)
      93           6 :     list = gcry_sexp_find_token (key, "protected-private-key", 0);
      94           6 :   if (!list)
      95           0 :     list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
      96           6 :   if (!list)
      97             :     {
      98           0 :       err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_SEXP);
      99           0 :       goto leave;
     100             :     }
     101             : 
     102           6 :   l2 = gcry_sexp_cadr (list);
     103           6 :   gcry_sexp_release (list);
     104           6 :   list = l2;
     105           6 :   l2 = NULL;
     106             : 
     107           6 :   name = gcry_sexp_nth_string (list, 0);
     108           6 :   if (!name)
     109             :     {
     110           0 :       err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
     111           0 :       goto leave;
     112             :     }
     113             : 
     114           6 :   err = gcry_md_open (&md, GCRY_MD_MD5, 0);
     115           6 :   if (err)
     116           0 :     goto leave;
     117             : 
     118           6 :   switch (gcry_pk_map_name (name))
     119             :     {
     120             :     case GCRY_PK_RSA:
     121           1 :       elems = "en";
     122           1 :       gcry_md_write (md, "\0\0\0\x07ssh-rsa", 11);
     123           1 :       break;
     124             : 
     125             :     case GCRY_PK_DSA:
     126           1 :       elems = "pqgy";
     127           1 :       gcry_md_write (md, "\0\0\0\x07ssh-dss", 11);
     128           1 :       break;
     129             : 
     130             :     case GCRY_PK_ECC:
     131           4 :       if (is_eddsa (list))
     132             :         {
     133           1 :           elems = "q";
     134           1 :           blobmode = 1;
     135             :           /* For now there is just one curve, thus no need to switch
     136             :              on it.  */
     137           1 :           gcry_md_write (md, "\0\0\0\x0b" "ssh-ed25519", 15);
     138             :         }
     139             :       else
     140             :         {
     141             :           /* We only support the 3 standard curves for now.  It is
     142             :              just a quick hack.  */
     143           3 :           elems = "q";
     144           3 :           gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20);
     145           3 :           l2 = gcry_sexp_find_token (list, "curve", 0);
     146           3 :           if (!l2)
     147           0 :             elems = "";
     148             :           else
     149             :             {
     150           3 :               gcry_free (name);
     151           3 :               name = gcry_sexp_nth_string (l2, 1);
     152           3 :               gcry_sexp_release (l2);
     153           3 :               l2 = NULL;
     154           3 :               if (!name)
     155           0 :                 elems = "";
     156           3 :               else if (!strcmp (name, "NIST P-256")||!strcmp (name, "nistp256"))
     157           1 :                 gcry_md_write (md, "256\0\0\0\x08nistp256", 15);
     158           2 :               else if (!strcmp (name, "NIST P-384")||!strcmp (name, "nistp384"))
     159           1 :                 gcry_md_write (md, "384\0\0\0\x08nistp384", 15);
     160           1 :               else if (!strcmp (name, "NIST P-521")||!strcmp (name, "nistp521"))
     161           1 :                 gcry_md_write (md, "521\0\0\0\x08nistp521", 15);
     162             :               else
     163           0 :                 elems = "";
     164             :             }
     165           3 :           if (!*elems)
     166           0 :             err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE);
     167             :         }
     168           4 :       break;
     169             : 
     170             :     default:
     171           0 :       elems = "";
     172           0 :       err = gpg_err_make (default_errsource, GPG_ERR_PUBKEY_ALGO);
     173           0 :       break;
     174             :     }
     175           6 :   if (err)
     176           0 :     goto leave;
     177             : 
     178             : 
     179          16 :   for (idx = 0, s = elems; *s; s++, idx++)
     180             :     {
     181          10 :       l2 = gcry_sexp_find_token (list, s, 1);
     182          10 :       if (!l2)
     183             :         {
     184           0 :           err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
     185           0 :           goto leave;
     186             :         }
     187          10 :       if (blobmode)
     188             :         {
     189             :           const char *blob;
     190             :           size_t bloblen;
     191             :           unsigned char lenbuf[4];
     192             : 
     193           1 :           blob = gcry_sexp_nth_data (l2, 1, &bloblen);
     194           1 :           if (!blob)
     195             :             {
     196           0 :               err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
     197           0 :               goto leave;
     198             :             }
     199           1 :           blob++;
     200           1 :           bloblen--;
     201           1 :           lenbuf[0] = bloblen >> 24;
     202           1 :           lenbuf[1] = bloblen >> 16;
     203           1 :           lenbuf[2] = bloblen >>  8;
     204           1 :           lenbuf[3] = bloblen;
     205           1 :           gcry_md_write (md, lenbuf, 4);
     206           1 :           gcry_md_write (md, blob, bloblen);
     207             :         }
     208             :       else
     209             :         {
     210             :           gcry_mpi_t a;
     211             :           unsigned char *buf;
     212             :           size_t buflen;
     213             : 
     214           9 :           a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
     215           9 :           gcry_sexp_release (l2);
     216           9 :           l2 = NULL;
     217           9 :           if (!a)
     218             :             {
     219           0 :               err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
     220           0 :               goto leave;
     221             :             }
     222             : 
     223           9 :           err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a);
     224           9 :           gcry_mpi_release (a);
     225           9 :           if (err)
     226           0 :             goto leave;
     227           9 :           gcry_md_write (md, buf, buflen);
     228           9 :           gcry_free (buf);
     229             :         }
     230             :     }
     231             : 
     232           6 :   *r_fpr = gcry_malloc (as_string? 61:20);
     233           6 :   if (!*r_fpr)
     234             :     {
     235           0 :       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
     236           0 :       goto leave;
     237             :     }
     238             : 
     239           6 :   if (as_string)
     240             :     {
     241           6 :       bin2hexcolon (gcry_md_read (md, GCRY_MD_MD5), 16, *r_fpr);
     242           6 :       *r_len = 3*16+1;
     243           6 :       strlwr (*r_fpr);
     244             :     }
     245             :   else
     246             :     {
     247           0 :       memcpy (*r_fpr, gcry_md_read (md, GCRY_MD_MD5), 16);
     248           0 :       *r_len = 16;
     249             :     }
     250           6 :   err = 0;
     251             : 
     252             :  leave:
     253           6 :   gcry_free (name);
     254           6 :   gcry_sexp_release (l2);
     255           6 :   gcry_md_close (md);
     256           6 :   gcry_sexp_release (list);
     257           6 :   return err;
     258             : }
     259             : 
     260             : /* Return the Secure Shell type fingerprint for KEY.  The length of
     261             :    the fingerprint is returned at R_LEN and the fingerprint itself at
     262             :    R_FPR.  In case of an error an error code is returned and NULL
     263             :    stored at R_FPR.  */
     264             : gpg_error_t
     265           0 : ssh_get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len)
     266             : {
     267           0 :   return get_fingerprint (key, r_fpr, r_len, 0);
     268             : }
     269             : 
     270             : 
     271             : /* Return the Secure Shell type fingerprint for KEY as a string.  The
     272             :    fingerprint is mallcoed and stored at R_FPRSTR.  In case of an
     273             :    error an error code is returned and NULL stored at R_FPRSTR.  */
     274             : gpg_error_t
     275           6 : ssh_get_fingerprint_string (gcry_sexp_t key, char **r_fprstr)
     276             : {
     277             :   gpg_error_t err;
     278             :   size_t dummy;
     279             :   void *string;
     280             : 
     281           6 :   err = get_fingerprint (key, &string, &dummy, 1);
     282           6 :   *r_fprstr = string;
     283           6 :   return err;
     284             : }

Generated by: LCOV version 1.11