From c3e663de847717f8001686464978a82aeee82a08 Mon Sep 17 00:00:00 2001 From: hgn Date: Mon, 2 Sep 2024 16:16:21 +0100 Subject: [PATCH] oppenssl and s2n versions --- .gitignore | 2 + builds2n.sh | 3 + buildtls.sh | 3 + servers2n.c | 498 ++++++++++++++++++++++++++++++++++++++++++++++++++++ servertls.c | 407 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 913 insertions(+) create mode 100755 builds2n.sh create mode 100755 buildtls.sh create mode 100644 servers2n.c create mode 100644 servertls.c diff --git a/.gitignore b/.gitignore index 36f971e..ec3e2b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ bin/* +*.pem +cert.h diff --git a/builds2n.sh b/builds2n.sh new file mode 100755 index 0000000..a77344f --- /dev/null +++ b/builds2n.sh @@ -0,0 +1,3 @@ +gcc -Wall -Wno-unused-function -ggdb3 -O0 -fsanitize=address servers2n.c \ + -ls2n \ + -o bin/servers2n && bin/servers2n ; echo exit: $? diff --git a/buildtls.sh b/buildtls.sh new file mode 100755 index 0000000..3fef495 --- /dev/null +++ b/buildtls.sh @@ -0,0 +1,3 @@ +clang -Wall -g -O0 -fsanitize=address servertls.c \ + -lcrypto -lssl \ + -o bin/servertls && bin/servertls ; echo exit: $? diff --git a/servers2n.c b/servers2n.c new file mode 100644 index 0000000..e93260e --- /dev/null +++ b/servers2n.c @@ -0,0 +1,498 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "http.h" +#include "cert.h" + +const char *WEBSITE = +"HTTP/1.0 200 OK\r\n" +"Server: u461\r\n" +"Content-Type: text/html\r\n" +"\r\n" +"

HELLO ITS A WEBSITE (delivered encrypted using amazon s2n TLS)

\r\n"; + +#define SERVER_HEADER "Server: u461\r\n" +#define HTTP_ERROR( X ) \ + "HTTP/1.0 " X "\r\n" SERVER_HEADER "Connection: close\r\n\r\n" + +const char *k_response_saturated = HTTP_ERROR( "503 Service Unavailable" ); +const char *k_response_parsefail = HTTP_ERROR( "500 Internal Server Error" ); +const char *k_response_toobig = HTTP_ERROR( "413 Payload Too Large" ); +const char *k_response_temp = HTTP_ERROR( "501 Not Implemented" ); +const char *k_response_timeout = HTTP_ERROR( "408 Request Timeout" ); + +#define MAX_CLIENTS 10 +#define REQUEST_MAX_SIZE 1024 + +struct client +{ + int connfd; + + enum state + { + k_state_none, + k_state_opening, + k_state_secured, + k_state_closing + } + state; + + struct http_request request; + struct s2n_connection *s2n; +} +_clients[ MAX_CLIENTS ]; +int _ticks_without_action = 0; +int _run_server = 1; + +static void int_handle( int sig ) +{ + _run_server = 0; + printf( "Ok stopping..\n" ); +} + +static void _write_s2n_error( FILE *fp, const char *prefix ) +{ + fprintf( fp, "%s | s2n Error: %s. %s\n", prefix, + s2n_strerror(s2n_errno, NULL), + s2n_strerror_debug(s2n_errno, NULL)); +} + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define write_s2n_error( FP ) \ + _write_s2n_error( FP, __FILE__ ":L" STRINGIZE(__LINE__) ); + +static int open_listen_socket( int port ) +{ + int listenfd; + struct sockaddr_in serv_addr = {0}; + listenfd = socket( AF_INET, SOCK_STREAM, 0 ); + + if( listenfd == -1 ) + { + fprintf( stderr, "socket() error: %s\n", strerror(errno) ); + return -1; + } + + if( fcntl( listenfd, F_SETFL, O_NONBLOCK ) == -1 ) + { + fprintf( stderr, "fcntl() error: %s\n", strerror(errno) ); + return -1; + } + + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl( INADDR_ANY ); + serv_addr.sin_port = htons( port ); + + if( bind( listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ) == -1 ) + { + fprintf( stderr, "bind() error: %s\n", strerror(errno) ); + return -1; + } + + if( listen( listenfd, 10 ) == -1 ) + { + fprintf( stderr, "listen() error: %s\n", strerror(errno) ); + return -1; + } + + return listenfd; +} + +int _accept_any_new_client( int listenfd, struct s2n_config *conf ) +{ + int fd = accept( listenfd, (struct sockaddr*)NULL, NULL ); + if( fd == -1 ) + { + if( !( errno == EAGAIN || errno == EWOULDBLOCK ) ) + { + fprintf( stderr, "accept() warning: %s\n", strerror(errno) ); + } + + return 0; + } + + if( fcntl( fd, F_SETFL, O_NONBLOCK ) == -1 ) + { + fprintf( stderr, "fcntl() error: %s\n", strerror(errno) ); + close( fd ); + return 0; + } + + + struct client *client = NULL; + for( int i=0; istate == k_state_none ) + { + client = c; + break; + } + } + + if( client == NULL ) + { + fprintf( stderr, "Server saturated, cannot accept new client.\n" ); + //write( fd, k_response_saturated, strlen(k_response_saturated) ); + close( fd ); + return 0; + } + + memset( client, 0, sizeof(struct client) ); + client->connfd = fd; + + printf( "Accepted new client (%d)\n", fd ); + + client->s2n = s2n_connection_new( S2N_SERVER ); + + if( client->s2n == NULL ) + { + write_s2n_error( stderr ); + goto _cleanup_sock; + } + + if( s2n_connection_set_config( client->s2n, conf ) == -1 ) + { + write_s2n_error( stderr ); + goto _cleanup_s2n; + } + + if( s2n_connection_set_blinding( client->s2n, + S2N_SELF_SERVICE_BLINDING ) == -1 ) + { + write_s2n_error( stderr ); + goto _cleanup_s2n; + } + + if( s2n_connection_set_fd( client->s2n, client->connfd ) == -1 ) + { + write_s2n_error( stderr ); + goto _cleanup_s2n; + } + + client->state = k_state_opening; + return 1; + +_cleanup_s2n: + s2n_connection_free( client->s2n ); + +_cleanup_sock: + close( client->connfd ); + return 0; +} + +/* returns number of currently handshaking */ +int _process_handshakes(void) +{ + int verifying = 0; + for( int i=0; istate == k_state_opening ) + { + s2n_blocked_status blocked; + if( s2n_negotiate( c->s2n, &blocked ) == 0 ) + { + printf( "handshake completed\n" ); + c->state = k_state_secured; + } + else + { + if( s2n_error_get_type( s2n_errno ) != S2N_ERR_T_BLOCKED ) + { + write_s2n_error( stderr ); + s2n_connection_free( c->s2n ); + close( c->connfd ); + c->state = k_state_none; + } + else verifying ++; + } + } + } + + return verifying; +} + +/* returns number of shutting down */ +int _process_shutdowns(void) +{ + int closing = 0; + for( int i=0; istate == k_state_closing ) + { + s2n_blocked_status blocked; + if( s2n_shutdown( c->s2n, &blocked ) == 0 ) + { + printf( "sucessfuly closed\n" ); + s2n_connection_free( c->s2n ); + close( c->connfd ); + c->state = k_state_none; + } + else + { + if( s2n_error_get_type( s2n_errno ) != S2N_ERR_T_BLOCKED ) + { + write_s2n_error( stderr ); + s2n_connection_free( c->s2n ); + close( c->connfd ); + c->state = k_state_none; + } + else closing ++; + } + } + } + + if( closing ) + printf( "Still closing: %d\n", closing ); + return closing; +} + +int s2nsend_busy( struct s2n_connection *conn, const void *buf, int len ) +{ + int written = 0; + while( written < len ) + { + s2n_blocked_status blocked; + int w = s2n_send( conn, buf + written, len - written, &blocked); + if( w >= 0 ) + { + written += w; + } + else if( s2n_error_get_type(s2n_errno) == S2N_ERR_T_BLOCKED ) + { + } + else + { + write_s2n_error( stderr ); + return -1; + } + + struct timespec spec; + spec.tv_sec = 0; + spec.tv_nsec = 10000000; /* 0.01s (100 tick)*/ + nanosleep( &spec, NULL ); + } + return 1; +} + +/* returns -1 if error, 0 if no action/disconnect, 1 if recieved data/sent */ +int client_handle_requests( struct client *client ) +{ + char recv_buf[ 512 ]; + //int len = recv( client->connfd, recv_buf, sizeof(recv_buf), 0 ); + + s2n_blocked_status blocked; + int len = s2n_recv( client->s2n, recv_buf, sizeof(recv_buf), &blocked ); + + if( len > 0 ) + { + //printf( "RAW BUF ------\n%.*s\n-----------\n", len, recv_buf ); + + int remaining = len; + while( remaining ) + { + /* New data has been read off the socket */ + int amt = http_request_parse( &client->request, + recv_buf + (len-remaining), + remaining ); + if( amt == -1 ) + { + fprintf( stderr, "[#%d][http parser] There was %s while %s.\n" + " line: %d, column: %d\n", + client->connfd, + ehttp_parse_error[ client->request.error ], + ehttp_parse_state[ client->request.state ], + client->request.line, client->request.col ); + + if( s2nsend_busy( client->s2n, k_response_parsefail, + strlen( k_response_parsefail )) == -1 ) + { + s2n_connection_free( client->s2n ); + close( client->connfd ); + client->state = k_state_none; + } + else + { + client->state = k_state_closing; + } + + return -1; + } + else + { + remaining -= amt; + + if( client->request.state == k_parse_state_complete ) + { + http_fprintf_request_info( stdout, &client->request ); + + if( !strncmp( client->request.resource, "/", + client->request.resource_len ) ) + { + printf( "Gave website :D\n" ); + if( s2nsend_busy( client->s2n, WEBSITE, strlen(WEBSITE) ) + == -1 ) + { + s2n_connection_free( client->s2n ); + close( client->connfd ); + client->state = k_state_none; + return -1; + } + } + else + { + fprintf( stderr, "Responding #%d with 501\n", client->connfd ); + if( s2nsend_busy( client->s2n, + k_response_temp, strlen(k_response_temp) ) + == -1 ) + { + s2n_connection_free( client->s2n ); + close( client->connfd ); + client->state = k_state_none; + return -1; + } + } + + printf( "Setting state to closing!\n" ); + /* reset parser */ + memset( &client->request, 0, sizeof(struct http_request) ); + client->state = k_state_closing; + } + } + } + return 1; + } + else if( len == 0 ) + { + printf( "Client #%d disconnected\n", client->connfd ); + client->state = k_state_closing; + return 0; + } + else + { + if( s2n_error_get_type( s2n_errno ) == S2N_ERR_T_BLOCKED ) + { + return 0; + } + else + { + write_s2n_error( stderr ); + s2n_connection_free( client->s2n ); + close( client->connfd ); + client->state = k_state_none; + return -1; + } + } +} + +int _process_requests(void) +{ + int closing = 0; + for( int i=0; istate == k_state_secured ) + client_handle_requests( c ); + } + return 0; +} + +int main(int argc, char *argv[]) +{ + signal( SIGINT, int_handle ); + signal( SIGPIPE, SIG_IGN ); + + printf( "Configuring s2n\n" ); + s2n_init(); + struct s2n_config *s2n_conf = s2n_config_new(); + if( s2n_conf == NULL ) + { + write_s2n_error( stderr ); + return 1; + } + + struct s2n_cert_chain_and_key *s2n_cert = s2n_cert_chain_and_key_new(); + if( s2n_cert == NULL ) + { + write_s2n_error( stderr ); + return 1; + } + + if( s2n_cert_chain_and_key_load_pem( s2n_cert, + SERVER_CHAIN_CERT_PEM, + SERVER_PRIV_PEM ) == -1 ) + { + write_s2n_error( stderr ); + s2n_cert_chain_and_key_free( s2n_cert ); + s2n_config_free( s2n_conf ); + return 1; + } + + if( s2n_config_add_cert_chain_and_key_to_store( s2n_conf, s2n_cert ) == -1 ) + { + write_s2n_error( stderr ); + s2n_cert_chain_and_key_free( s2n_cert ); + s2n_config_free( s2n_conf ); + return 1; + } + printf( "s2n configured\n" ); + + int listenfd = open_listen_socket( 1521 ); + + if( listenfd == -1 ) + { + fprintf( stderr, "Failed opening listen socket\n" ); + s2n_cert_chain_and_key_free( s2n_cert ); + s2n_config_free( s2n_conf ); + return 1; + } + + int ticks_without_action = 0; + + while( _run_server ) + { + _accept_any_new_client( listenfd, s2n_conf ); + _process_handshakes(); + _process_shutdowns(); + _process_requests(); + + struct timespec spec; + spec.tv_sec = 0; + spec.tv_nsec = 50000000; /* 0.05s (20 tick)*/ + nanosleep( &spec, NULL ); + } + + printf( "Closing active connections\n" ); + while(1) + { + if( _process_shutdowns() ) + { + struct timespec spec; + spec.tv_sec = 0; + spec.tv_nsec = 100000000; /* 0.10s (10 tick)*/ + nanosleep( &spec, NULL ); + } + else break; + } + printf( "Done\n" ); + + s2n_cert_chain_and_key_free( s2n_cert ); + s2n_config_free( s2n_conf ); + close( listenfd ); +} diff --git a/servertls.c b/servertls.c new file mode 100644 index 0000000..e9e5613 --- /dev/null +++ b/servertls.c @@ -0,0 +1,407 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "http.h" + +const char *WEBSITE = +"HTTP/1.0 200 OK\r\n" +"Server: u461\r\n" +"Content-Type: text/html\r\n" +"\r\n" +"

HELLO ITS A SECURE WEBSITE

\r\n"; + +#define SERVER_HEADER "Server: u461\r\n" +#define HTTP_ERROR( X ) \ + "HTTP/1.0 " X "\r\n" SERVER_HEADER "Connection: close\r\n\r\n" + +const char *k_response_saturated = HTTP_ERROR( "503 Service Unavailable" ); +const char *k_response_parsefail = HTTP_ERROR( "500 Internal Server Error" ); +const char *k_response_toobig = HTTP_ERROR( "413 Payload Too Large" ); +const char *k_response_temp = HTTP_ERROR( "501 Not Implemented" ); +const char *k_response_timeout = HTTP_ERROR( "408 Request Timeout" ); + +int _run_server = 1; +static const char ssl_cache_id[] = "u461_net http/tls session cache"; + +static void int_handle( int sig ) +{ + printf( "Stopping server..\n" ); + _run_server = 0; +} + +SSL_CTX *create_ssl_context(void) +{ + SSL_CTX *ctx = SSL_CTX_new( TLS_server_method() ); + + if( !ctx ) + { + fprintf( stderr, "SSL_CTX_new error: " ); + ERR_print_errors_fp( stderr ); + return NULL; + } + + if( !SSL_CTX_set_min_proto_version( ctx, TLS1_2_VERSION ) ) + { + SSL_CTX_free( ctx ); + fprintf( stderr, "SSL_CTX_set_min_proto_version error: " ); + ERR_print_errors_fp( stderr ); + return NULL; + } + + long opts = SSL_OP_IGNORE_UNEXPECTED_EOF | + SSL_OP_NO_RENEGOTIATION | + SSL_OP_CIPHER_SERVER_PREFERENCE; + + SSL_CTX_set_options( ctx, opts ); + + if( SSL_CTX_use_certificate_chain_file( ctx, "chain.pem" ) <= 0 ) + { + SSL_CTX_free( ctx ); + fprintf( stderr, "SSL_CTX_use_certificate_chain_file error: " ); + ERR_print_errors_fp( stderr ); + return NULL; + } + + if( SSL_CTX_use_PrivateKey_file( ctx, "priv.pem", SSL_FILETYPE_PEM ) <= 0 ) + { + SSL_CTX_free( ctx ); + fprintf( stderr, "SSL_CTX_use_PrivateKey_file error: " ); + ERR_print_errors_fp(stderr); + return NULL; + } + + SSL_CTX_set_session_id_context( ctx, (void *)ssl_cache_id, + sizeof(ssl_cache_id) ); + SSL_CTX_set_session_cache_mode( ctx, SSL_SESS_CACHE_SERVER ); + SSL_CTX_sess_set_cache_size( ctx, 1024 ); + SSL_CTX_set_timeout( ctx, 3600 ); + SSL_CTX_set_verify( ctx, SSL_VERIFY_NONE, NULL ); + + return ctx; +} + +#define MAX_CLIENTS 10 + +struct client +{ + int connfd, closing; + SSL *ssl; + struct http_request request; +} +_clients[ MAX_CLIENTS ]; + +int open_listen_socket( int port ) +{ + int listenfd; + struct sockaddr_in serv_addr = {0}; + for( int i=0; iconnfd == -1 ) + { + client = c; + break; + } + } + + if( client ) + { + memset( client, 0, sizeof(struct client) ); + client->connfd = fd; + printf( "Creating SSL connection for %d\n", client->connfd ); + + client->ssl = SSL_new( tls_ctx ); + + if( client->ssl == NULL ) + { + fprintf( stderr, "Failed to SSL_new.\n" ); + close( client->connfd ); + client->connfd = -1; + } + else + { + if( SSL_set_fd( client->ssl, client->connfd ) ) + { + if( SSL_accept( client->ssl ) <= 0 ) + { + fprintf( stderr, "SSL_accept() failure: " ); + ERR_print_errors_fp( stderr ); + fprintf( stderr, "\n" ); + SSL_free( client->ssl ); + close( fd ); + client->connfd = -1; + } + else + { + printf( "Accepted new client (%d)\n", fd ); + return 1; + } + } + else + { + fprintf( stderr, "Failed to SSL_set_fd.\n" ); + SSL_free( client->ssl ); + close( client->connfd ); + client->connfd = -1; + } + } + } + else + { + fprintf( stderr, "Server saturated, cannot accept new client.\n" ); + close( fd ); + } + } + + return 0; +} + +/* returns -1 if error, 0 if no action/disconnect, 1 if recieved data/sent */ +int client_handle_requests( struct client *client ) +{ + char recv_buf[ 512 ]; + int len = SSL_read( client->ssl, recv_buf, sizeof(recv_buf) ); + + if( len > 0 ) + { + //printf( "RAW BUF ------\n%.*s\n-----------\n", len, recv_buf ); + + int remaining = len; + while( remaining ) + { + /* New data has been read off the socket */ + int amt = http_request_parse( &client->request, + recv_buf + (len-remaining), + remaining ); + if( amt == -1 ) + { + fprintf( stderr, "[#%d][http parser] There was %s while %s.\n" + " line: %d, column: %d\n", + client->connfd, + ehttp_parse_error[ client->request.error ], + ehttp_parse_state[ client->request.state ], + client->request.line, client->request.col ); + + SSL_write( client->ssl, k_response_parsefail, + strlen(k_response_parsefail) ); + + SSL_shutdown( client->ssl ); + client->closing = 1; + return -1; + } + else + { + remaining -= amt; + + if( client->request.state == k_parse_state_complete ) + { + http_fprintf_request_info( stdout, &client->request ); + + if( !strncmp( client->request.resource, "/", + client->request.resource_len ) ) + { + printf( "Gave website :D\n" ); + SSL_write( client->ssl, WEBSITE, strlen(WEBSITE) ); + } + else + { + fprintf( stderr, "Responding #%d with 501\n", client->connfd ); + SSL_write( client->ssl, + k_response_temp, strlen(k_response_temp) ); + } + + //client->total_request_bytes = 0; + + /* reset parser */ + memset( &client->request, 0, sizeof(struct http_request) ); + + SSL_shutdown( client->ssl ); + client->closing = 1; + return 1; + } + else + { + } + } + } + + return 1; + } + else + { + int reason = SSL_get_error( client->ssl, len ); + + if( reason == SSL_ERROR_WANT_READ ) + { + return 0; + } + else + { + fprintf( stderr, "Error with client %d. SSL error code: %d\n", + client->connfd, reason ); + SSL_free( client->ssl ); + close( client->connfd ); + client->connfd = -1; + return -1; + } + } +} + +int _handle_ssl_shutdowns() +{ + int num_closing = 0; + + for( int i=0; iconnfd == -1 ) continue; + + if( client->closing ) + { + if( SSL_shutdown( client->ssl ) ) + { + SSL_free( client->ssl ); + close( client->connfd ); + client->connfd = -1; + client->closing = 0; + } + else + { + num_closing ++; + } + } + } + + return num_closing; +} + +int main( int argc, char *argv[] ) +{ + signal( SIGINT, int_handle ); + signal( SIGPIPE, SIG_IGN ); + + SSL_CTX *ctx = create_ssl_context(); + + if( !ctx ) + { + fprintf( stderr, "Failed to create SSL context.\n" ); + return 1; + } + + int listenfd = open_listen_socket( 1521 ); + if( listenfd == -1 ) + { + fprintf( stderr, "Failed to open listen socket.\n" ); + return 1; + } + + while( _run_server ) + { + _handle_ssl_shutdowns(); + _accept_any_new_client( ctx, listenfd ); + + /* Handle incoming data */ + for( int i=0; iconnfd == -1 ) continue; + + // if( client_timeout_step( client ) ) continue; + + client_handle_requests( client ); + } + + struct timespec spec; + spec.tv_sec = 0; + spec.tv_nsec = 50000000; /* 0.05s (20 tick)*/ + nanosleep( &spec, NULL ); + } + + /* shutdown sequence */ + printf( "Closing connections...\n" ); + for( int i=0; iconnfd == -1 ) continue; + client->closing = 1; + } + + while( _handle_ssl_shutdowns() ) + { + struct timespec spec; + spec.tv_sec = 0; + spec.tv_nsec = 50000000; /* 0.05s (20 tick)*/ + nanosleep( &spec, NULL ); + } + + printf( "Done...\n" ); + + close( listenfd ); + + SSL_CTX_free( ctx ); + return 0; +} -- 2.25.1