/** * @file SecureSocket.cpp * @brief implementation of the Secure Socket class * @author Mohamed Amine Mzoughi */ #ifdef OPENSSL #include "SecureSocket.h" #include #ifndef LINUX // to avoid link problems in prod/test program // Update : with the newer versions of OpenSSL, there's no need to include it //#include #endif ASecureSocket::SecureSocketGlobalInitializer& ASecureSocket::SecureSocketGlobalInitializer::instance() { static SecureSocketGlobalInitializer inst{}; return inst; } ASecureSocket::SecureSocketGlobalInitializer::SecureSocketGlobalInitializer() { InitializeSSL(); } ASecureSocket::SecureSocketGlobalInitializer::~SecureSocketGlobalInitializer() { DestroySSL(); } /** * @brief constructor of the Secure Socket * * @param oLogger - a callabck to a logger function void(const std::string&) * @param eSSLVersion - SSL/TLS protocol version * */ ASecureSocket::ASecureSocket(const LogFnCallback& oLogger, const OpenSSLProtocol eSSLVersion, const SettingsFlag eSettings /*= ALL_FLAGS*/) : ASocket(oLogger, eSettings), m_eOpenSSLProtocol(eSSLVersion), m_globalInitializer(SecureSocketGlobalInitializer::instance()) { } /** * @brief destructor of the secure socket object * It's a pure virtual destructor but an implementation is provided below. * this to avoid creating a dummy pure virtual method to transform the class * to an abstract one. */ ASecureSocket::~ASecureSocket() { } void ASecureSocket::SetUpCtxClient(SSLSocket& Socket) { switch (m_eOpenSSLProtocol) { default: case OpenSSLProtocol::TLS: // Standard Protocol as of 11/2018, OpenSSL will choose highest possible TLS standard between peers Socket.m_pMTHDSSL = const_cast(TLS_client_method()); break; case OpenSSLProtocol::SSL_V23: Socket.m_pMTHDSSL = const_cast(SSLv23_client_method()); break; #ifndef LINUX // deprecated in newer versions of OpenSSL //case OpenSSLProtocol::SSL_V2: //Socket.m_pMTHDSSL = const_cast(SSLv2_client_method()); //break; #endif // deprecated /*case OpenSSLProtocol::SSL_V3: Socket.m_pMTHDSSL = const_cast(SSLv3_client_method()); break;*/ case OpenSSLProtocol::TLS_V1: Socket.m_pMTHDSSL = const_cast(TLSv1_client_method()); break; } Socket.m_pCTXSSL = SSL_CTX_new(Socket.m_pMTHDSSL); } void ASecureSocket::SetUpCtxServer(SSLSocket& Socket) { switch (m_eOpenSSLProtocol) { default: case OpenSSLProtocol::TLS: // Standard Protocol as of 11/2018, OpenSSL will choose highest possible TLS standard between peers Socket.m_pMTHDSSL = const_cast(TLS_server_method()); break; #ifndef LINUX //case OpenSSLProtocol::SSL_V2: //Socket.m_pMTHDSSL = const_cast(SSLv2_server_method()); //break; #endif // deprecated /*case OpenSSLProtocol::SSL_V3: Socket.m_pMTHDSSL = const_cast(SSLv3_server_method()); break;*/ case OpenSSLProtocol::TLS_V1: Socket.m_pMTHDSSL = const_cast(TLSv1_server_method()); break; case OpenSSLProtocol::SSL_V23: Socket.m_pMTHDSSL = const_cast(SSLv23_server_method()); break; } Socket.m_pCTXSSL = SSL_CTX_new(Socket.m_pMTHDSSL); } void ASecureSocket::InitializeSSL() { /* Initialize malloc, free, etc for OpenSSL's use. */ //CRYPTO_malloc_init(); /* Initialize OpenSSL's SSL libraries: load encryption & hash algorithms for SSL */ SSL_library_init(); /* Load the error strings for good error reporting */ SSL_load_error_strings(); /* Load BIO error strings. */ //ERR_load_BIO_strings(); /* Load all available encryption algorithms. */ OpenSSL_add_all_algorithms(); } void ASecureSocket::DestroySSL() { ERR_free_strings(); EVP_cleanup(); } void ASecureSocket::ShutdownSSL(SSLSocket& SSLSock) { if (SSLSock.m_pSSL != nullptr) { /* send the close_notify alert to the peer. */ SSL_shutdown(SSLSock.m_pSSL); // must be called before SSL_free SSL_free(SSLSock.m_pSSL); SSL_CTX_free(SSLSock.m_pCTXSSL); SSLSock.m_pSSL = nullptr; } } const char* ASecureSocket::GetSSLErrorString(int iErrorCode) { switch (iErrorCode) { case SSL_ERROR_NONE: return "The TLS/SSL I/O operation completed."; break; case SSL_ERROR_ZERO_RETURN: return "The TLS/SSL connection has been closed."; break; case SSL_ERROR_WANT_READ: return "The read operation did not complete; " "the same TLS/SSL I/O function should be called again later."; break; case SSL_ERROR_WANT_WRITE: return "The write operation did not complete; " "the same TLS/SSL I/O function should be called again later."; break; case SSL_ERROR_WANT_CONNECT: return "The connect operation did not complete; " "the same TLS/SSL I/O function should be called again later."; break; case SSL_ERROR_WANT_ACCEPT: return "The accept operation did not complete; " "the same TLS/SSL I/O function should be called again later."; break; case SSL_ERROR_WANT_X509_LOOKUP: return "The operation did not complete because an application callback set" " by SSL_CTX_set_client_cert_cb() has asked to be called again. " "The TLS/SSL I/O function should be called again later."; break; case SSL_ERROR_SYSCALL: return "Some I/O error occurred. The OpenSSL error queue may contain" " more information on the error."; break; case SSL_ERROR_SSL: return "A failure in the SSL library occurred, usually a protocol error. " "The OpenSSL error queue contains more information on the error."; break; default: return "Unknown error !"; break; } } int ASecureSocket::AlwaysTrueCallback(X509_STORE_CTX* pCTX, void* pArg) { return 1; } #endif