From 769606f01e17ca633f8c2a4cc16aa5e0ed94627d Mon Sep 17 00:00:00 2001 From: Brad Arant Date: Mon, 11 Apr 2022 21:06:21 -0700 Subject: [PATCH] an attempt --- #TCPServer.cpp# | 164 ++++++++++++++++++++++++++++++++ TCPServer.cpp | 47 +++++---- TCPServer.h | 6 ++ TLSServer.cpp | 100 ++++++++----------- TLSServer.h | 50 ++++------ TLSSession.h | 53 ----------- TLSSession.cpp => TLSSocket.cpp | 26 +++-- TLSSocket.h | 21 ++++ 8 files changed, 298 insertions(+), 169 deletions(-) create mode 100644 #TCPServer.cpp# delete mode 100644 TLSSession.h rename TLSSession.cpp => TLSSocket.cpp (89%) create mode 100644 TLSSocket.h diff --git a/#TCPServer.cpp# b/#TCPServer.cpp# new file mode 100644 index 0000000..576fb0e --- /dev/null +++ b/#TCPServer.cpp# @@ -0,0 +1,164 @@ +#include "TCPServer.h" +#include "EPoll.h" +#include "TCPSession.h" +#include "Exception.h" +#include "Log.h" + +namespace core { + + TCPServer::TCPServer(EPoll &ePoll, IPAddress address, std::string delimiter, int depth, std::string text) + : TCPSocket(ePoll, text), commands(delimiter, depth) { + + commands.add(subscriptions, "publish"); + commands.add(subscriptions, "unpublish"); + commands.add(subscriptions, "subscribe"); + commands.add(subscriptions, "unsubscribe"); + commands.add(subscriptions, "catalog"); + commands.add(subscriptions, "event"); + + setDescriptor(socket(AF_INET, SOCK_STREAM, 0)); + int yes = 1; + setsockopt(getDescriptor(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); + + if(bind(getDescriptor(), address.getPointer(), address.addressLength) < 0) + throw coreutils::Exception("Error on bind to socket: " + std::to_string(errno)); + + if(listen(getDescriptor(), 20) < 0) + throw coreutils::Exception("Error on listen to socket"); + + if(tls) + tls->tlsServer(); + + } + + TCPServer::~TCPServer() { + coreutils::Log(coreutils::LOG_DEBUG_2) << "Closing server socket " << getDescriptor() << "."; + close(getDescriptor()); + } + + void TLS::tlsServer() + { + + + SSL_library_init(); + SSL_load_error_strings(); + + lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t)); + for(int i = 0; i < CRYPTO_num_locks(); ++i) + pthread_mutex_init(&(lockarray[i]), NULL); + + CRYPTO_set_id_callback((unsigned long (*)())thread_id); + CRYPTO_set_locking_callback((void (*)(int, int, const char *, int))lock_callback); + + SSLeay_add_ssl_algorithms(); + RAND_load_file("/dev/hwrng", 1024); + + if(!(ctx = SSL_CTX_new(SSLv23_server_method()))) + throw coreutils::Exception("Error while setting server method SSLv23."); + SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); + // SSL_CTX_set_generate_session_id(ctx, generate_session_id); + SSL_CTX_set_cipher_list(ctx, "ECDH-ECDSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DH$ if(SSL_CTX_use_certificate_file(ctx, sip_cert, SSL_FILETYPE_PEM) <= 0) + throw coreutils::Exception("Error looking up certificate."); + if(SSL_CTX_use_PrivateKey_file(ctx, sip_key, SSL_FILETYPE_PEM) < 0) + throw coreutils::Exception("Error with private key."); + if(SSL_CTX_check_private_key(ctx) != 1) + throw coreutils::Exception("Private key does not match certificate."); + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + SSL_CTX_set_verify_depth(ctx, 1); + if(!SSL_CTX_load_verify_locations(ctx, sip_cacert, NULL)) + throw coreutils::Exception("Cannot verify locations."); + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(sip_cacert)); + coreutils::Log(coreutils::LOG_DEBUG_1) << + + void TCPServer::onDataReceived(std::string data) { + lock.lock(); + TCPSession *session = accept(); + if(session) + sessions.push_back(session); + lock.unlock(); + } + + TCPSession * TCPServer::accept() { + + try { + + TCPSession *session = getSocketAccept(ePoll); + session->setDescriptor(::accept(getDescriptor(), (struct sockaddr *)&session->ipAddress.addr, &session->ipAddress.addressLength)); + // if(blackList && blackList->contains(session->ipAddress.getClientAddress())) { + // session->shutdown(); + // Log(LOG_WARN) << "Client at IP address " << session->ipAddress.getClientAddress() << " is blacklisted and was denied a connection."; + // return NULL; + // } + // if(whiteList && !whiteList->contains(session->ipAddress.getClientAddress())) { + // session->shutdown(); + // Log(LOG_WARN) << "Client at IP address " << session->ipAddress.getClientAddress() << " is not authorized and was denied a connection."; + // return NULL; + // } + return session; + } + catch(coreutils::Exception e) { + coreutils::Log(coreutils::LOG_EXCEPT) << "Major error on session initialization. Error is '" << e.text << "'."; + } + catch(...) { + coreutils::Log(coreutils::LOG_EXCEPT) << "Unnspecified error on session initialization."; + } + return NULL; + } + + void TCPServer::removeFromSessionList(TCPSession *session) { + std::vector::iterator cursor; + lock.lock(); + for(cursor = sessions.begin(); cursor < sessions.end(); ++cursor) + if(*cursor == session) { + sessions.erase(cursor); + break; + } + lock.unlock(); + } + + void TCPServer::sessionErrorHandler(std::string errorString, std::stringstream &out) { + throw coreutils::Exception(errorString); + } + + TCPSession * TCPServer::getSocketAccept(EPoll &ePoll) { + return new TCPSession(ePoll, *this); + } + + void TCPServer::output(std::stringstream &out) { + out << "Use the 'help' command to list the commands for this server." << std::endl; + } + + int TCPServer::processCommand(coreutils::ZString &request, TCPSession &session) { + int sequence = 0; + for(auto *sessionx : sessions) { + session.out << "|" << ++sequence; + sessionx->output(session.out); + session.out << "|" << std::endl; + } + return 1; + } + + void TCPServer::sendToAll(std::stringstream &data) { + for(auto session : sessions) + session->write(data.str()); + data.str(""); + } + + void TCPServer::sendToAll(std::stringstream &data, TCPSession &sender) { + for(auto session : sessions) + if(session != &sender) + session->write(data.str()); + data.str(""); + } + + void TCPServer::sendToAll(std::stringstream &data, TCPSession &sender, SessionFilter filter) { + for(auto session : sessions) + if(filter.test(*session)) + if(session != &sender) + session->write(data.str()); + data.str(""); + } + +} diff --git a/TCPServer.cpp b/TCPServer.cpp index 24adf2d..e98fa89 100644 --- a/TCPServer.cpp +++ b/TCPServer.cpp @@ -6,25 +6,30 @@ namespace core { - TCPServer::TCPServer(EPoll &ePoll, IPAddress address, std::string delimiter, int depth, std::string text) - : TCPSocket(ePoll, text), commands(delimiter, depth) { + TCPServer::TCPServer(EPoll &ePoll, + IPAddress address, + std::string delimiter, + int depth, + std::string text + TSLServer *tls) + : TCPSocket(ePoll, text), commands(delimiter, depth), tls(tls) { - commands.add(subscriptions, "publish"); - commands.add(subscriptions, "unpublish"); - commands.add(subscriptions, "subscribe"); - commands.add(subscriptions, "unsubscribe"); - commands.add(subscriptions, "catalog"); - commands.add(subscriptions, "event"); + commands.add(subscriptions, "publish"); + commands.add(subscriptions, "unpublish"); + commands.add(subscriptions, "subscribe"); + commands.add(subscriptions, "unsubscribe"); + commands.add(subscriptions, "catalog"); + commands.add(subscriptions, "event"); - setDescriptor(socket(AF_INET, SOCK_STREAM, 0)); - int yes = 1; - setsockopt(getDescriptor(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); + setDescriptor(socket(AF_INET, SOCK_STREAM, 0)); + int yes = 1; + setsockopt(getDescriptor(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); - if(bind(getDescriptor(), address.getPointer(), address.addressLength) < 0) - throw coreutils::Exception("Error on bind to socket: " + std::to_string(errno)); + if(bind(getDescriptor(), address.getPointer(), address.addressLength) < 0) + throw coreutils::Exception("Error on bind to socket: " + std::to_string(errno)); - if(listen(getDescriptor(), 20) < 0) - throw coreutils::Exception("Error on listen to socket"); + if(listen(getDescriptor(), 20) < 0) + throw coreutils::Exception("Error on listen to socket"); } @@ -72,10 +77,10 @@ namespace core { std::vector::iterator cursor; lock.lock(); for(cursor = sessions.begin(); cursor < sessions.end(); ++cursor) - if(*cursor == session) { + if(*cursor == session) { sessions.erase(cursor); break; - } + } lock.unlock(); } @@ -100,20 +105,20 @@ namespace core { } return 1; } - + void TCPServer::sendToAll(std::stringstream &data) { for(auto session : sessions) session->write(data.str()); data.str(""); } - + void TCPServer::sendToAll(std::stringstream &data, TCPSession &sender) { for(auto session : sessions) if(session != &sender) session->write(data.str()); data.str(""); } - + void TCPServer::sendToAll(std::stringstream &data, TCPSession &sender, SessionFilter filter) { for(auto session : sessions) if(filter.test(*session)) @@ -121,5 +126,5 @@ namespace core { session->write(data.str()); data.str(""); } - + } diff --git a/TCPServer.h b/TCPServer.h index 98aa8f3..5f15a1a 100644 --- a/TCPServer.h +++ b/TCPServer.h @@ -115,6 +115,12 @@ namespace core { SubscriptionManager subscriptions; + /// + /// The TLS context for the server. + /// + + TLSServer *tlsServer; + protected: /// diff --git a/TLSServer.cpp b/TLSServer.cpp index dcee0d6..f539bfb 100644 --- a/TLSServer.cpp +++ b/TLSServer.cpp @@ -1,66 +1,50 @@ #include "TLSServer.h" -#include "TLSSession.h" -#include "EPoll.h" -#include "TCPSession.h" -#include "Exception.h" namespace core { - - static pthread_mutex_t *lockarray; - static unsigned long thread_id(void) { - return ((unsigned long) pthread_self()); - } - - static void lock_callback(int mode, int type, const char *file, int line) { - if(mode & CRYPTO_LOCK) - pthread_mutex_lock(&(lockarray[type])); - else - pthread_mutex_unlock(&(lockarray[type])); - } - - TLSServer::TLSServer(EPoll &ePoll, IPAddress address) : TCPServer(ePoll, address) { + void TLSServer::TLSServer() { - SSL_library_init(); - SSL_load_error_strings(); - - lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t)); - for(int i = 0; i < CRYPTO_num_locks(); ++i) - pthread_mutex_init(&(lockarray[i]), NULL); - - CRYPTO_set_id_callback((unsigned long (*)())thread_id); - CRYPTO_set_locking_callback((void (*)(int, int, const char *, int))lock_callback); - - SSLeay_add_ssl_algorithms(); - RAND_load_file("/dev/hwrng", 1024); + SSL_library_init(); + SSL_load_error_strings(); + + lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t)); + for(int i = 0; i < CRYPTO_num_locks(); ++i) + pthread_mutex_init(&(lockarray[i]), NULL); + + CRYPTO_set_id_callback((unsigned long (*)())thread_id); + CRYPTO_set_locking_callback((void (*)(int, int, const char *, int))lock_callback); + + SSLeay_add_ssl_algorithms(); + RAND_load_file("/dev/hwrng", 1024); + + if(!(ctx = SSL_CTX_new(SSLv23_server_method()))) + throw coreutils::Exception("Error while setting server method SSLv23."); + + SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); + SSL_CTX_set_generate_session_id(ctx, generate_session_id); + SSL_CTX_set_cipher_list(ctx, "ECDH-ECDSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA"); + + if(SSL_CTX_use_certificate_file(ctx, sip_cert, SSL_FILETYPE_PEM) <= 0) + throw coreutils::Exception("Error looking up certificate."); + + if(SSL_CTX_use_PrivateKey_file(ctx, sip_key, SSL_FILETYPE_PEM) < 0) + throw coreutils::Exception("Error with private key."); + + if(SSL_CTX_check_private_key(ctx) != 1) + throw coreutils::Exception("Private key does not match certificate."); + + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + SSL_CTX_set_verify_depth(ctx, 1); + + if(!SSL_CTX_load_verify_locations(ctx, sip_cacert, NULL)) + throw coreutils::Exception("Cannot verify locations."); + + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(sip_cacert)); + + coreutils::Log(coreutils::LOG_DEBUG_1) << "Server key authenticated."; - if(!(ctx = SSL_CTX_new(SSLv23_server_method()))) - throw coreutils::Exception("Error while setting server method SSLv23."); - SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); - SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); - // SSL_CTX_set_generate_session_id(ctx, generate_session_id); - SSL_CTX_set_cipher_list(ctx, "ECDH-ECDSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA"); - if(SSL_CTX_use_certificate_file(ctx, sip_cert, SSL_FILETYPE_PEM) <= 0) - throw coreutils::Exception("Error looking up certificate."); - if(SSL_CTX_use_PrivateKey_file(ctx, sip_key, SSL_FILETYPE_PEM) < 0) - throw coreutils::Exception("Error with private key."); - if(SSL_CTX_check_private_key(ctx) != 1) - throw coreutils::Exception("Private key does not match certificate."); - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); - SSL_CTX_set_verify_depth(ctx, 1); - if(!SSL_CTX_load_verify_locations(ctx, sip_cacert, NULL)) - throw coreutils::Exception("Cannot verify locations."); - SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(sip_cacert)); - coreutils::Log(coreutils::LOG_DEBUG_1) << "Server key authenticated."; } - - TLSServer::~TLSServer() { - - } - - TCPSession * TLSServer::getSocketAccept() { - return new TLSSession(ePoll, *this); - } - + } diff --git a/TLSServer.h b/TLSServer.h index c854613..09d1681 100644 --- a/TLSServer.h +++ b/TLSServer.h @@ -1,54 +1,42 @@ -#ifndef TLSServerSocket_h__ -#define TLSServerSocket_h__ +#ifndef __TLSServer_h__ +#define __TLSServer_h__ -#include "Socket.h" -#include "TCPServer.h" -#include "Command.h" -#include "TCPSession.h" -#include "IPAddress.h" +#include "pthreads.h" namespace core { - + /// - /// TLSServer + /// Use the TLSServer object to initialize an SSL/TLS context for the server. /// - /// Manage a socket connection as a TLS server type. Connections to the socket are processed through - /// the accept functionality. - /// - - class TLSServer : public TCPServer { - + + class TLSServer { + public: - + /// /// The constructor. /// - /// @param ePoll the BMAEPoll instance that manages the socket. - /// @param url the IP address for the socket to receive connection requests. - /// @param port the port number that the socket will listen on. - /// @param commandName the name of the command used to invoke the status display for this object. - /// @return the instance of the BMATLSServerSocket. - - TLSServer(EPoll &ePoll, IPAddress address); - + + TLSServer(); + /// /// The destructor for this object. /// - - ~TLSServer(); - TCPSession * getSocketAccept(); + ~TLSServer(); + + SSL_CTX *ctx; - SSL_CTX *ctx; - private: char *sip_cacert = (char *)"../testkeys/certs/pbxca.crt"; char *sip_cert = (char *)"../testkeys/certs/pbxserver.crt"; char *sip_key = (char *)"../testkeys/certs/pbxserver.key"; - + + pthread_mutex_t *lockarray; + }; - + } #endif diff --git a/TLSSession.h b/TLSSession.h deleted file mode 100644 index 741a0f7..0000000 --- a/TLSSession.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef __TLSSession_h__ -#define __TLSSession_h__ - -#include "includes" -#include "TCPSession.h" -#include "TLSServer.h" -#include - -namespace core { - - class TLSServer; - - /// - /// TLSSession - /// - /// Provides a network TLS socket. - /// - /// For accessing TLS network functions use this object. The connection oriented nature of TLS - /// provides a single client persistent connection with data error correction and a durable - /// synchronous data connection. - /// - - class TLSSession : public TCPSession { - - public: - - TLSSession(EPoll &ePoll, TCPServer &server); - ~TLSSession(); - - /// - /// The output method is called by a socket session (Session) and - /// will output the detail information for the client socket. When extending - /// TLSSocket or Session you can override the method to add attributes - /// to the list. - /// - - virtual void output(std::stringstream &out); - virtual void protocol(coreutils::ZString &data) override; - - protected: - void receiveData(coreutils::ZString &buffer) override; - void onRegister(); - void onRegistered(); - - private: - bool initialized = false; - SSL *ssl; - - }; - -} - -#endif diff --git a/TLSSession.cpp b/TLSSocket.cpp similarity index 89% rename from TLSSession.cpp rename to TLSSocket.cpp index 24efdd0..56b8f9f 100644 --- a/TLSSession.cpp +++ b/TLSSocket.cpp @@ -1,11 +1,25 @@ -#include "TLSSession.h" -#include "EPoll.h" -#include "Log.h" +#include "TLS.h" #include "Exception.h" namespace core { + + static unsigned long thread_id(void) { + return ((unsigned long) pthread_self()); + } - static int generate_session_id(const SSL *ssl, unsigned char *id, unsigned int *id_len) { + static void lock_callback(int mode, int type, const char *file, int line) { + if(mode & CRYPTO_LOCK) + pthread_mutex_lock(&(lockarray[type])); + else + pthread_mutex_unlock(&(lockarray[type])); + } + + + TLS::~TLS() { + + } + + static int generate_session_id(const SSL *ssl, unsigned char *id, unsigned int *id_len) { char *session_id_prefix = (char *)"BARANT"; unsigned int count = 0; coreutils::Log(coreutils::LOG_DEBUG_3) << "Generating unique session id."; @@ -27,7 +41,7 @@ namespace core { throw std::string("Certificate verification failed."); coreutils::Log(coreutils::LOG_DEBUG_3) << "Certificate verified successfully."; } - else + else coreutils::Log(coreutils::LOG_DEBUG_3) << "No client certificate."; } @@ -119,5 +133,5 @@ namespace core { out << "|" << ipAddress.getClientAddressAndPort(); } + } - \ No newline at end of file diff --git a/TLSSocket.h b/TLSSocket.h new file mode 100644 index 0000000..26916e6 --- /dev/null +++ b/TLSSocket.h @@ -0,0 +1,21 @@ +#ifndef __TLSSocket_h__ +#define __TLSSocket_h__ + +namespace core { + + /// + /// Instantiate the TLSSocket object into the TCPSocket to + /// encrypt the TCP connection. + /// + + class TLSSocket { + + public: + TLSSocket(); + ~TLSSocket(); + + }; + +} + +#endif