1 #include <gnutls/gnutls.h>
2 #include <gnutls/openpgp.h>
3 #include <gnutls/x509.h>
14 Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
15 Date: Tue, 01 Apr 2008
16 License: GPL v3 or later
18 monkeysphere private key translator: execute this with an
19 ASCII-armored private RSA key on stdin (at the moment, only
20 passphraseless keys work).
22 It will spit out a PEM-encoded version of the key on stdout, which
23 can be fed into ssh-add like this:
25 gpg --export-secret-keys $KEYID | monkeysphere | ssh-add -c /dev/stdin
27 Requirements: I've only built this so far with GnuTLS v2.3.4 --
28 version 2.2.0 does not contain the appropriate pieces.
30 Notes: gpgkey2ssh doesn't seem to provide the same public
33 0 wt215@squeak:~/monkeysphere$ gpg --export-secret-keys 1DCDF89F | ~dkg/src/monkeysphere/monkeysphere | ssh-add -c /dev/stdin
35 OpenPGP RSA Key, with 1024 bits
36 Identity added: /dev/stdin (/dev/stdin)
37 The user has to confirm each use of the key
38 0 wt215@squeak:~/monkeysphere$ ssh-add -L
39 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC9gWQqfrnhQKDQnND/3eOexpddE64J+1zp9fcyCje7H5LKclb6DBV2HS6WgW32PJhIzvP+fYZM3dzXea3fpv14y1SicXiRBDgF9SnsNA1qWn2RyzkLcKy7PmM0PDYtU1oiLTcQj/xkWcqW2sLKHT/WW+vZP5XP7RMGN/yWNMfE2Q== /dev/stdin
40 0 wt215@squeak:~/monkeysphere$ gpgkey2ssh 1DCDF89F
41 ssh-rsa AAAAB3NzaC1yc2EAAACBAL2BZCp+ueFAoNCc0P/d457Gl10Trgn7XOn19zIKN7sfkspyVvoMFXYdLpaBbfY8mEjO8/59hkzd3Nd5rd+m/XjLVKJxeJEEOAX1Kew0DWpafZHLOQtwrLs+YzQ8Ni1TWiItNxCP/GRZypbawsodP9Zb69k/lc/tEwY3/JY0x8TZAAAAAwEAAQ== COMMENT
42 0 wt215@squeak:~/monkeysphere$
47 void err(const char* fmt, ...) {
50 vfprintf(stderr, fmt, ap);
55 void init_datum(gnutls_datum_t* d) {
59 void free_datum(gnutls_datum_t* d) {
65 /* read the passed-in string, store in a single datum */
66 int set_datum_string(gnutls_datum_t* d, const char* s) {
67 unsigned int x = strlen(s)+1;
68 unsigned char* c = NULL;
70 c = gnutls_realloc(d->data, x);
75 memcpy(d->data, s, x);
79 /* read the passed-in file descriptor until EOF, store in a single
81 int set_datum_fd(gnutls_datum_t* d, int fd) {
82 unsigned int bufsize = 1024;
85 FILE* f = fdopen(fd, "r");
86 if (bufsize > d->size) {
88 d->data = gnutls_realloc(d->data, bufsize);
89 if (d->data == NULL) {
90 err("out of memory!\n");
99 err("could not fdopen FD %d\n", fd);
102 while (!feof(f) && !ferror(f)) {
103 if (len == bufsize) {
104 /* allocate more space by doubling: */
106 d->data = gnutls_realloc(d->data, bufsize);
107 if (d->data == NULL) {
108 err("out of memory!\n");
113 len += fread(d->data + len, 1, bufsize - len, f);
114 /* err("read %d bytes\n", len); */
117 err("Error reading from fd %d (error: %d) (error: %d '%s')\n", fd, ferror(f), errno, strerror(errno));
121 /* touch up buffer size to match reality: */
122 d->data = gnutls_realloc(d->data, len);
127 /* read the file indicated (by na1me) in the fname parameter. store
128 its entire contents in a single datum. */
129 int set_datum_file(gnutls_datum_t* d, const char* fname) {
131 unsigned char* c = NULL;
135 if (0 != stat(fname, &sbuf)) {
136 err("failed to stat '%s'\n", fname);
140 c = gnutls_realloc(d->data, sbuf.st_size);
142 err("failed to allocate %d bytes for '%s'\n", sbuf.st_size, fname);
147 d->size = sbuf.st_size;
148 file = fopen(fname, "r");
150 err("failed to open '%s' for reading\n", fname);
154 x = fread(d->data, d->size, 1, file);
156 err("tried to read %d bytes, read %d instead from '%s'\n", d->size, x, fname);
165 int main(int argc, char* argv[]) {
166 const char* version = NULL;
168 gnutls_x509_privkey_t x509_privkey;
173 const char *certfile, *keyfile;
174 gnutls_certificate_credentials_t pgp_creds;
176 gnutls_datum_t m, e, d, p, q, u;
177 /* gnutls_x509_crt_t crt; */
179 gnutls_openpgp_privkey_t pgp_privkey;
180 gnutls_openpgp_crt_fmt_t pgp_format;
181 gnutls_pk_algorithm_t pgp_algo;
182 unsigned int pgp_bits;
184 char output_data[10240];
185 size_t ods = sizeof(output_data);
195 if (ret = gnutls_global_init(), ret) {
196 err("Failed to do gnutls_global_init() (error: %d)\n", ret);
202 version = gnutls_check_version(NULL);
205 err("gnutls version: %s\n", version);
207 err("no version found!\n");
211 if (ret = gnutls_x509_privkey_init(&x509_privkey), ret) {
212 err("Failed to initialize X.509 private key (error: %d)\n", ret);
216 if (ret = gnutls_openpgp_privkey_init(&pgp_privkey), ret) {
217 err("Failed to initialized OpenPGP private key (error: %d)\n", ret);
221 /* slurp in the private key from stdin */
222 if (ret = set_datum_fd(&data, 0), ret) {
223 err("didn't read file descriptor 0\n");
227 /* Or, instead, read in key from a file name:
228 if (ret = set_datum_file(&data, argv[1]), ret) {
229 err("didn't read file '%s'\n", argv[1]);
234 /* treat the passed file as an X.509 private key, and extract its
237 /* if (ret = gnutls_x509_privkey_import(x509_privkey, &data, GNUTLS_X509_FMT_PEM), ret) { */
238 /* err("Failed to import the X.509 key (error: %d)\n", ret); */
241 /* gnutls_x509_privkey_export_rsa_raw(x509_privkey, &m, &e, &d, &p, &q, &u); */
243 /* try to print the PEM-encoded private key: */
244 /* ret = gnutls_x509_privkey_export (x509_privkey, */
245 /* GNUTLS_X509_FMT_PEM, */
248 /* printf("ret: %u; ods: %u;\n", ret, ods); */
249 /* if (ret == 0) { */
250 /* write(0, output_data, ods); */
254 /* format could be either: GNUTLS_OPENPGP_FMT_RAW,
255 GNUTLS_OPENPGP_FMT_BASE64 */
256 pgp_format = GNUTLS_OPENPGP_FMT_RAW;
257 if (ret = gnutls_openpgp_privkey_import (pgp_privkey, &data, pgp_format, NULL, 0), ret) {
258 err("failed to import the OpenPGP private key (error: %d)\n", ret);
261 pgp_algo = gnutls_openpgp_privkey_get_pk_algorithm(pgp_privkey, &pgp_bits);
263 err("failed to get OpenPGP key algorithm (error: %d)\n", pgp_algo);
266 if (pgp_algo != GNUTLS_PK_RSA) {
267 err("OpenPGP Key was not RSA (actual algorithm was: %d)\n", pgp_algo);
271 err("OpenPGP RSA Key, with %d bits\n", pgp_bits);
274 ret = gnutls_openpgp_privkey_export_rsa_raw(pgp_privkey, &m, &e, &d, &p, &q, &u);
275 if (GNUTLS_E_SUCCESS != ret) {
276 err ("failed to export RSA key parameters (error: %0x)\n", ret);
280 ret = gnutls_x509_privkey_import_rsa_raw (x509_privkey, &m, &e, &d, &p, &q, &u);
281 if (GNUTLS_E_SUCCESS != ret) {
282 err ("failed to import RSA key parameters (error: %d)\n", ret);
285 /* const gnutls_datum_t * m, const gnutls_datum_t * e, const gnutls_datum_t * d, const gnutls_datum_t * p, const gnutls_datum_t * q, const gnutls_datum_t * u); */
287 ret = gnutls_x509_privkey_fix(x509_privkey);
289 err("failed to fix up the private key in X.509 format (error: %d)\n", ret);
292 ret = gnutls_x509_privkey_export (x509_privkey,
296 printf("ret: %u; ods: %u;\n", ret, ods);
298 write(1, output_data, ods);
302 gnutls_x509_privkey_deinit(x509_privkey);
303 gnutls_openpgp_privkey_deinit(pgp_privkey);
304 gnutls_global_deinit();