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