qa.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /**
  2. * \file qa.c
  3. * \brief QA controller and engine.
  4. *
  5. * After retrieving a valid configuration from the frontend, this file takes
  6. * care of running the actual mainloop.
  7. */
  8. #include <assert.h>
  9. #include <error.h>
  10. #include <stdio.h>
  11. #include <stdint.h>
  12. #include <string.h>
  13. #include <unistd.h>
  14. #include <bsd/sys/queue.h>
  15. #include <openssl/err.h>
  16. #include <openssl/pem.h>
  17. #include <openssl/ssl.h>
  18. #include <openssl/x509.h>
  19. #include "qa/qa.h"
  20. #include "qa/questions/questions.h"
  21. #include "qa/qa_sock.h"
  22. static int qa_dispose(X509 *crt, RSA *rsa);
  23. /**
  24. * \Handle unexpected error.
  25. *
  26. * Function handling fatal errors: exit immediately, reporting eventual errors
  27. * coming from openssl/bio or the standard errno.
  28. */
  29. void
  30. qa_abort(const char *reason)
  31. {
  32. //ERR_print_errors_fp(stderr);
  33. exit(EXIT_FAILURE);
  34. }
  35. /**
  36. * \brief Loads a valid ssl certificate from file.
  37. *
  38. * \return NULL in case of error, a X509* structure otherwise.
  39. */
  40. X509*
  41. get_local_cert(const char *src)
  42. {
  43. X509 *crt;
  44. FILE *fp;
  45. if (!strcmp(src, "-")) fp = stdin;
  46. else if (!(fp = fopen(src, "r")))
  47. return NULL;
  48. crt = PEM_read_X509(fp, NULL, 0, NULL);
  49. return crt;
  50. }
  51. /**
  52. * \brief Loads a valid rsa public key from file.
  53. *
  54. * /return NULL in case of error, a X509* structure otherwise.
  55. */
  56. RSA*
  57. get_local_rsa(const char *src)
  58. {
  59. RSA *rsa = NULL;
  60. FILE *fp;
  61. if (!strcmp(src, "-")) fp = stdin;
  62. else if (!(fp = fopen(src, "r")))
  63. return NULL;
  64. rsa = PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL);
  65. return rsa;
  66. }
  67. /**
  68. * \brief Print out a valid RSA Private Key.
  69. *
  70. */
  71. static void
  72. print_rsa_private(RSA *rsa)
  73. {
  74. size_t i;
  75. char *dec, *hex;
  76. const struct {
  77. const char *desc;
  78. BIGNUM *n;
  79. } items[5] = {
  80. {"Public Modulus", rsa->n},
  81. {"Prime Factor p", rsa->p},
  82. {"Prime Factor q", rsa->q},
  83. {"Public Exponent", rsa->e},
  84. {"Private Exponent", rsa->d},
  85. };
  86. assert(rsa); /* && rsa->p && rsa->q && rsa->e); */
  87. for (i=0; i!=5; i++) {
  88. if (!items[i].n) continue;
  89. dec = BN_bn2dec(items[i].n);
  90. hex = BN_bn2hex(items[i].n);
  91. fprintf(stdout, "\t%-22s : %-15s (0x%s)\n", items[i].desc, dec, hex);
  92. OPENSSL_free(dec);
  93. OPENSSL_free(hex);
  94. }
  95. }
  96. /**
  97. * \brief Given an initial configuration, stuctures the program flow.
  98. *
  99. * \param[in] args Initial configuration given from a frontend.
  100. */
  101. int
  102. qa_init(const struct qa_conf* conf)
  103. {
  104. int exitcode;
  105. X509 *crt = NULL;
  106. RSA *rsa = NULL;
  107. /* bind stdout/stderr to a BIO shit to be used externally */
  108. bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
  109. bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
  110. /* Initialize SSL Library by registering algorithms. */
  111. SSL_library_init();
  112. if (!conf->attacks) select_all_questions();
  113. else select_question(conf->attacks);
  114. if (!questions.lh_first) error(EXIT_FAILURE, 0, "No valid question selected.");
  115. if (conf->src_type == REMOTE)
  116. crt = get_remote_cert(conf->src);
  117. else if (conf->src_type == LOCAL_X509)
  118. crt = get_local_cert(conf->src);
  119. else if (conf->src_type == LOCAL_RSA)
  120. rsa = get_local_rsa(conf->src);
  121. else
  122. error(EXIT_FAILURE, 0, "iternal error: unable to determine source type.");
  123. if (!crt && !rsa)
  124. error(EXIT_FAILURE, errno, "Unable to open source.");
  125. exitcode = qa_dispose(crt, rsa);
  126. X509_free(crt);
  127. return exitcode;
  128. }
  129. static int
  130. qa_dispose(X509 *crt, RSA *rsa)
  131. {
  132. RSA *pub;
  133. RSA *priv;
  134. qa_question_t *q;
  135. if (!rsa && crt) pub = X509_get_pubkey(crt)->pkey.rsa;
  136. else pub = rsa;
  137. printf("[+] Certificate acquired\n");
  138. LIST_FOREACH(q, &questions, qs) {
  139. printf( "[-] Running: %s\n", q->pretty_name);
  140. /*
  141. * Run setup. If it fails, then print an error message and go to the next
  142. * question.
  143. */
  144. if (q->setup && q->setup() <= 0) {
  145. fprintf(stderr, "[x] Unexpected error loading question %s\n", q->pretty_name);
  146. continue;
  147. }
  148. /*
  149. * Run test. If the test is undecidible or either ok, go on. Otherwise,
  150. * print an error message and go to the next question.
  151. */
  152. if (q->test && q->test(crt) < 0) {
  153. fprintf(stderr, "[|] Question %s cannot attack the given certificate.\n", q->pretty_name);
  154. continue;
  155. }
  156. /*
  157. * Attempt to attack RSA. If the attack went ok, there's no need to go
  158. * on. Print out a nice message and then quit.
  159. */
  160. if (q->ask_rsa &&
  161. (priv = q->ask_rsa(pub))) {
  162. fprintf(stderr, "[\\] Key Broken using %s.\n", q->pretty_name);
  163. print_rsa_private(priv);
  164. return EXIT_SUCCESS;
  165. }
  166. /*
  167. * Attempt to attack the X509 certificate.
  168. */
  169. if (crt && q->ask_crt) q->ask_crt(crt);
  170. /*
  171. * Shut down the given question. If it fails, print an error messae and go
  172. * on.
  173. */
  174. if (q->teardown && q->teardown() <= 0) {
  175. fprintf(stderr, "[x] Unexpected error shutting down question %s.\n", q->pretty_name);
  176. continue;
  177. }
  178. }
  179. /*
  180. * Key seems resistent: exit with status -1
  181. */
  182. return -1;
  183. }