Implemented basic SSL
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								src/client.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,13 @@
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <openssl/bio.h>
 | 
			
		||||
#include <openssl/err.h>
 | 
			
		||||
#include <openssl/pem.h>
 | 
			
		||||
#include <openssl/ssl.h>
 | 
			
		||||
#include <openssl/conf.h>
 | 
			
		||||
#include <openssl/engine.h>
 | 
			
		||||
#include <openssl/dh.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user