1 #include "gnutls-helpers.h"
3 #include <gnutls/openpgp.h>
4 #include <gnutls/x509.h>
14 #include <arpa/inet.h>
18 Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
20 License: GPL v3 or later
22 monkeysphere public key translator: execute this with an ssh
23 private key on stdin. It currently only works with RSA keys.
25 it should eventually work with OpenSSH-style public keys instead of
26 the full private key, but it was easier to do this way.
28 It shoud spit out a version of the public key suitable for acting
29 as an OpenPGP public sub key packet.
33 int main(int argc, char* argv[]) {
36 gnutls_x509_privkey_t x509_privkey;
37 gnutls_openpgp_crt_t openpgp_crt;
38 gnutls_openpgp_keyid_t keyid;
39 printable_keyid p_keyid;
41 unsigned int usage, bits;
42 gnutls_pk_algorithm_t algo;
44 unsigned char packettag;
45 unsigned char openpgpversion;
48 unsigned char openpgpalgo;
49 unsigned int packetlen;
52 gnutls_datum_t m, e, d, p, q, u, g, y;
53 gnutls_datum_t algolabel;
55 char output_data[10240];
57 size_t uidsz = sizeof(userid);
59 const gnutls_datum_t* all[5];
62 char* const args[] = {"/usr/bin/base64", "--wrap=0", NULL};
80 init_datum(&algolabel);
84 /* slurp in the private key from stdin */
85 if (ret = set_datum_fd(&data, 0), ret) {
86 err("didn't read file descriptor 0\n");
91 if (ret = gnutls_x509_privkey_init(&x509_privkey), ret) {
92 err("Failed to initialize private key structure (error: %d)\n", ret);
96 err("assuming PEM formatted private key\n");
97 if (ret = gnutls_x509_privkey_import(x509_privkey, &data, GNUTLS_X509_FMT_PEM), ret) {
98 err("failed to import the PEM-encoded private key (error: %d)\n", ret);
102 algo = gnutls_x509_privkey_get_pk_algorithm(x509_privkey);
104 err("failed to get the algorithm of the PEM-encoded public key (error: %d)\n", algo);
106 } else if (algo == GNUTLS_PK_RSA) {
107 err("RSA private key\n");
108 ret = gnutls_x509_privkey_export_rsa_raw(x509_privkey, &m, &e, &d, &p, &q, &u);
109 if (GNUTLS_E_SUCCESS != ret) {
110 err ("failed to export RSA key parameters (error: %d)\n", ret);
113 err("Modulus size %d, exponent size %d\n", m.size, e.size);
114 } else if (algo == GNUTLS_PK_DSA) {
115 err("DSA Key, not implemented!!\n", bits);
118 err("Key was not RSA or DSA -- can't deal! (actual algorithm was: %d)\n", algo);
122 /* now we have algo, and the various MPI data are set. Can we
123 export them as a public subkey packet? */
125 /* this packet should be tagged 14, and should contain:
128 4 octets: time of generation (seconds since 1970)
129 1 octet: algo (http://tools.ietf.org/html/rfc4880#section-5.5.2 implies 1 for RSA)
135 packetlen = 1 + 4 + 1;
136 /* FIXME: this is RSA only. for DSA, there'll be more: */
137 packetlen += get_openpgp_mpi_size(&m) + get_openpgp_mpi_size(&e);
139 /* FIXME: we should generate this bound more cleanly -- i just
140 happen to know that 65535 is 2^16-1: */
141 if (packetlen > 65535) {
142 err("packet length is too long (%d)\n", packetlen);
146 /* we're going to emit an old-style packet, with tag 14 (public
147 subkey), with a two-octet packet length */
148 packettag = 0x80 | (14 << 2) | 1;
150 write(1, &packettag, sizeof(packettag));
151 plen = htons(packetlen);
152 write(1, &plen, sizeof(plen));
155 write(1, &openpgpversion, 1);
157 timestamp = time(NULL);
158 clunkytime = htonl(timestamp);
159 write(1, &clunkytime, 4);
161 /* FIXME: handle things other than RSA */
163 write(1, &openpgpalgo, 1);
165 write_openpgp_mpi_to_fd(1, &m);
166 write_openpgp_mpi_to_fd(1, &e);
168 gnutls_x509_privkey_deinit(x509_privkey);
169 gnutls_global_deinit();