From 0bf8c0ccc31156904f660ce1a764b8dd2347e88c Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Fri, 11 Dec 2020 16:25:26 +0100 Subject: [PATCH] Implemented basic SSL --- Makefile | 2 +- src/client.c | 39 +++++++++++++--------- src/necronda-server.c | 75 +++++++++++++++++++++++++++++++++++++++---- src/necronda-server.h | 21 ++++++++++-- 4 files changed, 112 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 9af2dff..f2dfb3c 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ packages: compile: @echo "Compiling..." @mkdir -p bin - gcc src/necronda-server.c -o bin/necronda-server -std=c11 -D_POSIX_C_SOURCE + gcc src/necronda-server.c -o bin/necronda-server -std=c11 -D_POSIX_C_SOURCE -lssl -lcrypto @echo "Finished compiling!" install: | packages update compile diff --git a/src/client.c b/src/client.c index b48e624..65c60d7 100644 --- a/src/client.c +++ b/src/client.c @@ -40,27 +40,34 @@ int client_request_handler() { return 0; } -int client_connection_handler(int client) { - char buf1[256]; - char buf2[256]; +int client_connection_handler(sock *client) { + int ret; print("Connection accepted from %s (%s) [%s]", client_addr_str, client_addr_str, "N/A"); - sprintf(buf1, "Hello World!\nYour address is: %s\n", client_addr_str); - send(client, buf1, strlen(buf1), 0); - int len = -1; - while (len == -1) { - len = recv(client, &buf1, sizeof(buf1), 0); - } - sprintf(buf2, "Thank you, %.*s!\nGood bye!\n", len, buf1); - send(client, buf2, strlen(buf2), 0); + if (client->enc) { + client->ssl = SSL_new(client->ctx); + SSL_set_fd(client->ssl, client->socket); - close(client); + ret = SSL_accept(client->ssl); + if (ret <= 0) { + print(ERR_STR "Unable to perform handshake: %s" CLR_STR, ssl_get_error(client->ssl, ret)); + goto close; + } + } + + close: + if (client->enc) { + SSL_shutdown(client->ssl); + } + shutdown(client->socket, SHUT_RDWR); + close(client->socket); print("Connection closed"); return 0; } -int client_handler(int client, long client_num, struct sockaddr_in6 *client_addr) { +int client_handler(sock *client, long client_num, struct sockaddr_in6 *client_addr) { + int ret; struct sockaddr_in6 *server_addr; struct sockaddr_storage server_addr_storage; @@ -78,7 +85,7 @@ int client_handler(int client, long client_num, struct sockaddr_in6 *client_addr } socklen_t len = sizeof(server_addr_storage); - getsockname(client, (struct sockaddr *) &server_addr_storage, &len); + getsockname(client->socket, (struct sockaddr *) &server_addr_storage, &len); server_addr = (struct sockaddr_in6 *) &server_addr_storage; server_addr_str_ptr = malloc(INET6_ADDRSTRLEN); inet_ntop(server_addr->sin6_family, (void *) &server_addr->sin6_addr, server_addr_str_ptr, INET6_ADDRSTRLEN); @@ -90,10 +97,10 @@ int client_handler(int client, long client_num, struct sockaddr_in6 *client_addr log_base_prefix = malloc(256); sprintf(log_base_prefix, "[%24s][%s%4i%s]%s[%*s][%5i]%s ", - server_addr_str, R_STR, ntohs(server_addr->sin6_port), CLR_STR, + server_addr_str, client->enc ? HTTPS_STR : HTTP_STR, ntohs(server_addr->sin6_port), CLR_STR, color_table[client_num % 6], INET_ADDRSTRLEN, client_addr_str, ntohs(client_addr->sin6_port), CLR_STR); - int ret = client_connection_handler(client); + ret = client_connection_handler(client); free(client_addr_str_ptr); free(server_addr_str_ptr); free(log_base_prefix); diff --git a/src/necronda-server.c b/src/necronda-server.c index faa6958..66971e5 100644 --- a/src/necronda-server.c +++ b/src/necronda-server.c @@ -24,6 +24,47 @@ int active = 1; + +void openssl_init() { + SSL_library_init(); + SSL_load_error_strings(); + ERR_load_BIO_strings(); + OpenSSL_add_all_algorithms(); +} + +char *ssl_get_error(SSL *ssl, int ret) { + if (ret > 0) { + return NULL; + } + + unsigned long ret2 = ERR_get_error(); + char *err2 = strerror(errno); + char *err1 = (char *) ERR_reason_error_string(ret2); + + switch (SSL_get_error(ssl, ret)) { + case SSL_ERROR_NONE: + return "none"; + case SSL_ERROR_ZERO_RETURN: + return "closed"; + case SSL_ERROR_WANT_READ: + return "want read"; + case SSL_ERROR_WANT_WRITE: + return "want write"; + case SSL_ERROR_WANT_CONNECT: + return "want connect"; + case SSL_ERROR_WANT_ACCEPT: + return "want accept"; + case SSL_ERROR_WANT_X509_LOOKUP: + return "want x509 lookup"; + case SSL_ERROR_SYSCALL: + return ((ret2 == 0) ? ((ret == 0) ? "protocol violation" : err2) : err1); + case SSL_ERROR_SSL: + return err1; + default: + return "unknown error"; + } +} + void destroy() { fprintf(stderr, "\n" ERR_STR "Terminating forcefully!" CLR_STR "\n"); int status = 0; @@ -97,7 +138,8 @@ int main(int argc, const char *argv[]) { int ready_sockets_num = 0; long client_num = 0; - int client; + int client_fd; + sock client; struct sockaddr_in6 client_addr; unsigned int client_addr_len = sizeof(client_addr); @@ -139,7 +181,24 @@ int main(int argc, const char *argv[]) { signal(SIGINT, terminate); signal(SIGTERM, terminate); - // TODO implement TLS server side handshake + openssl_init(); + + client.ctx = SSL_CTX_new(TLS_server_method()); + SSL_CTX_set_options(client.ctx, SSL_OP_SINGLE_DH_USE); + SSL_CTX_set_verify(client.ctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_min_proto_version(client.ctx, TLS1_VERSION); + SSL_CTX_set_mode(client.ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_cipher_list(client.ctx, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"); + SSL_CTX_set_ecdh_auto(client.ctx, 1); + + if (SSL_CTX_use_certificate_chain_file(client.ctx, "/home/lorenz/cert/chakotay.pem") != 1) { + fprintf(stderr, ERR_STR "Unable to load certificate chain file: %s" CLR_STR "\n", ERR_reason_error_string(ERR_get_error())); + return 1; + } + if (SSL_CTX_use_PrivateKey_file(client.ctx, "/home/lorenz/cert/priv/chakotay.key", SSL_FILETYPE_PEM) != 1) { + fprintf(stderr, ERR_STR "Unable to load private key file: %s" CLR_STR "\n", ERR_reason_error_string(ERR_get_error())); + return 1; + } for (int i = 0; i < NUM_SOCKETS; i++) { if (listen(SOCKETS[i], LISTEN_BACKLOG) == -1) { @@ -168,8 +227,8 @@ int main(int argc, const char *argv[]) { for (int i = 0; i < NUM_SOCKETS; i++) { if (FD_ISSET(SOCKETS[i], &read_socket_fds)) { - client = accept(SOCKETS[i], (struct sockaddr *) &client_addr, &client_addr_len); - if (client == -1) { + client_fd = accept(SOCKETS[i], (struct sockaddr *) &client_addr, &client_addr_len); + if (client_fd == -1) { fprintf(parent_stderr, ERR_STR "Unable to accept connection: %s" CLR_STR "\n", strerror(errno)); continue; } @@ -179,11 +238,15 @@ int main(int argc, const char *argv[]) { // child signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); - return client_handler(client, client_num, &client_addr); + + client.socket = client_fd; + client.enc = i == 1; + + return client_handler(&client, client_num, &client_addr); } else if (pid > 0) { // parent client_num++; - close(client); + close(client_fd); for (int j = 0; j < MAX_CHILDREN; j++) { if (CHILDREN[j] == 0) { CHILDREN[j] = pid; diff --git a/src/necronda-server.h b/src/necronda-server.h index d6ccea8..175496b 100644 --- a/src/necronda-server.h +++ b/src/necronda-server.h @@ -10,6 +10,13 @@ #include #include +#include +#include +#include +#include +#include +#include +#include #define NUM_SOCKETS 2 @@ -18,13 +25,23 @@ #define ERR_STR "\x1B[1;31m" #define CLR_STR "\x1B[0m" -#define R_STR "\x1B[31m" -#define G_STR "\x1B[32m" +#define HTTP_STR "\x1B[1;31m" +#define HTTPS_STR "\x1B[1;32m" int SOCKETS[NUM_SOCKETS]; pid_t CHILDREN[MAX_CHILDREN]; FILE *parent_stdout, *parent_stderr; +typedef struct { + int enc:1; + int socket; + SSL_CTX *ctx; + SSL *ssl; + BIO *bio_in; + BIO *bio_out; +} sock; + +char *ssl_get_error(SSL *ssl, int ret); #endif //NECRONDA_SERVER_NECRONDA_SERVER_H