|
@@ -0,0 +1,151 @@
|
|
|
+#include <assert.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdint.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <netdb.h>
|
|
|
+
|
|
|
+#include <openssl/ssl.h>
|
|
|
+#include <openssl/err.h>
|
|
|
+#include <openssl/x509.h>
|
|
|
+#include <openssl/evp.h>
|
|
|
+#include <openssl/bio.h>
|
|
|
+
|
|
|
+#include "qa.h"
|
|
|
+#include "questions.h"
|
|
|
+#include "qa_sock.h"
|
|
|
+
|
|
|
+/**
|
|
|
+ * \brief Connection informations.
|
|
|
+ */
|
|
|
+struct qa_connection {
|
|
|
+ int socket; /**< socket file descriptor. */
|
|
|
+ SSL* ssl; /**< ssl handler for this connection. */
|
|
|
+ SSL_CTX* ctx; /**< ssl context used in this connection. */
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * \brief Destructor for a \ref qa_connection.
|
|
|
+ *
|
|
|
+ * Closes the socket, shuts down the connection, and frees all memory used for
|
|
|
+ * holding the connection.
|
|
|
+ * \note Input might be partial (ex. a socket exists, but not no ssl session).
|
|
|
+ *
|
|
|
+ * \param c The connection to be freed.
|
|
|
+ */
|
|
|
+static void qa_connection_free(struct qa_connection* c)
|
|
|
+{
|
|
|
+ if (c->socket)
|
|
|
+ close(c->socket);
|
|
|
+ if (c->ssl) {
|
|
|
+ SSL_shutdown(c->ssl);
|
|
|
+ SSL_free(c->ssl);
|
|
|
+ }
|
|
|
+ if (c->ctx)
|
|
|
+ SSL_CTX_free(c->ctx);
|
|
|
+
|
|
|
+ free(c);
|
|
|
+}
|
|
|
+
|
|
|
+void qa_abort(const char *reason)
|
|
|
+{
|
|
|
+ //ERR_print_errors_fp(stderr);
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int verify_callback(int ok, X509_STORE_CTX* ctx)
|
|
|
+{
|
|
|
+ return ok;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * \brief Set up a new ssl connection.
|
|
|
+ *
|
|
|
+ * Create a new \ref qa_connection, turning on OpenSSL (if not yet started), and
|
|
|
+ * opening a socket with the target server over ssl.
|
|
|
+ *
|
|
|
+ * \param[in] conf Configuration holding informations about the target.
|
|
|
+ * \return The new connection.
|
|
|
+ */
|
|
|
+struct qa_connection* qa_connection_new(const struct qa_conf* conf)
|
|
|
+{
|
|
|
+ struct qa_connection* c;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ c = malloc(sizeof(struct qa_connection));
|
|
|
+ if (!c) qa_abort("No Memory.");
|
|
|
+
|
|
|
+ /* Initialize SSL Library by registering algorithms. */
|
|
|
+ SSL_library_init();
|
|
|
+
|
|
|
+
|
|
|
+ c->ctx = SSL_CTX_new(SSLv23_client_method());
|
|
|
+ if (!c->ctx) {
|
|
|
+ qa_connection_free(c);
|
|
|
+ qa_abort("Cannot create context");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* is also the default. lol. */
|
|
|
+ SSL_CTX_set_verify(c->ctx, SSL_VERIFY_NONE, verify_callback);
|
|
|
+ c->ssl = SSL_new(c->ctx);
|
|
|
+ if (!c->ssl) {
|
|
|
+ qa_connection_free(c);
|
|
|
+ qa_abort("Cannot create ssl handle");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(c->socket = init_client(conf))) {
|
|
|
+ qa_connection_free(c);
|
|
|
+ qa_abort("Cannot create socket.");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!SSL_set_fd(c->ssl, c->socket)) {
|
|
|
+ qa_connection_free(c);
|
|
|
+ qa_abort("Cannot bind socket to ssl session");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* XXX. Handle errors appropriately using error codes from OpenSSL */
|
|
|
+ err = SSL_connect(c->ssl);
|
|
|
+ if (err != 1) {
|
|
|
+ qa_connection_free(c);
|
|
|
+ qa_abort("Cannot Connect");
|
|
|
+ }
|
|
|
+
|
|
|
+ SSL_set_connect_state(c->ssl);
|
|
|
+
|
|
|
+ return c;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * \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* args)
|
|
|
+{
|
|
|
+ X509 *crt;
|
|
|
+ struct qa_connection *c;
|
|
|
+ struct qa_question *q;
|
|
|
+
|
|
|
+ /* bind stdout to a BIO shit to be used externally */
|
|
|
+ bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
|
|
|
+
|
|
|
+ /* create a new connection, and download the certificate */
|
|
|
+ c = qa_connection_new(args);
|
|
|
+ crt = SSL_get_peer_certificate(c->ssl);
|
|
|
+ if (!crt) qa_abort("Cannot obtain certificate");
|
|
|
+
|
|
|
+ register_all_questions();
|
|
|
+for (q=questions.lh_first; q; q = q->qs.le_next) {
|
|
|
+ q->setup();
|
|
|
+ q->test(crt);
|
|
|
+ q->ask(crt);
|
|
|
+ q->teardown();
|
|
|
+ }
|
|
|
+
|
|
|
+ qa_connection_free(c);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|