123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /**
- * \file qa.c
- * \brief QA controller and engine.
- *
- * After retrieving a valid configuration from the frontend, this file takes
- * care of running the actual mainloop.
- */
- #include <assert.h>
- #include <error.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <string.h>
- #include <unistd.h>
- #include <bsd/sys/queue.h>
- #include <openssl/err.h>
- #include <openssl/pem.h>
- #include <openssl/ssl.h>
- #include <openssl/x509.h>
- #include "qa/qa.h"
- #include "qa/questions/questions.h"
- #include "qa/qa_sock.h"
- static int qa_dispose(X509 *crt, RSA *rsa);
- /**
- * \Handle unexpected error.
- *
- * Function handling fatal errors: exit immediately, reporting eventual errors
- * coming from openssl/bio or the standard errno.
- */
- void
- qa_abort(const char *reason)
- {
- //ERR_print_errors_fp(stderr);
- exit(EXIT_FAILURE);
- }
- /**
- * \brief Loads a valid ssl certificate from file.
- *
- * \return NULL in case of error, a X509* structure otherwise.
- */
- X509*
- get_local_cert(const char *src)
- {
- X509 *crt;
- FILE *fp;
- if (!strcmp(src, "-")) fp = stdin;
- else if (!(fp = fopen(src, "r")))
- return NULL;
- crt = PEM_read_X509(fp, NULL, 0, NULL);
- return crt;
- }
- /**
- * \brief Loads a valid rsa public key from file.
- *
- * /return NULL in case of error, a X509* structure otherwise.
- */
- RSA*
- get_local_rsa(const char *src)
- {
- RSA *rsa = NULL;
- FILE *fp;
- if (!strcmp(src, "-")) fp = stdin;
- else if (!(fp = fopen(src, "r")))
- return NULL;
- rsa = PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL);
- return rsa;
- }
- /**
- * \brief Print out a valid RSA Private Key.
- *
- */
- static void
- print_rsa_private(RSA *rsa)
- {
- size_t i;
- char *dec, *hex;
- const struct {
- const char *desc;
- BIGNUM *n;
- } items[5] = {
- {"Public Modulus", rsa->n},
- {"Prime Factor p", rsa->p},
- {"Prime Factor q", rsa->q},
- {"Public Exponent", rsa->e},
- {"Private Exponent", rsa->d},
- };
- assert(rsa); /* && rsa->p && rsa->q && rsa->e); */
- for (i=0; i!=5; i++) {
- if (!items[i].n) continue;
- dec = BN_bn2dec(items[i].n);
- hex = BN_bn2hex(items[i].n);
- fprintf(stdout, "\t%-22s : %-15s (0x%s)\n", items[i].desc, dec, hex);
- OPENSSL_free(dec);
- OPENSSL_free(hex);
- }
- }
- /**
- * \brief Given an initial configuration, stuctures the program flow.
- *
- * \param[in] args Initial configuration given from a frontend.
- */
- int
- qa_init(const struct qa_conf* conf)
- {
- int exitcode;
- X509 *crt = NULL;
- RSA *rsa = NULL;
- /* bind stdout/stderr to a BIO shit to be used externally */
- bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
- bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
- /* Initialize SSL Library by registering algorithms. */
- SSL_library_init();
- if (!conf->attacks) select_all_questions();
- else select_question(conf->attacks);
- if (!questions.lh_first) error(EXIT_FAILURE, 0, "No valid question selected.");
- if (conf->src_type == REMOTE)
- crt = get_remote_cert(conf->src);
- else if (conf->src_type == LOCAL_X509)
- crt = get_local_cert(conf->src);
- else if (conf->src_type == LOCAL_RSA)
- rsa = get_local_rsa(conf->src);
- else
- error(EXIT_FAILURE, 0, "iternal error: unable to determine source type.");
- if (!crt && !rsa)
- error(EXIT_FAILURE, errno, "Unable to open source.");
- exitcode = qa_dispose(crt, rsa);
- X509_free(crt);
- return exitcode;
- }
- static int
- qa_dispose(X509 *crt, RSA *rsa)
- {
- RSA *pub;
- RSA *priv;
- qa_question_t *q;
- if (!rsa && crt) pub = X509_get_pubkey(crt)->pkey.rsa;
- else pub = rsa;
- printf("[+] Certificate acquired\n");
- LIST_FOREACH(q, &questions, qs) {
- printf( "[-] Running: %s\n", q->pretty_name);
- /*
- * Run setup. If it fails, then print an error message and go to the next
- * question.
- */
- if (q->setup && q->setup() <= 0) {
- fprintf(stderr, "[x] Unexpected error loading question %s\n", q->pretty_name);
- continue;
- }
- /*
- * Run test. If the test is undecidible or either ok, go on. Otherwise,
- * print an error message and go to the next question.
- */
- if (q->test && q->test(crt) < 0) {
- fprintf(stderr, "[|] Question %s cannot attack the given certificate.\n", q->pretty_name);
- continue;
- }
- /*
- * Attempt to attack RSA. If the attack went ok, there's no need to go
- * on. Print out a nice message and then quit.
- */
- if (q->ask_rsa &&
- (priv = q->ask_rsa(pub))) {
- fprintf(stderr, "[\\] Key Broken using %s.\n", q->pretty_name);
- print_rsa_private(priv);
- return EXIT_SUCCESS;
- }
- /*
- * Attempt to attack the X509 certificate.
- */
- if (crt && q->ask_crt) q->ask_crt(crt);
- /*
- * Shut down the given question. If it fails, print an error messae and go
- * on.
- */
- if (q->teardown && q->teardown() <= 0) {
- fprintf(stderr, "[x] Unexpected error shutting down question %s.\n", q->pretty_name);
- continue;
- }
- }
- /*
- * Key seems resistent: exit with status -1
- */
- return -1;
- }
|