summaryrefslogtreecommitdiff
path: root/src/keytrans/ssh2gpg.c
blob: b14a54004e0d6568f1324fefc84dc14ed5c06333 (plain)
  1. #include "gnutls-helpers.h"
  2. #include <gnutls/openpgp.h>
  3. #include <gnutls/x509.h>
  4. /* for waitpid() */
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. /* for time() */
  8. #include <time.h>
  9. /* for htons() */
  10. #include <arpa/inet.h>
  11. /*
  12. Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
  13. Date: Sun, 2008-04-20
  14. License: GPL v3 or later
  15. monkeysphere public key translator: execute this with an ssh
  16. private key on stdin. It currently only works with RSA keys.
  17. it should eventually work with OpenSSH-style public keys instead of
  18. the full private key, but it was easier to do this way.
  19. It shoud spit out a version of the public key suitable for acting
  20. as an OpenPGP public sub key packet.
  21. */
  22. int main(int argc, char* argv[]) {
  23. gnutls_datum_t data;
  24. int ret;
  25. gnutls_x509_privkey_t x509_privkey;
  26. gnutls_openpgp_crt_t openpgp_crt;
  27. gnutls_openpgp_keyid_t keyid;
  28. printable_keyid p_keyid;
  29. unsigned int keyidx;
  30. unsigned int usage, bits;
  31. gnutls_pk_algorithm_t algo;
  32. unsigned char packettag;
  33. unsigned char openpgpversion;
  34. time_t timestamp;
  35. uint32_t clunkytime;
  36. unsigned char openpgpalgo;
  37. unsigned int packetlen;
  38. uint16_t plen;
  39. gnutls_datum_t m, e, d, p, q, u, g, y;
  40. gnutls_datum_t algolabel;
  41. char output_data[10240];
  42. char userid[10240];
  43. size_t uidsz = sizeof(userid);
  44. const gnutls_datum_t* all[5];
  45. int pipefd;
  46. pid_t child_pid;
  47. char* const args[] = {"/usr/bin/base64", "--wrap=0", NULL};
  48. const char* algoname;
  49. int mpicount;
  50. int pipestatus;
  51. init_gnutls();
  52. init_datum(&data);
  53. init_datum(&m);
  54. init_datum(&e);
  55. init_datum(&d);
  56. init_datum(&p);
  57. init_datum(&q);
  58. init_datum(&u);
  59. init_datum(&g);
  60. init_datum(&y);
  61. init_datum(&algolabel);
  62. init_keyid(keyid);
  63. /* slurp in the private key from stdin */
  64. if (ret = set_datum_fd(&data, 0), ret) {
  65. err("didn't read file descriptor 0\n");
  66. return 1;
  67. }
  68. if (ret = gnutls_x509_privkey_init(&x509_privkey), ret) {
  69. err("Failed to initialize private key structure (error: %d)\n", ret);
  70. return 1;
  71. }
  72. err("assuming PEM formatted private key\n");
  73. if (ret = gnutls_x509_privkey_import(x509_privkey, &data, GNUTLS_X509_FMT_PEM), ret) {
  74. err("failed to import the PEM-encoded private key (error: %d)\n", ret);
  75. return ret;
  76. }
  77. algo = gnutls_x509_privkey_get_pk_algorithm(x509_privkey);
  78. if (algo < 0) {
  79. err("failed to get the algorithm of the PEM-encoded public key (error: %d)\n", algo);
  80. return algo;
  81. } else if (algo == GNUTLS_PK_RSA) {
  82. err("RSA private key\n");
  83. ret = gnutls_x509_privkey_export_rsa_raw(x509_privkey, &m, &e, &d, &p, &q, &u);
  84. if (GNUTLS_E_SUCCESS != ret) {
  85. err ("failed to export RSA key parameters (error: %d)\n", ret);
  86. return 1;
  87. }
  88. err("Modulus size %d, exponent size %d\n", m.size, e.size);
  89. } else if (algo == GNUTLS_PK_DSA) {
  90. err("DSA Key, not implemented!!\n", bits);
  91. return 1;
  92. } else {
  93. err("Key was not RSA or DSA -- can't deal! (actual algorithm was: %d)\n", algo);
  94. return 1;
  95. }
  96. /* now we have algo, and the various MPI data are set. Can we
  97. export them as a public subkey packet? */
  98. /* this packet should be tagged 14, and should contain:
  99. 1 octet: version (4)
  100. 4 octets: time of generation (seconds since 1970)
  101. 1 octet: algo (http://tools.ietf.org/html/rfc4880#section-5.5.2 implies 1 for RSA)
  102. MPI: modulus
  103. MPI: exponent
  104. */
  105. packetlen = 1 + 4 + 1;
  106. /* FIXME: this is RSA only. for DSA, there'll be more: */
  107. packetlen += get_openpgp_mpi_size(&m) + get_openpgp_mpi_size(&e);
  108. /* FIXME: we should generate this bound more cleanly -- i just
  109. happen to know that 65535 is 2^16-1: */
  110. if (packetlen > 65535) {
  111. err("packet length is too long (%d)\n", packetlen);
  112. return 1;
  113. }
  114. /* we're going to emit an old-style packet, with tag 14 (public
  115. subkey), with a two-octet packet length */
  116. packettag = 0x80 | (14 << 2) | 1;
  117. write(1, &packettag, sizeof(packettag));
  118. plen = htons(packetlen);
  119. write(1, &plen, sizeof(plen));
  120. openpgpversion = 4;
  121. write(1, &openpgpversion, 1);
  122. timestamp = time(NULL);
  123. clunkytime = htonl(timestamp);
  124. write(1, &clunkytime, 4);
  125. /* FIXME: handle things other than RSA */
  126. openpgpalgo = 1;
  127. write(1, &openpgpalgo, 1);
  128. write_openpgp_mpi_to_fd(1, &m);
  129. write_openpgp_mpi_to_fd(1, &e);
  130. gnutls_x509_privkey_deinit(x509_privkey);
  131. gnutls_global_deinit();
  132. return 0;
  133. }