638666baabe416ec4c0dcdcbe528db373763bb96
[monkeysphere.git] / main.c
1 #include "gnutls-helpers.h"
2
3 #include <gnutls/openpgp.h>
4 #include <gnutls/x509.h>
5
6 /* 
7    Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
8    Date: Tue, 01 Apr 2008
9    License: GPL v3 or later
10
11    monkeysphere private key translator: execute this with an GPG
12    secret key on stdin (at the moment, only passphraseless RSA keys
13    work).
14
15    It will spit out a PEM-encoded version of the key on stdout, which
16    can be fed into ssh-add like this:
17
18     gpg --export-secret-keys $KEYID | monkeysphere | ssh-add -c /dev/stdin
19
20    Requirements: I've only built this so far with GnuTLS v2.3.4 --
21    version 2.2.0 does not contain the appropriate pieces.
22
23    Notes: gpgkey2ssh doesn't seem to provide the same public
24    keys. Mighty weird!
25
26 0 wt215@squeak:~/monkeysphere$ gpg --export-secret-keys 1DCDF89F | ~dkg/src/monkeysphere/monkeysphere  | ssh-add -c /dev/stdin
27 gnutls version: 2.3.4
28 OpenPGP RSA Key, with 1024 bits
29 Identity added: /dev/stdin (/dev/stdin)
30 The user has to confirm each use of the key
31 0 wt215@squeak:~/monkeysphere$ ssh-add -L
32 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC9gWQqfrnhQKDQnND/3eOexpddE64J+1zp9fcyCje7H5LKclb6DBV2HS6WgW32PJhIzvP+fYZM3dzXea3fpv14y1SicXiRBDgF9SnsNA1qWn2RyzkLcKy7PmM0PDYtU1oiLTcQj/xkWcqW2sLKHT/WW+vZP5XP7RMGN/yWNMfE2Q== /dev/stdin
33 0 wt215@squeak:~/monkeysphere$ gpgkey2ssh 1DCDF89F
34 ssh-rsa AAAAB3NzaC1yc2EAAACBAL2BZCp+ueFAoNCc0P/d457Gl10Trgn7XOn19zIKN7sfkspyVvoMFXYdLpaBbfY8mEjO8/59hkzd3Nd5rd+m/XjLVKJxeJEEOAX1Kew0DWpafZHLOQtwrLs+YzQ8Ni1TWiItNxCP/GRZypbawsodP9Zb69k/lc/tEwY3/JY0x8TZAAAAAwEAAQ== COMMENT
35 0 wt215@squeak:~/monkeysphere$ 
36
37  */
38
39
40
41 int main(int argc, char* argv[]) {
42   gnutls_x509_privkey_t x509_privkey;
43   gnutls_datum_t data, test, clean;
44   int ret;
45
46   /*  
47       const char *certfile, *keyfile;
48       gnutls_certificate_credentials_t pgp_creds;
49   */
50   gnutls_datum_t m, e, d, p, q, u, g, y, x;
51
52   /*  gnutls_x509_crt_t crt; */
53
54   gnutls_openpgp_privkey_t pgp_privkey;
55   gnutls_pk_algorithm_t pgp_algo;
56   unsigned int pgp_bits;
57
58   char output_data[10240];
59   size_t ods = sizeof(output_data);
60
61   init_gnutls();
62   
63   init_datum(&data);
64   init_datum(&test);
65   init_datum(&clean);
66   init_datum(&m);
67   init_datum(&e);
68   init_datum(&d);
69   init_datum(&p);
70   init_datum(&q);
71   init_datum(&u);
72   init_datum(&g);
73   init_datum(&y);
74   init_datum(&x);
75
76
77   if (ret = gnutls_x509_privkey_init(&x509_privkey), ret) {
78     err("Failed to initialize X.509 private key (error: %d)\n", ret);
79     return 1;
80   }
81
82   if (ret = gnutls_openpgp_privkey_init(&pgp_privkey), ret) {
83     err("Failed to initialized OpenPGP private key (error: %d)\n", ret);
84     return 1;
85   }
86
87   /* slurp in the private key from stdin */
88   if (ret = set_datum_fd(&data, 0), ret) {
89     err("didn't read file descriptor 0\n");
90     return 1;
91   }
92
93   /* Or, instead, read in key from a file name: 
94   if (ret = set_datum_file(&data, argv[1]), ret) {
95     err("didn't read file '%s'\n", argv[1]);
96     return 1;
97   }
98 */
99
100   /* treat the passed file as an X.509 private key, and extract its
101      component values: */
102
103 /*   if (ret = gnutls_x509_privkey_import(x509_privkey, &data, GNUTLS_X509_FMT_PEM), ret) { */
104 /*     err("Failed to import the X.509 key (error: %d)\n", ret); */
105 /*     return 1; */
106 /*   } */
107 /*   gnutls_x509_privkey_export_rsa_raw(x509_privkey, &m, &e, &d, &p, &q, &u); */
108
109   /* try to print the PEM-encoded private key: */
110 /*   ret = gnutls_x509_privkey_export (x509_privkey, */
111 /*                                  GNUTLS_X509_FMT_PEM, */
112 /*                                  output_data, */
113 /*                                  &ods); */
114 /*   printf("ret: %u; ods: %u;\n", ret, ods); */
115 /*   if (ret == 0) { */
116 /*     write(0, output_data, ods); */
117 /*   } */
118
119   /* format could be either: GNUTLS_OPENPGP_FMT_RAW,
120      GNUTLS_OPENPGP_FMT_BASE64; if MONKEYSPHERE_RAW is set, use RAW,
121      otherwise, use BASE64: */
122
123   if (getenv("MONKEYSPHERE_RAW")) {
124     err("assuming RAW formatted private keys\n");
125     if (ret = gnutls_openpgp_privkey_import(pgp_privkey, &data, GNUTLS_OPENPGP_FMT_RAW, NULL, 0), ret)
126       err("failed to import the OpenPGP private key in RAW format (error: %d)\n", ret);
127   } else {
128     err("assuming BASE64 formatted private keys\n");
129     if (ret = gnutls_openpgp_privkey_import (pgp_privkey, &data, GNUTLS_OPENPGP_FMT_BASE64, NULL, 0), ret)
130       err("failed to import the OpenPGP private key in BASE64 format (error: %d)\n", ret);
131   }
132
133   pgp_algo = gnutls_openpgp_privkey_get_pk_algorithm(pgp_privkey, &pgp_bits);
134   if (pgp_algo < 0) {
135     err("failed to get OpenPGP key algorithm (error: %d)\n", pgp_algo);
136     return 1;
137   }
138   if (pgp_algo == GNUTLS_PK_RSA) {
139     err("OpenPGP RSA Key, with %d bits\n", pgp_bits);
140     ret = gnutls_openpgp_privkey_export_rsa_raw(pgp_privkey, &m, &e, &d, &p, &q, &u);
141     if (GNUTLS_E_SUCCESS != ret) {
142       err ("failed to export RSA key parameters (error: %d)\n", ret);
143       return 1;
144     }
145
146     ret = gnutls_x509_privkey_import_rsa_raw (x509_privkey, &m, &e, &d, &p, &q, &u); 
147     if (GNUTLS_E_SUCCESS != ret) {
148       err ("failed to import RSA key parameters (error: %d)\n", ret);
149       return 1;
150     }
151   } else if (pgp_algo == GNUTLS_PK_DSA) {
152     err("OpenPGP DSA Key, with %d bits\n", pgp_bits);
153     ret = gnutls_openpgp_privkey_export_dsa_raw(pgp_privkey, &p, &q, &g, &y, &x);
154     if (GNUTLS_E_SUCCESS != ret) {
155       err ("failed to export DSA key parameters (error: %d)\n", ret);
156       return 1;
157     }
158
159     ret = gnutls_x509_privkey_import_dsa_raw (x509_privkey, &p, &q, &g, &y, &x); 
160     if (GNUTLS_E_SUCCESS != ret) {
161       err ("failed to import DSA key parameters (error: %d)\n", ret);
162       return 1;
163     }
164   } else {
165     err("OpenPGP Key was not RSA or DSA -- can't deal! (actual algorithm was: %d)\n", pgp_algo);
166     return 1;
167   }
168   
169   ret = gnutls_x509_privkey_fix(x509_privkey);
170   if (ret != 0) {
171     err("failed to fix up the private key in X.509 format (error: %d)\n", ret);
172     return 1; 
173   }
174   ret = gnutls_x509_privkey_export (x509_privkey,
175                                     GNUTLS_X509_FMT_PEM,
176                                     output_data,
177                                     &ods);
178   printf("ret: %u; ods: %u;\n", ret, ods);
179   if (ret == 0) {
180     write(1, output_data, ods);
181   }
182
183
184   gnutls_x509_privkey_deinit(x509_privkey);
185   gnutls_openpgp_privkey_deinit(pgp_privkey);
186   gnutls_global_deinit();
187   return 0;
188 }