summaryrefslogtreecommitdiff
path: root/main.c
blob: 8c3129db65dc90a969ae65d4bf655cab565716b9 (plain)
  1. #include <gnutls/gnutls.h>
  2. #include <gnutls/openpgp.h>
  3. #include <gnutls/x509.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <errno.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <unistd.h>
  11. #include <stdarg.h>
  12. /*
  13. Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
  14. Date: Tue, 01 Apr 2008
  15. License: GPL v3 or later
  16. monkeysphere private key translator: execute this with an
  17. ASCII-armored private RSA key on stdin (at the moment, only
  18. passphraseless keys work).
  19. It will spit out a PEM-encoded version of the key on stdout, which
  20. can be fed into ssh-add like this:
  21. gpg --export-secret-keys $KEYID | monkeysphere | ssh-add -c /dev/stdin
  22. Requirements: I've only built this so far with GnuTLS v2.3.4 --
  23. version 2.2.0 does not contain the appropriate pieces.
  24. Notes: gpgkey2ssh doesn't seem to provide the same public
  25. keys. Mighty weird!
  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. void err(const char* fmt, ...) {
  38. va_list ap;
  39. va_start(ap, fmt);
  40. vfprintf(stderr, fmt, ap);
  41. va_end(ap);
  42. }
  43. void init_datum(gnutls_datum_t* d) {
  44. d->data = NULL;
  45. d->size = 0;
  46. }
  47. void free_datum(gnutls_datum_t* d) {
  48. gnutls_free(d->data);
  49. d->data = NULL;
  50. d->size = 0;
  51. }
  52. /* read the passed-in string, store in a single datum */
  53. int set_datum_string(gnutls_datum_t* d, const char* s) {
  54. unsigned int x = strlen(s)+1;
  55. unsigned char* c = NULL;
  56. c = gnutls_realloc(d->data, x);
  57. if (NULL == c)
  58. return -1;
  59. d->data = c;
  60. d->size = x;
  61. memcpy(d->data, s, x);
  62. return 0;
  63. }
  64. /* read the passed-in file descriptor until EOF, store in a single
  65. datum */
  66. int set_datum_fd(gnutls_datum_t* d, int fd) {
  67. unsigned int bufsize = 1024;
  68. unsigned int len = 0;
  69. FILE* f = fdopen(fd, "r");
  70. if (bufsize > d->size) {
  71. bufsize = 1024;
  72. d->data = gnutls_realloc(d->data, bufsize);
  73. if (d->data == NULL) {
  74. err("out of memory!\n");
  75. return -1;
  76. }
  77. d->size = bufsize;
  78. } else {
  79. bufsize = d->size;
  80. }
  81. f = fdopen(fd, "r");
  82. if (NULL == f) {
  83. err("could not fdopen FD %d\n", fd);
  84. }
  85. clearerr(f);
  86. while (!feof(f) && !ferror(f)) {
  87. if (len == bufsize) {
  88. /* allocate more space by doubling: */
  89. bufsize *= 2;
  90. d->data = gnutls_realloc(d->data, bufsize);
  91. if (d->data == NULL) {
  92. err("out of memory!\n");
  93. return -1;
  94. };
  95. d->size = bufsize;
  96. }
  97. len += fread(d->data + len, 1, bufsize - len, f);
  98. /* err("read %d bytes\n", len); */
  99. }
  100. if (ferror(f)) {
  101. err("Error reading from fd %d (error: %d) (error: %d '%s')\n", fd, ferror(f), errno, strerror(errno));
  102. return -1;
  103. }
  104. /* touch up buffer size to match reality: */
  105. d->data = gnutls_realloc(d->data, len);
  106. d->size = len;
  107. return 0;
  108. }
  109. /* read the file indicated (by na1me) in the fname parameter. store
  110. its entire contents in a single datum. */
  111. int set_datum_file(gnutls_datum_t* d, const char* fname) {
  112. struct stat sbuf;
  113. unsigned char* c = NULL;
  114. FILE* file = NULL;
  115. size_t x = 0;
  116. if (0 != stat(fname, &sbuf)) {
  117. err("failed to stat '%s'\n", fname);
  118. return -1;
  119. }
  120. c = gnutls_realloc(d->data, sbuf.st_size);
  121. if (NULL == c) {
  122. err("failed to allocate %d bytes for '%s'\n", sbuf.st_size, fname);
  123. return -1;
  124. }
  125. d->data = c;
  126. d->size = sbuf.st_size;
  127. file = fopen(fname, "r");
  128. if (NULL == file) {
  129. err("failed to open '%s' for reading\n", fname);
  130. return -1;
  131. }
  132. x = fread(d->data, d->size, 1, file);
  133. if (x != 1) {
  134. err("tried to read %d bytes, read %d instead from '%s'\n", d->size, x, fname);
  135. fclose(file);
  136. return -1;
  137. }
  138. fclose(file);
  139. return 0;
  140. }
  141. int main(int argc, char* argv[]) {
  142. const char* version = NULL;
  143. gnutls_x509_privkey_t x509_privkey;
  144. gnutls_datum_t data;
  145. int ret;
  146. /*
  147. const char *certfile, *keyfile;
  148. gnutls_certificate_credentials_t pgp_creds;
  149. */
  150. gnutls_datum_t m, e, d, p, q, u;
  151. /* gnutls_x509_crt_t crt; */
  152. gnutls_openpgp_privkey_t pgp_privkey;
  153. gnutls_openpgp_crt_fmt_t pgp_format;
  154. gnutls_pk_algorithm_t pgp_algo;
  155. unsigned int pgp_bits;
  156. char output_data[10240];
  157. size_t ods = sizeof(output_data);
  158. init_datum(&data);
  159. init_datum(&m);
  160. init_datum(&e);
  161. init_datum(&d);
  162. init_datum(&p);
  163. init_datum(&q);
  164. init_datum(&u);
  165. if (ret = gnutls_global_init(), ret) {
  166. err("Failed to do gnutls_global_init() (error: %d)\n", ret);
  167. return 1;
  168. }
  169. version = gnutls_check_version(NULL);
  170. if (version)
  171. err("gnutls version: %s\n", version);
  172. else {
  173. err("no version found!\n");
  174. return 1;
  175. }
  176. if (ret = gnutls_x509_privkey_init(&x509_privkey), ret) {
  177. err("Failed to initialize X.509 private key (error: %d)\n", ret);
  178. return 1;
  179. }
  180. if (ret = gnutls_openpgp_privkey_init(&pgp_privkey), ret) {
  181. err("Failed to initialized OpenPGP private key (error: %d)\n", ret);
  182. return 1;
  183. }
  184. /* slurp in the private key from stdin */
  185. if (ret = set_datum_fd(&data, 0), ret) {
  186. err("didn't read file descriptor 0\n");
  187. return 1;
  188. }
  189. /* Or, instead, read in key from a file name:
  190. if (ret = set_datum_file(&data, argv[1]), ret) {
  191. err("didn't read file '%s'\n", argv[1]);
  192. return 1;
  193. }
  194. */
  195. /* treat the passed file as an X.509 private key, and extract its
  196. component values: */
  197. /* if (ret = gnutls_x509_privkey_import(x509_privkey, &data, GNUTLS_X509_FMT_PEM), ret) { */
  198. /* err("Failed to import the X.509 key (error: %d)\n", ret); */
  199. /* return 1; */
  200. /* } */
  201. /* gnutls_x509_privkey_export_rsa_raw(x509_privkey, &m, &e, &d, &p, &q, &u); */
  202. /* try to print the PEM-encoded private key: */
  203. /* ret = gnutls_x509_privkey_export (x509_privkey, */
  204. /* GNUTLS_X509_FMT_PEM, */
  205. /* output_data, */
  206. /* &ods); */
  207. /* printf("ret: %u; ods: %u;\n", ret, ods); */
  208. /* if (ret == 0) { */
  209. /* write(0, output_data, ods); */
  210. /* } */
  211. /* format could be either: GNUTLS_OPENPGP_FMT_RAW,
  212. GNUTLS_OPENPGP_FMT_BASE64 */
  213. pgp_format = GNUTLS_OPENPGP_FMT_RAW;
  214. if (ret = gnutls_openpgp_privkey_import (pgp_privkey, &data, pgp_format, NULL, 0), ret) {
  215. err("failed to import the OpenPGP private key (error: %d)\n", ret);
  216. return 1;
  217. }
  218. pgp_algo = gnutls_openpgp_privkey_get_pk_algorithm(pgp_privkey, &pgp_bits);
  219. if (pgp_algo < 0) {
  220. err("failed to get OpenPGP key algorithm (error: %d)\n", pgp_algo);
  221. return 1;
  222. }
  223. if (pgp_algo != GNUTLS_PK_RSA) {
  224. err("OpenPGP Key was not RSA (actual algorithm was: %d)\n", pgp_algo);
  225. return 1;
  226. }
  227. err("OpenPGP RSA Key, with %d bits\n", pgp_bits);
  228. ret = gnutls_openpgp_privkey_export_rsa_raw(pgp_privkey, &m, &e, &d, &p, &q, &u);
  229. if (GNUTLS_E_SUCCESS != ret) {
  230. err ("failed to export RSA key parameters (error: %0x)\n", ret);
  231. return 1;
  232. }
  233. ret = gnutls_x509_privkey_import_rsa_raw (x509_privkey, &m, &e, &d, &p, &q, &u);
  234. if (GNUTLS_E_SUCCESS != ret) {
  235. err ("failed to import RSA key parameters (error: %d)\n", ret);
  236. return 1;
  237. }
  238. /* 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); */
  239. ret = gnutls_x509_privkey_fix(x509_privkey);
  240. if (ret != 0) {
  241. err("failed to fix up the private key in X.509 format (error: %d)\n", ret);
  242. return 1;
  243. }
  244. ret = gnutls_x509_privkey_export (x509_privkey,
  245. GNUTLS_X509_FMT_PEM,
  246. output_data,
  247. &ods);
  248. printf("ret: %u; ods: %u;\n", ret, ods);
  249. if (ret == 0) {
  250. write(1, output_data, ods);
  251. }
  252. gnutls_x509_privkey_deinit(x509_privkey);
  253. gnutls_openpgp_privkey_deinit(pgp_privkey);
  254. gnutls_global_deinit();
  255. return 0;
  256. }