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/>.
36 unsigned char *buffer
;
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. */
49 retrieve_key_material (FILE *fp
, const char *hexkeyid
, int *algorithm_id
,
50 pkdbuf_t
**pkdbuf
, size_t *pkdbuf_n
)
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. */
60 unsigned char *buffer
;
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. */
82 i
= read_line (fp
, &line
, &line_size
, &max_length
);
87 err
= gpg_error_from_syserror ();
88 goto leave
; /* Error. */
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
++)
105 continue; /* No fields at all - skip line. */
109 if ( (!strcmp (fields
[0], "sub") || !strcmp (fields
[0], "pub") )
111 (((strlen (hexkeyid
) == 8)
112 && (strlen (fields
[4]) == 16)
113 && (! strcmp (fields
[4] + 8, hexkeyid
)))
114 || ((strlen (hexkeyid
) == 16)
115 && (! strcmp (fields
[4], hexkeyid
)))))
118 /* Save algorithm ID. */
119 id
= atoi (fields
[3]);
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
);
139 err
= gcry_mpi_scan (&mpi
, GCRYMPI_FMT_HEX
, fields
[3], 0, NULL
);
143 err
= gcry_mpi_aprint (GCRYMPI_FMT_STD
, &buffer
, &buffer_n
, mpi
);
144 gcry_mpi_release (mpi
);
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
;
157 *pkdbuf
= pkdbuf_new
;
158 *pkdbuf_n
= pkdbuf_new_n
;
165 for (i
= 0; i
< pkdbuf_new_n
; i
++)
166 xfree (pkdbuf_new
[i
].buffer
);
177 key_to_blob (unsigned char **blob
, size_t *blob_n
, const char *identifier
, ...)
179 unsigned char *blob_new
;
181 unsigned char uint32_buffer
[4];
188 stream
= gnupg_tmpfile ();
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
);
198 ret
= fwrite (identifier
, identifier_n
, 1, stream
);
201 va_start (ap
, identifier
);
204 pkd
= va_arg (ap
, pkdbuf_t
*);
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
);
214 ret
= fwrite (pkd
->buffer
, pkd
->buffer_n
, 1, stream
);
218 blob_new_n
= ftell (stream
);
221 blob_new
= xmalloc (blob_new_n
);
222 ret
= fread (blob_new
, blob_new_n
, 1, stream
);
226 *blob_n
= blob_new_n
;
234 main (int argc
, char **argv
)
246 struct b64state b64_state
;
247 const char *identifier
;
252 algorithm_id
= 0; /* (avoid cc warning) */
253 identifier
= NULL
; /* (avoid cc warning) */
259 ret
= asprintf (&command
,
260 "gpg --list-keys --with-colons --with-key-data '%s'",
264 fp
= popen (command
, "r");
267 err
= retrieve_key_material (fp
, keyid
, &algorithm_id
, &pkdbuf
, &pkdbuf_n
);
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
);
285 printf ("%s ", identifier
);
287 err
= b64enc_start (&b64_state
, stdout
, "");
289 err
= b64enc_write (&b64_state
, blob
, blob_n
);
291 err
= b64enc_finish (&b64_state
);
294 printf (" COMMENT\n");