Make use of the card's extended capabilities.
[gnupg.git] / tools / gpgkey2ssh.c
blob903fb5bd62719dad0e347a6f63518f399e9b1309
1 /* gpgkey2ssh.c - Converter (Debug helper)
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 /*
21 FIXME: This tool needs some cleanup:
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.
29 #include <config.h>
31 #include <gcrypt.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <assert.h>
35 #include <stdio.h>
36 #include <errno.h>
38 #include "util.h"
39 #include "sysutils.h"
43 typedef struct pkdbuf
45 unsigned char *buffer;
46 size_t buffer_n;
47 } pkdbuf_t;
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 retrieve_key_material (FILE *fp, const char *hexkeyid, int *algorithm_id,
59 pkdbuf_t **pkdbuf, size_t *pkdbuf_n)
61 pkdbuf_t *pkdbuf_new;
62 pkdbuf_t *pkdbuf_tmp;
63 size_t pkdbuf_new_n;
64 gcry_error_t err = 0;
65 char *line = NULL; /* read_line() buffer. */
66 size_t line_size = 0; /* Helper for for read_line. */
67 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;
73 pkdbuf_new = NULL;
74 pkdbuf_new_n = 0;
75 id = 0;
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 (;;)
84 char *p;
85 char *fields[6];
86 int nfields;
87 size_t max_length;
88 gcry_mpi_t mpi;
90 max_length = 4096;
91 i = read_line (fp, &line, &line_size, &max_length);
92 if (!i)
93 break; /* EOF. */
94 if (i < 0)
96 err = gpg_error_from_syserror ();
97 goto leave; /* Error. */
99 if (!max_length)
101 err = gpg_error (GPG_ERR_TRUNCATED);
102 goto leave; /* Line truncated - we better stop processing. */
105 /* Parse the line into fields. */
106 for (nfields=0, p=line; p && nfields < DIM (fields); nfields++)
108 fields[nfields] = p;
109 p = strchr (p, ':');
110 if (p)
111 *(p++) = 0;
113 if (!nfields)
114 continue; /* No fields at all - skip line. */
116 if (!found_key)
118 if ( (!strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
119 && nfields > 4 &&
120 (((strlen (hexkeyid) == 8)
121 && (strlen (fields[4]) == 16)
122 && (! strcmp (fields[4] + 8, hexkeyid)))
123 || ((strlen (hexkeyid) == 16)
124 && (! strcmp (fields[4], hexkeyid)))))
126 found_key = 1;
127 /* Save algorithm ID. */
128 id = atoi (fields[3]);
130 continue;
133 if ( !strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
134 break; /* Next key - stop. */
136 if ( strcmp (fields[0], "pkd") )
137 continue; /* Not a key data record. */
139 /* FIXME, necessary? */
141 i = atoi (fields[1]);
142 if ((nfields < 4) || (i < 0))
144 err = gpg_error (GPG_ERR_GENERAL);
145 goto leave;
148 err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_HEX, fields[3], 0, NULL);
149 if (err)
150 mpi = NULL;
152 err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &buffer, &buffer_n, mpi);
153 gcry_mpi_release (mpi);
154 if (err)
155 goto leave;
157 pkdbuf_tmp = xrealloc (pkdbuf_new, sizeof (*pkdbuf_new) * (pkdbuf_new_n + 1));
158 if (pkdbuf_new != pkdbuf_tmp)
159 pkdbuf_new = pkdbuf_tmp;
160 pkdbuf_new[pkdbuf_new_n].buffer = buffer;
161 pkdbuf_new[pkdbuf_new_n].buffer_n = buffer_n;
162 pkdbuf_new_n++;
165 *algorithm_id = id;
166 *pkdbuf = pkdbuf_new;
167 *pkdbuf_n = pkdbuf_new_n;
169 leave:
171 if (err)
172 if (pkdbuf_new)
174 for (i = 0; i < pkdbuf_new_n; i++)
175 xfree (pkdbuf_new[i].buffer);
176 xfree (pkdbuf_new);
178 xfree (line);
180 return err;
186 key_to_blob (unsigned char **blob, size_t *blob_n, const char *identifier, ...)
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;
197 stream = gnupg_tmpfile ();
198 assert (stream);
200 identifier_n = strlen (identifier);
201 uint32_buffer[0] = identifier_n >> 24;
202 uint32_buffer[1] = identifier_n >> 16;
203 uint32_buffer[2] = identifier_n >> 8;
204 uint32_buffer[3] = identifier_n >> 0;
205 ret = fwrite (uint32_buffer, sizeof (uint32_buffer), 1, stream);
206 assert (ret == 1);
207 ret = fwrite (identifier, identifier_n, 1, stream);
208 assert (ret == 1);
210 va_start (ap, identifier);
211 while (1)
213 pkd = va_arg (ap, pkdbuf_t *);
214 if (! pkd)
215 break;
217 uint32_buffer[0] = pkd->buffer_n >> 24;
218 uint32_buffer[1] = pkd->buffer_n >> 16;
219 uint32_buffer[2] = pkd->buffer_n >> 8;
220 uint32_buffer[3] = pkd->buffer_n >> 0;
221 ret = fwrite (uint32_buffer, sizeof (uint32_buffer), 1, stream);
222 assert (ret == 1);
223 ret = fwrite (pkd->buffer, pkd->buffer_n, 1, stream);
224 assert (ret == 1);
227 blob_new_n = ftell (stream);
228 rewind (stream);
230 blob_new = xmalloc (blob_new_n);
231 ret = fread (blob_new, blob_new_n, 1, stream);
232 assert (ret == 1);
234 *blob = blob_new;
235 *blob_n = blob_new_n;
237 fclose (stream);
239 return 0;
243 main (int argc, char **argv)
245 const char *keyid;
246 int algorithm_id;
247 pkdbuf_t *pkdbuf;
248 size_t pkdbuf_n;
249 char *command;
250 FILE *fp;
251 int ret;
252 gcry_error_t err;
253 unsigned char *blob;
254 size_t blob_n;
255 struct b64state b64_state;
256 const char *identifier;
258 pkdbuf = NULL;
259 pkdbuf_n = 0;
261 algorithm_id = 0; /* (avoid cc warning) */
262 identifier = NULL; /* (avoid cc warning) */
264 assert (argc == 2);
266 keyid = argv[1];
268 ret = asprintf (&command,
269 "gpg --list-keys --with-colons --with-key-data '%s'",
270 keyid);
271 assert (ret > 0);
273 fp = popen (command, "r");
274 assert (fp);
276 err = retrieve_key_material (fp, keyid, &algorithm_id, &pkdbuf, &pkdbuf_n);
277 assert (! err);
278 assert ((algorithm_id == 1) || (algorithm_id == 17));
280 if (algorithm_id == 1)
282 identifier = "ssh-rsa";
283 ret = key_to_blob (&blob, &blob_n, identifier,
284 &pkdbuf[1], &pkdbuf[0], NULL);
286 else if (algorithm_id == 17)
288 identifier = "ssh-dss";
289 ret = key_to_blob (&blob, &blob_n, identifier,
290 &pkdbuf[0], &pkdbuf[1], &pkdbuf[2], &pkdbuf[3], NULL);
292 assert (! ret);
294 printf ("%s ", identifier);
296 err = b64enc_start (&b64_state, stdout, "");
297 assert (! err);
298 err = b64enc_write (&b64_state, blob, blob_n);
299 assert (! err);
300 err = b64enc_finish (&b64_state);
301 assert (! err);
303 printf (" COMMENT\n");
305 return 0;