2008-10-21 Marcus Brinkmann <marcus@g10code.com>
[gnupg.git] / tools / gpgkey2ssh.c
blob0c0985d4163172ebe57d43607451ab3167ba73ef
1 /* gpgkey2ssh.c - Converter ...
2 * Copyright (C) 2005 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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/>.
20 #include <config.h>
22 #include <gcrypt.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <stdio.h>
27 #include <errno.h>
29 #include "util.h"
30 #include "sysutils.h"
34 typedef struct pkdbuf
36 unsigned char *buffer;
37 size_t buffer_n;
38 } pkdbuf_t;
42 /* Retrieve the public key material for the RSA key, whose fingerprint
43 is FPR, from gpg output, which can be read through the stream FP.
44 The RSA modulus will be stored at the address of M and MLEN, the
45 public exponent at E and ELEN. Returns zero on success, an error
46 code on failure. Caller must release the allocated buffers at M
47 and E if the function returns success. */
48 static gpg_error_t
49 retrieve_key_material (FILE *fp, const char *hexkeyid, int *algorithm_id,
50 pkdbuf_t **pkdbuf, size_t *pkdbuf_n)
52 pkdbuf_t *pkdbuf_new;
53 pkdbuf_t *pkdbuf_tmp;
54 size_t pkdbuf_new_n;
55 gcry_error_t err = 0;
56 char *line = NULL; /* read_line() buffer. */
57 size_t line_size = 0; /* Helper for for read_line. */
58 int found_key = 0; /* Helper to find a matching key. */
59 int id;
60 unsigned char *buffer;
61 size_t buffer_n;
62 int i;
64 pkdbuf_new = NULL;
65 pkdbuf_new_n = 0;
66 id = 0;
68 /* Loop over all records until we have found the subkey
69 corresponsing to the fingerprint. Inm general the first record
70 should be the pub record, but we don't rely on that. Given that
71 we only need to look at one key, it is sufficient to compare the
72 keyid so that we don't need to look at "fpr" records. */
73 for (;;)
75 char *p;
76 char *fields[6];
77 int nfields;
78 size_t max_length;
79 gcry_mpi_t mpi;
81 max_length = 4096;
82 i = read_line (fp, &line, &line_size, &max_length);
83 if (!i)
84 break; /* EOF. */
85 if (i < 0)
87 err = gpg_error_from_syserror ();
88 goto leave; /* Error. */
90 if (!max_length)
92 err = gpg_error (GPG_ERR_TRUNCATED);
93 goto leave; /* Line truncated - we better stop processing. */
96 /* Parse the line into fields. */
97 for (nfields=0, p=line; p && nfields < DIM (fields); nfields++)
99 fields[nfields] = p;
100 p = strchr (p, ':');
101 if (p)
102 *(p++) = 0;
104 if (!nfields)
105 continue; /* No fields at all - skip line. */
107 if (!found_key)
109 if ( (!strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
110 && nfields > 4 &&
111 (((strlen (hexkeyid) == 8)
112 && (strlen (fields[4]) == 16)
113 && (! strcmp (fields[4] + 8, hexkeyid)))
114 || ((strlen (hexkeyid) == 16)
115 && (! strcmp (fields[4], hexkeyid)))))
117 found_key = 1;
118 /* Save algorithm ID. */
119 id = atoi (fields[3]);
121 continue;
124 if ( !strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
125 break; /* Next key - stop. */
127 if ( strcmp (fields[0], "pkd") )
128 continue; /* Not a key data record. */
130 /* FIXME, necessary? */
132 i = atoi (fields[1]);
133 if ((nfields < 4) || (i < 0))
135 err = gpg_error (GPG_ERR_GENERAL);
136 goto leave;
139 err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_HEX, fields[3], 0, NULL);
140 if (err)
141 mpi = NULL;
143 err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &buffer, &buffer_n, mpi);
144 gcry_mpi_release (mpi);
145 if (err)
146 goto leave;
148 pkdbuf_tmp = xrealloc (pkdbuf_new, sizeof (*pkdbuf_new) * (pkdbuf_new_n + 1));
149 if (pkdbuf_new != pkdbuf_tmp)
150 pkdbuf_new = pkdbuf_tmp;
151 pkdbuf_new[pkdbuf_new_n].buffer = buffer;
152 pkdbuf_new[pkdbuf_new_n].buffer_n = buffer_n;
153 pkdbuf_new_n++;
156 *algorithm_id = id;
157 *pkdbuf = pkdbuf_new;
158 *pkdbuf_n = pkdbuf_new_n;
160 leave:
162 if (err)
163 if (pkdbuf_new)
165 for (i = 0; i < pkdbuf_new_n; i++)
166 xfree (pkdbuf_new[i].buffer);
167 xfree (pkdbuf_new);
169 xfree (line);
171 return err;
177 key_to_blob (unsigned char **blob, size_t *blob_n, const char *identifier, ...)
179 unsigned char *blob_new;
180 size_t blob_new_n;
181 unsigned char uint32_buffer[4];
182 u32 identifier_n;
183 FILE *stream;
184 va_list ap;
185 int ret;
186 pkdbuf_t *pkd;
188 stream = gnupg_tmpfile ();
189 assert (stream);
191 identifier_n = strlen (identifier);
192 uint32_buffer[0] = identifier_n >> 24;
193 uint32_buffer[1] = identifier_n >> 16;
194 uint32_buffer[2] = identifier_n >> 8;
195 uint32_buffer[3] = identifier_n >> 0;
196 ret = fwrite (uint32_buffer, sizeof (uint32_buffer), 1, stream);
197 assert (ret == 1);
198 ret = fwrite (identifier, identifier_n, 1, stream);
199 assert (ret == 1);
201 va_start (ap, identifier);
202 while (1)
204 pkd = va_arg (ap, pkdbuf_t *);
205 if (! pkd)
206 break;
208 uint32_buffer[0] = pkd->buffer_n >> 24;
209 uint32_buffer[1] = pkd->buffer_n >> 16;
210 uint32_buffer[2] = pkd->buffer_n >> 8;
211 uint32_buffer[3] = pkd->buffer_n >> 0;
212 ret = fwrite (uint32_buffer, sizeof (uint32_buffer), 1, stream);
213 assert (ret == 1);
214 ret = fwrite (pkd->buffer, pkd->buffer_n, 1, stream);
215 assert (ret == 1);
218 blob_new_n = ftell (stream);
219 rewind (stream);
221 blob_new = xmalloc (blob_new_n);
222 ret = fread (blob_new, blob_new_n, 1, stream);
223 assert (ret == 1);
225 *blob = blob_new;
226 *blob_n = blob_new_n;
228 fclose (stream);
230 return 0;
234 main (int argc, char **argv)
236 const char *keyid;
237 int algorithm_id;
238 pkdbuf_t *pkdbuf;
239 size_t pkdbuf_n;
240 char *command;
241 FILE *fp;
242 int ret;
243 gcry_error_t err;
244 unsigned char *blob;
245 size_t blob_n;
246 struct b64state b64_state;
247 const char *identifier;
249 pkdbuf = NULL;
250 pkdbuf_n = 0;
252 algorithm_id = 0; /* (avoid cc warning) */
253 identifier = NULL; /* (avoid cc warning) */
255 assert (argc == 2);
257 keyid = argv[1];
259 ret = asprintf (&command,
260 "gpg --list-keys --with-colons --with-key-data '%s'",
261 keyid);
262 assert (ret > 0);
264 fp = popen (command, "r");
265 assert (fp);
267 err = retrieve_key_material (fp, keyid, &algorithm_id, &pkdbuf, &pkdbuf_n);
268 assert (! err);
269 assert ((algorithm_id == 1) || (algorithm_id == 17));
271 if (algorithm_id == 1)
273 identifier = "ssh-rsa";
274 ret = key_to_blob (&blob, &blob_n, identifier,
275 &pkdbuf[0], &pkdbuf[1], NULL);
277 else if (algorithm_id == 17)
279 identifier = "ssh-dsa";
280 ret = key_to_blob (&blob, &blob_n, identifier,
281 &pkdbuf[0], &pkdbuf[1], &pkdbuf[2], &pkdbuf[3], NULL);
283 assert (! ret);
285 printf ("%s ", identifier);
287 err = b64enc_start (&b64_state, stdout, "");
288 assert (! err);
289 err = b64enc_write (&b64_state, blob, blob_n);
290 assert (! err);
291 err = b64enc_finish (&b64_state);
292 assert (! err);
294 printf (" COMMENT\n");
296 return 0;