qa.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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 "config.h"
  9. #include <assert.h>
  10. #include <error.h>
  11. #include <stdio.h>
  12. #include <stdint.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #ifdef HAVE_OPENMPI
  16. #include <mpi.h>
  17. #endif
  18. #include <bsd/sys/queue.h>
  19. #include <openssl/err.h>
  20. #include <openssl/pem.h>
  21. #include <openssl/ssl.h>
  22. #include <openssl/x509.h>
  23. #include "qa/qa.h"
  24. #include "qa/questions/questions.h"
  25. #include "qa/qa_sock.h"
  26. static int qa_dispose(X509 *crt, RSA *rsa);
  27. /**
  28. * \Handle unexpected error.
  29. *
  30. * Function handling fatal errors: exit immediately, reporting eventual errors
  31. * coming from openssl/bio or the standard errno.
  32. */
  33. void
  34. qa_abort(const char *reason)
  35. {
  36. //ERR_print_errors_fp(stderr);
  37. exit(EXIT_FAILURE);
  38. }
  39. /**
  40. * \brief Loads a valid ssl certificate from file.
  41. *
  42. * \return NULL in case of error, a X509* structure otherwise.
  43. */
  44. X509*
  45. get_local_cert(const char *src)
  46. {
  47. X509 *crt;
  48. FILE *fp;
  49. if (!strcmp(src, "-")) fp = stdin;
  50. else if (!(fp = fopen(src, "r")))
  51. return NULL;
  52. crt = PEM_read_X509(fp, NULL, 0, NULL);
  53. return crt;
  54. }
  55. /**
  56. * \brief Loads a valid rsa public key from file.
  57. *
  58. * \return NULL in case of error, a X509* structure otherwise.
  59. */
  60. RSA*
  61. get_local_rsa(const char *src)
  62. {
  63. EVP_PKEY *pkey = NULL;
  64. FILE *fp;
  65. if (!strcmp(src, "-")) fp = stdin;
  66. else if (!(fp = fopen(src, "r")))
  67. return NULL;
  68. pkey = PEM_read_PUBKEY(fp, &pkey, NULL, NULL);
  69. if (pkey == NULL)
  70. return NULL;
  71. if (pkey->type != EVP_PKEY_RSA) {
  72. EVP_PKEY_free(pkey);
  73. return NULL;
  74. }
  75. return pkey->pkey.rsa;
  76. /* rsa = PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL); */
  77. }
  78. /**
  79. * \brief Given an initial configuration, stuctures the program flow.
  80. *
  81. * \param[in] args Initial configuration given from a frontend.
  82. */
  83. int
  84. qa_init(const struct qa_conf* conf)
  85. {
  86. X509 *crt = NULL;
  87. RSA *rsa = NULL;
  88. /* bind stdout/stderr to a BIO shit to be used externally */
  89. bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
  90. bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
  91. if (conf->attacks) select_question(conf->attacks);
  92. if (!questions.lh_first) error(EXIT_FAILURE, 0, "No valid question selected.");
  93. if (conf->src_type == REMOTE)
  94. crt = get_remote_cert(conf->src);
  95. else if (conf->src_type == LOCAL_X509)
  96. crt = get_local_cert(conf->src);
  97. else if (conf->src_type == LOCAL_RSA)
  98. rsa = get_local_rsa(conf->src);
  99. else
  100. error(EXIT_FAILURE, 0, "iternal error: unable to determine source type.");
  101. if (!crt && !rsa)
  102. error(EXIT_FAILURE, errno, "Unable to open source \"%s\" :", conf->src);
  103. int ret = qa_dispose(crt, rsa);
  104. X509_free(crt);
  105. return ret;
  106. }
  107. static int
  108. qa_dispose(X509 *crt, RSA *rsa)
  109. {
  110. int exit_code = EXIT_SUCCESS;
  111. RSA *pub;
  112. qa_question_t *q;
  113. EVP_PKEY *pkey;
  114. #ifdef HAVE_OPENMPI
  115. int proc, procs;
  116. /* i; */
  117. #endif
  118. if (!rsa && crt) {
  119. pkey = X509_get_pubkey(crt);
  120. if (pkey && pkey->type == EVP_PKEY_RSA) pub = pkey->pkey.rsa;
  121. else {
  122. fprintf(stderr, "[!] Unsupported certificate\n");
  123. goto end;
  124. }
  125. }
  126. else pub = rsa;
  127. printf("[+] Certificate acquired\n");
  128. #ifdef HAVE_OPENMPI
  129. MPI_Comm_rank(MPI_COMM_WORLD, &proc);
  130. MPI_Comm_size(MPI_COMM_WORLD, &procs);
  131. /* i = 0; */
  132. #endif
  133. LIST_FOREACH(q, &questions, qs) {
  134. #ifdef HAVE_OPENMPI
  135. // if (i++ % procs != proc) continue;
  136. #endif
  137. printf( "[-] Running: %s\n", q->pretty_name);
  138. switch (run_question(q, crt, pub)) {
  139. case -3:
  140. fprintf(stderr, "[x] Unexpected error shutting down question %s\n", q->pretty_name);
  141. exit_code = EXIT_FAILURE;
  142. case -2:
  143. fprintf(stderr, "[x] Unexpected error loading question %s\n", q->pretty_name);
  144. exit_code = EXIT_FAILURE;
  145. break;
  146. case -1:
  147. fprintf(stderr, "[|] Question %s cannot attack the given certificate.\n", q->pretty_name);
  148. exit_code = EXIT_SUCCESS;
  149. break;
  150. case 0 :
  151. fprintf(stderr, "[♥] Key is resistant to %s\n", q->pretty_name);
  152. exit_code = EXIT_SUCCESS;
  153. break;
  154. default:
  155. fprintf(stderr, "[\\] Key has been Broken using %s.\n", q->pretty_name);
  156. exit_code = EXIT_SUCCESS;
  157. goto end;
  158. }
  159. }
  160. end:
  161. QA_library_del();
  162. /*
  163. * Key seems resistent: exit successfully.
  164. */
  165. return exit_code;
  166. }