LCOV - code coverage report
Current view: top level - tools - gpgkey2ssh.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 148 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 3 0.0 %

          Line data    Source code
       1             : /* gpgkey2ssh.c - Converter  (Debug helper)
       2             :  *      Copyright (C) 2005 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG is distributed in the hope that it will be useful, but WITHOUT
      12             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      13             :  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      14             :  * License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : /* 
      21             :    FIXME:  This tool needs some cleanup:
      22             : 
      23             :    - Do not use assert() for error output.
      24             :    - Add proper option parsing and standard options.
      25             :    - retrieve_key_material needs to take the ordinal at field 1 in account.
      26             :    0 Write a man page.
      27             : */
      28             : 
      29             : #include <config.h>
      30             : 
      31             : #include <gcrypt.h>
      32             : #include <unistd.h>
      33             : #include <stdlib.h>
      34             : #include <assert.h>
      35             : #include <stdio.h>
      36             : #include <errno.h>
      37             : 
      38             : #include "util.h"
      39             : #include "sysutils.h"
      40             : 
      41             : 
      42             : 
      43             : typedef struct pkdbuf
      44             : {
      45             :   unsigned char *buffer;
      46             :   size_t buffer_n;
      47             : } pkdbuf_t;
      48             : 
      49             : 
      50             : 
      51             : /* Retrieve the public key material for the RSA key, whose fingerprint
      52             :    is FPR, from gpg output, which can be read through the stream FP.
      53             :    The RSA modulus will be stored at the address of M and MLEN, the
      54             :    public exponent at E and ELEN.  Returns zero on success, an error
      55             :    code on failure.  Caller must release the allocated buffers at M
      56             :    and E if the function returns success.  */
      57             : static gpg_error_t
      58           0 : retrieve_key_material (FILE *fp, const char *hexkeyid, int *algorithm_id,
      59             :                        pkdbuf_t **pkdbuf, size_t *pkdbuf_n)
      60             : {
      61             :   pkdbuf_t *pkdbuf_new;
      62             :   pkdbuf_t *pkdbuf_tmp;
      63             :   size_t pkdbuf_new_n;
      64           0 :   gcry_error_t err = 0;
      65           0 :   char *line = NULL;    /* read_line() buffer. */
      66           0 :   size_t line_size = 0; /* Helper for for read_line. */
      67           0 :   int found_key = 0;    /* Helper to find a matching key. */
      68             :   int id;
      69             :   unsigned char *buffer;
      70             :   size_t buffer_n;
      71             :   int i;
      72             : 
      73           0 :   pkdbuf_new = NULL;
      74           0 :   pkdbuf_new_n = 0;
      75           0 :   id = 0;
      76             : 
      77             :   /* Loop over all records until we have found the subkey
      78             :      corresponsing to the fingerprint. Inm general the first record
      79             :      should be the pub record, but we don't rely on that.  Given that
      80             :      we only need to look at one key, it is sufficient to compare the
      81             :      keyid so that we don't need to look at "fpr" records. */
      82             :   for (;;)
      83             :     {
      84             :       char *p;
      85             :       char *fields[6];
      86             :       int nfields;
      87             :       size_t max_length;
      88             :       gcry_mpi_t mpi;
      89             : 
      90           0 :       max_length = 4096;
      91           0 :       i = read_line (fp, &line, &line_size, &max_length);
      92           0 :       if (!i)
      93           0 :         break; /* EOF. */
      94           0 :       if (i < 0)
      95             :         {
      96           0 :           err = gpg_error_from_syserror ();
      97           0 :           goto leave; /* Error. */
      98             :         }
      99           0 :       if (!max_length)
     100             :         {
     101           0 :           err = gpg_error (GPG_ERR_TRUNCATED);
     102           0 :           goto leave;  /* Line truncated - we better stop processing.  */
     103             :         }
     104             : 
     105             :       /* Parse the line into fields. */
     106           0 :       for (nfields=0, p=line; p && nfields < DIM (fields); nfields++)
     107             :         {
     108           0 :           fields[nfields] = p;
     109           0 :           p = strchr (p, ':');
     110           0 :           if (p)
     111           0 :             *(p++) = 0;
     112             :         }
     113           0 :       if (!nfields)
     114           0 :         continue; /* No fields at all - skip line.  */
     115             : 
     116           0 :       if (!found_key)
     117             :         {
     118           0 :           if ( (!strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
     119           0 :                && nfields > 4 &&
     120           0 :                (((strlen (hexkeyid) == 8)
     121           0 :                  && (strlen (fields[4]) == 16)
     122           0 :                  && (! strcmp (fields[4] + 8, hexkeyid)))
     123           0 :                 || ((strlen (hexkeyid) == 16)
     124           0 :                     && (! strcmp (fields[4], hexkeyid)))))
     125             :             {
     126           0 :               found_key = 1;
     127             :               /* Save algorithm ID.  */
     128           0 :               id = atoi (fields[3]);
     129             :             }
     130           0 :           continue;
     131             :         }
     132             :       
     133           0 :       if ( !strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
     134             :         break; /* Next key - stop.  */
     135             : 
     136           0 :       if ( strcmp (fields[0], "pkd") )
     137           0 :         continue; /* Not a key data record.  */
     138             : 
     139             :       /* FIXME, necessary?  */
     140             : 
     141           0 :       i = atoi (fields[1]);
     142           0 :       if ((nfields < 4) || (i < 0))
     143             :         {
     144           0 :           err = gpg_error (GPG_ERR_GENERAL);
     145           0 :           goto leave;
     146             :         }
     147             : 
     148           0 :       err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_HEX, fields[3], 0, NULL);
     149           0 :       if (err)
     150           0 :         mpi = NULL;
     151             : 
     152           0 :       err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &buffer, &buffer_n, mpi);
     153           0 :       gcry_mpi_release (mpi);
     154           0 :       if (err)
     155           0 :         goto leave;
     156             : 
     157           0 :       pkdbuf_tmp = xrealloc (pkdbuf_new, sizeof (*pkdbuf_new) * (pkdbuf_new_n + 1));
     158           0 :       if (pkdbuf_new != pkdbuf_tmp)
     159           0 :         pkdbuf_new = pkdbuf_tmp;
     160           0 :       pkdbuf_new[pkdbuf_new_n].buffer = buffer;
     161           0 :       pkdbuf_new[pkdbuf_new_n].buffer_n = buffer_n;
     162           0 :       pkdbuf_new_n++;
     163           0 :     }
     164             : 
     165           0 :   *algorithm_id = id;
     166           0 :   *pkdbuf = pkdbuf_new;
     167           0 :   *pkdbuf_n = pkdbuf_new_n;
     168             : 
     169             :  leave:
     170             : 
     171           0 :   if (err)
     172           0 :     if (pkdbuf_new)
     173             :       {
     174           0 :         for (i = 0; i < pkdbuf_new_n; i++)
     175           0 :           xfree (pkdbuf_new[i].buffer);
     176           0 :         xfree (pkdbuf_new);
     177             :       }
     178           0 :   xfree (line);
     179             : 
     180           0 :   return err;
     181             : }
     182             : 
     183             : 
     184             : 
     185             : int
     186           0 : key_to_blob (unsigned char **blob, size_t *blob_n, const char *identifier, ...)
     187             : {
     188             :   unsigned char *blob_new;
     189             :   size_t blob_new_n;
     190             :   unsigned char uint32_buffer[4];
     191             :   u32 identifier_n;
     192             :   FILE *stream;
     193             :   va_list ap;
     194             :   int ret;
     195             :   pkdbuf_t *pkd;
     196             : 
     197           0 :   stream = gnupg_tmpfile ();
     198           0 :   assert (stream);
     199             : 
     200           0 :   identifier_n = strlen (identifier);
     201           0 :   uint32_buffer[0] = identifier_n >> 24;
     202           0 :   uint32_buffer[1] = identifier_n >> 16;
     203           0 :   uint32_buffer[2] = identifier_n >>  8;
     204           0 :   uint32_buffer[3] = identifier_n >>  0;
     205           0 :   ret = fwrite (uint32_buffer, sizeof (uint32_buffer), 1, stream);
     206           0 :   assert (ret == 1);
     207           0 :   ret = fwrite (identifier, identifier_n, 1, stream);
     208           0 :   assert (ret == 1);
     209             : 
     210           0 :   va_start (ap, identifier);
     211             :   while (1)
     212             :     {
     213           0 :       pkd = va_arg (ap, pkdbuf_t *);
     214           0 :       if (! pkd)
     215           0 :         break;
     216             : 
     217           0 :       uint32_buffer[0] = pkd->buffer_n >> 24;
     218           0 :       uint32_buffer[1] = pkd->buffer_n >> 16;
     219           0 :       uint32_buffer[2] = pkd->buffer_n >>  8;
     220           0 :       uint32_buffer[3] = pkd->buffer_n >>  0;
     221           0 :       ret = fwrite (uint32_buffer, sizeof (uint32_buffer), 1, stream);
     222           0 :       assert (ret == 1);
     223           0 :       ret = fwrite (pkd->buffer, pkd->buffer_n, 1, stream);
     224           0 :       assert (ret == 1);
     225           0 :     }
     226             : 
     227           0 :   va_end (ap);
     228             : 
     229           0 :   blob_new_n = ftell (stream);
     230           0 :   rewind (stream);
     231             : 
     232           0 :   blob_new = xmalloc (blob_new_n);
     233           0 :   ret = fread (blob_new, blob_new_n, 1, stream);
     234           0 :   assert (ret == 1);
     235             : 
     236           0 :   *blob = blob_new;
     237           0 :   *blob_n = blob_new_n;
     238             : 
     239           0 :   fclose (stream);
     240             : 
     241           0 :   return 0;
     242             : }
     243             : 
     244             : int
     245           0 : main (int argc, char **argv)
     246             : {
     247             :   const char *keyid;
     248             :   int algorithm_id;
     249             :   pkdbuf_t *pkdbuf;
     250             :   size_t pkdbuf_n;
     251           0 :   char *command = NULL;
     252             :   FILE *fp;
     253             :   int ret;
     254             :   gcry_error_t err;
     255             :   unsigned char *blob;
     256             :   size_t blob_n;
     257             :   struct b64state b64_state;
     258             :   const char *identifier;
     259             : 
     260           0 :   pkdbuf = NULL;
     261           0 :   pkdbuf_n = 0;
     262             : 
     263           0 :   algorithm_id = 0;  /* (avoid cc warning) */
     264           0 :   identifier = NULL; /* (avoid cc warning) */
     265             : 
     266           0 :   if (argc != 2)
     267             :     {
     268           0 :       fprintf (stderr, "Usage: %s KEYID\n", argv[0]);
     269           0 :       exit (1);
     270             :     }
     271           0 :   if (strcmp (argv[1], "--help") == 0)
     272             :     {
     273           0 :       fprintf (stderr, "Usage: %s KEYID\n", argv[0]);
     274           0 :       fprintf (stderr, "\n");
     275           0 :       fprintf (stderr,
     276             :                "Convert a gpg key to a format appropriate for inclusion in an\n"
     277             :                "ssh authorized_keys file.\n");
     278           0 :       exit (0);
     279             :     }
     280             : 
     281           0 :   keyid = argv[1];
     282             : 
     283           0 :   asprintf (&command,
     284             :             "gpg2 --list-keys --with-colons --with-key-data '%s'",
     285             :             keyid);
     286           0 :   if (! command)
     287             :     {
     288           0 :       fprintf (stderr, "Out of memory.\n");
     289           0 :       exit (1);
     290             :     }
     291             : 
     292           0 :   fp = popen (command, "r");
     293           0 :   if (! fp)
     294             :     {
     295           0 :       fprintf (stderr, "Failed to running: '%s'\n", command);
     296           0 :       exit (1);
     297             :     }
     298             : 
     299           0 :   err = retrieve_key_material (fp, keyid, &algorithm_id, &pkdbuf, &pkdbuf_n);
     300           0 :   if (err)
     301             :     {
     302           0 :       fprintf (stderr, "Error looking up key: %s\n", gpg_strerror (err));
     303           0 :       exit (1);
     304             :     }
     305           0 :   if (! ((algorithm_id == 1) || (algorithm_id == 17)))
     306             :     {
     307           0 :       fprintf (stderr, "Unsupported algorithm: %d\n", algorithm_id);
     308           0 :       exit (1);
     309             :     }
     310             : 
     311           0 :   if (algorithm_id == 1)
     312             :     {
     313           0 :       identifier = "ssh-rsa";
     314           0 :       ret = key_to_blob (&blob, &blob_n, identifier,
     315             :                          &pkdbuf[1], &pkdbuf[0], NULL);
     316             :     }
     317           0 :   else if (algorithm_id == 17)
     318             :     {
     319           0 :       identifier = "ssh-dss";
     320           0 :       ret = key_to_blob (&blob, &blob_n, identifier,
     321             :                          &pkdbuf[0], &pkdbuf[1], &pkdbuf[2], &pkdbuf[3], NULL);
     322             :     }
     323           0 :   assert (! ret);
     324             : 
     325           0 :   printf ("%s ", identifier);
     326             : 
     327           0 :   err = b64enc_start (&b64_state, stdout, "");
     328           0 :   assert (! err);
     329           0 :   err = b64enc_write (&b64_state, blob, blob_n);
     330           0 :   assert (! err);
     331           0 :   err = b64enc_finish (&b64_state);
     332           0 :   assert (! err);
     333             : 
     334           0 :   printf (" COMMENT\n");
     335             : 
     336           0 :   return 0;
     337             : }

Generated by: LCOV version 1.11