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/>.
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.
45 unsigned char *buffer
;
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. */
58 retrieve_key_material (FILE *fp
, const char *hexkeyid
, int *algorithm_id
,
59 pkdbuf_t
**pkdbuf
, size_t *pkdbuf_n
)
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. */
69 unsigned char *buffer
;
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. */
91 i
= read_line (fp
, &line
, &line_size
, &max_length
);
96 err
= gpg_error_from_syserror ();
97 goto leave
; /* Error. */
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
++)
114 continue; /* No fields at all - skip line. */
118 if ( (!strcmp (fields
[0], "sub") || !strcmp (fields
[0], "pub") )
120 (((strlen (hexkeyid
) == 8)
121 && (strlen (fields
[4]) == 16)
122 && (! strcmp (fields
[4] + 8, hexkeyid
)))
123 || ((strlen (hexkeyid
) == 16)
124 && (! strcmp (fields
[4], hexkeyid
)))))
127 /* Save algorithm ID. */
128 id
= atoi (fields
[3]);
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
);
148 err
= gcry_mpi_scan (&mpi
, GCRYMPI_FMT_HEX
, fields
[3], 0, NULL
);
152 err
= gcry_mpi_aprint (GCRYMPI_FMT_STD
, &buffer
, &buffer_n
, mpi
);
153 gcry_mpi_release (mpi
);
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
;
166 *pkdbuf
= pkdbuf_new
;
167 *pkdbuf_n
= pkdbuf_new_n
;
174 for (i
= 0; i
< pkdbuf_new_n
; i
++)
175 xfree (pkdbuf_new
[i
].buffer
);
186 key_to_blob (unsigned char **blob
, size_t *blob_n
, const char *identifier
, ...)
188 unsigned char *blob_new
;
190 unsigned char uint32_buffer
[4];
197 stream
= gnupg_tmpfile ();
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
);
207 ret
= fwrite (identifier
, identifier_n
, 1, stream
);
210 va_start (ap
, identifier
);
213 pkd
= va_arg (ap
, pkdbuf_t
*);
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
);
223 ret
= fwrite (pkd
->buffer
, pkd
->buffer_n
, 1, stream
);
227 blob_new_n
= ftell (stream
);
230 blob_new
= xmalloc (blob_new_n
);
231 ret
= fread (blob_new
, blob_new_n
, 1, stream
);
235 *blob_n
= blob_new_n
;
243 main (int argc
, char **argv
)
255 struct b64state b64_state
;
256 const char *identifier
;
261 algorithm_id
= 0; /* (avoid cc warning) */
262 identifier
= NULL
; /* (avoid cc warning) */
268 ret
= asprintf (&command
,
269 "gpg --list-keys --with-colons --with-key-data '%s'",
273 fp
= popen (command
, "r");
276 err
= retrieve_key_material (fp
, keyid
, &algorithm_id
, &pkdbuf
, &pkdbuf_n
);
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
);
294 printf ("%s ", identifier
);
296 err
= b64enc_start (&b64_state
, stdout
, "");
298 err
= b64enc_write (&b64_state
, blob
, blob_n
);
300 err
= b64enc_finish (&b64_state
);
303 printf (" COMMENT\n");