From 84941bcc9f25cbe3fd3b2604080d0a1cfd8fbaa7 Mon Sep 17 00:00:00 2001 From: peterbell10 Date: Wed, 30 Aug 2017 15:00:06 +0100 Subject: Update mbedtls to 2.5.1 (#3964) * Renaming changes: * macro prefix "POLARSSL" -> "MBEDTLS" * functions now prefixed with "mbedtls_" * rename PolarSSL++ -> mbedTLS++ * rename polarssl submodule * Use mbedtls' AES-CFB8 implementation. * Add cSslConfig to wrap mbedtls_ssl_config * Update cTCPLink and cBlockingSslClientSocket to use cSslConfig * Use cSslConfig in cHTTPServer * Use cSslConfig for cMojangAPI::SecureRequest * CI Fixes * Set -fomit-frame-pointer on the right target --- .gitmodules | 6 +- CMakeLists.txt | 16 +- Tools/ProtoProxy/CMakeLists.txt | 28 +-- Tools/ProtoProxy/Connection.cpp | 4 +- Tools/ProtoProxy/Connection.h | 6 +- Tools/ProtoProxy/Server.h | 4 +- lib/mbedtls | 1 + lib/mbedtls.cmake | 10 + lib/polarssl | 1 - lib/polarssl.cmake | 10 - src/Bindings/LuaTCPLink.cpp | 4 +- src/Bindings/ManualBindings.cpp | 14 +- src/CMakeLists.txt | 10 +- src/ClientHandle.cpp | 4 +- src/HTTP/HTTPServer.cpp | 29 ++- src/HTTP/HTTPServer.h | 14 +- src/HTTP/SslHTTPServerConnection.cpp | 20 +- src/HTTP/SslHTTPServerConnection.h | 12 +- src/HTTP/UrlClient.cpp | 4 +- src/OSSupport/TCPLinkImpl.cpp | 37 +-- src/OSSupport/TCPLinkImpl.h | 2 +- src/PolarSSL++/AesCfb128Decryptor.cpp | 67 ----- src/PolarSSL++/AesCfb128Decryptor.h | 51 ---- src/PolarSSL++/AesCfb128Encryptor.cpp | 68 ------ src/PolarSSL++/AesCfb128Encryptor.h | 50 ---- src/PolarSSL++/BlockingSslClientSocket.cpp | 359 --------------------------- src/PolarSSL++/BlockingSslClientSocket.h | 116 --------- src/PolarSSL++/BufferedSslContext.cpp | 93 ------- src/PolarSSL++/BufferedSslContext.h | 52 ---- src/PolarSSL++/CMakeLists.txt | 41 ---- src/PolarSSL++/CallbackSslContext.cpp | 60 ----- src/PolarSSL++/CallbackSslContext.h | 64 ----- src/PolarSSL++/CryptoKey.cpp | 149 ------------ src/PolarSSL++/CryptoKey.h | 76 ------ src/PolarSSL++/CtrDrbgContext.cpp | 49 ---- src/PolarSSL++/CtrDrbgContext.h | 63 ----- src/PolarSSL++/EntropyContext.cpp | 29 --- src/PolarSSL++/EntropyContext.h | 31 --- src/PolarSSL++/RsaPrivateKey.cpp | 174 ------------- src/PolarSSL++/RsaPrivateKey.h | 67 ----- src/PolarSSL++/Sha1Checksum.cpp | 138 ----------- src/PolarSSL++/Sha1Checksum.h | 52 ---- src/PolarSSL++/SslContext.cpp | 307 ----------------------- src/PolarSSL++/SslContext.h | 156 ------------ src/PolarSSL++/X509Cert.cpp | 38 --- src/PolarSSL++/X509Cert.h | 41 ---- src/Protocol/Authenticator.cpp | 2 +- src/Protocol/MojangAPI.cpp | 44 +++- src/Protocol/Protocol_1_8.cpp | 2 +- src/Protocol/Protocol_1_8.h | 4 +- src/Protocol/Protocol_1_9.cpp | 2 +- src/Protocol/Protocol_1_9.h | 4 +- src/Server.h | 2 +- src/UUID.cpp | 4 +- src/mbedTLS++/AesCfb128Decryptor.cpp | 55 +++++ src/mbedTLS++/AesCfb128Decryptor.h | 48 ++++ src/mbedTLS++/AesCfb128Encryptor.cpp | 55 +++++ src/mbedTLS++/AesCfb128Encryptor.h | 47 ++++ src/mbedTLS++/BlockingSslClientSocket.cpp | 377 +++++++++++++++++++++++++++++ src/mbedTLS++/BlockingSslClientSocket.h | 119 +++++++++ src/mbedTLS++/BufferedSslContext.cpp | 93 +++++++ src/mbedTLS++/BufferedSslContext.h | 53 ++++ src/mbedTLS++/CMakeLists.txt | 44 ++++ src/mbedTLS++/CallbackSslContext.cpp | 60 +++++ src/mbedTLS++/CallbackSslContext.h | 65 +++++ src/mbedTLS++/CryptoKey.cpp | 149 ++++++++++++ src/mbedTLS++/CryptoKey.h | 76 ++++++ src/mbedTLS++/CtrDrbgContext.cpp | 51 ++++ src/mbedTLS++/CtrDrbgContext.h | 63 +++++ src/mbedTLS++/EntropyContext.cpp | 29 +++ src/mbedTLS++/EntropyContext.h | 31 +++ src/mbedTLS++/ErrorCodes.h | 18 ++ src/mbedTLS++/RsaPrivateKey.cpp | 174 +++++++++++++ src/mbedTLS++/RsaPrivateKey.h | 67 +++++ src/mbedTLS++/Sha1Checksum.cpp | 138 +++++++++++ src/mbedTLS++/Sha1Checksum.h | 52 ++++ src/mbedTLS++/SslConfig.cpp | 287 ++++++++++++++++++++++ src/mbedTLS++/SslConfig.h | 93 +++++++ src/mbedTLS++/SslContext.cpp | 157 ++++++++++++ src/mbedTLS++/SslContext.h | 124 ++++++++++ src/mbedTLS++/X509Cert.cpp | 38 +++ src/mbedTLS++/X509Cert.h | 41 ++++ tests/HTTP/CMakeLists.txt | 4 +- tests/Network/CMakeLists.txt | 26 +- 84 files changed, 2789 insertions(+), 2536 deletions(-) create mode 160000 lib/mbedtls create mode 100644 lib/mbedtls.cmake delete mode 160000 lib/polarssl delete mode 100644 lib/polarssl.cmake delete mode 100644 src/PolarSSL++/AesCfb128Decryptor.cpp delete mode 100644 src/PolarSSL++/AesCfb128Decryptor.h delete mode 100644 src/PolarSSL++/AesCfb128Encryptor.cpp delete mode 100644 src/PolarSSL++/AesCfb128Encryptor.h delete mode 100644 src/PolarSSL++/BlockingSslClientSocket.cpp delete mode 100644 src/PolarSSL++/BlockingSslClientSocket.h delete mode 100644 src/PolarSSL++/BufferedSslContext.cpp delete mode 100644 src/PolarSSL++/BufferedSslContext.h delete mode 100644 src/PolarSSL++/CMakeLists.txt delete mode 100644 src/PolarSSL++/CallbackSslContext.cpp delete mode 100644 src/PolarSSL++/CallbackSslContext.h delete mode 100644 src/PolarSSL++/CryptoKey.cpp delete mode 100644 src/PolarSSL++/CryptoKey.h delete mode 100644 src/PolarSSL++/CtrDrbgContext.cpp delete mode 100644 src/PolarSSL++/CtrDrbgContext.h delete mode 100644 src/PolarSSL++/EntropyContext.cpp delete mode 100644 src/PolarSSL++/EntropyContext.h delete mode 100644 src/PolarSSL++/RsaPrivateKey.cpp delete mode 100644 src/PolarSSL++/RsaPrivateKey.h delete mode 100644 src/PolarSSL++/Sha1Checksum.cpp delete mode 100644 src/PolarSSL++/Sha1Checksum.h delete mode 100644 src/PolarSSL++/SslContext.cpp delete mode 100644 src/PolarSSL++/SslContext.h delete mode 100644 src/PolarSSL++/X509Cert.cpp delete mode 100644 src/PolarSSL++/X509Cert.h create mode 100644 src/mbedTLS++/AesCfb128Decryptor.cpp create mode 100644 src/mbedTLS++/AesCfb128Decryptor.h create mode 100644 src/mbedTLS++/AesCfb128Encryptor.cpp create mode 100644 src/mbedTLS++/AesCfb128Encryptor.h create mode 100644 src/mbedTLS++/BlockingSslClientSocket.cpp create mode 100644 src/mbedTLS++/BlockingSslClientSocket.h create mode 100644 src/mbedTLS++/BufferedSslContext.cpp create mode 100644 src/mbedTLS++/BufferedSslContext.h create mode 100644 src/mbedTLS++/CMakeLists.txt create mode 100644 src/mbedTLS++/CallbackSslContext.cpp create mode 100644 src/mbedTLS++/CallbackSslContext.h create mode 100644 src/mbedTLS++/CryptoKey.cpp create mode 100644 src/mbedTLS++/CryptoKey.h create mode 100644 src/mbedTLS++/CtrDrbgContext.cpp create mode 100644 src/mbedTLS++/CtrDrbgContext.h create mode 100644 src/mbedTLS++/EntropyContext.cpp create mode 100644 src/mbedTLS++/EntropyContext.h create mode 100644 src/mbedTLS++/ErrorCodes.h create mode 100644 src/mbedTLS++/RsaPrivateKey.cpp create mode 100644 src/mbedTLS++/RsaPrivateKey.h create mode 100644 src/mbedTLS++/Sha1Checksum.cpp create mode 100644 src/mbedTLS++/Sha1Checksum.h create mode 100644 src/mbedTLS++/SslConfig.cpp create mode 100644 src/mbedTLS++/SslConfig.h create mode 100644 src/mbedTLS++/SslContext.cpp create mode 100644 src/mbedTLS++/SslContext.h create mode 100644 src/mbedTLS++/X509Cert.cpp create mode 100644 src/mbedTLS++/X509Cert.h diff --git a/.gitmodules b/.gitmodules index aebe6ea3c..74cf7bbe4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,9 +7,9 @@ [submodule "Server/Plugins/ChatLog"] path = Server/Plugins/ChatLog url = https://github.com/cuberite/ChatLog.git -[submodule "lib/polarssl"] - path = lib/polarssl - url = https://github.com/cuberite/polarssl.git +[submodule "lib/mbedtls"] + path = lib/mbedtls + url = https://github.com/ARMmbed/mbedtls.git ignore = dirty [submodule "lib/SQLiteCpp"] path = lib/SQLiteCpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b92ca8e8..2e3c51854 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# This is the top-level CMakeLists.txt file for the Cuberite project +# This is the top-level CMakeLists.txt file for the Cuberite project # # Use CMake to generate the build files for your platform # @@ -209,8 +209,8 @@ link_directories(lib/jsoncpp/src/lib_json) if (NOT EXISTS ${PROJECT_SOURCE_DIR}/lib/SQLiteCpp/CMakeLists.txt) message(FATAL_ERROR "SQLiteCpp is missing in folder lib/SQLiteCpp. Have you initialized the submodules / downloaded the extra libraries?") endif() -if (NOT EXISTS ${PROJECT_SOURCE_DIR}/lib/polarssl/CMakeLists.txt) - message(FATAL_ERROR "PolarSSL is missing in folder lib/polarssl. Have you initialized the submodules / downloaded the extra libraries?") +if (NOT EXISTS ${PROJECT_SOURCE_DIR}/lib/mbedtls/CMakeLists.txt) + message(FATAL_ERROR "mbedTLS is missing in folder lib/mbedtls. Have you initialized the submodules / downloaded the extra libraries?") endif() if (NOT EXISTS ${PROJECT_SOURCE_DIR}/lib/libevent/CMakeLists.txt) message(FATAL_ERROR "LibEvent is missing in folder lib/libevent. Have you initialized and updated the submodules / downloaded the extra libraries?") @@ -274,13 +274,13 @@ if (WIN32) endif() # We use EXCLUDE_FROM_ALL so that only the explicit dependencies are used -# (PolarSSL also has test and example programs in their CMakeLists.txt, we don't want those) -include(lib/polarssl.cmake EXCLUDE_FROM_ALL) +# (mbedTLS also has test and example programs in their CMakeLists.txt, we don't want those) +include(lib/mbedtls.cmake EXCLUDE_FROM_ALL) if(NOT MSVC AND "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm") - # mbed TLS uses the frame pointer's register in inline assembly: + # mbed TLS uses the frame pointer's register in inline assembly for its bignum implementation: # https://tls.mbed.org/kb/development/arm-thumb-error-r7-cannot-be-used-in-asm-here - target_compile_options(mbedtls PUBLIC -fomit-frame-pointer) + target_compile_options(mbedcrypto PRIVATE -fomit-frame-pointer) endif() set_exe_flags() @@ -302,7 +302,9 @@ if (MSVC) jsoncpp_lib_static lua luaexpat + mbedcrypto mbedtls + mbedx509 sqlite SQLiteCpp tolualib diff --git a/Tools/ProtoProxy/CMakeLists.txt b/Tools/ProtoProxy/CMakeLists.txt index 76e9fa609..c64a97428 100644 --- a/Tools/ProtoProxy/CMakeLists.txt +++ b/Tools/ProtoProxy/CMakeLists.txt @@ -8,7 +8,7 @@ set_lib_flags() # Set include paths to the used libraries: include_directories(SYSTEM "../../lib") -include_directories(SYSTEM "../../lib/polarssl/include") +include_directories(SYSTEM "../../lib/mbedtls/include") include_directories("../../src") function(flatten_files arg1) @@ -20,7 +20,7 @@ function(flatten_files arg1) set(${arg1} "${res}" PARENT_SCOPE) endfunction() -include(../../lib/polarssl.cmake) +include(../../lib/mbedtls.cmake) add_subdirectory(../../lib/zlib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/lib/zlib) set_exe_flags() @@ -30,12 +30,12 @@ set(SHARED_SRC ../../src/ByteBuffer.cpp ../../src/StringUtils.cpp ../../src/UUID.cpp - ../../src/PolarSSL++/AesCfb128Decryptor.cpp - ../../src/PolarSSL++/AesCfb128Encryptor.cpp - ../../src/PolarSSL++/CryptoKey.cpp - ../../src/PolarSSL++/CtrDrbgContext.cpp - ../../src/PolarSSL++/EntropyContext.cpp - ../../src/PolarSSL++/RsaPrivateKey.cpp + ../../src/mbedTLS++/AesCfb128Decryptor.cpp + ../../src/mbedTLS++/AesCfb128Encryptor.cpp + ../../src/mbedTLS++/CryptoKey.cpp + ../../src/mbedTLS++/CtrDrbgContext.cpp + ../../src/mbedTLS++/EntropyContext.cpp + ../../src/mbedTLS++/RsaPrivateKey.cpp ../../src/LoggerListeners.cpp ../../src/Logger.cpp ) @@ -43,12 +43,12 @@ set(SHARED_HDR ../../src/ByteBuffer.h ../../src/StringUtils.h ../../src/UUID.h - ../../src/PolarSSL++/AesCfb128Decryptor.h - ../../src/PolarSSL++/AesCfb128Encryptor.h - ../../src/PolarSSL++/CryptoKey.h - ../../src/PolarSSL++/CtrDrbgContext.h - ../../src/PolarSSL++/EntropyContext.h - ../../src/PolarSSL++/RsaPrivateKey.h + ../../src/mbedTLS++/AesCfb128Decryptor.h + ../../src/mbedTLS++/AesCfb128Encryptor.h + ../../src/mbedTLS++/CryptoKey.h + ../../src/mbedTLS++/CtrDrbgContext.h + ../../src/mbedTLS++/EntropyContext.h + ../../src/mbedTLS++/RsaPrivateKey.h ) set(SHARED_OSS_SRC ../../src/OSSupport/CriticalSection.cpp diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index 2804a881c..c54157f05 100644 --- a/Tools/ProtoProxy/Connection.cpp +++ b/Tools/ProtoProxy/Connection.cpp @@ -1,4 +1,4 @@ - + // Connection.cpp // Interfaces to the cConnection class representing a single pair of connected sockets @@ -7,7 +7,7 @@ #include "Connection.h" #include "Server.h" #include -#include "PolarSSL++/CryptoKey.h" +#include "mbedTLS++/CryptoKey.h" #include "../../src/Logger.h" #ifdef _WIN32 diff --git a/Tools/ProtoProxy/Connection.h b/Tools/ProtoProxy/Connection.h index 8aacaaa7f..226623c93 100644 --- a/Tools/ProtoProxy/Connection.h +++ b/Tools/ProtoProxy/Connection.h @@ -1,4 +1,4 @@ - + // Connection.h // Interfaces to the cConnection class representing a single pair of connected sockets @@ -10,8 +10,8 @@ #pragma once #include "ByteBuffer.h" -#include "PolarSSL++/AesCfb128Decryptor.h" -#include "PolarSSL++/AesCfb128Encryptor.h" +#include "mbedTLS++/AesCfb128Decryptor.h" +#include "mbedTLS++/AesCfb128Encryptor.h" diff --git a/Tools/ProtoProxy/Server.h b/Tools/ProtoProxy/Server.h index bfa16c36c..6e930835e 100644 --- a/Tools/ProtoProxy/Server.h +++ b/Tools/ProtoProxy/Server.h @@ -1,4 +1,4 @@ - + // Server.h // Interfaces to the cServer class encapsulating the entire "server" @@ -9,7 +9,7 @@ #pragma once -#include "PolarSSL++/RsaPrivateKey.h" +#include "mbedTLS++/RsaPrivateKey.h" diff --git a/lib/mbedtls b/lib/mbedtls new file mode 160000 index 000000000..f2a597fa3 --- /dev/null +++ b/lib/mbedtls @@ -0,0 +1 @@ +Subproject commit f2a597fa3dd1c7b15e0fee62f6932b253295803d diff --git a/lib/mbedtls.cmake b/lib/mbedtls.cmake new file mode 100644 index 000000000..c33ed8959 --- /dev/null +++ b/lib/mbedtls.cmake @@ -0,0 +1,10 @@ + +# This script includes PolarSSL, if not already included. +# It is needed for when multiple projects reference PolarSSL. + +if(NOT TARGET mbedtls) + message("including mbedtls") + set(ENABLE_TESTING OFF CACHE BOOL "Disable tests") + set(ENABLE_PROGRAMS OFF CACHE BOOL "Disable programs") + add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/mbedtls/ ${CMAKE_CURRENT_BINARY_DIR}/lib/mbedtls EXCLUDE_FROM_ALL) +endif() diff --git a/lib/polarssl b/lib/polarssl deleted file mode 160000 index 4f4c5b745..000000000 --- a/lib/polarssl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4f4c5b7450631e46a94cb89adf4a7737fbb178bc diff --git a/lib/polarssl.cmake b/lib/polarssl.cmake deleted file mode 100644 index 3506d0fb4..000000000 --- a/lib/polarssl.cmake +++ /dev/null @@ -1,10 +0,0 @@ - -# This script includes PolarSSL, if not already included. -# It is needed for when multiple projects reference PolarSSL. - -if(NOT TARGET mbedtls) - message("including polarssl") - set(ENABLE_TESTING OFF CACHE BOOL "Disable tests") - set(ENABLE_PROGRAMS OFF CACHE BOOL "Disable programs") - add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/polarssl/ ${CMAKE_CURRENT_BINARY_DIR}/lib/polarssl EXCLUDE_FROM_ALL) -endif() diff --git a/src/Bindings/LuaTCPLink.cpp b/src/Bindings/LuaTCPLink.cpp index 905dfc5ac..3933e9b36 100644 --- a/src/Bindings/LuaTCPLink.cpp +++ b/src/Bindings/LuaTCPLink.cpp @@ -6,8 +6,8 @@ #include "Globals.h" #include "LuaTCPLink.h" #include "LuaServerHandle.h" -#include "../PolarSSL++/X509Cert.h" -#include "../PolarSSL++/CryptoKey.h" +#include "../mbedTLS++/X509Cert.h" +#include "../mbedTLS++/CryptoKey.h" diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index ee9cb61e9..d4477bf4e 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -1,4 +1,4 @@ - + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "ManualBindings.h" @@ -6,8 +6,8 @@ #include #include #include "tolua++/include/tolua++.h" -#include "polarssl/md5.h" -#include "polarssl/sha1.h" +#include "mbedtls/md5.h" +#include "mbedtls/sha1.h" #include "PluginLua.h" #include "PluginManager.h" #include "LuaWindow.h" @@ -1838,7 +1838,7 @@ static int tolua_md5(lua_State * tolua_S) { return 0; } - md5(SourceString, len, Output); + mbedtls_md5(SourceString, len, Output); lua_pushlstring(tolua_S, reinterpret_cast(Output), ARRAYCOUNT(Output)); return 1; } @@ -1869,7 +1869,7 @@ static int tolua_md5HexString(lua_State * tolua_S) { return 0; } - md5(SourceString, len, md5Output); + mbedtls_md5(SourceString, len, md5Output); // Convert the md5 checksum to hex string: std::stringstream Output; @@ -1896,7 +1896,7 @@ static int tolua_sha1(lua_State * tolua_S) { return 0; } - sha1(SourceString, len, Output); + mbedtls_sha1(SourceString, len, Output); lua_pushlstring(tolua_S, reinterpret_cast(Output), ARRAYCOUNT(Output)); return 1; } @@ -1915,7 +1915,7 @@ static int tolua_sha1HexString(lua_State * tolua_S) { return 0; } - sha1(SourceString, len, sha1Output); + mbedtls_sha1(SourceString, len, sha1Output); // Convert the sha1 checksum to hex string: std::stringstream Output; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d7eb4e903..08bb2c270 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,13 +1,13 @@ -project (Cuberite) +project (Cuberite) include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/") include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/jsoncpp/include") -include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/polarssl/include") +include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/mbedtls/include") include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libevent/include") set(FOLDERS - OSSupport HTTP Items Blocks Protocol Generating PolarSSL++ Bindings + OSSupport HTTP Items Blocks Protocol Generating mbedTLS++ Bindings WorldStorage Mobs Entities Simulator Simulator/IncrementalRedstoneSimulator BlockEntities UI Noise ) @@ -177,7 +177,7 @@ endif() if (NOT MSVC) # Bindings need to reference other folders, so they are done here instead # lib dependencies are not included - include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/../lib/polarssl/include") + include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/../lib/mbedtls/include") foreach(folder ${FOLDERS}) add_subdirectory(${folder}) @@ -349,7 +349,7 @@ if (NOT MSVC) OSSupport HTTPServer Bindings Items Blocks Noise Protocol Generating WorldStorage Mobs Entities Simulator IncrementalRedstoneSimulator - BlockEntities UI PolarSSL++ + BlockEntities UI mbedTLS++ ) endif () diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index dbd6d4b4e..6923c9855 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1,4 +1,4 @@ -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "ClientHandle.h" #include "Server.h" @@ -33,7 +33,7 @@ #include "CompositeChat.h" #include "Items/ItemSword.h" -#include "polarssl/md5.h" +#include "mbedtls/md5.h" diff --git a/src/HTTP/HTTPServer.cpp b/src/HTTP/HTTPServer.cpp index 836dfa6e9..24c09aa38 100644 --- a/src/HTTP/HTTPServer.cpp +++ b/src/HTTP/HTTPServer.cpp @@ -1,4 +1,4 @@ - + // HTTPServer.cpp // Implements the cHTTPServer class representing a HTTP webserver that uses cListenThread and cSocketThreads for processing @@ -9,6 +9,7 @@ #include "HTTPServerConnection.h" #include "HTTPFormParser.h" #include "SslHTTPServerConnection.h" +#include "mbedTLS++/SslConfig.h" @@ -88,17 +89,23 @@ bool cHTTPServer::Initialize(void) AString KeyFile = cFile::ReadWholeFile("webadmin/httpskey.pem"); if (!CertFile.empty() && !KeyFile.empty()) { - m_Cert.reset(new cX509Cert); - int res = m_Cert->Parse(CertFile.data(), CertFile.size()); + auto Cert = std::make_shared(); + int res = Cert->Parse(CertFile.data(), CertFile.size()); if (res == 0) { - m_CertPrivKey.reset(new cCryptoKey); - int res2 = m_CertPrivKey->ParsePrivate(KeyFile.data(), KeyFile.size(), ""); - if (res2 != 0) + auto CertPrivKey = std::make_shared(); + res = CertPrivKey->ParsePrivate(KeyFile.data(), KeyFile.size(), ""); + if (res == 0) + { + // Modifyable locally but otherwise must be const + auto Config = cSslConfig::MakeDefaultConfig(false); + Config->SetOwnCert(Cert, CertPrivKey); + m_SslConfig = std::move(Config); + } + else { // Reading the private key failed, reset the cert: - LOGWARNING("WebServer: Cannot read HTTPS certificate private key: -0x%x", -res2); - m_Cert.reset(); + LOGWARNING("WebServer: Cannot read HTTPS certificate private key: -0x%x", -res); } } else @@ -108,7 +115,7 @@ bool cHTTPServer::Initialize(void) } // Notify the admin about the HTTPS / HTTP status - if (m_Cert.get() == nullptr) + if (m_SslConfig == nullptr) { LOGWARNING("WebServer: The server will run in unsecured HTTP mode."); LOGINFO("Put a valid HTTPS certificate in file 'webadmin/httpscert.crt' and its corresponding private key to 'webadmin/httpskey.pem' (without any password) to enable HTTPS support"); @@ -184,9 +191,9 @@ cTCPLink::cCallbacksPtr cHTTPServer::OnIncomingConnection(const AString & a_Remo UNUSED(a_RemoteIPAddress); UNUSED(a_RemotePort); - if (m_Cert.get() != nullptr) + if (m_SslConfig != nullptr) { - return std::make_shared(*this, m_Cert, m_CertPrivKey); + return std::make_shared(*this, m_SslConfig); } else { diff --git a/src/HTTP/HTTPServer.h b/src/HTTP/HTTPServer.h index cd944bb89..a2d5d84fc 100644 --- a/src/HTTP/HTTPServer.h +++ b/src/HTTP/HTTPServer.h @@ -1,4 +1,4 @@ - + // HTTPServer.h // Declares the cHTTPServer class representing a HTTP webserver that uses cListenThread and cSocketThreads for processing @@ -11,8 +11,8 @@ #include "../OSSupport/Network.h" #include "../IniFile.h" -#include "PolarSSL++/CryptoKey.h" -#include "PolarSSL++/X509Cert.h" +#include "mbedTLS++/CryptoKey.h" +#include "mbedTLS++/X509Cert.h" @@ -21,6 +21,7 @@ // fwd: class cHTTPIncomingRequest; class cHTTPServerConnection; +class cSslConfig; @@ -70,11 +71,8 @@ protected: /** The callbacks to call for various events */ cCallbacks * m_Callbacks; - /** The server certificate to use for the SSL connections */ - cX509CertPtr m_Cert; - - /** The private key for m_Cert. */ - cCryptoKeyPtr m_CertPrivKey; + /** Configuration for server ssl connections. */ + std::shared_ptr m_SslConfig; /** Called by cHTTPServerListenCallbacks when there's a new incoming connection. diff --git a/src/HTTP/SslHTTPServerConnection.cpp b/src/HTTP/SslHTTPServerConnection.cpp index 547e6de3a..99fb1b956 100644 --- a/src/HTTP/SslHTTPServerConnection.cpp +++ b/src/HTTP/SslHTTPServerConnection.cpp @@ -1,4 +1,4 @@ - + // SslHTTPConnection.cpp // Implements the cSslHTTPServerConnection class representing a HTTP connection made over a SSL link @@ -11,14 +11,18 @@ -cSslHTTPServerConnection::cSslHTTPServerConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey) : +cSslHTTPServerConnection::cSslHTTPServerConnection(cHTTPServer & a_HTTPServer, std::shared_ptr a_Config): super(a_HTTPServer), - m_Ssl(64000), - m_Cert(a_Cert), - m_PrivateKey(a_PrivateKey) + m_Ssl(64000) { - m_Ssl.Initialize(false); - m_Ssl.SetOwnCert(a_Cert, a_PrivateKey); + if (a_Config != nullptr) + { + m_Ssl.Initialize(a_Config); + } + else + { + m_Ssl.Initialize(false); + } } @@ -59,7 +63,7 @@ void cSslHTTPServerConnection::OnReceivedData(const char * a_Data, size_t a_Size // The link may have closed while processing the data, bail out: return; } - else if (NumRead == POLARSSL_ERR_NET_WANT_READ) + else if (NumRead == MBEDTLS_ERR_SSL_WANT_READ) { // SSL requires us to send data to peer first, do so by "sending" empty data: SendData(nullptr, 0); diff --git a/src/HTTP/SslHTTPServerConnection.h b/src/HTTP/SslHTTPServerConnection.h index 0f56d082f..894a2cc4a 100644 --- a/src/HTTP/SslHTTPServerConnection.h +++ b/src/HTTP/SslHTTPServerConnection.h @@ -1,4 +1,4 @@ - + // SslHTTPServerConnection.h // Declares the cSslHTTPServerConnection class representing a HTTP connection made over an SSL link @@ -10,7 +10,7 @@ #pragma once #include "HTTPServerConnection.h" -#include "PolarSSL++/BufferedSslContext.h" +#include "mbedTLS++/BufferedSslContext.h" @@ -24,19 +24,13 @@ class cSslHTTPServerConnection : public: /** Creates a new connection on the specified server. Sends the specified cert as the server certificate, uses the private key for decryption. */ - cSslHTTPServerConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey); + cSslHTTPServerConnection(cHTTPServer & a_HTTPServer, std::shared_ptr a_Config); virtual ~cSslHTTPServerConnection() override; protected: cBufferedSslContext m_Ssl; - /** The certificate to send to the client */ - cX509CertPtr m_Cert; - - /** The private key used for the certificate */ - cCryptoKeyPtr m_PrivateKey; - // cHTTPConnection overrides: virtual void OnReceivedData(const char * a_Data, size_t a_Size) override; // Data is received from the client virtual void SendData(const void * a_Data, size_t a_Size) override; // Data is to be sent to client diff --git a/src/HTTP/UrlClient.cpp b/src/HTTP/UrlClient.cpp index f7d12028d..29ee7e18d 100644 --- a/src/HTTP/UrlClient.cpp +++ b/src/HTTP/UrlClient.cpp @@ -7,8 +7,8 @@ #include "UrlClient.h" #include "UrlParser.h" #include "HTTPMessageParser.h" -#include "../PolarSSL++/X509Cert.h" -#include "../PolarSSL++/CryptoKey.h" +#include "../mbedTLS++/X509Cert.h" +#include "../mbedTLS++/CryptoKey.h" diff --git a/src/OSSupport/TCPLinkImpl.cpp b/src/OSSupport/TCPLinkImpl.cpp index 06eff9b09..4aba89e5c 100644 --- a/src/OSSupport/TCPLinkImpl.cpp +++ b/src/OSSupport/TCPLinkImpl.cpp @@ -1,10 +1,11 @@ - + // TCPLinkImpl.cpp // Implements the cTCPLinkImpl class implementing the TCP link functionality #include "Globals.h" #include "TCPLinkImpl.h" +#include "mbedTLS++/SslConfig.h" #include "NetworkSingleton.h" #include "ServerHandleImpl.h" #include "event2/buffer.h" @@ -245,26 +246,29 @@ AString cTCPLinkImpl::StartTLSClient( { return "TLS is already active on this link"; } - if ( - ((a_OwnCert == nullptr) && (a_OwnPrivKey != nullptr)) || - ((a_OwnCert != nullptr) && (a_OwnPrivKey != nullptr)) - ) + if ((a_OwnCert == nullptr) != (a_OwnPrivKey == nullptr)) { return "Either provide both the certificate and private key, or neither"; } // Create the TLS context: - m_TlsContext.reset(new cLinkTlsContext(*this)); - m_TlsContext->Initialize(true); + m_TlsContext = std::make_shared(*this); if (a_OwnCert != nullptr) { - m_TlsContext->SetOwnCert(a_OwnCert, a_OwnPrivKey); + auto Config = cSslConfig::MakeDefaultConfig(true); + Config->SetOwnCert(std::move(a_OwnCert), std::move(a_OwnPrivKey)); + m_TlsContext->Initialize(Config); + } + else + { + m_TlsContext->Initialize(true); } + m_TlsContext->SetSelf(cLinkTlsContextWPtr(m_TlsContext)); // Start the handshake: m_TlsContext->Handshake(); - return ""; + return {}; } @@ -282,15 +286,18 @@ AString cTCPLinkImpl::StartTLSServer( { return "TLS is already active on this link"; } - if ((a_OwnCert == nullptr) || (a_OwnPrivKey == nullptr)) + if ((a_OwnCert == nullptr) || (a_OwnPrivKey == nullptr)) { return "Provide the server certificate and private key"; } // Create the TLS context: - m_TlsContext.reset(new cLinkTlsContext(*this)); - m_TlsContext->Initialize(false); - m_TlsContext->SetOwnCert(a_OwnCert, a_OwnPrivKey); + m_TlsContext = std::make_shared(*this); + { + auto Config = cSslConfig::MakeDefaultConfig(false); + Config->SetOwnCert(a_OwnCert, a_OwnPrivKey); + m_TlsContext->Initialize(std::move(Config)); + } m_TlsContext->SetSelf(cLinkTlsContextWPtr(m_TlsContext)); // Push the initial data: @@ -298,7 +305,7 @@ AString cTCPLinkImpl::StartTLSServer( // Start the handshake: m_TlsContext->Handshake(); - return ""; + return {}; } @@ -659,7 +666,7 @@ int cTCPLinkImpl::cLinkTlsContext::ReceiveEncrypted(unsigned char * a_Buffer, si // If there's nothing queued in the buffer, report empty buffer: if (m_EncryptedData.empty()) { - return POLARSSL_ERR_NET_WANT_READ; + return MBEDTLS_ERR_SSL_WANT_READ; } // Copy as much data as possible to the provided buffer: diff --git a/src/OSSupport/TCPLinkImpl.h b/src/OSSupport/TCPLinkImpl.h index 0437353fb..0bd19b127 100644 --- a/src/OSSupport/TCPLinkImpl.h +++ b/src/OSSupport/TCPLinkImpl.h @@ -14,7 +14,7 @@ #include "Network.h" #include #include -#include "../PolarSSL++/SslContext.h" +#include "../mbedTLS++/SslContext.h" diff --git a/src/PolarSSL++/AesCfb128Decryptor.cpp b/src/PolarSSL++/AesCfb128Decryptor.cpp deleted file mode 100644 index 0aba1c42c..000000000 --- a/src/PolarSSL++/AesCfb128Decryptor.cpp +++ /dev/null @@ -1,67 +0,0 @@ - -// AesCfb128Decryptor.cpp - -// Implements the cAesCfb128Decryptor class decrypting data using AES CFB-128 - -#include "Globals.h" -#include "AesCfb128Decryptor.h" - - - - - -cAesCfb128Decryptor::cAesCfb128Decryptor(void) : - m_IVOffset(0), - m_IsValid(false) -{ -} - - - - - -cAesCfb128Decryptor::~cAesCfb128Decryptor() -{ - // Clear the leftover in-memory data, so that they can't be accessed by a backdoor - memset(&m_Aes, 0, sizeof(m_Aes)); -} - - - - - -void cAesCfb128Decryptor::Init(const Byte a_Key[16], const Byte a_IV[16]) -{ - ASSERT(!IsValid()); // Cannot Init twice - - memcpy(m_IV, a_IV, 16); - aes_setkey_enc(&m_Aes, a_Key, 128); - m_IsValid = true; -} - - - - - -void cAesCfb128Decryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length) -{ - ASSERT(IsValid()); // Must Init() first - - // PolarSSL doesn't support AES-CFB8, need to implement it manually: - for (size_t i = 0; i < a_Length; i++) - { - Byte Buffer[sizeof(m_IV)]; - aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer); - for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++) - { - m_IV[idx] = m_IV[idx + 1]; - } - m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i]; - a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0]; - } -} - - - - - diff --git a/src/PolarSSL++/AesCfb128Decryptor.h b/src/PolarSSL++/AesCfb128Decryptor.h deleted file mode 100644 index 56b96d3b3..000000000 --- a/src/PolarSSL++/AesCfb128Decryptor.h +++ /dev/null @@ -1,51 +0,0 @@ - -// AesCfb128Decryptor.h - -// Declares the cAesCfb128Decryptor class decrypting data using AES CFB-128 - - - - - -#pragma once - -#include "polarssl/aes.h" - - - - - -/** Decrypts data using the AES / CFB 128 algorithm */ -class cAesCfb128Decryptor -{ -public: - - cAesCfb128Decryptor(void); - ~cAesCfb128Decryptor(); - - /** Initializes the decryptor with the specified Key / IV */ - void Init(const Byte a_Key[16], const Byte a_IV[16]); - - /** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */ - void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length); - - /** Returns true if the object has been initialized with the Key / IV */ - bool IsValid(void) const { return m_IsValid; } - -protected: - aes_context m_Aes; - - /** The InitialVector, used by the CFB mode decryption */ - Byte m_IV[16]; - - /** Current offset in the m_IV, used by the CFB mode decryption */ - size_t m_IVOffset; - - /** Indicates whether the object has been initialized with the Key / IV */ - bool m_IsValid; -} ; - - - - - diff --git a/src/PolarSSL++/AesCfb128Encryptor.cpp b/src/PolarSSL++/AesCfb128Encryptor.cpp deleted file mode 100644 index ac0262e69..000000000 --- a/src/PolarSSL++/AesCfb128Encryptor.cpp +++ /dev/null @@ -1,68 +0,0 @@ - -// AesCfb128Encryptor.cpp - -// Implements the cAesCfb128Encryptor class encrypting data using AES CFB-128 - -#include "Globals.h" -#include "AesCfb128Encryptor.h" - - - - - -cAesCfb128Encryptor::cAesCfb128Encryptor(void) : - m_IVOffset(0), - m_IsValid(false) -{ -} - - - - - -cAesCfb128Encryptor::~cAesCfb128Encryptor() -{ - // Clear the leftover in-memory data, so that they can't be accessed by a backdoor - memset(&m_Aes, 0, sizeof(m_Aes)); -} - - - - - -void cAesCfb128Encryptor::Init(const Byte a_Key[16], const Byte a_IV[16]) -{ - ASSERT(!IsValid()); // Cannot Init twice - ASSERT(m_IVOffset == 0); - - memcpy(m_IV, a_IV, 16); - aes_setkey_enc(&m_Aes, a_Key, 128); - m_IsValid = true; -} - - - - - -void cAesCfb128Encryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length) -{ - ASSERT(IsValid()); // Must Init() first - - // PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves: - for (size_t i = 0; i < a_Length; i++) - { - Byte Buffer[sizeof(m_IV)]; - aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer); - for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++) - { - m_IV[idx] = m_IV[idx + 1]; - } - a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0]; - m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i]; - } -} - - - - - diff --git a/src/PolarSSL++/AesCfb128Encryptor.h b/src/PolarSSL++/AesCfb128Encryptor.h deleted file mode 100644 index 71280a098..000000000 --- a/src/PolarSSL++/AesCfb128Encryptor.h +++ /dev/null @@ -1,50 +0,0 @@ - -// AesCfb128Encryptor.h - -// Declares the cAesCfb128Encryptor class encrypting data using AES CFB-128 - - - - - -#pragma once - -#include "polarssl/aes.h" - - - - - -/** Encrypts data using the AES / CFB (128) algorithm */ -class cAesCfb128Encryptor -{ -public: - cAesCfb128Encryptor(void); - ~cAesCfb128Encryptor(); - - /** Initializes the decryptor with the specified Key / IV */ - void Init(const Byte a_Key[16], const Byte a_IV[16]); - - /** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */ - void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length); - - /** Returns true if the object has been initialized with the Key / IV */ - bool IsValid(void) const { return m_IsValid; } - -protected: - aes_context m_Aes; - - /** The InitialVector, used by the CFB mode encryption */ - Byte m_IV[16]; - - /** Current offset in the m_IV, used by the CFB mode encryption */ - size_t m_IVOffset; - - /** Indicates whether the object has been initialized with the Key / IV */ - bool m_IsValid; -} ; - - - - - diff --git a/src/PolarSSL++/BlockingSslClientSocket.cpp b/src/PolarSSL++/BlockingSslClientSocket.cpp deleted file mode 100644 index 7d7fc4ccf..000000000 --- a/src/PolarSSL++/BlockingSslClientSocket.cpp +++ /dev/null @@ -1,359 +0,0 @@ - -// BlockingSslClientSocket.cpp - -// Implements the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it - -#include "Globals.h" -#include "BlockingSslClientSocket.h" - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cBlockingSslClientSocketConnectCallbacks: - -class cBlockingSslClientSocketConnectCallbacks: - public cNetwork::cConnectCallbacks -{ - /** The socket object that is using this instance of the callbacks. */ - cBlockingSslClientSocket & m_Socket; - - virtual void OnConnected(cTCPLink & a_Link) override - { - m_Socket.OnConnected(); - } - - virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override - { - m_Socket.OnConnectError(a_ErrorMsg); - } - -public: - cBlockingSslClientSocketConnectCallbacks(cBlockingSslClientSocket & a_Socket): - m_Socket(a_Socket) - { - } -}; - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cBlockingSslClientSocketLinkCallbacks: - -class cBlockingSslClientSocketLinkCallbacks: - public cTCPLink::cCallbacks -{ - cBlockingSslClientSocket & m_Socket; - - virtual void OnLinkCreated(cTCPLinkPtr a_Link) override - { - m_Socket.SetLink(a_Link); - } - - - virtual void OnReceivedData(const char * a_Data, size_t a_Length) override - { - m_Socket.OnReceivedData(a_Data, a_Length); - } - - - virtual void OnRemoteClosed(void) override - { - m_Socket.OnDisconnected(); - } - - - virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override - { - m_Socket.OnDisconnected(); - } - -public: - - cBlockingSslClientSocketLinkCallbacks(cBlockingSslClientSocket & a_Socket): - m_Socket(a_Socket) - { - } -}; - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cBlockingSslClientSocket: - -cBlockingSslClientSocket::cBlockingSslClientSocket(void) : - m_Ssl(*this), - m_IsConnected(false) -{ - // Nothing needed yet -} - - - - - -bool cBlockingSslClientSocket::Connect(const AString & a_ServerName, UInt16 a_Port) -{ - // If already connected, report an error: - if (m_IsConnected) - { - // TODO: Handle this better - if connected to the same server and port, and the socket is alive, return success - m_LastErrorText = "Already connected"; - return false; - } - - // Connect the underlying socket: - m_ServerName = a_ServerName; - if (!cNetwork::Connect(a_ServerName, a_Port, - std::make_shared(*this), - std::make_shared(*this)) - ) - { - return false; - } - - // Wait for the connection to succeed or fail: - m_Event.Wait(); - if (!m_IsConnected) - { - return false; - } - - // Initialize the SSL: - int ret = m_Ssl.Initialize(true); - if (ret != 0) - { - Printf(m_LastErrorText, "SSL initialization failed: -0x%x", -ret); - return false; - } - - // If we have been assigned a trusted CA root cert store, push it into the SSL context: - if (m_CACerts.get() != nullptr) - { - m_Ssl.SetCACerts(m_CACerts, m_ExpectedPeerName); - } - - ret = m_Ssl.Handshake(); - if (ret != 0) - { - Printf(m_LastErrorText, "SSL handshake failed: -0x%x", -ret); - return false; - } - - return true; -} - - - - - - -bool cBlockingSslClientSocket::SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName) -{ - // Warn if used multiple times, but don't signal an error: - if (m_CACerts.get() != nullptr) - { - LOGWARNING( - "SSL: Trying to set multiple trusted CA root cert stores, only the last one will be used. Name: %s", - a_ExpectedPeerName.c_str() - ); - } - - // Parse the cert: - m_CACerts.reset(new cX509Cert); - int ret = m_CACerts->Parse(a_CACerts.data(), a_CACerts.size()); - if (ret < 0) - { - Printf(m_LastErrorText, "CA cert parsing failed: -0x%x", -ret); - return false; - } - m_ExpectedPeerName = a_ExpectedPeerName; - - return true; -} - - - - - -bool cBlockingSslClientSocket::Send(const void * a_Data, size_t a_NumBytes) -{ - if (!m_IsConnected) - { - m_LastErrorText = "Socket is closed"; - return false; - } - - // Keep sending the data until all of it is sent: - const char * Data = reinterpret_cast(a_Data); - size_t NumBytes = a_NumBytes; - for (;;) - { - int res = m_Ssl.WritePlain(Data, a_NumBytes); - if (res < 0) - { - ASSERT(res != POLARSSL_ERR_NET_WANT_READ); // This should never happen with callback-based SSL - ASSERT(res != POLARSSL_ERR_NET_WANT_WRITE); // This should never happen with callback-based SSL - Printf(m_LastErrorText, "Data cannot be written to SSL context: -0x%x", -res); - return false; - } - else - { - Data += res; - NumBytes -= static_cast(res); - if (NumBytes == 0) - { - return true; - } - } - } -} - - - - - - -int cBlockingSslClientSocket::Receive(void * a_Data, size_t a_MaxBytes) -{ - // Even if m_IsConnected is false (socket disconnected), the SSL context may have more data in the queue - int res = m_Ssl.ReadPlain(a_Data, a_MaxBytes); - if (res < 0) - { - Printf(m_LastErrorText, "Data cannot be read form SSL context: -0x%x", -res); - } - return res; -} - - - - - -void cBlockingSslClientSocket::Disconnect(void) -{ - // Ignore if not connected - if (!m_IsConnected) - { - return; - } - - m_Ssl.NotifyClose(); - m_IsConnected = false; - - // Grab a copy of the socket so that we know it doesn't change under our hands: - auto socket = m_Socket; - if (socket != nullptr) - { - socket->Close(); - } - - m_Socket.reset(); -} - - - - - -int cBlockingSslClientSocket::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) -{ - // Wait for any incoming data, if there is none: - cCSLock Lock(m_CSIncomingData); - while (m_IsConnected && m_IncomingData.empty()) - { - cCSUnlock Unlock(Lock); - m_Event.Wait(); - } - - // If we got disconnected, report an error after processing all data: - if (!m_IsConnected && m_IncomingData.empty()) - { - return POLARSSL_ERR_NET_RECV_FAILED; - } - - // Copy the data from the incoming buffer into the specified space: - size_t NumToCopy = std::min(a_NumBytes, m_IncomingData.size()); - memcpy(a_Buffer, m_IncomingData.data(), NumToCopy); - m_IncomingData.erase(0, NumToCopy); - return static_cast(NumToCopy); -} - - - - - -int cBlockingSslClientSocket::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) -{ - cTCPLinkPtr Socket(m_Socket); // Make a copy so that multiple threads don't race on deleting the socket. - if (Socket == nullptr) - { - return POLARSSL_ERR_NET_SEND_FAILED; - } - if (!Socket->Send(a_Buffer, a_NumBytes)) - { - // PolarSSL's net routines distinguish between connection reset and general failure, we don't need to - return POLARSSL_ERR_NET_SEND_FAILED; - } - return static_cast(a_NumBytes); -} - - - - - -void cBlockingSslClientSocket::OnConnected(void) -{ - m_IsConnected = true; - m_Event.Set(); -} - - - - - -void cBlockingSslClientSocket::OnConnectError(const AString & a_ErrorMsg) -{ - LOG("Cannot connect to %s: \"%s\"", m_ServerName.c_str(), a_ErrorMsg.c_str()); - m_Event.Set(); -} - - - - - -void cBlockingSslClientSocket::OnReceivedData(const char * a_Data, size_t a_Size) -{ - { - cCSLock Lock(m_CSIncomingData); - m_IncomingData.append(a_Data, a_Size); - } - m_Event.Set(); -} - - - - - -void cBlockingSslClientSocket::SetLink(cTCPLinkPtr a_Link) -{ - m_Socket = a_Link; -} - - - - - -void cBlockingSslClientSocket::OnDisconnected(void) -{ - m_IsConnected = false; - m_Socket.reset(); - m_Event.Set(); -} - - - - diff --git a/src/PolarSSL++/BlockingSslClientSocket.h b/src/PolarSSL++/BlockingSslClientSocket.h deleted file mode 100644 index 651d750e6..000000000 --- a/src/PolarSSL++/BlockingSslClientSocket.h +++ /dev/null @@ -1,116 +0,0 @@ - -// BlockingSslClientSocket.h - -// Declares the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it - - - - - -#pragma once - -#include "OSSupport/Network.h" -#include "CallbackSslContext.h" - - - - - -class cBlockingSslClientSocket : - protected cCallbackSslContext::cDataCallbacks -{ -public: - cBlockingSslClientSocket(void); - - virtual ~cBlockingSslClientSocket(void) override - { - Disconnect(); - } - - /** Connects to the specified server and performs SSL handshake. - Returns true if successful, false on failure. Sets internal error text on failure. */ - bool Connect(const AString & a_ServerName, UInt16 a_Port); - - /** Sends the specified data over the connection. - Returns true if successful, false on failure. Sets the internal error text on failure. */ - bool Send(const void * a_Data, size_t a_NumBytes); - - /** Receives data from the connection. - Blocks until there is any data available, then returns as much as possible. - Returns the number of bytes actually received, negative number on failure. - Sets the internal error text on failure. */ - int Receive(void * a_Data, size_t a_MaxBytes); - - /** Disconnects the connection gracefully, if possible. - Note that this also frees the internal SSL context, so all the certificates etc. are lost. */ - void Disconnect(void); - - /** Sets the root certificates that are to be trusted. Forces the connection to use strict cert - verification. Needs to be used before calling Connect(). - a_ExpectedPeerName is the name that we expect to receive in the SSL peer's cert; verification will fail if - the presented name is different (possible MITM). - Returns true on success, false on failure. Sets internal error text on failure. */ - bool SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName); - - /** Returns the text of the last error that has occurred in this instance. */ - const AString & GetLastErrorText(void) const { return m_LastErrorText; } - -protected: - friend class cBlockingSslClientSocketConnectCallbacks; - friend class cBlockingSslClientSocketLinkCallbacks; - - /** The SSL context used for the socket */ - cCallbackSslContext m_Ssl; - - /** The underlying socket to the SSL server */ - cTCPLinkPtr m_Socket; - - /** The object used to signal state changes in the socket (the cause of the blocking). */ - cEvent m_Event; - - /** The trusted CA root cert store, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */ - cX509CertPtr m_CACerts; - - /** The expected SSL peer's name, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */ - AString m_ExpectedPeerName; - - /** The hostname to which the socket is connecting (stored for error reporting). */ - AString m_ServerName; - - /** Text of the last error that has occurred. */ - AString m_LastErrorText; - - /** Set to true if the connection established successfully. */ - std::atomic m_IsConnected; - - /** Protects m_IncomingData against multithreaded access. */ - cCriticalSection m_CSIncomingData; - - /** Buffer for the data incoming on the network socket. - Protected by m_CSIncomingData. */ - AString m_IncomingData; - - - /** Called when the connection is established successfully. */ - void OnConnected(void); - - /** Called when an error occurs while connecting the socket. */ - void OnConnectError(const AString & a_ErrorMsg); - - /** Called when there's incoming data from the socket. */ - void OnReceivedData(const char * a_Data, size_t a_Size); - - /** Called when the link for the connection is created. */ - void SetLink(cTCPLinkPtr a_Link); - - /** Called when the link is disconnected, either gracefully or by an error. */ - void OnDisconnected(void); - - // cCallbackSslContext::cDataCallbacks overrides: - virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override; - virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override; -} ; - - - - diff --git a/src/PolarSSL++/BufferedSslContext.cpp b/src/PolarSSL++/BufferedSslContext.cpp deleted file mode 100644 index c8d4736f7..000000000 --- a/src/PolarSSL++/BufferedSslContext.cpp +++ /dev/null @@ -1,93 +0,0 @@ - -// BufferedSslContext.cpp - -// Implements the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer - -#include "Globals.h" -#include "BufferedSslContext.h" - - - - - -cBufferedSslContext::cBufferedSslContext(size_t a_BufferSize): - m_OutgoingData(a_BufferSize), - m_IncomingData(a_BufferSize) -{ -} - - - - - -size_t cBufferedSslContext::WriteIncoming(const void * a_Data, size_t a_NumBytes) -{ - size_t NumBytes = std::min(m_IncomingData.GetFreeSpace(), a_NumBytes); - if (NumBytes > 0) - { - m_IncomingData.Write(a_Data, NumBytes); - return NumBytes; - } - return 0; -} - - - - - -size_t cBufferedSslContext::ReadOutgoing(void * a_Data, size_t a_DataMaxSize) -{ - size_t NumBytes = std::min(m_OutgoingData.GetReadableSpace(), a_DataMaxSize); - if (NumBytes > 0) - { - m_OutgoingData.ReadBuf(a_Data, NumBytes); - m_OutgoingData.CommitRead(); - return NumBytes; - } - return 0; -} - - - - - -int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) -{ - // Called when PolarSSL wants to read encrypted data from the SSL peer - // Read the data from the buffer inside this object, where the owner has stored them using WriteIncoming(): - size_t NumBytes = std::min(a_NumBytes, m_IncomingData.GetReadableSpace()); - if (NumBytes == 0) - { - return POLARSSL_ERR_NET_WANT_READ; - } - if (!m_IncomingData.ReadBuf(a_Buffer, NumBytes)) - { - m_IncomingData.ResetRead(); - return POLARSSL_ERR_NET_RECV_FAILED; - } - m_IncomingData.CommitRead(); - return static_cast(NumBytes); -} - - - - - -int cBufferedSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) -{ - // Called when PolarSSL wants to write encrypted data to the SSL peer - // Write the data into the buffer inside this object, where the owner can later read them using ReadOutgoing(): - if (!m_OutgoingData.CanWriteBytes(a_NumBytes)) - { - return POLARSSL_ERR_NET_WANT_WRITE; - } - if (!m_OutgoingData.Write(reinterpret_cast(a_Buffer), a_NumBytes)) - { - return POLARSSL_ERR_NET_SEND_FAILED; - } - return static_cast(a_NumBytes); -} - - - - diff --git a/src/PolarSSL++/BufferedSslContext.h b/src/PolarSSL++/BufferedSslContext.h deleted file mode 100644 index ab058a52e..000000000 --- a/src/PolarSSL++/BufferedSslContext.h +++ /dev/null @@ -1,52 +0,0 @@ - -// BufferedSslContext.h - -// Declares the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer - - - - - -#pragma once - -#include "SslContext.h" - - - - - -class cBufferedSslContext : - public cSslContext -{ - typedef cSslContext super; - -public: - /** Creates a new context with the buffers of specified size for the encrypted / decrypted data. */ - cBufferedSslContext(size_t a_BufferSize = 64000); - - /** Stores the specified data in the "incoming" buffer, to be process by the SSL decryptor. - This is the data received from the SSL peer. - Returns the number of bytes actually stored. If 0 is returned, owner should check the error state. */ - size_t WriteIncoming(const void * a_Data, size_t a_NumBytes); - - /** Retrieves data from the "outgoing" buffer, after being processed by the SSL encryptor. - This is the data to be sent to the SSL peer. - Returns the number of bytes actually retrieved. */ - size_t ReadOutgoing(void * a_Data, size_t a_DataMaxSize); - -protected: - /** Buffer for the data that has been encrypted into the SSL stream and should be sent out. */ - cByteBuffer m_OutgoingData; - - /** Buffer for the data that has come in and needs to be decrypted from the SSL stream. */ - cByteBuffer m_IncomingData; - - - // cSslContext overrides: - virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override; - virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override; -} ; - - - - diff --git a/src/PolarSSL++/CMakeLists.txt b/src/PolarSSL++/CMakeLists.txt deleted file mode 100644 index 3d77e15d1..000000000 --- a/src/PolarSSL++/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -project (Cuberite) - -include_directories ("${PROJECT_SOURCE_DIR}/../") - -set(SRCS - AesCfb128Decryptor.cpp - AesCfb128Encryptor.cpp - BlockingSslClientSocket.cpp - BufferedSslContext.cpp - CallbackSslContext.cpp - CtrDrbgContext.cpp - CryptoKey.cpp - EntropyContext.cpp - RsaPrivateKey.cpp - Sha1Checksum.cpp - SslContext.cpp - X509Cert.cpp -) - -set(HDRS - AesCfb128Decryptor.h - AesCfb128Encryptor.h - BlockingSslClientSocket.h - BufferedSslContext.h - CallbackSslContext.h - CtrDrbgContext.h - CryptoKey.h - EntropyContext.h - RsaPrivateKey.h - SslContext.h - Sha1Checksum.h - X509Cert.h -) - -if(NOT MSVC) - add_library(PolarSSL++ ${SRCS} ${HDRS}) - - if (UNIX) - target_link_libraries(PolarSSL++ mbedtls) - endif() -endif() diff --git a/src/PolarSSL++/CallbackSslContext.cpp b/src/PolarSSL++/CallbackSslContext.cpp deleted file mode 100644 index e061e3f03..000000000 --- a/src/PolarSSL++/CallbackSslContext.cpp +++ /dev/null @@ -1,60 +0,0 @@ - -// CallbackSslContext.cpp - -// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data - -#include "Globals.h" -#include "CallbackSslContext.h" - - - - - - -cCallbackSslContext::cCallbackSslContext(void) : - m_Callbacks(nullptr) -{ - // Nothing needed, but the constructor needs to exist so -} - - - - - -cCallbackSslContext::cCallbackSslContext(cCallbackSslContext::cDataCallbacks & a_Callbacks) : - m_Callbacks(&a_Callbacks) -{ -} - - - - - -int cCallbackSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) -{ - if (m_Callbacks == nullptr) - { - LOGWARNING("SSL: Trying to receive data with no callbacks, aborting."); - return POLARSSL_ERR_NET_RECV_FAILED; - } - return m_Callbacks->ReceiveEncrypted(a_Buffer, a_NumBytes); -} - - - - - -int cCallbackSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) -{ - if (m_Callbacks == nullptr) - { - LOGWARNING("SSL: Trying to send data with no callbacks, aborting."); - return POLARSSL_ERR_NET_SEND_FAILED; - } - return m_Callbacks->SendEncrypted(a_Buffer, a_NumBytes); -} - - - - - diff --git a/src/PolarSSL++/CallbackSslContext.h b/src/PolarSSL++/CallbackSslContext.h deleted file mode 100644 index 1fc131182..000000000 --- a/src/PolarSSL++/CallbackSslContext.h +++ /dev/null @@ -1,64 +0,0 @@ - -// CallbackSslContext.h - -// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data - - - - - -#pragma once - -#include "SslContext.h" - - - - - -class cCallbackSslContext : - public cSslContext -{ -public: - /** Interface used as a data sink for the SSL peer data. */ - class cDataCallbacks - { - public: - // Force a virtual destructor in descendants: - virtual ~cDataCallbacks() {} - - /** Called when PolarSSL wants to read encrypted data from the SSL peer. - The returned value is the number of bytes received, or a PolarSSL error on failure. - The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate - that there's currently no more data and that there might be more data in the future. In such cases the - SSL operation that invoked this call will terminate with the same return value, so that the owner is - notified of this condition and can potentially restart the operation later on. */ - virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0; - - /** Called when PolarSSL wants to write encrypted data to the SSL peer. - The returned value is the number of bytes sent, or a PolarSSL error on failure. - The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate - that there's currently no more data and that there might be more data in the future. In such cases the - SSL operation that invoked this call will terminate with the same return value, so that the owner is - notified of this condition and can potentially restart the operation later on. */ - virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0; - } ; - - - /** Creates a new SSL context with no callbacks assigned */ - cCallbackSslContext(void); - - /** Creates a new SSL context with the specified callbacks */ - cCallbackSslContext(cDataCallbacks & a_Callbacks); - -protected: - /** The callbacks to use to send and receive SSL peer data */ - cDataCallbacks * m_Callbacks; - - // cSslContext overrides: - virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override; - virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override; -}; - - - - diff --git a/src/PolarSSL++/CryptoKey.cpp b/src/PolarSSL++/CryptoKey.cpp deleted file mode 100644 index b01fee5f9..000000000 --- a/src/PolarSSL++/CryptoKey.cpp +++ /dev/null @@ -1,149 +0,0 @@ - -// CryptoKey.cpp - -// Implements the cCryptoKey class representing a RSA public key in PolarSSL - -#include "Globals.h" -#include "CryptoKey.h" - - - - - -cCryptoKey::cCryptoKey(void) -{ - pk_init(&m_Pk); - m_CtrDrbg.Initialize("rsa_pubkey", 10); -} - - - - - -cCryptoKey::cCryptoKey(const AString & a_PublicKeyData) -{ - pk_init(&m_Pk); - m_CtrDrbg.Initialize("rsa_pubkey", 10); - int res = ParsePublic(a_PublicKeyData.data(), a_PublicKeyData.size()); - if (res != 0) - { - LOGWARNING("Failed to parse public key: -0x%x", res); - ASSERT(!"Cannot parse PubKey"); - return; - } -} - - - - - -cCryptoKey::cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password) -{ - pk_init(&m_Pk); - m_CtrDrbg.Initialize("rsa_privkey", 11); - int res = ParsePrivate(a_PrivateKeyData.data(), a_PrivateKeyData.size(), a_Password); - if (res != 0) - { - LOGWARNING("Failed to parse private key: -0x%x", res); - ASSERT(!"Cannot parse PrivKey"); - return; - } -} - - - - - -cCryptoKey::~cCryptoKey() -{ - pk_free(&m_Pk); -} - - - - - -int cCryptoKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) -{ - ASSERT(IsValid()); - - size_t DecryptedLen = a_DecryptedMaxLength; - int res = pk_decrypt(&m_Pk, - a_EncryptedData, a_EncryptedLength, - a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength, - ctr_drbg_random, m_CtrDrbg.GetInternal() - ); - if (res != 0) - { - return res; - } - return static_cast(DecryptedLen); -} - - - - - -int cCryptoKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) -{ - ASSERT(IsValid()); - - size_t EncryptedLength = a_EncryptedMaxLength; - int res = pk_encrypt(&m_Pk, - a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength, - ctr_drbg_random, m_CtrDrbg.GetInternal() - ); - if (res != 0) - { - return res; - } - return static_cast(EncryptedLength); -} - - - - - - -int cCryptoKey::ParsePublic(const void * a_Data, size_t a_NumBytes) -{ - ASSERT(!IsValid()); // Cannot parse a second key - - return pk_parse_public_key(&m_Pk, reinterpret_cast(a_Data), a_NumBytes); -} - - - - - - -int cCryptoKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password) -{ - ASSERT(!IsValid()); // Cannot parse a second key - - if (a_Password.empty()) - { - return pk_parse_key(&m_Pk, reinterpret_cast(a_Data), a_NumBytes, nullptr, 0); - } - else - { - return pk_parse_key( - &m_Pk, - reinterpret_cast(a_Data), a_NumBytes, - reinterpret_cast(a_Password.c_str()), a_Password.size() - ); - } -} - - - - - -bool cCryptoKey::IsValid(void) const -{ - return (pk_get_type(&m_Pk) != POLARSSL_PK_NONE); -} - - - - diff --git a/src/PolarSSL++/CryptoKey.h b/src/PolarSSL++/CryptoKey.h deleted file mode 100644 index db15cefb4..000000000 --- a/src/PolarSSL++/CryptoKey.h +++ /dev/null @@ -1,76 +0,0 @@ - -// CryptoKey.h - -// Declares the cCryptoKey class representing a RSA public key in PolarSSL - - - - - -#pragma once - -#include "CtrDrbgContext.h" -#include "polarssl/pk.h" - - - - - -class cCryptoKey -{ - friend class cSslContext; - -public: - /** Constructs an empty key instance. Before use, it needs to be filled by ParsePublic() or ParsePrivate() */ - cCryptoKey(void); - - /** Constructs the public key out of the DER- or PEM-encoded pubkey data */ - cCryptoKey(const AString & a_PublicKeyData); - - /** Constructs the private key out of the DER- or PEM-encoded privkey data, with the specified password. - If a_Password is empty, no password is assumed. */ - cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password); - - ~cCryptoKey(); - - /** Decrypts the data using the stored public key - Both a_EncryptedData and a_DecryptedData must be at least bytes large. - Returns the number of bytes decrypted, or negative number for error. */ - int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength); - - /** Encrypts the data using the stored public key - Both a_EncryptedData and a_DecryptedData must be at least bytes large. - Returns the number of bytes decrypted, or negative number for error. */ - int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); - - /** Parses the specified data into a public key representation. - The key can be DER- or PEM-encoded. - Returns 0 on success, PolarSSL error code on failure. */ - int ParsePublic(const void * a_Data, size_t a_NumBytes); - - /** Parses the specified data into a private key representation. - If a_Password is empty, no password is assumed. - The key can be DER- or PEM-encoded. - Returns 0 on success, PolarSSL error code on failure. */ - int ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password); - - /** Returns true if the contained key is valid. */ - bool IsValid(void) const; - -protected: - /** The PolarSSL representation of the key data */ - pk_context m_Pk; - - /** The random generator used in encryption and decryption */ - cCtrDrbgContext m_CtrDrbg; - - - /** Returns the internal context ptr. Only use in PolarSSL API calls. */ - pk_context * GetInternal(void) { return &m_Pk; } -} ; - -typedef std::shared_ptr cCryptoKeyPtr; - - - - diff --git a/src/PolarSSL++/CtrDrbgContext.cpp b/src/PolarSSL++/CtrDrbgContext.cpp deleted file mode 100644 index c2243db38..000000000 --- a/src/PolarSSL++/CtrDrbgContext.cpp +++ /dev/null @@ -1,49 +0,0 @@ - -// CtrDrbgContext.cpp - -// Implements the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL - -#include "Globals.h" -#include "CtrDrbgContext.h" -#include "EntropyContext.h" - - - - - -cCtrDrbgContext::cCtrDrbgContext(void) : - m_EntropyContext(new cEntropyContext), - m_IsValid(false) -{ -} - - - - - -cCtrDrbgContext::cCtrDrbgContext(const std::shared_ptr & a_EntropyContext) : - m_EntropyContext(a_EntropyContext), - m_IsValid(false) -{ -} - - - - - -int cCtrDrbgContext::Initialize(const void * a_Custom, size_t a_CustomSize) -{ - if (m_IsValid) - { - // Already initialized - return 0; - } - - int res = ctr_drbg_init(&m_CtrDrbg, entropy_func, &(m_EntropyContext->m_Entropy), reinterpret_cast(a_Custom), a_CustomSize); - m_IsValid = (res == 0); - return res; -} - - - - diff --git a/src/PolarSSL++/CtrDrbgContext.h b/src/PolarSSL++/CtrDrbgContext.h deleted file mode 100644 index 20d687015..000000000 --- a/src/PolarSSL++/CtrDrbgContext.h +++ /dev/null @@ -1,63 +0,0 @@ - -// CtrDrbgContext.h - -// Declares the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL - - - - - -#pragma once - -#include "polarssl/ctr_drbg.h" - - - - - -// fwd: EntropyContext.h -class cEntropyContext; - - - - - -class cCtrDrbgContext -{ - friend class cSslContext; - friend class cRsaPrivateKey; - friend class cCryptoKey; - -public: - /** Constructs the context with a new entropy context. */ - cCtrDrbgContext(void); - - /** Constructs the context with the specified entropy context. */ - cCtrDrbgContext(const std::shared_ptr & a_EntropyContext); - - /** Initializes the context. - a_Custom is optional additional data to use for entropy, nullptr is accepted. - Returns 0 if successful, PolarSSL error code on failure. */ - int Initialize(const void * a_Custom, size_t a_CustomSize); - - /** Returns true if the object is valid (has been initialized properly) */ - bool IsValid(void) const { return m_IsValid; } - -protected: - /** The entropy source used for generating the random */ - std::shared_ptr m_EntropyContext; - - /** The random generator context */ - ctr_drbg_context m_CtrDrbg; - - /** Set to true if the object is valid (has been initialized properly) */ - bool m_IsValid; - - - /** Returns the internal context ptr. Only use in PolarSSL API calls. */ - ctr_drbg_context * GetInternal(void) { return &m_CtrDrbg; } -} ; - - - - diff --git a/src/PolarSSL++/EntropyContext.cpp b/src/PolarSSL++/EntropyContext.cpp deleted file mode 100644 index 9c59b3f11..000000000 --- a/src/PolarSSL++/EntropyContext.cpp +++ /dev/null @@ -1,29 +0,0 @@ - -// EntropyContext.cpp - -// Implements the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL - -#include "Globals.h" -#include "EntropyContext.h" - - - - - -cEntropyContext::cEntropyContext(void) -{ - entropy_init(&m_Entropy); -} - - - - - -cEntropyContext::~cEntropyContext() -{ - entropy_free(&m_Entropy); -} - - - - diff --git a/src/PolarSSL++/EntropyContext.h b/src/PolarSSL++/EntropyContext.h deleted file mode 100644 index 69671d32f..000000000 --- a/src/PolarSSL++/EntropyContext.h +++ /dev/null @@ -1,31 +0,0 @@ - -// EntropyContext.h - -// Declares the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL - - - - - -#pragma once - -#include "polarssl/entropy.h" - - - - - -class cEntropyContext -{ - friend class cCtrDrbgContext; -public: - cEntropyContext(void); - ~cEntropyContext(); - -protected: - entropy_context m_Entropy; -} ; - - - - diff --git a/src/PolarSSL++/RsaPrivateKey.cpp b/src/PolarSSL++/RsaPrivateKey.cpp deleted file mode 100644 index 5705b01f2..000000000 --- a/src/PolarSSL++/RsaPrivateKey.cpp +++ /dev/null @@ -1,174 +0,0 @@ - -// RsaPrivateKey.cpp - -#include "Globals.h" -#include "RsaPrivateKey.h" -#include - - - - - -cRsaPrivateKey::cRsaPrivateKey(void) -{ - rsa_init(&m_Rsa, RSA_PKCS_V15, 0); - m_CtrDrbg.Initialize("RSA", 3); -} - - - - - -cRsaPrivateKey::cRsaPrivateKey(const cRsaPrivateKey & a_Other) -{ - rsa_init(&m_Rsa, RSA_PKCS_V15, 0); - rsa_copy(&m_Rsa, &a_Other.m_Rsa); - m_CtrDrbg.Initialize("RSA", 3); -} - - - - - -cRsaPrivateKey::~cRsaPrivateKey() -{ - rsa_free(&m_Rsa); -} - - - - - -bool cRsaPrivateKey::Generate(unsigned a_KeySizeBits) -{ - int res = rsa_gen_key(&m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), a_KeySizeBits, 65537); - if (res != 0) - { - LOG("RSA key generation failed: -0x%x", -res); - return false; - } - - return true; -} - - - - - -AString cRsaPrivateKey::GetPubKeyDER(void) -{ - class cPubKey - { - public: - cPubKey(rsa_context * a_Rsa) : - m_IsValid(false) - { - pk_init(&m_Key); - if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0) - { - ASSERT(!"Cannot init PrivKey context"); - return; - } - if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0) - { - ASSERT(!"Cannot copy PrivKey to PK context"); - return; - } - m_IsValid = true; - } - - ~cPubKey() - { - if (m_IsValid) - { - pk_free(&m_Key); - } - } - - operator pk_context * (void) { return &m_Key; } - - protected: - bool m_IsValid; - pk_context m_Key; - } PkCtx(&m_Rsa); - - unsigned char buf[3000]; - int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf)); - if (res < 0) - { - return AString(); - } - return AString(reinterpret_cast(buf + sizeof(buf) - res), static_cast(res)); -} - - - - - -int cRsaPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) -{ - if (a_EncryptedLength < m_Rsa.len) - { - LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u", - __FUNCTION__, static_cast(a_EncryptedLength), static_cast(m_Rsa.len) - ); - ASSERT(!"Invalid a_DecryptedMaxLength!"); - return -1; - } - if (a_DecryptedMaxLength < m_Rsa.len) - { - LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u", - __FUNCTION__, static_cast(a_EncryptedLength), static_cast(m_Rsa.len) - ); - ASSERT(!"Invalid a_DecryptedMaxLength!"); - return -1; - } - size_t DecryptedLength; - int res = rsa_pkcs1_decrypt( - &m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), RSA_PRIVATE, &DecryptedLength, - a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength - ); - if (res != 0) - { - return -1; - } - return static_cast(DecryptedLength); -} - - - - - -int cRsaPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) -{ - if (a_EncryptedMaxLength < m_Rsa.len) - { - LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u", - __FUNCTION__, static_cast(a_EncryptedMaxLength), static_cast(m_Rsa.len) - ); - ASSERT(!"Invalid a_DecryptedMaxLength!"); - return -1; - } - if (a_PlainLength < m_Rsa.len) - { - LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u", - __FUNCTION__, static_cast(a_PlainLength), static_cast(m_Rsa.len) - ); - ASSERT(!"Invalid a_PlainLength!"); - return -1; - } - int res = rsa_pkcs1_encrypt( - &m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), RSA_PRIVATE, - a_PlainLength, a_PlainData, a_EncryptedData - ); - if (res != 0) - { - return -1; - } - return static_cast(m_Rsa.len); -} - - - - - diff --git a/src/PolarSSL++/RsaPrivateKey.h b/src/PolarSSL++/RsaPrivateKey.h deleted file mode 100644 index 595ba5663..000000000 --- a/src/PolarSSL++/RsaPrivateKey.h +++ /dev/null @@ -1,67 +0,0 @@ - -// RsaPrivateKey.h - -// Declares the cRsaPrivateKey class representing a private key for RSA operations. - - - - - -#pragma once - -#include "CtrDrbgContext.h" -#include "polarssl/rsa.h" - - - - - -/** Encapsulates an RSA private key used in PKI cryptography */ -class cRsaPrivateKey -{ - friend class cSslContext; - -public: - /** Creates a new empty object, the key is not assigned */ - cRsaPrivateKey(void); - - /** Deep-copies the key from a_Other */ - cRsaPrivateKey(const cRsaPrivateKey & a_Other); - - ~cRsaPrivateKey(); - - /** Generates a new key within this object, with the specified size in bits. - Returns true on success, false on failure. */ - bool Generate(unsigned a_KeySizeBits = 1024); - - /** Returns the public key part encoded in ASN1 DER encoding */ - AString GetPubKeyDER(void); - - /** Decrypts the data using RSAES-PKCS#1 algorithm. - Both a_EncryptedData and a_DecryptedData must be at least bytes large. - Returns the number of bytes decrypted, or negative number for error. */ - int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength); - - /** Encrypts the data using RSAES-PKCS#1 algorithm. - Both a_EncryptedData and a_DecryptedData must be at least bytes large. - Returns the number of bytes decrypted, or negative number for error. */ - int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); - -protected: - /** The PolarSSL key context */ - rsa_context m_Rsa; - - /** The random generator used for generating the key and encryption / decryption */ - cCtrDrbgContext m_CtrDrbg; - - - /** Returns the internal context ptr. Only use in PolarSSL API calls. */ - rsa_context * GetInternal(void) { return &m_Rsa; } -} ; - -typedef std::shared_ptr cRsaPrivateKeyPtr; - - - - - diff --git a/src/PolarSSL++/Sha1Checksum.cpp b/src/PolarSSL++/Sha1Checksum.cpp deleted file mode 100644 index 5a56c18b0..000000000 --- a/src/PolarSSL++/Sha1Checksum.cpp +++ /dev/null @@ -1,138 +0,0 @@ - -// Sha1Checksum.cpp - -// Declares the cSha1Checksum class representing the SHA-1 checksum calculator - -#include "Globals.h" -#include "Sha1Checksum.h" - - - - - -/* -// Self-test the hash formatting for known values: -// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48 -// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1 -// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6 - -static class Test -{ -public: - Test(void) - { - AString DigestNotch, DigestJeb, DigestSimon; - Byte Digest[20]; - cSha1Checksum Checksum; - Checksum.Update((const Byte *)"Notch", 5); - Checksum.Finalize(Digest); - cSha1Checksum::DigestToJava(Digest, DigestNotch); - Checksum.Restart(); - Checksum.Update((const Byte *)"jeb_", 4); - Checksum.Finalize(Digest); - cSha1Checksum::DigestToJava(Digest, DigestJeb); - Checksum.Restart(); - Checksum.Update((const Byte *)"simon", 5); - Checksum.Finalize(Digest); - cSha1Checksum::DigestToJava(Digest, DigestSimon); - printf("Notch: \"%s\"\n", DigestNotch.c_str()); - printf("jeb_: \"%s\"\n", DigestJeb.c_str()); - printf("simon: \"%s\"\n", DigestSimon.c_str()); - assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48"); - assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1"); - assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6"); - } -} test; -*/ - - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cSha1Checksum: - -cSha1Checksum::cSha1Checksum(void) : - m_DoesAcceptInput(true) -{ - sha1_starts(&m_Sha1); -} - - - - - -void cSha1Checksum::Update(const Byte * a_Data, size_t a_Length) -{ - ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed - - sha1_update(&m_Sha1, a_Data, a_Length); -} - - - - - -void cSha1Checksum::Finalize(cSha1Checksum::Checksum & a_Output) -{ - ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed - - sha1_finish(&m_Sha1, a_Output); - m_DoesAcceptInput = false; -} - - - - - -void cSha1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out) -{ - Checksum Digest; - memcpy(Digest, a_Digest, sizeof(Digest)); - - bool IsNegative = (Digest[0] >= 0x80); - if (IsNegative) - { - // Two's complement: - bool carry = true; // Add one to the whole number - for (int i = 19; i >= 0; i--) - { - Digest[i] = ~Digest[i]; - if (carry) - { - carry = (Digest[i] == 0xff); - Digest[i]++; - } - } - } - a_Out.clear(); - a_Out.reserve(40); - for (int i = 0; i < 20; i++) - { - AppendPrintf(a_Out, "%02x", Digest[i]); - } - while ((a_Out.length() > 0) && (a_Out[0] == '0')) - { - a_Out.erase(0, 1); - } - if (IsNegative) - { - a_Out.insert(0, "-"); - } -} - - - - - - -void cSha1Checksum::Restart(void) -{ - sha1_starts(&m_Sha1); - m_DoesAcceptInput = true; -} - - - - diff --git a/src/PolarSSL++/Sha1Checksum.h b/src/PolarSSL++/Sha1Checksum.h deleted file mode 100644 index b78fbfc62..000000000 --- a/src/PolarSSL++/Sha1Checksum.h +++ /dev/null @@ -1,52 +0,0 @@ - -// Sha1Checksum.h - -// Declares the cSha1Checksum class representing the SHA-1 checksum calculator - - - - - -#pragma once - -#include "polarssl/sha1.h" - - - - - -/** Calculates a SHA1 checksum for data stream */ -class cSha1Checksum -{ -public: - typedef Byte Checksum[20]; // The type used for storing the checksum - - cSha1Checksum(void); - - /** Adds the specified data to the checksum */ - void Update(const Byte * a_Data, size_t a_Length); - - /** Calculates and returns the final checksum */ - void Finalize(Checksum & a_Output); - - /** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */ - bool DoesAcceptInput(void) const { return m_DoesAcceptInput; } - - /** Converts a raw 160-bit SHA1 digest into a Java Hex representation - According to http://wiki.vg/Protocol_Encryption - */ - static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut); - - /** Clears the current context and start a new checksum calculation */ - void Restart(void); - -protected: - /** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */ - bool m_DoesAcceptInput; - - sha1_context m_Sha1; -} ; - - - - diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp deleted file mode 100644 index 557f81db4..000000000 --- a/src/PolarSSL++/SslContext.cpp +++ /dev/null @@ -1,307 +0,0 @@ - -// SslContext.cpp - -// Implements the cSslContext class that holds everything a single SSL context needs to function - -#include "Globals.h" -#include "SslContext.h" -#include "EntropyContext.h" -#include "CtrDrbgContext.h" -#include "polarssl/debug.h" - - - - - -cSslContext::cSslContext(void) : - m_IsValid(false), - m_HasHandshaken(false) -{ - memset(&m_Ssl, 0, sizeof(m_Ssl)); -} - - - - - -cSslContext::~cSslContext() -{ - if (m_IsValid) - { - ssl_free(&m_Ssl); - } -} - - - - - -int cSslContext::Initialize(bool a_IsClient, const std::shared_ptr & a_CtrDrbg) -{ - // Check double-initialization: - if (m_IsValid) - { - LOGWARNING("SSL: Double initialization is not supported."); - return POLARSSL_ERR_SSL_BAD_INPUT_DATA; // There is no return value well-suited for this, reuse this one. - } - - // Set the CtrDrbg context, create a new one if needed: - m_CtrDrbg = a_CtrDrbg; - if (m_CtrDrbg.get() == nullptr) - { - m_CtrDrbg.reset(new cCtrDrbgContext); - m_CtrDrbg->Initialize("Cuberite", 8); - } - - // Initialize PolarSSL's structures: - memset(&m_Ssl, 0, sizeof(m_Ssl)); - int res = ssl_init(&m_Ssl); - if (res != 0) - { - return res; - } - ssl_set_endpoint(&m_Ssl, a_IsClient ? SSL_IS_CLIENT : SSL_IS_SERVER); - ssl_set_authmode(&m_Ssl, SSL_VERIFY_NONE); // We cannot verify because we don't have a CA chain, required by PolarSSL, implemented yet (TODO) - ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg); - ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this); - - #ifdef _DEBUG - /* - // These functions allow us to debug SSL and certificate problems, but produce way too much output, - // so they're disabled until someone needs them - ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this); - debug_set_threshold(2); - - ssl_set_verify(&m_Ssl, &SSLVerifyCert, this); - //*/ - - /* - // Set ciphersuite to the easiest one to decode, so that the connection can be wireshark-decoded: - static const int CipherSuites[] = - { - TLS_RSA_WITH_RC4_128_MD5, - TLS_RSA_WITH_RC4_128_SHA, - TLS_RSA_WITH_AES_128_CBC_SHA, - 0, // Must be 0-terminated! - }; - ssl_set_ciphersuites(&m_Ssl, CipherSuites); - //*/ - #endif - - m_IsValid = true; - return 0; -} - - - - - -void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey) -{ - ASSERT(m_IsValid); // Call Initialize() first - - // Check that both the cert and the key is valid: - if ((a_OwnCert.get() == nullptr) || (a_OwnCertPrivKey.get() == nullptr)) - { - LOGWARNING("SSL: Own certificate is not valid, skipping the set."); - return; - } - - // Make sure we have the cert stored for later, PolarSSL only uses the cert later on - m_OwnCert = a_OwnCert; - m_OwnCertPrivKey = a_OwnCertPrivKey; - - // Set into the context: - ssl_set_own_cert_rsa(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey->GetInternal()); -} - - - - - -void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey) -{ - ASSERT(m_IsValid); // Call Initialize() first - - // Check that both the cert and the key is valid: - if ((a_OwnCert.get() == nullptr) || (a_OwnCertPrivKey.get() == nullptr)) - { - LOGWARNING("SSL: Own certificate is not valid, skipping the set."); - return; - } - - // Make sure we have the cert stored for later, PolarSSL only uses the cert later on - m_OwnCert = a_OwnCert; - m_OwnCertPrivKey2 = a_OwnCertPrivKey; - - // Set into the context: - ssl_set_own_cert(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey2->GetInternal()); -} - - - - - -void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName) -{ - ASSERT(m_IsValid); // Call Initialize() first - - // Store the data in our internal buffers, to avoid losing the pointers later on - // PolarSSL will need these after this call returns, and the caller may move / delete the data before that: - m_ExpectedPeerName = a_ExpectedPeerName; - m_CACerts = a_CACert; - - // Set the trusted CA root cert store: - ssl_set_authmode(&m_Ssl, SSL_VERIFY_REQUIRED); - ssl_set_ca_chain(&m_Ssl, m_CACerts->GetInternal(), nullptr, m_ExpectedPeerName.empty() ? nullptr : m_ExpectedPeerName.c_str()); -} - - - - - -int cSslContext::WritePlain(const void * a_Data, size_t a_NumBytes) -{ - ASSERT(m_IsValid); // Need to call Initialize() first - if (!m_HasHandshaken) - { - int res = Handshake(); - if (res != 0) - { - return res; - } - } - - return ssl_write(&m_Ssl, reinterpret_cast(a_Data), a_NumBytes); -} - - - - - -int cSslContext::ReadPlain(void * a_Data, size_t a_MaxBytes) -{ - ASSERT(m_IsValid); // Need to call Initialize() first - if (!m_HasHandshaken) - { - int res = Handshake(); - if (res != 0) - { - return res; - } - } - - return ssl_read(&m_Ssl, reinterpret_cast(a_Data), a_MaxBytes); -} - - - - - -int cSslContext::Handshake(void) -{ - ASSERT(m_IsValid); // Need to call Initialize() first - ASSERT(!m_HasHandshaken); // Must not call twice - - int res = ssl_handshake(&m_Ssl); - if (res == 0) - { - m_HasHandshaken = true; - } - return res; -} - - - - - -int cSslContext::NotifyClose(void) -{ - return ssl_close_notify(&m_Ssl); -} - - - - - -#ifdef _DEBUG - void cSslContext::SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text) - { - if (a_Level > 3) - { - // Don't want the trace messages - return; - } - - // Remove the terminating LF: - size_t len = strlen(a_Text) - 1; - while ((len > 0) && (a_Text[len] <= 32)) - { - len--; - } - AString Text(a_Text, len + 1); - - LOGD("SSL (%d): %s", a_Level, Text.c_str()); - } - - - - - - int cSslContext::SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags) - { - char buf[1024]; - UNUSED(a_This); - - LOG("Verify requested for (Depth %d):", a_Depth); - x509_crt_info(buf, sizeof(buf) - 1, "", a_Crt); - LOG("%s", buf); - - int Flags = *a_Flags; - if ((Flags & BADCERT_EXPIRED) != 0) - { - LOG(" ! server certificate has expired"); - } - - if ((Flags & BADCERT_REVOKED) != 0) - { - LOG(" ! server certificate has been revoked"); - } - - if ((Flags & BADCERT_CN_MISMATCH) != 0) - { - LOG(" ! CN mismatch"); - } - - if ((Flags & BADCERT_NOT_TRUSTED) != 0) - { - LOG(" ! self-signed or not signed by a trusted CA"); - } - - if ((Flags & BADCRL_NOT_TRUSTED) != 0) - { - LOG(" ! CRL not trusted"); - } - - if ((Flags & BADCRL_EXPIRED) != 0) - { - LOG(" ! CRL expired"); - } - - if ((Flags & BADCERT_OTHER) != 0) - { - LOG(" ! other (unknown) flag"); - } - - if (Flags == 0) - { - LOG(" This certificate has no flags"); - } - - return 0; - } -#endif // _DEBUG - - - - diff --git a/src/PolarSSL++/SslContext.h b/src/PolarSSL++/SslContext.h deleted file mode 100644 index 0588122ba..000000000 --- a/src/PolarSSL++/SslContext.h +++ /dev/null @@ -1,156 +0,0 @@ - -// SslContext.h - -// Declares the cSslContext class that holds everything a single SSL context needs to function - - - - - -#pragma once - -#include "polarssl/ssl.h" -#include "../ByteBuffer.h" -#include "CryptoKey.h" -#include "RsaPrivateKey.h" -#include "X509Cert.h" - - - - - -// fwd: -class cCtrDrbgContext; - - - - - -/** -Acts as a generic SSL encryptor / decryptor between the two endpoints. The "owner" of this class is expected -to create it, initialize it and then provide the means of reading and writing data through the SSL link. -This is an abstract base class, there are descendants that handle the specific aspects of how the SSL peer -data comes into the system: - - cBufferedSslContext uses a cByteBuffer to read and write the data - - cCallbackSslContext uses callbacks to provide the data -*/ -class cSslContext abstract -{ -public: - /** Creates a new uninitialized context */ - cSslContext(void); - - virtual ~cSslContext(); - - /** Initializes the context for use as a server or client. - Returns 0 on success, PolarSSL error on failure. */ - int Initialize(bool a_IsClient, const std::shared_ptr & a_CtrDrbg = {}); - - /** Returns true if the object has been initialized properly. */ - bool IsValid(void) const { return m_IsValid; } - - /** Sets the certificate to use as our own. Must be used when representing a server, optional when client. - Must be called after Initialize(). */ - void SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey); - - /** Sets the certificate to use as our own. Must be used when representing a server, optional when client. - Must be called after Initialize(). */ - void SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey); - - /** Sets a cert chain as the trusted cert store for this context. Must be called after Initialize(). - Calling this will switch the context into strict cert verification mode. - a_ExpectedPeerName is the CommonName that we expect the SSL peer to have in its cert, - if it is different, the verification will fail. An empty string will disable the CN check. */ - void SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName); - - /** Writes data to be encrypted and sent to the SSL peer. Will perform SSL handshake, if needed. - Returns the number of bytes actually written, or PolarSSL error code. - If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any - cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call - this function again with the same parameters. Note that this may repeat a few times before the data is - actually written, mainly due to initial handshake. */ - int WritePlain(const void * a_Data, size_t a_NumBytes); - - /** Reads data decrypted from the SSL stream. Will perform SSL handshake, if needed. - Returns the number of bytes actually read, or PolarSSL error code. - If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any - cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call - this function again with the same parameters. Note that this may repeat a few times before the data is - actually read, mainly due to initial handshake. */ - int ReadPlain(void * a_Data, size_t a_MaxBytes); - - /** Performs the SSL handshake. - Returns zero on success, PoladSSL error code on failure. - If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any - cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call - this function again. Note that this may repeat a few times before the handshake is completed. */ - int Handshake(void); - - /** Returns true if the SSL handshake has been completed. */ - bool HasHandshaken(void) const { return m_HasHandshaken; } - - /** Notifies the SSL peer that the connection is being closed. - Returns 0 on success, PolarSSL error code on failure. */ - int NotifyClose(void); - -protected: - /** True if the object has been initialized properly. */ - bool m_IsValid; - - /** The random generator to use */ - std::shared_ptr m_CtrDrbg; - - /** The SSL context that PolarSSL uses. */ - ssl_context m_Ssl; - - /** The certificate that we present to the peer. */ - cX509CertPtr m_OwnCert; - - /** Private key for m_OwnCert, if initialized from a cRsaPrivateKey. */ - cRsaPrivateKeyPtr m_OwnCertPrivKey; - - /** Private key for m_OwnCert, if initialized from a cCryptoKey. */ - cCryptoKeyPtr m_OwnCertPrivKey2; - - /** True if the SSL handshake has been completed. */ - bool m_HasHandshaken; - - /** A copy of the trusted CA root cert store that is passed to us in SetCACerts(), so that the pointer - stays valid even after the call, when PolarSSL finally uses it. */ - cX509CertPtr m_CACerts; - - /** Buffer for the expected peer name. We need to buffer it because the caller may free the string they - give us before PolarSSL consumes the raw pointer it gets to the CN. */ - AString m_ExpectedPeerName; - - - /** The callback used by PolarSSL when it wants to read encrypted data. */ - static int ReceiveEncrypted(void * a_This, unsigned char * a_Buffer, size_t a_NumBytes) - { - return (reinterpret_cast(a_This))->ReceiveEncrypted(a_Buffer, a_NumBytes); - } - - /** The callback used by PolarSSL when it wants to write encrypted data. */ - static int SendEncrypted(void * a_This, const unsigned char * a_Buffer, size_t a_NumBytes) - { - return (reinterpret_cast(a_This))->SendEncrypted(a_Buffer, a_NumBytes); - } - - #ifdef _DEBUG - /** The callback used by PolarSSL to output debug messages */ - static void SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text); - - /** The callback used by PolarSSL to log information on the cert chain */ - static int SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags); - #endif // _DEBUG - - /** Called when PolarSSL wants to read encrypted data. */ - virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0; - - /** Called when PolarSSL wants to write encrypted data. */ - virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0; -} ; - - - - diff --git a/src/PolarSSL++/X509Cert.cpp b/src/PolarSSL++/X509Cert.cpp deleted file mode 100644 index ed65639a5..000000000 --- a/src/PolarSSL++/X509Cert.cpp +++ /dev/null @@ -1,38 +0,0 @@ - -// X509Cert.cpp - -// Implements the cX509Cert class representing a wrapper over X509 certs in PolarSSL - -#include "Globals.h" -#include "X509Cert.h" - - - - - -cX509Cert::cX509Cert(void) -{ - x509_crt_init(&m_Cert); -} - - - - - -cX509Cert::~cX509Cert() -{ - x509_crt_free(&m_Cert); -} - - - - - -int cX509Cert::Parse(const void * a_CertContents, size_t a_Size) -{ - return x509_crt_parse(&m_Cert, reinterpret_cast(a_CertContents), a_Size); -} - - - - diff --git a/src/PolarSSL++/X509Cert.h b/src/PolarSSL++/X509Cert.h deleted file mode 100644 index 45f714d14..000000000 --- a/src/PolarSSL++/X509Cert.h +++ /dev/null @@ -1,41 +0,0 @@ - -// X509Cert.h - -// Declares the cX509Cert class representing a wrapper over X509 certs in PolarSSL - - - - - -#pragma once - -#include "polarssl/x509_crt.h" - - - - - -class cX509Cert -{ - friend class cSslContext; - -public: - cX509Cert(void); - ~cX509Cert(void); - - /** Parses the certificate chain data into the context. - Returns 0 on succes, or PolarSSL error code on failure. */ - int Parse(const void * a_CertContents, size_t a_Size); - -protected: - x509_crt m_Cert; - - /** Returns the internal cert ptr. Only use in PolarSSL API calls. */ - x509_crt * GetInternal(void) { return &m_Cert; } -} ; - -typedef std::shared_ptr cX509CertPtr; - - - - diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp index d46127d34..445a3dff5 100644 --- a/src/Protocol/Authenticator.cpp +++ b/src/Protocol/Authenticator.cpp @@ -11,7 +11,7 @@ #include "../IniFile.h" #include "json/json.h" -#include "PolarSSL++/BlockingSslClientSocket.h" +#include "mbedTLS++/BlockingSslClientSocket.h" diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 5a11356c1..0b14d1cac 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -1,4 +1,4 @@ - + // MojangAPI.cpp // Implements the cMojangAPI class representing the various API points provided by Mojang's webservices, and a cache for their results @@ -9,7 +9,8 @@ #include "SQLiteCpp/Statement.h" #include "../IniFile.h" #include "json/json.h" -#include "PolarSSL++/BlockingSslClientSocket.h" +#include "mbedTLS++/BlockingSslClientSocket.h" +#include "mbedTLS++/SslConfig.h" #include "../RankManager.h" #include "../OSSupport/IsThread.h" #include "../Root.h" @@ -39,9 +40,9 @@ const int MAX_PER_QUERY = 100; /** Returns the CA certificates that should be trusted for Mojang-related connections. */ -static const AString & GetCACerts(void) +static cX509CertPtr GetCACerts(void) { - static const AString Cert( + static const char CertString[] = // GeoTrust root CA cert // Currently used for signing *.mojang.com's cert // Exported from Mozilla Firefox's built-in CA repository @@ -140,9 +141,33 @@ static const AString & GetCACerts(void) "VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n" "WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n" "-----END CERTIFICATE-----\n" - ); + ; + + static auto X509Cert = [&]() + { + auto Cert = std::make_shared(); + VERIFY(0 == Cert->Parse(CertString, sizeof(CertString))); + return Cert; + }(); + + return X509Cert; +} - return Cert; + + + + +/** Returns the config to be used for secure requests. */ +static std::shared_ptr GetSslConfig() +{ + static const std::shared_ptr Config = []() + { + auto Conf = cSslConfig::MakeDefaultConfig(true); + Conf->SetCACerts(GetCACerts()); + Conf->SetAuthMode(eSslAuthMode::Required); + return Conf; + }(); + return Config; } @@ -432,7 +457,8 @@ bool cMojangAPI::SecureRequest(const AString & a_ServerName, const AString & a_R { // Connect the socket: cBlockingSslClientSocket Socket; - Socket.SetTrustedRootCertsFromString(GetCACerts(), a_ServerName); + Socket.SetSslConfig(GetSslConfig()); + Socket.SetExpectedPeerName(a_ServerName); if (!Socket.Connect(a_ServerName, 443)) { LOGWARNING("%s: Can't connect to %s: %s", __FUNCTION__, a_ServerName.c_str(), Socket.GetLastErrorText().c_str()); @@ -452,13 +478,13 @@ bool cMojangAPI::SecureRequest(const AString & a_ServerName, const AString & a_R { int ret = Socket.Receive(buf, sizeof(buf)); - if ((ret == POLARSSL_ERR_NET_WANT_READ) || (ret == POLARSSL_ERR_NET_WANT_WRITE)) + if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE)) { // This value should never be returned, it is handled internally by cBlockingSslClientSocket LOGWARNING("%s: SSL reading failed internally", __FUNCTION__); return false; } - if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) + if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { break; } diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index c77af1029..7f4b074ce 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -11,7 +11,7 @@ Implements the 1.8 protocol classes: #include "json/json.h" #include "Protocol_1_8.h" #include "ChunkDataSerializer.h" -#include "PolarSSL++/Sha1Checksum.h" +#include "mbedTLS++/Sha1Checksum.h" #include "Packetizer.h" #include "../ClientHandle.h" diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h index b04e5c5f0..d3d0daf0a 100644 --- a/src/Protocol/Protocol_1_8.h +++ b/src/Protocol/Protocol_1_8.h @@ -29,8 +29,8 @@ Declares the 1.8 protocol classes: #pragma warning(pop) #endif -#include "PolarSSL++/AesCfb128Decryptor.h" -#include "PolarSSL++/AesCfb128Encryptor.h" +#include "mbedTLS++/AesCfb128Decryptor.h" +#include "mbedTLS++/AesCfb128Encryptor.h" diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index c6e007984..c440a94ca 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -17,7 +17,7 @@ Implements the 1.9 protocol classes: #include "json/json.h" #include "Protocol_1_9.h" #include "ChunkDataSerializer.h" -#include "PolarSSL++/Sha1Checksum.h" +#include "mbedTLS++/Sha1Checksum.h" #include "Packetizer.h" #include "../ClientHandle.h" diff --git a/src/Protocol/Protocol_1_9.h b/src/Protocol/Protocol_1_9.h index b4fdc7f67..3fbbe86da 100644 --- a/src/Protocol/Protocol_1_9.h +++ b/src/Protocol/Protocol_1_9.h @@ -35,8 +35,8 @@ Declares the 1.9 protocol classes: #pragma warning(pop) #endif -#include "PolarSSL++/AesCfb128Decryptor.h" -#include "PolarSSL++/AesCfb128Encryptor.h" +#include "mbedTLS++/AesCfb128Decryptor.h" +#include "mbedTLS++/AesCfb128Encryptor.h" diff --git a/src/Server.h b/src/Server.h index ffdee64d9..ab821c102 100644 --- a/src/Server.h +++ b/src/Server.h @@ -22,7 +22,7 @@ #pragma warning(disable:4702) #endif -#include "PolarSSL++/RsaPrivateKey.h" +#include "mbedTLS++/RsaPrivateKey.h" #ifdef _MSC_VER #pragma warning(pop) diff --git a/src/UUID.cpp b/src/UUID.cpp index e2713157d..866bf817e 100644 --- a/src/UUID.cpp +++ b/src/UUID.cpp @@ -5,7 +5,7 @@ #include "Globals.h" #include "UUID.h" -#include "polarssl/md5.h" +#include "mbedtls/md5.h" /** UUID normalised in textual form. */ @@ -265,7 +265,7 @@ cUUID cUUID::GenerateVersion3(const AString & a_Name) cUUID UUID; // Generate an md5 checksum, and use it as base for the ID: const Byte * ByteString = reinterpret_cast(a_Name.data()); - md5(ByteString, a_Name.length(), UUID.m_UUID.data()); + mbedtls_md5(ByteString, a_Name.length(), UUID.m_UUID.data()); // Insert version number UUID.m_UUID[6] = (UUID.m_UUID[6] & 0x0f) | 0x30; diff --git a/src/mbedTLS++/AesCfb128Decryptor.cpp b/src/mbedTLS++/AesCfb128Decryptor.cpp new file mode 100644 index 000000000..78a7ab9c5 --- /dev/null +++ b/src/mbedTLS++/AesCfb128Decryptor.cpp @@ -0,0 +1,55 @@ + +// AesCfb128Decryptor.cpp + +// Implements the cAesCfb128Decryptor class decrypting data using AES CFB-128 + +#include "Globals.h" +#include "AesCfb128Decryptor.h" + + + + + +cAesCfb128Decryptor::cAesCfb128Decryptor(void): + m_IsValid(false) +{ + mbedtls_aes_init(&m_Aes); +} + + + + + +cAesCfb128Decryptor::~cAesCfb128Decryptor() +{ + // Clear the leftover in-memory data, so that they can't be accessed by a backdoor + mbedtls_aes_free(&m_Aes); +} + + + + + +void cAesCfb128Decryptor::Init(const Byte a_Key[16], const Byte a_IV[16]) +{ + ASSERT(!IsValid()); // Cannot Init twice + + memcpy(m_IV, a_IV, 16); + mbedtls_aes_setkey_enc(&m_Aes, a_Key, 128); + m_IsValid = true; +} + + + + + +void cAesCfb128Decryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length) +{ + ASSERT(IsValid()); // Must Init() first + mbedtls_aes_crypt_cfb8(&m_Aes, MBEDTLS_AES_DECRYPT, a_Length, m_IV, a_EncryptedIn, a_DecryptedOut); +} + + + + + diff --git a/src/mbedTLS++/AesCfb128Decryptor.h b/src/mbedTLS++/AesCfb128Decryptor.h new file mode 100644 index 000000000..54c5536ea --- /dev/null +++ b/src/mbedTLS++/AesCfb128Decryptor.h @@ -0,0 +1,48 @@ + +// AesCfb128Decryptor.h + +// Declares the cAesCfb128Decryptor class decrypting data using AES CFB-128 + + + + + +#pragma once + +#include "mbedtls/aes.h" + + + + + +/** Decrypts data using the AES / CFB 128 algorithm */ +class cAesCfb128Decryptor +{ +public: + + cAesCfb128Decryptor(void); + ~cAesCfb128Decryptor(); + + /** Initializes the decryptor with the specified Key / IV */ + void Init(const Byte a_Key[16], const Byte a_IV[16]); + + /** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */ + void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length); + + /** Returns true if the object has been initialized with the Key / IV */ + bool IsValid(void) const { return m_IsValid; } + +protected: + mbedtls_aes_context m_Aes; + + /** The InitialVector, used by the CFB mode decryption */ + Byte m_IV[16]; + + /** Indicates whether the object has been initialized with the Key / IV */ + bool m_IsValid; +} ; + + + + + diff --git a/src/mbedTLS++/AesCfb128Encryptor.cpp b/src/mbedTLS++/AesCfb128Encryptor.cpp new file mode 100644 index 000000000..11582fc19 --- /dev/null +++ b/src/mbedTLS++/AesCfb128Encryptor.cpp @@ -0,0 +1,55 @@ + +// AesCfb128Encryptor.cpp + +// Implements the cAesCfb128Encryptor class encrypting data using AES CFB-128 + +#include "Globals.h" +#include "AesCfb128Encryptor.h" + + + + + +cAesCfb128Encryptor::cAesCfb128Encryptor(void): + m_IsValid(false) +{ + mbedtls_aes_init(&m_Aes); +} + + + + + +cAesCfb128Encryptor::~cAesCfb128Encryptor() +{ + // Clear the leftover in-memory data, so that they can't be accessed by a backdoor + mbedtls_aes_free(&m_Aes); +} + + + + + +void cAesCfb128Encryptor::Init(const Byte a_Key[16], const Byte a_IV[16]) +{ + ASSERT(!IsValid()); // Cannot Init twice + + memcpy(m_IV, a_IV, 16); + mbedtls_aes_setkey_enc(&m_Aes, a_Key, 128); + m_IsValid = true; +} + + + + + +void cAesCfb128Encryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length) +{ + ASSERT(IsValid()); // Must Init() first + mbedtls_aes_crypt_cfb8(&m_Aes, MBEDTLS_AES_ENCRYPT, a_Length, m_IV, a_PlainIn, a_EncryptedOut); +} + + + + + diff --git a/src/mbedTLS++/AesCfb128Encryptor.h b/src/mbedTLS++/AesCfb128Encryptor.h new file mode 100644 index 000000000..6bfa6b5c9 --- /dev/null +++ b/src/mbedTLS++/AesCfb128Encryptor.h @@ -0,0 +1,47 @@ + +// AesCfb128Encryptor.h + +// Declares the cAesCfb128Encryptor class encrypting data using AES CFB-128 + + + + + +#pragma once + +#include "mbedtls/aes.h" + + + + + +/** Encrypts data using the AES / CFB (128) algorithm */ +class cAesCfb128Encryptor +{ +public: + cAesCfb128Encryptor(void); + ~cAesCfb128Encryptor(); + + /** Initializes the decryptor with the specified Key / IV */ + void Init(const Byte a_Key[16], const Byte a_IV[16]); + + /** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */ + void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length); + + /** Returns true if the object has been initialized with the Key / IV */ + bool IsValid(void) const { return m_IsValid; } + +protected: + mbedtls_aes_context m_Aes; + + /** The InitialVector, used by the CFB mode encryption */ + Byte m_IV[16]; + + /** Indicates whether the object has been initialized with the Key / IV */ + bool m_IsValid; +} ; + + + + + diff --git a/src/mbedTLS++/BlockingSslClientSocket.cpp b/src/mbedTLS++/BlockingSslClientSocket.cpp new file mode 100644 index 000000000..6f765f607 --- /dev/null +++ b/src/mbedTLS++/BlockingSslClientSocket.cpp @@ -0,0 +1,377 @@ + +// BlockingSslClientSocket.cpp + +// Implements the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it + +#include "Globals.h" +#include "BlockingSslClientSocket.h" + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cBlockingSslClientSocketConnectCallbacks: + +class cBlockingSslClientSocketConnectCallbacks: + public cNetwork::cConnectCallbacks +{ + /** The socket object that is using this instance of the callbacks. */ + cBlockingSslClientSocket & m_Socket; + + virtual void OnConnected(cTCPLink & a_Link) override + { + m_Socket.OnConnected(); + } + + virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override + { + m_Socket.OnConnectError(a_ErrorMsg); + } + +public: + cBlockingSslClientSocketConnectCallbacks(cBlockingSslClientSocket & a_Socket): + m_Socket(a_Socket) + { + } +}; + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cBlockingSslClientSocketLinkCallbacks: + +class cBlockingSslClientSocketLinkCallbacks: + public cTCPLink::cCallbacks +{ + cBlockingSslClientSocket & m_Socket; + + virtual void OnLinkCreated(cTCPLinkPtr a_Link) override + { + m_Socket.SetLink(a_Link); + } + + + virtual void OnReceivedData(const char * a_Data, size_t a_Length) override + { + m_Socket.OnReceivedData(a_Data, a_Length); + } + + + virtual void OnRemoteClosed(void) override + { + m_Socket.OnDisconnected(); + } + + + virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override + { + m_Socket.OnDisconnected(); + } + +public: + + cBlockingSslClientSocketLinkCallbacks(cBlockingSslClientSocket & a_Socket): + m_Socket(a_Socket) + { + } +}; + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cBlockingSslClientSocket: + +cBlockingSslClientSocket::cBlockingSslClientSocket(void) : + m_Ssl(*this), + m_IsConnected(false) +{ + // Nothing needed yet +} + + + + + +bool cBlockingSslClientSocket::Connect(const AString & a_ServerName, UInt16 a_Port) +{ + // If already connected, report an error: + if (m_IsConnected) + { + // TODO: Handle this better - if connected to the same server and port, and the socket is alive, return success + m_LastErrorText = "Already connected"; + return false; + } + + // Connect the underlying socket: + m_ServerName = a_ServerName; + if (!cNetwork::Connect(a_ServerName, a_Port, + std::make_shared(*this), + std::make_shared(*this)) + ) + { + return false; + } + + // Wait for the connection to succeed or fail: + m_Event.Wait(); + if (!m_IsConnected) + { + return false; + } + + // Initialize the SSL: + int ret = 0; + if (m_Config != nullptr) + { + ret = m_Ssl.Initialize(m_Config); + } + else + { + ret = m_Ssl.Initialize(true); + } + + if (ret != 0) + { + Printf(m_LastErrorText, "SSL initialization failed: -0x%x", -ret); + return false; + } + + // If we have been assigned a trusted CA root cert store, push it into the SSL context: + if (!m_ExpectedPeerName.empty()) + { + m_Ssl.SetExpectedPeerName(m_ExpectedPeerName); + } + + ret = m_Ssl.Handshake(); + if (ret != 0) + { + Printf(m_LastErrorText, "SSL handshake failed: -0x%x", -ret); + return false; + } + + return true; +} + + + + + + +void cBlockingSslClientSocket::SetExpectedPeerName(AString a_ExpectedPeerName) +{ + ASSERT(!m_IsConnected); // Must be called before connect + + // Warn if used multiple times, but don't signal an error: + if (!m_ExpectedPeerName.empty()) + { + LOGWARNING( + "SSL: Trying to set multiple expected peer names, only the last one will be used. Name: %s", + a_ExpectedPeerName.c_str() + ); + } + + m_ExpectedPeerName = std::move(a_ExpectedPeerName); +} + + + + + +void cBlockingSslClientSocket::SetSslConfig(std::shared_ptr a_Config) +{ + ASSERT(!m_IsConnected); // Must be called before connect + + // Warn if used multiple times, but don't signal an error: + if (m_Config != nullptr) + { + LOGWARNING("SSL: Trying to set multiple configurations, only the last one will be used."); + } + + m_Config = std::move(a_Config); +} + + + + + +bool cBlockingSslClientSocket::Send(const void * a_Data, size_t a_NumBytes) +{ + if (!m_IsConnected) + { + m_LastErrorText = "Socket is closed"; + return false; + } + + // Keep sending the data until all of it is sent: + const char * Data = reinterpret_cast(a_Data); + size_t NumBytes = a_NumBytes; + for (;;) + { + int res = m_Ssl.WritePlain(Data, a_NumBytes); + if (res < 0) + { + ASSERT(res != MBEDTLS_ERR_SSL_WANT_READ); // This should never happen with callback-based SSL + ASSERT(res != MBEDTLS_ERR_SSL_WANT_WRITE); // This should never happen with callback-based SSL + Printf(m_LastErrorText, "Data cannot be written to SSL context: -0x%x", -res); + return false; + } + else + { + Data += res; + NumBytes -= static_cast(res); + if (NumBytes == 0) + { + return true; + } + } + } +} + + + + + + +int cBlockingSslClientSocket::Receive(void * a_Data, size_t a_MaxBytes) +{ + // Even if m_IsConnected is false (socket disconnected), the SSL context may have more data in the queue + int res = m_Ssl.ReadPlain(a_Data, a_MaxBytes); + if (res < 0) + { + Printf(m_LastErrorText, "Data cannot be read form SSL context: -0x%x", -res); + } + return res; +} + + + + + +void cBlockingSslClientSocket::Disconnect(void) +{ + // Ignore if not connected + if (!m_IsConnected) + { + return; + } + + m_Ssl.NotifyClose(); + m_IsConnected = false; + + // Grab a copy of the socket so that we know it doesn't change under our hands: + auto socket = m_Socket; + if (socket != nullptr) + { + socket->Close(); + } + + m_Socket.reset(); +} + + + + + +int cBlockingSslClientSocket::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) +{ + // Wait for any incoming data, if there is none: + cCSLock Lock(m_CSIncomingData); + while (m_IsConnected && m_IncomingData.empty()) + { + cCSUnlock Unlock(Lock); + m_Event.Wait(); + } + + // If we got disconnected, report an error after processing all data: + if (!m_IsConnected && m_IncomingData.empty()) + { + return MBEDTLS_ERR_NET_RECV_FAILED; + } + + // Copy the data from the incoming buffer into the specified space: + size_t NumToCopy = std::min(a_NumBytes, m_IncomingData.size()); + memcpy(a_Buffer, m_IncomingData.data(), NumToCopy); + m_IncomingData.erase(0, NumToCopy); + return static_cast(NumToCopy); +} + + + + + +int cBlockingSslClientSocket::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) +{ + cTCPLinkPtr Socket(m_Socket); // Make a copy so that multiple threads don't race on deleting the socket. + if (Socket == nullptr) + { + return MBEDTLS_ERR_NET_SEND_FAILED; + } + if (!Socket->Send(a_Buffer, a_NumBytes)) + { + // mbedTLS's net routines distinguish between connection reset and general failure, we don't need to + return MBEDTLS_ERR_NET_SEND_FAILED; + } + return static_cast(a_NumBytes); +} + + + + + +void cBlockingSslClientSocket::OnConnected(void) +{ + m_IsConnected = true; + m_Event.Set(); +} + + + + + +void cBlockingSslClientSocket::OnConnectError(const AString & a_ErrorMsg) +{ + LOG("Cannot connect to %s: \"%s\"", m_ServerName.c_str(), a_ErrorMsg.c_str()); + m_Event.Set(); +} + + + + + +void cBlockingSslClientSocket::OnReceivedData(const char * a_Data, size_t a_Size) +{ + { + cCSLock Lock(m_CSIncomingData); + m_IncomingData.append(a_Data, a_Size); + } + m_Event.Set(); +} + + + + + +void cBlockingSslClientSocket::SetLink(cTCPLinkPtr a_Link) +{ + m_Socket = a_Link; +} + + + + + +void cBlockingSslClientSocket::OnDisconnected(void) +{ + m_IsConnected = false; + m_Socket.reset(); + m_Event.Set(); +} + + + + diff --git a/src/mbedTLS++/BlockingSslClientSocket.h b/src/mbedTLS++/BlockingSslClientSocket.h new file mode 100644 index 000000000..24ee32680 --- /dev/null +++ b/src/mbedTLS++/BlockingSslClientSocket.h @@ -0,0 +1,119 @@ + +// BlockingSslClientSocket.h + +// Declares the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it + + + + + +#pragma once + +#include "OSSupport/Network.h" +#include "CallbackSslContext.h" + + + + + +class cBlockingSslClientSocket : + protected cCallbackSslContext::cDataCallbacks +{ +public: + cBlockingSslClientSocket(void); + + virtual ~cBlockingSslClientSocket(void) override + { + Disconnect(); + } + + /** Connects to the specified server and performs SSL handshake. + Returns true if successful, false on failure. Sets internal error text on failure. */ + bool Connect(const AString & a_ServerName, UInt16 a_Port); + + /** Sends the specified data over the connection. + Returns true if successful, false on failure. Sets the internal error text on failure. */ + bool Send(const void * a_Data, size_t a_NumBytes); + + /** Receives data from the connection. + Blocks until there is any data available, then returns as much as possible. + Returns the number of bytes actually received, negative number on failure. + Sets the internal error text on failure. */ + int Receive(void * a_Data, size_t a_MaxBytes); + + /** Disconnects the connection gracefully, if possible. + Note that this also frees the internal SSL context, so all the certificates etc. are lost. */ + void Disconnect(void); + + /** Sets the Expected peer name. + Needs to be used before calling Connect(). + \param a_ExpectedPeerName Name that we expect to receive in the SSL peer's cert; verification will fail if + the presented name is different (possible MITM). */ + void SetExpectedPeerName(AString a_ExpectedPeerName); + + /** Set the config to be used by the SSL context. + Config must not be modified after calling connect. */ + void SetSslConfig(std::shared_ptr a_Config); + + /** Returns the text of the last error that has occurred in this instance. */ + const AString & GetLastErrorText(void) const { return m_LastErrorText; } + +protected: + friend class cBlockingSslClientSocketConnectCallbacks; + friend class cBlockingSslClientSocketLinkCallbacks; + + /** The SSL context used for the socket */ + cCallbackSslContext m_Ssl; + + /** The underlying socket to the SSL server */ + cTCPLinkPtr m_Socket; + + /** The object used to signal state changes in the socket (the cause of the blocking). */ + cEvent m_Event; + + /** The configuration to be used by the SSL context. Set by SetSslConfig(). */ + std::shared_ptr m_Config; + + /** The expected SSL peer's name, if we are to verify the cert strictly. Set by SetExpectedPeerName(). */ + AString m_ExpectedPeerName; + + /** The hostname to which the socket is connecting (stored for error reporting). */ + AString m_ServerName; + + /** Text of the last error that has occurred. */ + AString m_LastErrorText; + + /** Set to true if the connection established successfully. */ + std::atomic m_IsConnected; + + /** Protects m_IncomingData against multithreaded access. */ + cCriticalSection m_CSIncomingData; + + /** Buffer for the data incoming on the network socket. + Protected by m_CSIncomingData. */ + AString m_IncomingData; + + + /** Called when the connection is established successfully. */ + void OnConnected(void); + + /** Called when an error occurs while connecting the socket. */ + void OnConnectError(const AString & a_ErrorMsg); + + /** Called when there's incoming data from the socket. */ + void OnReceivedData(const char * a_Data, size_t a_Size); + + /** Called when the link for the connection is created. */ + void SetLink(cTCPLinkPtr a_Link); + + /** Called when the link is disconnected, either gracefully or by an error. */ + void OnDisconnected(void); + + // cCallbackSslContext::cDataCallbacks overrides: + virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override; + virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override; +} ; + + + + diff --git a/src/mbedTLS++/BufferedSslContext.cpp b/src/mbedTLS++/BufferedSslContext.cpp new file mode 100644 index 000000000..5cdf04323 --- /dev/null +++ b/src/mbedTLS++/BufferedSslContext.cpp @@ -0,0 +1,93 @@ + +// BufferedSslContext.cpp + +// Implements the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer + +#include "Globals.h" +#include "BufferedSslContext.h" + + + + + +cBufferedSslContext::cBufferedSslContext(size_t a_BufferSize): + m_OutgoingData(a_BufferSize), + m_IncomingData(a_BufferSize) +{ +} + + + + + +size_t cBufferedSslContext::WriteIncoming(const void * a_Data, size_t a_NumBytes) +{ + size_t NumBytes = std::min(m_IncomingData.GetFreeSpace(), a_NumBytes); + if (NumBytes > 0) + { + m_IncomingData.Write(a_Data, NumBytes); + return NumBytes; + } + return 0; +} + + + + + +size_t cBufferedSslContext::ReadOutgoing(void * a_Data, size_t a_DataMaxSize) +{ + size_t NumBytes = std::min(m_OutgoingData.GetReadableSpace(), a_DataMaxSize); + if (NumBytes > 0) + { + m_OutgoingData.ReadBuf(a_Data, NumBytes); + m_OutgoingData.CommitRead(); + return NumBytes; + } + return 0; +} + + + + + +int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) +{ + // Called when mbedTLS wants to read encrypted data from the SSL peer + // Read the data from the buffer inside this object, where the owner has stored them using WriteIncoming(): + size_t NumBytes = std::min(a_NumBytes, m_IncomingData.GetReadableSpace()); + if (NumBytes == 0) + { + return MBEDTLS_ERR_SSL_WANT_READ; + } + if (!m_IncomingData.ReadBuf(a_Buffer, NumBytes)) + { + m_IncomingData.ResetRead(); + return MBEDTLS_ERR_NET_RECV_FAILED; + } + m_IncomingData.CommitRead(); + return static_cast(NumBytes); +} + + + + + +int cBufferedSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) +{ + // Called when mbedTLS wants to write encrypted data to the SSL peer + // Write the data into the buffer inside this object, where the owner can later read them using ReadOutgoing(): + if (!m_OutgoingData.CanWriteBytes(a_NumBytes)) + { + return MBEDTLS_ERR_SSL_WANT_WRITE; + } + if (!m_OutgoingData.Write(reinterpret_cast(a_Buffer), a_NumBytes)) + { + return MBEDTLS_ERR_NET_SEND_FAILED; + } + return static_cast(a_NumBytes); +} + + + + diff --git a/src/mbedTLS++/BufferedSslContext.h b/src/mbedTLS++/BufferedSslContext.h new file mode 100644 index 000000000..9c9dd8f73 --- /dev/null +++ b/src/mbedTLS++/BufferedSslContext.h @@ -0,0 +1,53 @@ + +// BufferedSslContext.h + +// Declares the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer + + + + + +#pragma once + +#include "SslContext.h" +#include "ErrorCodes.h" + + + + + +class cBufferedSslContext : + public cSslContext +{ + typedef cSslContext super; + +public: + /** Creates a new context with the buffers of specified size for the encrypted / decrypted data. */ + cBufferedSslContext(size_t a_BufferSize = 64000); + + /** Stores the specified data in the "incoming" buffer, to be process by the SSL decryptor. + This is the data received from the SSL peer. + Returns the number of bytes actually stored. If 0 is returned, owner should check the error state. */ + size_t WriteIncoming(const void * a_Data, size_t a_NumBytes); + + /** Retrieves data from the "outgoing" buffer, after being processed by the SSL encryptor. + This is the data to be sent to the SSL peer. + Returns the number of bytes actually retrieved. */ + size_t ReadOutgoing(void * a_Data, size_t a_DataMaxSize); + +protected: + /** Buffer for the data that has been encrypted into the SSL stream and should be sent out. */ + cByteBuffer m_OutgoingData; + + /** Buffer for the data that has come in and needs to be decrypted from the SSL stream. */ + cByteBuffer m_IncomingData; + + + // cSslContext overrides: + virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override; + virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override; +} ; + + + + diff --git a/src/mbedTLS++/CMakeLists.txt b/src/mbedTLS++/CMakeLists.txt new file mode 100644 index 000000000..18ef22312 --- /dev/null +++ b/src/mbedTLS++/CMakeLists.txt @@ -0,0 +1,44 @@ +project (Cuberite) + +include_directories ("${PROJECT_SOURCE_DIR}/../") + +set(SRCS + AesCfb128Decryptor.cpp + AesCfb128Encryptor.cpp + BlockingSslClientSocket.cpp + BufferedSslContext.cpp + CallbackSslContext.cpp + CtrDrbgContext.cpp + CryptoKey.cpp + EntropyContext.cpp + RsaPrivateKey.cpp + Sha1Checksum.cpp + SslConfig.cpp + SslContext.cpp + X509Cert.cpp +) + +set(HDRS + AesCfb128Decryptor.h + AesCfb128Encryptor.h + BlockingSslClientSocket.h + BufferedSslContext.h + CallbackSslContext.h + CtrDrbgContext.h + CryptoKey.h + EntropyContext.h + ErrorCodes.h + RsaPrivateKey.h + SslConfig.h + SslContext.h + Sha1Checksum.h + X509Cert.h +) + +if(NOT MSVC) + add_library(mbedTLS++ ${SRCS} ${HDRS}) + + if (UNIX) + target_link_libraries(mbedTLS++ mbedtls) + endif() +endif() diff --git a/src/mbedTLS++/CallbackSslContext.cpp b/src/mbedTLS++/CallbackSslContext.cpp new file mode 100644 index 000000000..26bcec2ff --- /dev/null +++ b/src/mbedTLS++/CallbackSslContext.cpp @@ -0,0 +1,60 @@ + +// CallbackSslContext.cpp + +// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data + +#include "Globals.h" +#include "CallbackSslContext.h" + + + + + + +cCallbackSslContext::cCallbackSslContext(void) : + m_Callbacks(nullptr) +{ + // Nothing needed, but the constructor needs to exist so +} + + + + + +cCallbackSslContext::cCallbackSslContext(cCallbackSslContext::cDataCallbacks & a_Callbacks) : + m_Callbacks(&a_Callbacks) +{ +} + + + + + +int cCallbackSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) +{ + if (m_Callbacks == nullptr) + { + LOGWARNING("SSL: Trying to receive data with no callbacks, aborting."); + return MBEDTLS_ERR_NET_RECV_FAILED; + } + return m_Callbacks->ReceiveEncrypted(a_Buffer, a_NumBytes); +} + + + + + +int cCallbackSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) +{ + if (m_Callbacks == nullptr) + { + LOGWARNING("SSL: Trying to send data with no callbacks, aborting."); + return MBEDTLS_ERR_NET_SEND_FAILED; + } + return m_Callbacks->SendEncrypted(a_Buffer, a_NumBytes); +} + + + + + diff --git a/src/mbedTLS++/CallbackSslContext.h b/src/mbedTLS++/CallbackSslContext.h new file mode 100644 index 000000000..da1abb707 --- /dev/null +++ b/src/mbedTLS++/CallbackSslContext.h @@ -0,0 +1,65 @@ + +// CallbackSslContext.h + +// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data + + + + + +#pragma once + +#include "SslContext.h" +#include "ErrorCodes.h" + + + + + +class cCallbackSslContext : + public cSslContext +{ +public: + /** Interface used as a data sink for the SSL peer data. */ + class cDataCallbacks + { + public: + // Force a virtual destructor in descendants: + virtual ~cDataCallbacks() {} + + /** Called when mbedTLS wants to read encrypted data from the SSL peer. + The returned value is the number of bytes received, or a mbedTLS error on failure. + The implementation can return MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE to indicate + that there's currently no more data and that there might be more data in the future. In such cases the + SSL operation that invoked this call will terminate with the same return value, so that the owner is + notified of this condition and can potentially restart the operation later on. */ + virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0; + + /** Called when mbedTLS wants to write encrypted data to the SSL peer. + The returned value is the number of bytes sent, or a mbedTLS error on failure. + The implementation can return MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE to indicate + that there's currently no more data and that there might be more data in the future. In such cases the + SSL operation that invoked this call will terminate with the same return value, so that the owner is + notified of this condition and can potentially restart the operation later on. */ + virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0; + } ; + + + /** Creates a new SSL context with no callbacks assigned */ + cCallbackSslContext(void); + + /** Creates a new SSL context with the specified callbacks */ + cCallbackSslContext(cDataCallbacks & a_Callbacks); + +protected: + /** The callbacks to use to send and receive SSL peer data */ + cDataCallbacks * m_Callbacks; + + // cSslContext overrides: + virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override; + virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override; +}; + + + + diff --git a/src/mbedTLS++/CryptoKey.cpp b/src/mbedTLS++/CryptoKey.cpp new file mode 100644 index 000000000..4ebb0f300 --- /dev/null +++ b/src/mbedTLS++/CryptoKey.cpp @@ -0,0 +1,149 @@ + +// CryptoKey.cpp + +// Implements the cCryptoKey class representing a RSA public key in mbedTLS + +#include "Globals.h" +#include "CryptoKey.h" + + + + + +cCryptoKey::cCryptoKey(void) +{ + mbedtls_pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_pubkey", 10); +} + + + + + +cCryptoKey::cCryptoKey(const AString & a_PublicKeyData) +{ + mbedtls_pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_pubkey", 10); + int res = ParsePublic(a_PublicKeyData.data(), a_PublicKeyData.size()); + if (res != 0) + { + LOGWARNING("Failed to parse public key: -0x%x", res); + ASSERT(!"Cannot parse PubKey"); + return; + } +} + + + + + +cCryptoKey::cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password) +{ + mbedtls_pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_privkey", 11); + int res = ParsePrivate(a_PrivateKeyData.data(), a_PrivateKeyData.size(), a_Password); + if (res != 0) + { + LOGWARNING("Failed to parse private key: -0x%x", res); + ASSERT(!"Cannot parse PrivKey"); + return; + } +} + + + + + +cCryptoKey::~cCryptoKey() +{ + mbedtls_pk_free(&m_Pk); +} + + + + + +int cCryptoKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) +{ + ASSERT(IsValid()); + + size_t DecryptedLen = a_DecryptedMaxLength; + int res = mbedtls_pk_decrypt(&m_Pk, + a_EncryptedData, a_EncryptedLength, + a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength, + mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal() + ); + if (res != 0) + { + return res; + } + return static_cast(DecryptedLen); +} + + + + + +int cCryptoKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) +{ + ASSERT(IsValid()); + + size_t EncryptedLength = a_EncryptedMaxLength; + int res = mbedtls_pk_encrypt(&m_Pk, + a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength, + mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal() + ); + if (res != 0) + { + return res; + } + return static_cast(EncryptedLength); +} + + + + + + +int cCryptoKey::ParsePublic(const void * a_Data, size_t a_NumBytes) +{ + ASSERT(!IsValid()); // Cannot parse a second key + + return mbedtls_pk_parse_public_key(&m_Pk, reinterpret_cast(a_Data), a_NumBytes); +} + + + + + + +int cCryptoKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password) +{ + ASSERT(!IsValid()); // Cannot parse a second key + + if (a_Password.empty()) + { + return mbedtls_pk_parse_key(&m_Pk, reinterpret_cast(a_Data), a_NumBytes, nullptr, 0); + } + else + { + return mbedtls_pk_parse_key( + &m_Pk, + reinterpret_cast(a_Data), a_NumBytes, + reinterpret_cast(a_Password.c_str()), a_Password.size() + ); + } +} + + + + + +bool cCryptoKey::IsValid(void) const +{ + return (mbedtls_pk_get_type(&m_Pk) != MBEDTLS_PK_NONE); +} + + + + diff --git a/src/mbedTLS++/CryptoKey.h b/src/mbedTLS++/CryptoKey.h new file mode 100644 index 000000000..1a74090ac --- /dev/null +++ b/src/mbedTLS++/CryptoKey.h @@ -0,0 +1,76 @@ + +// CryptoKey.h + +// Declares the cCryptoKey class representing a RSA public key in mbedTLS + + + + + +#pragma once + +#include "CtrDrbgContext.h" +#include "mbedtls/pk.h" + + + + + +class cCryptoKey +{ + friend class cSslConfig; + +public: + /** Constructs an empty key instance. Before use, it needs to be filled by ParsePublic() or ParsePrivate() */ + cCryptoKey(void); + + /** Constructs the public key out of the DER- or PEM-encoded pubkey data */ + cCryptoKey(const AString & a_PublicKeyData); + + /** Constructs the private key out of the DER- or PEM-encoded privkey data, with the specified password. + If a_Password is empty, no password is assumed. */ + cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password); + + ~cCryptoKey(); + + /** Decrypts the data using the stored public key + Both a_EncryptedData and a_DecryptedData must be at least bytes large. + Returns the number of bytes decrypted, or negative number for error. */ + int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength); + + /** Encrypts the data using the stored public key + Both a_EncryptedData and a_DecryptedData must be at least bytes large. + Returns the number of bytes decrypted, or negative number for error. */ + int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); + + /** Parses the specified data into a public key representation. + The key can be DER- or PEM-encoded. + Returns 0 on success, mbedTLS error code on failure. */ + int ParsePublic(const void * a_Data, size_t a_NumBytes); + + /** Parses the specified data into a private key representation. + If a_Password is empty, no password is assumed. + The key can be DER- or PEM-encoded. + Returns 0 on success, mbedTLS error code on failure. */ + int ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password); + + /** Returns true if the contained key is valid. */ + bool IsValid(void) const; + +protected: + /** The mbedTLS representation of the key data */ + mbedtls_pk_context m_Pk; + + /** The random generator used in encryption and decryption */ + cCtrDrbgContext m_CtrDrbg; + + + /** Returns the internal context ptr. Only use in mbedTLS API calls. */ + mbedtls_pk_context * GetInternal(void) { return &m_Pk; } +} ; + +typedef std::shared_ptr cCryptoKeyPtr; + + + + diff --git a/src/mbedTLS++/CtrDrbgContext.cpp b/src/mbedTLS++/CtrDrbgContext.cpp new file mode 100644 index 000000000..bd4a55000 --- /dev/null +++ b/src/mbedTLS++/CtrDrbgContext.cpp @@ -0,0 +1,51 @@ + +// CtrDrbgContext.cpp + +// Implements the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in mbedTLS + +#include "Globals.h" +#include "CtrDrbgContext.h" +#include "EntropyContext.h" + + + + + +cCtrDrbgContext::cCtrDrbgContext(void) : + m_EntropyContext(std::make_shared()), + m_IsValid(false) +{ + mbedtls_ctr_drbg_init(&m_CtrDrbg); +} + + + + + +cCtrDrbgContext::cCtrDrbgContext(const std::shared_ptr & a_EntropyContext) : + m_EntropyContext(a_EntropyContext), + m_IsValid(false) +{ + mbedtls_ctr_drbg_init(&m_CtrDrbg); +} + + + + + +int cCtrDrbgContext::Initialize(const void * a_Custom, size_t a_CustomSize) +{ + if (m_IsValid) + { + // Already initialized + return 0; + } + + int res = mbedtls_ctr_drbg_seed(&m_CtrDrbg, mbedtls_entropy_func, &(m_EntropyContext->m_Entropy), reinterpret_cast(a_Custom), a_CustomSize); + m_IsValid = (res == 0); + return res; +} + + + + diff --git a/src/mbedTLS++/CtrDrbgContext.h b/src/mbedTLS++/CtrDrbgContext.h new file mode 100644 index 000000000..21d786c2e --- /dev/null +++ b/src/mbedTLS++/CtrDrbgContext.h @@ -0,0 +1,63 @@ + +// CtrDrbgContext.h + +// Declares the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in mbedTLS + + + + + +#pragma once + +#include "mbedtls/ctr_drbg.h" + + + + + +// fwd: EntropyContext.h +class cEntropyContext; + + + + + +class cCtrDrbgContext +{ + friend class cSslConfig; + friend class cRsaPrivateKey; + friend class cCryptoKey; + +public: + /** Constructs the context with a new entropy context. */ + cCtrDrbgContext(void); + + /** Constructs the context with the specified entropy context. */ + cCtrDrbgContext(const std::shared_ptr & a_EntropyContext); + + /** Initializes the context. + a_Custom is optional additional data to use for entropy, nullptr is accepted. + Returns 0 if successful, mbedTLS error code on failure. */ + int Initialize(const void * a_Custom, size_t a_CustomSize); + + /** Returns true if the object is valid (has been initialized properly) */ + bool IsValid(void) const { return m_IsValid; } + +protected: + /** The entropy source used for generating the random */ + std::shared_ptr m_EntropyContext; + + /** The random generator context */ + mbedtls_ctr_drbg_context m_CtrDrbg; + + /** Set to true if the object is valid (has been initialized properly) */ + bool m_IsValid; + + + /** Returns the internal context ptr. Only use in mbedTLS API calls. */ + mbedtls_ctr_drbg_context * GetInternal(void) { return &m_CtrDrbg; } +} ; + + + + diff --git a/src/mbedTLS++/EntropyContext.cpp b/src/mbedTLS++/EntropyContext.cpp new file mode 100644 index 000000000..aea056f4e --- /dev/null +++ b/src/mbedTLS++/EntropyContext.cpp @@ -0,0 +1,29 @@ + +// EntropyContext.cpp + +// Implements the cEntropyContext class representing a wrapper over entropy contexts in mbedTLS + +#include "Globals.h" +#include "EntropyContext.h" + + + + + +cEntropyContext::cEntropyContext(void) +{ + mbedtls_entropy_init(&m_Entropy); +} + + + + + +cEntropyContext::~cEntropyContext() +{ + mbedtls_entropy_free(&m_Entropy); +} + + + + diff --git a/src/mbedTLS++/EntropyContext.h b/src/mbedTLS++/EntropyContext.h new file mode 100644 index 000000000..37b6f120e --- /dev/null +++ b/src/mbedTLS++/EntropyContext.h @@ -0,0 +1,31 @@ + +// EntropyContext.h + +// Declares the cEntropyContext class representing a wrapper over entropy contexts in mbedTLS + + + + + +#pragma once + +#include "mbedtls/entropy.h" + + + + + +class cEntropyContext +{ + friend class cCtrDrbgContext; +public: + cEntropyContext(void); + ~cEntropyContext(); + +protected: + mbedtls_entropy_context m_Entropy; +} ; + + + + diff --git a/src/mbedTLS++/ErrorCodes.h b/src/mbedTLS++/ErrorCodes.h new file mode 100644 index 000000000..36ef86fec --- /dev/null +++ b/src/mbedTLS++/ErrorCodes.h @@ -0,0 +1,18 @@ + +/** Error codes from mbedtls net_sockets.h */ +// TODO: Replace with std::error_code + +#define MBEDTLS_ERR_NET_SOCKET_FAILED -0x0042 /**< Failed to open a socket. */ +#define MBEDTLS_ERR_NET_CONNECT_FAILED -0x0044 /**< The connection to the given server / port failed. */ +#define MBEDTLS_ERR_NET_BIND_FAILED -0x0046 /**< Binding of the socket failed. */ +#define MBEDTLS_ERR_NET_LISTEN_FAILED -0x0048 /**< Could not listen on the socket. */ +#define MBEDTLS_ERR_NET_ACCEPT_FAILED -0x004A /**< Could not accept the incoming connection. */ +#define MBEDTLS_ERR_NET_RECV_FAILED -0x004C /**< Reading information from the socket failed. */ +#define MBEDTLS_ERR_NET_SEND_FAILED -0x004E /**< Sending information through the socket failed. */ +#define MBEDTLS_ERR_NET_CONN_RESET -0x0050 /**< Connection was reset by peer. */ +#define MBEDTLS_ERR_NET_UNKNOWN_HOST -0x0052 /**< Failed to get an IP address for the given hostname. */ +#define MBEDTLS_ERR_NET_BUFFER_TOO_SMALL -0x0043 /**< Buffer is too small to hold the data. */ +#define MBEDTLS_ERR_NET_INVALID_CONTEXT -0x0045 /**< The context is invalid, eg because it was free()ed. */ + + + diff --git a/src/mbedTLS++/RsaPrivateKey.cpp b/src/mbedTLS++/RsaPrivateKey.cpp new file mode 100644 index 000000000..3dfb3bac3 --- /dev/null +++ b/src/mbedTLS++/RsaPrivateKey.cpp @@ -0,0 +1,174 @@ + +// RsaPrivateKey.cpp + +#include "Globals.h" +#include "RsaPrivateKey.h" +#include "mbedtls/pk.h" + + + + + +cRsaPrivateKey::cRsaPrivateKey(void) +{ + mbedtls_rsa_init(&m_Rsa, MBEDTLS_RSA_PKCS_V15, 0); + m_CtrDrbg.Initialize("RSA", 3); +} + + + + + +cRsaPrivateKey::cRsaPrivateKey(const cRsaPrivateKey & a_Other) +{ + mbedtls_rsa_init(&m_Rsa, MBEDTLS_RSA_PKCS_V15, 0); + mbedtls_rsa_copy(&m_Rsa, &a_Other.m_Rsa); + m_CtrDrbg.Initialize("RSA", 3); +} + + + + + +cRsaPrivateKey::~cRsaPrivateKey() +{ + mbedtls_rsa_free(&m_Rsa); +} + + + + + +bool cRsaPrivateKey::Generate(unsigned a_KeySizeBits) +{ + int res = mbedtls_rsa_gen_key(&m_Rsa, mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal(), a_KeySizeBits, 65537); + if (res != 0) + { + LOG("RSA key generation failed: -0x%x", -res); + return false; + } + + return true; +} + + + + + +AString cRsaPrivateKey::GetPubKeyDER(void) +{ + class cPubKey + { + public: + cPubKey(mbedtls_rsa_context * a_Rsa) : + m_IsValid(false) + { + mbedtls_pk_init(&m_Key); + if (mbedtls_pk_setup(&m_Key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) != 0) + { + ASSERT(!"Cannot init PrivKey context"); + return; + } + if (mbedtls_rsa_copy(mbedtls_pk_rsa(m_Key), a_Rsa) != 0) + { + ASSERT(!"Cannot copy PrivKey to PK context"); + return; + } + m_IsValid = true; + } + + ~cPubKey() + { + if (m_IsValid) + { + mbedtls_pk_free(&m_Key); + } + } + + operator mbedtls_pk_context * (void) { return &m_Key; } + + protected: + bool m_IsValid; + mbedtls_pk_context m_Key; + } PkCtx(&m_Rsa); + + unsigned char buf[3000]; + int res = mbedtls_pk_write_pubkey_der(PkCtx, buf, sizeof(buf)); + if (res < 0) + { + return AString(); + } + return AString(reinterpret_cast(buf + sizeof(buf) - res), static_cast(res)); +} + + + + + +int cRsaPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) +{ + if (a_EncryptedLength < m_Rsa.len) + { + LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u", + __FUNCTION__, static_cast(a_EncryptedLength), static_cast(m_Rsa.len) + ); + ASSERT(!"Invalid a_DecryptedMaxLength!"); + return -1; + } + if (a_DecryptedMaxLength < m_Rsa.len) + { + LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u", + __FUNCTION__, static_cast(a_EncryptedLength), static_cast(m_Rsa.len) + ); + ASSERT(!"Invalid a_DecryptedMaxLength!"); + return -1; + } + size_t DecryptedLength; + int res = mbedtls_rsa_pkcs1_decrypt( + &m_Rsa, mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal(), MBEDTLS_RSA_PRIVATE, &DecryptedLength, + a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength + ); + if (res != 0) + { + return -1; + } + return static_cast(DecryptedLength); +} + + + + + +int cRsaPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) +{ + if (a_EncryptedMaxLength < m_Rsa.len) + { + LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u", + __FUNCTION__, static_cast(a_EncryptedMaxLength), static_cast(m_Rsa.len) + ); + ASSERT(!"Invalid a_DecryptedMaxLength!"); + return -1; + } + if (a_PlainLength < m_Rsa.len) + { + LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u", + __FUNCTION__, static_cast(a_PlainLength), static_cast(m_Rsa.len) + ); + ASSERT(!"Invalid a_PlainLength!"); + return -1; + } + int res = mbedtls_rsa_pkcs1_encrypt( + &m_Rsa, mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal(), MBEDTLS_RSA_PRIVATE, + a_PlainLength, a_PlainData, a_EncryptedData + ); + if (res != 0) + { + return -1; + } + return static_cast(m_Rsa.len); +} + + + + + diff --git a/src/mbedTLS++/RsaPrivateKey.h b/src/mbedTLS++/RsaPrivateKey.h new file mode 100644 index 000000000..7be0152b7 --- /dev/null +++ b/src/mbedTLS++/RsaPrivateKey.h @@ -0,0 +1,67 @@ + +// RsaPrivateKey.h + +// Declares the cRsaPrivateKey class representing a private key for RSA operations. + + + + + +#pragma once + +#include "CtrDrbgContext.h" +#include "mbedtls/rsa.h" + + + + + +/** Encapsulates an RSA private key used in PKI cryptography */ +class cRsaPrivateKey +{ + friend class cSslContext; + +public: + /** Creates a new empty object, the key is not assigned */ + cRsaPrivateKey(void); + + /** Deep-copies the key from a_Other */ + cRsaPrivateKey(const cRsaPrivateKey & a_Other); + + ~cRsaPrivateKey(); + + /** Generates a new key within this object, with the specified size in bits. + Returns true on success, false on failure. */ + bool Generate(unsigned a_KeySizeBits = 1024); + + /** Returns the public key part encoded in ASN1 DER encoding */ + AString GetPubKeyDER(void); + + /** Decrypts the data using RSAES-PKCS#1 algorithm. + Both a_EncryptedData and a_DecryptedData must be at least bytes large. + Returns the number of bytes decrypted, or negative number for error. */ + int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength); + + /** Encrypts the data using RSAES-PKCS#1 algorithm. + Both a_EncryptedData and a_DecryptedData must be at least bytes large. + Returns the number of bytes decrypted, or negative number for error. */ + int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); + +protected: + /** The mbedTLS key context */ + mbedtls_rsa_context m_Rsa; + + /** The random generator used for generating the key and encryption / decryption */ + cCtrDrbgContext m_CtrDrbg; + + + /** Returns the internal context ptr. Only use in mbedTLS API calls. */ + mbedtls_rsa_context * GetInternal(void) { return &m_Rsa; } +} ; + +typedef std::shared_ptr cRsaPrivateKeyPtr; + + + + + diff --git a/src/mbedTLS++/Sha1Checksum.cpp b/src/mbedTLS++/Sha1Checksum.cpp new file mode 100644 index 000000000..9c82d92fe --- /dev/null +++ b/src/mbedTLS++/Sha1Checksum.cpp @@ -0,0 +1,138 @@ + +// Sha1Checksum.cpp + +// Declares the cSha1Checksum class representing the SHA-1 checksum calculator + +#include "Globals.h" +#include "Sha1Checksum.h" + + + + + +/* +// Self-test the hash formatting for known values: +// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48 +// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1 +// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6 + +static class Test +{ +public: + Test(void) + { + AString DigestNotch, DigestJeb, DigestSimon; + Byte Digest[20]; + cSha1Checksum Checksum; + Checksum.Update((const Byte *)"Notch", 5); + Checksum.Finalize(Digest); + cSha1Checksum::DigestToJava(Digest, DigestNotch); + Checksum.Restart(); + Checksum.Update((const Byte *)"jeb_", 4); + Checksum.Finalize(Digest); + cSha1Checksum::DigestToJava(Digest, DigestJeb); + Checksum.Restart(); + Checksum.Update((const Byte *)"simon", 5); + Checksum.Finalize(Digest); + cSha1Checksum::DigestToJava(Digest, DigestSimon); + printf("Notch: \"%s\"\n", DigestNotch.c_str()); + printf("jeb_: \"%s\"\n", DigestJeb.c_str()); + printf("simon: \"%s\"\n", DigestSimon.c_str()); + assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48"); + assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1"); + assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6"); + } +} test; +*/ + + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cSha1Checksum: + +cSha1Checksum::cSha1Checksum(void) : + m_DoesAcceptInput(true) +{ + mbedtls_sha1_starts(&m_Sha1); +} + + + + + +void cSha1Checksum::Update(const Byte * a_Data, size_t a_Length) +{ + ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed + + mbedtls_sha1_update(&m_Sha1, a_Data, a_Length); +} + + + + + +void cSha1Checksum::Finalize(cSha1Checksum::Checksum & a_Output) +{ + ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed + + mbedtls_sha1_finish(&m_Sha1, a_Output); + m_DoesAcceptInput = false; +} + + + + + +void cSha1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out) +{ + Checksum Digest; + memcpy(Digest, a_Digest, sizeof(Digest)); + + bool IsNegative = (Digest[0] >= 0x80); + if (IsNegative) + { + // Two's complement: + bool carry = true; // Add one to the whole number + for (int i = 19; i >= 0; i--) + { + Digest[i] = ~Digest[i]; + if (carry) + { + carry = (Digest[i] == 0xff); + Digest[i]++; + } + } + } + a_Out.clear(); + a_Out.reserve(40); + for (int i = 0; i < 20; i++) + { + AppendPrintf(a_Out, "%02x", Digest[i]); + } + while ((a_Out.length() > 0) && (a_Out[0] == '0')) + { + a_Out.erase(0, 1); + } + if (IsNegative) + { + a_Out.insert(0, "-"); + } +} + + + + + + +void cSha1Checksum::Restart(void) +{ + mbedtls_sha1_starts(&m_Sha1); + m_DoesAcceptInput = true; +} + + + + diff --git a/src/mbedTLS++/Sha1Checksum.h b/src/mbedTLS++/Sha1Checksum.h new file mode 100644 index 000000000..43180e531 --- /dev/null +++ b/src/mbedTLS++/Sha1Checksum.h @@ -0,0 +1,52 @@ + +// Sha1Checksum.h + +// Declares the cSha1Checksum class representing the SHA-1 checksum calculator + + + + + +#pragma once + +#include "mbedtls/sha1.h" + + + + + +/** Calculates a SHA1 checksum for data stream */ +class cSha1Checksum +{ +public: + typedef Byte Checksum[20]; // The type used for storing the checksum + + cSha1Checksum(void); + + /** Adds the specified data to the checksum */ + void Update(const Byte * a_Data, size_t a_Length); + + /** Calculates and returns the final checksum */ + void Finalize(Checksum & a_Output); + + /** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */ + bool DoesAcceptInput(void) const { return m_DoesAcceptInput; } + + /** Converts a raw 160-bit SHA1 digest into a Java Hex representation + According to http://wiki.vg/Protocol_Encryption + */ + static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut); + + /** Clears the current context and start a new checksum calculation */ + void Restart(void); + +protected: + /** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */ + bool m_DoesAcceptInput; + + mbedtls_sha1_context m_Sha1; +} ; + + + + diff --git a/src/mbedTLS++/SslConfig.cpp b/src/mbedTLS++/SslConfig.cpp new file mode 100644 index 000000000..9dec49776 --- /dev/null +++ b/src/mbedTLS++/SslConfig.cpp @@ -0,0 +1,287 @@ + +#include "Globals.h" + +#include "mbedTLS++/SslConfig.h" +#include "EntropyContext.h" +#include "CtrDrbgContext.h" +#include "CryptoKey.h" +#include "X509Cert.h" + + +// This allows us to debug SSL and certificate problems, but produce way too much output, +// so it's disabled until someone needs it +// #define ENABLE_SSL_DEBUG_MSG + + +#if defined(_DEBUG) && defined(ENABLE_SSL_DEBUG_MSG) + #include "mbedtls/debug.h" + + + namespace + { + void SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Filename, int a_LineNo, const char * a_Text) + { + if (a_Level > 3) + { + // Don't want the trace messages + return; + } + + // Remove the terminating LF: + size_t len = strlen(a_Text) - 1; + while ((len > 0) && (a_Text[len] <= 32)) + { + len--; + } + AString Text(a_Text, len + 1); + + LOGD("SSL (%d): %s", a_Level, Text.c_str()); + } + + + + + + int SSLVerifyCert(void * a_This, mbedtls_x509_crt * a_Crt, int a_Depth, uint32_t * a_Flags) + { + char buf[1024]; + UNUSED(a_This); + + LOG("Verify requested for (Depth %d):", a_Depth); + mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", a_Crt); + LOG("%s", buf); + + uint32_t Flags = *a_Flags; + if ((Flags & MBEDTLS_X509_BADCERT_EXPIRED) != 0) + { + LOG(" ! server certificate has expired"); + } + + if ((Flags & MBEDTLS_X509_BADCERT_REVOKED) != 0) + { + LOG(" ! server certificate has been revoked"); + } + + if ((Flags & MBEDTLS_X509_BADCERT_CN_MISMATCH) != 0) + { + LOG(" ! CN mismatch"); + } + + if ((Flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) != 0) + { + LOG(" ! self-signed or not signed by a trusted CA"); + } + + if ((Flags & MBEDTLS_X509_BADCRL_NOT_TRUSTED) != 0) + { + LOG(" ! CRL not trusted"); + } + + if ((Flags & MBEDTLS_X509_BADCRL_EXPIRED) != 0) + { + LOG(" ! CRL expired"); + } + + if ((Flags & MBEDTLS_X509_BADCERT_OTHER) != 0) + { + LOG(" ! other (unknown) flag"); + } + + if (Flags == 0) + { + LOG(" This certificate has no flags"); + } + + return 0; + } + } +#endif // defined(_DEBUG) && defined(ENABLE_SSL_DEBUG_MSG) + + + + +//////////////////////////////////////////////////////////////////////////////// +// cSslConfig: + +cSslConfig::cSslConfig() +{ + mbedtls_ssl_config_init(&m_Config); +} + + + + + +cSslConfig::~cSslConfig() +{ + mbedtls_ssl_config_free(&m_Config); +} + + + + + +int cSslConfig::InitDefaults(const bool a_IsClient) +{ + return mbedtls_ssl_config_defaults( + &m_Config, + a_IsClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT + ); +} + + + + + +void cSslConfig::SetAuthMode(const eSslAuthMode a_AuthMode) +{ + const int Mode = [=]() + { + switch (a_AuthMode) + { + case eSslAuthMode::None: return MBEDTLS_SSL_VERIFY_NONE; + case eSslAuthMode::Optional: return MBEDTLS_SSL_VERIFY_OPTIONAL; + case eSslAuthMode::Required: return MBEDTLS_SSL_VERIFY_REQUIRED; + case eSslAuthMode::Unset: return MBEDTLS_SSL_VERIFY_UNSET; + #ifndef __clang__ + default: return MBEDTLS_SSL_VERIFY_OPTIONAL; + #endif + } + }(); + + mbedtls_ssl_conf_authmode(&m_Config, Mode); +} + + + + + +void cSslConfig::SetRng(cCtrDrbgContextPtr a_CtrDrbg) +{ + ASSERT(a_CtrDrbg != nullptr); + m_CtrDrbg = std::move(a_CtrDrbg); + mbedtls_ssl_conf_rng(&m_Config, mbedtls_ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg); +} + + + + + +void cSslConfig::SetDebugCallback(cDebugCallback a_CallbackFun, void * a_CallbackData) +{ + mbedtls_ssl_conf_dbg(&m_Config, a_CallbackFun, a_CallbackData); +} + + + + + +void cSslConfig::SetOwnCert(cX509CertPtr a_OwnCert, cCryptoKeyPtr a_OwnCertPrivKey) +{ + ASSERT(a_OwnCert != nullptr); + ASSERT(a_OwnCertPrivKey != nullptr); + + // Make sure we have the cert stored for later, mbedTLS only uses the cert later on + m_OwnCert = std::move(a_OwnCert); + m_OwnCertPrivKey = std::move(a_OwnCertPrivKey); + + // Set into the config: + mbedtls_ssl_conf_own_cert(&m_Config, m_OwnCert->GetInternal(), m_OwnCertPrivKey->GetInternal()); +} + + + + + +void cSslConfig::SetVerifyCallback(cVerifyCallback a_CallbackFun, void * a_CallbackData) +{ + mbedtls_ssl_conf_verify(&m_Config, a_CallbackFun, a_CallbackData); +} + + + + + +void cSslConfig::SetCipherSuites(std::vector a_CipherSuites) +{ + m_CipherSuites = std::move(a_CipherSuites); + m_CipherSuites.push_back(0); // Must be null terminated + mbedtls_ssl_conf_ciphersuites(&m_Config, m_CipherSuites.data()); +} + + + + + +void cSslConfig::SetCACerts(cX509CertPtr a_CACert) +{ + m_CACerts = std::move(a_CACert); + mbedtls_ssl_conf_ca_chain(&m_Config, m_CACerts->GetInternal(), nullptr); +} + + + + + +std::shared_ptr cSslConfig::MakeDefaultConfig(bool a_IsClient) +{ + // TODO: Default CA chain and SetAuthMode(eSslAuthMode::Required) + auto Ret = std::make_shared(); + + Ret->InitDefaults(a_IsClient); + + { + auto CtrDrbg = std::make_shared(); + CtrDrbg->Initialize("Cuberite", 8); + Ret->SetRng(std::move(CtrDrbg)); + } + + Ret->SetAuthMode(eSslAuthMode::None); // We cannot verify because we don't have a CA chain + + #ifdef _DEBUG + #ifdef ENABLE_SSL_DEBUG_MSG + Ret->SetDebugCallback(&SSLDebugMessage, nullptr); + Ret->SetVerifyCallback(SSLVerifyCert, nullptr); + mbedtls_debug_set_threshold(2); + #endif + + /* + // Set ciphersuite to the easiest one to decode, so that the connection can be wireshark-decoded: + Ret->SetCipherSuites( + { + MBEDTLS_TLS_RSA_WITH_RC4_128_MD5, + MBEDTLS_TLS_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + } + ); + */ + #endif + + return Ret; +} + + + + + +std::shared_ptr cSslConfig::GetDefaultClientConfig() +{ + static const std::shared_ptr ClientConfig = MakeDefaultConfig(true); + return ClientConfig; +} + + + + + +std::shared_ptr cSslConfig::GetDefaultServerConfig() +{ + static const std::shared_ptr ServerConfig = MakeDefaultConfig(false); + return ServerConfig; +} + + + + diff --git a/src/mbedTLS++/SslConfig.h b/src/mbedTLS++/SslConfig.h new file mode 100644 index 000000000..47a4f7b59 --- /dev/null +++ b/src/mbedTLS++/SslConfig.h @@ -0,0 +1,93 @@ + +#pragma once + +#include "mbedtls/ssl.h" + +// fwd: +class cCryptoKey; +class cCtrDrbgContext; +class cX509Cert; + +using cCryptoKeyPtr = std::shared_ptr; +using cCtrDrbgContextPtr = std::shared_ptr; +using cX509CertPtr = std::shared_ptr; + +enum class eSslAuthMode +{ + None = 0, // MBEDTLS_SSL_VERIFY_NONE + Optional = 1, // MBEDTLS_SSL_VERIFY_OPTIONAL + Required = 2, // MBEDTLS_SSL_VERIFY_REQUIRED + Unset = 3, // MBEDTLS_SSL_VERIFY_UNSET +}; + + + +class cSslConfig +{ + friend class cSslContext; +public: + /** Type of the SSL debug callback. + Parameters are: + void * Opaque context for the callback + int Debug level + const char * File name + int Line number + const char * Message */ + using cDebugCallback = void(*)(void *, int, const char *, int, const char *); + + /** Type of the SSL certificate verify callback. + Parameters are: + void * Opaque context for the callback + mbedtls_x509_crt * Current cert + int Cert chain depth + uint32_t * Verification flags */ + using cVerifyCallback = int(*)(void *, mbedtls_x509_crt *, int, uint32_t *); + + cSslConfig(); + ~cSslConfig(); + + /** Initialize with mbedTLS default settings. */ + int InitDefaults(bool a_IsClient); + + /** Set the authorization mode. */ + void SetAuthMode(eSslAuthMode a_AuthMode); + + /** Set the random number generator. */ + void SetRng(cCtrDrbgContextPtr a_CtrDrbg); + + /** Set the debug callback. */ + void SetDebugCallback(cDebugCallback a_CallbackFun, void * a_CallbackData); + + /** Set the certificate verify callback. */ + void SetVerifyCallback(cVerifyCallback a_CallbackFun, void * a_CallbackData); + + /** Set the enabled cipher suites. */ + void SetCipherSuites(std::vector a_CipherSuites); + + /** Set the certificate to use for connections. */ + void SetOwnCert(cX509CertPtr a_OwnCert, cCryptoKeyPtr a_OwnCertPrivKey); + + /** Set the trusted certificate authority chain. */ + void SetCACerts(cX509CertPtr a_CACert); + + /** Creates a new config with some sensible defaults on top of mbedTLS basic settings. */ + static std::shared_ptr MakeDefaultConfig(bool a_IsClient); + + /** Returns the default config for client connections. */ + static std::shared_ptr GetDefaultClientConfig(); + + /** Returns the default config for server connections. */ + static std::shared_ptr GetDefaultServerConfig(); + +private: + + /** Returns a pointer to the wrapped mbedtls representation. */ + const mbedtls_ssl_config * GetInternal() const { return &m_Config; } + + mbedtls_ssl_config m_Config; + cCtrDrbgContextPtr m_CtrDrbg; + cX509CertPtr m_OwnCert; + cCryptoKeyPtr m_OwnCertPrivKey; + cX509CertPtr m_CACerts; + std::vector m_CipherSuites; +}; diff --git a/src/mbedTLS++/SslContext.cpp b/src/mbedTLS++/SslContext.cpp new file mode 100644 index 000000000..e86da3fd2 --- /dev/null +++ b/src/mbedTLS++/SslContext.cpp @@ -0,0 +1,157 @@ + +// SslContext.cpp + +// Implements the cSslContext class that holds everything a single SSL context needs to function + +#include "Globals.h" +#include "mbedTLS++/SslContext.h" +#include "mbedTLS++/SslConfig.h" + + + + + +cSslContext::cSslContext(void) : + m_IsValid(false), + m_HasHandshaken(false) +{ + mbedtls_ssl_init(&m_Ssl); +} + + + + + +cSslContext::~cSslContext() +{ + mbedtls_ssl_free(&m_Ssl); +} + + + + + +int cSslContext::Initialize(std::shared_ptr a_Config) +{ + // Check double-initialization: + if (m_IsValid) + { + LOGWARNING("SSL: Double initialization is not supported."); + return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; // There is no return value well-suited for this, reuse this one. + } + + // Check the Config: + m_Config = a_Config; + if (m_Config == nullptr) + { + ASSERT(!"Config must not be nullptr"); + return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; + } + + // Apply the configuration to the ssl context + int res = mbedtls_ssl_setup(&m_Ssl, m_Config->GetInternal()); + if (res != 0) + { + return res; + } + + // Set the io callbacks + mbedtls_ssl_set_bio(&m_Ssl, this, SendEncrypted, ReceiveEncrypted, nullptr); + + m_IsValid = true; + return 0; +} + + + + + +int cSslContext::Initialize(bool a_IsClient) +{ + if (a_IsClient) + { + return Initialize(cSslConfig::GetDefaultClientConfig()); + } + else + { + return Initialize(cSslConfig::GetDefaultServerConfig()); + } +} + + + + + +void cSslContext::SetExpectedPeerName(const AString & a_ExpectedPeerName) +{ + ASSERT(m_IsValid); // Call Initialize() first + mbedtls_ssl_set_hostname(&m_Ssl, a_ExpectedPeerName.c_str()); +} + + + + + +int cSslContext::WritePlain(const void * a_Data, size_t a_NumBytes) +{ + ASSERT(m_IsValid); // Need to call Initialize() first + if (!m_HasHandshaken) + { + int res = Handshake(); + if (res != 0) + { + return res; + } + } + + return mbedtls_ssl_write(&m_Ssl, reinterpret_cast(a_Data), a_NumBytes); +} + + + + + +int cSslContext::ReadPlain(void * a_Data, size_t a_MaxBytes) +{ + ASSERT(m_IsValid); // Need to call Initialize() first + if (!m_HasHandshaken) + { + int res = Handshake(); + if (res != 0) + { + return res; + } + } + + return mbedtls_ssl_read(&m_Ssl, reinterpret_cast(a_Data), a_MaxBytes); +} + + + + + +int cSslContext::Handshake(void) +{ + ASSERT(m_IsValid); // Need to call Initialize() first + ASSERT(!m_HasHandshaken); // Must not call twice + + int res = mbedtls_ssl_handshake(&m_Ssl); + if (res == 0) + { + m_HasHandshaken = true; + } + return res; +} + + + + + +int cSslContext::NotifyClose(void) +{ + return mbedtls_ssl_close_notify(&m_Ssl); +} + + + + diff --git a/src/mbedTLS++/SslContext.h b/src/mbedTLS++/SslContext.h new file mode 100644 index 000000000..c51a9f149 --- /dev/null +++ b/src/mbedTLS++/SslContext.h @@ -0,0 +1,124 @@ + +// SslContext.h + +// Declares the cSslContext class that holds everything a single SSL context needs to function + + + + + +#pragma once + +#include "mbedtls/ssl.h" +#include "../ByteBuffer.h" + + + + + +// fwd: +class cCtrDrbgContext; +class cSslConfig; + + + + + +/** +Acts as a generic SSL encryptor / decryptor between the two endpoints. The "owner" of this class is expected +to create it, initialize it and then provide the means of reading and writing data through the SSL link. +This is an abstract base class, there are descendants that handle the specific aspects of how the SSL peer +data comes into the system: + - cBufferedSslContext uses a cByteBuffer to read and write the data + - cCallbackSslContext uses callbacks to provide the data +*/ +class cSslContext abstract +{ +public: + /** Creates a new uninitialized context */ + cSslContext(void); + + virtual ~cSslContext(); + + /** Initializes the context for use as a server or client. + a_Config must not be nullptr and the config must not be changed after this call. + Returns 0 on success, mbedTLS error on failure. */ + int Initialize(std::shared_ptr a_Config); + + /** Initializes the context using the default config. */ + int Initialize(bool a_IsClient); + + /** Returns true if the object has been initialized properly. */ + bool IsValid(void) const { return m_IsValid; } + + /** Sets the SSL peer name expected for this context. Must be called after Initialize(). + \param a_ExpectedPeerName CommonName that we expect the SSL peer to have in its cert, + if it is different, the verification will fail. An empty string will disable the CN check. */ + void SetExpectedPeerName(const AString & a_ExpectedPeerName); + + /** Writes data to be encrypted and sent to the SSL peer. Will perform SSL handshake, if needed. + Returns the number of bytes actually written, or mbedTLS error code. + If the return value is MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, the owner should send any + cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call + this function again with the same parameters. Note that this may repeat a few times before the data is + actually written, mainly due to initial handshake. */ + int WritePlain(const void * a_Data, size_t a_NumBytes); + + /** Reads data decrypted from the SSL stream. Will perform SSL handshake, if needed. + Returns the number of bytes actually read, or mbedTLS error code. + If the return value is MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, the owner should send any + cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call + this function again with the same parameters. Note that this may repeat a few times before the data is + actually read, mainly due to initial handshake. */ + int ReadPlain(void * a_Data, size_t a_MaxBytes); + + /** Performs the SSL handshake. + Returns zero on success, mbedTLS error code on failure. + If the return value is MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, the owner should send any + cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call + this function again. Note that this may repeat a few times before the handshake is completed. */ + int Handshake(void); + + /** Returns true if the SSL handshake has been completed. */ + bool HasHandshaken(void) const { return m_HasHandshaken; } + + /** Notifies the SSL peer that the connection is being closed. + Returns 0 on success, mbedTLS error code on failure. */ + int NotifyClose(void); + +protected: + + /** Configuration of the SSL context. */ + std::shared_ptr m_Config; + + /** The SSL context that mbedTLS uses. */ + mbedtls_ssl_context m_Ssl; + + /** True if the object has been initialized properly. */ + bool m_IsValid; + + /** True if the SSL handshake has been completed. */ + bool m_HasHandshaken; + + /** The callback used by mbedTLS when it wants to read encrypted data. */ + static int ReceiveEncrypted(void * a_This, unsigned char * a_Buffer, size_t a_NumBytes) + { + return (reinterpret_cast(a_This))->ReceiveEncrypted(a_Buffer, a_NumBytes); + } + + /** The callback used by mbedTLS when it wants to write encrypted data. */ + static int SendEncrypted(void * a_This, const unsigned char * a_Buffer, size_t a_NumBytes) + { + return (reinterpret_cast(a_This))->SendEncrypted(a_Buffer, a_NumBytes); + } + + /** Called when mbedTLS wants to read encrypted data. */ + virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0; + + /** Called when mbedTLS wants to write encrypted data. */ + virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0; +} ; + + + + diff --git a/src/mbedTLS++/X509Cert.cpp b/src/mbedTLS++/X509Cert.cpp new file mode 100644 index 000000000..1e51dd2b7 --- /dev/null +++ b/src/mbedTLS++/X509Cert.cpp @@ -0,0 +1,38 @@ + +// X509Cert.cpp + +// Implements the cX509Cert class representing a wrapper over X509 certs in mbedTLS + +#include "Globals.h" +#include "X509Cert.h" + + + + + +cX509Cert::cX509Cert(void) +{ + mbedtls_x509_crt_init(&m_Cert); +} + + + + + +cX509Cert::~cX509Cert() +{ + mbedtls_x509_crt_free(&m_Cert); +} + + + + + +int cX509Cert::Parse(const void * a_CertContents, size_t a_Size) +{ + return mbedtls_x509_crt_parse(&m_Cert, reinterpret_cast(a_CertContents), a_Size); +} + + + + diff --git a/src/mbedTLS++/X509Cert.h b/src/mbedTLS++/X509Cert.h new file mode 100644 index 000000000..4234308ff --- /dev/null +++ b/src/mbedTLS++/X509Cert.h @@ -0,0 +1,41 @@ + +// X509Cert.h + +// Declares the cX509Cert class representing a wrapper over X509 certs in mbedTLS + + + + + +#pragma once + +#include "mbedtls/x509_crt.h" + + + + + +class cX509Cert +{ + friend class cSslConfig; + +public: + cX509Cert(void); + ~cX509Cert(void); + + /** Parses the certificate chain data into the context. + Returns 0 on succes, or mbedTLS error code on failure. */ + int Parse(const void * a_CertContents, size_t a_Size); + +protected: + mbedtls_x509_crt m_Cert; + + /** Returns the internal cert ptr. Only use in mbedTLS API calls. */ + mbedtls_x509_crt * GetInternal(void) { return &m_Cert; } +} ; + +typedef std::shared_ptr cX509CertPtr; + + + + diff --git a/tests/HTTP/CMakeLists.txt b/tests/HTTP/CMakeLists.txt index 5529ed082..32f95a339 100644 --- a/tests/HTTP/CMakeLists.txt +++ b/tests/HTTP/CMakeLists.txt @@ -1,8 +1,8 @@ -enable_testing() +enable_testing() include_directories(${CMAKE_SOURCE_DIR}/src/) include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/lib/libevent/include) -include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/lib/polarssl/include) +include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/lib/mbedtls/include) add_definitions(-DTEST_GLOBALS=1) diff --git a/tests/Network/CMakeLists.txt b/tests/Network/CMakeLists.txt index 617e3ccc9..60c40cdf4 100644 --- a/tests/Network/CMakeLists.txt +++ b/tests/Network/CMakeLists.txt @@ -1,8 +1,8 @@ -enable_testing() +enable_testing() include_directories(${CMAKE_SOURCE_DIR}/src/) include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/lib/libevent/include) -include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/lib/polarssl/include) +include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/lib/mbedtls/include) add_definitions(-DTEST_GLOBALS=1) @@ -18,11 +18,12 @@ set (Network_SRCS ${CMAKE_SOURCE_DIR}/src/OSSupport/NetworkSingleton.cpp ${CMAKE_SOURCE_DIR}/src/OSSupport/ServerHandleImpl.cpp ${CMAKE_SOURCE_DIR}/src/OSSupport/TCPLinkImpl.cpp - ${CMAKE_SOURCE_DIR}/src/PolarSSL++/CtrDrbgContext.cpp - ${CMAKE_SOURCE_DIR}/src/PolarSSL++/CryptoKey.cpp - ${CMAKE_SOURCE_DIR}/src/PolarSSL++/EntropyContext.cpp - ${CMAKE_SOURCE_DIR}/src/PolarSSL++/SslContext.cpp - ${CMAKE_SOURCE_DIR}/src/PolarSSL++/X509Cert.cpp + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/CtrDrbgContext.cpp + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/CryptoKey.cpp + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/EntropyContext.cpp + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/SslConfig.cpp + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/SslContext.cpp + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/X509Cert.cpp ${CMAKE_SOURCE_DIR}/src/StringUtils.cpp ) @@ -39,11 +40,12 @@ set (Network_HDRS ${CMAKE_SOURCE_DIR}/src/OSSupport/ServerHandleImpl.h ${CMAKE_SOURCE_DIR}/src/OSSupport/TCPLinkImpl.h ${CMAKE_SOURCE_DIR}/src/OSSupport/Queue.h - ${CMAKE_SOURCE_DIR}/src/PolarSSL++/CtrDrbgContext.h - ${CMAKE_SOURCE_DIR}/src/PolarSSL++/CryptoKey.h - ${CMAKE_SOURCE_DIR}/src/PolarSSL++/EntropyContext.h - ${CMAKE_SOURCE_DIR}/src/PolarSSL++/SslContext.h - ${CMAKE_SOURCE_DIR}/src/PolarSSL++/X509Cert.h + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/CtrDrbgContext.h + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/CryptoKey.h + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/EntropyContext.h + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/SslConfig.h + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/SslContext.h + ${CMAKE_SOURCE_DIR}/src/mbedTLS++/X509Cert.h ${CMAKE_SOURCE_DIR}/src/StringUtils.h ) -- cgit v1.2.3