From 3687ef397c83773fe3f3807a31ec435df6573dcf Mon Sep 17 00:00:00 2001 From: peterbell10 Date: Mon, 28 Aug 2017 12:48:02 +0100 Subject: Cleanup Vector3 constructors and Abs --- src/Bindings/ManualBindings.cpp | 8 +++---- src/Entities/ProjectileEntity.cpp | 2 +- src/Vector3.h | 49 ++++++++++++--------------------------- 3 files changed, 20 insertions(+), 39 deletions(-) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index ee9cb61e9..f329c0020 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -2995,7 +2995,7 @@ static int tolua_cLineBlockTracer_FirstSolidHitTrace(lua_State * tolua_S) Vector3d hitCoords; Vector3i hitBlockCoords; eBlockFace hitBlockFace; - auto isHit = cLineBlockTracer::FirstSolidHitTrace(*world, start, end, hitCoords, hitBlockCoords, hitBlockFace); + auto isHit = cLineBlockTracer::FirstSolidHitTrace(*world, *start, *end, hitCoords, hitBlockCoords, hitBlockFace); L.Push(isHit); if (!isHit) { @@ -3093,7 +3093,7 @@ static int tolua_cLineBlockTracer_LineOfSightTrace(lua_State * tolua_S) } int lineOfSight = cLineBlockTracer::losAirWater; L.GetStackValue(idx + 7, lineOfSight); - L.Push(cLineBlockTracer::LineOfSightTrace(*world, start, end, lineOfSight)); + L.Push(cLineBlockTracer::LineOfSightTrace(*world, *start, *end, lineOfSight)); return 1; } @@ -3532,7 +3532,7 @@ static int tolua_cBoundingBox_CalcLineIntersection(lua_State * a_LuaState) bool res; if (L.GetStackValues(2, min, max, pt1, pt2)) // Try the static signature first { - res = cBoundingBox::CalcLineIntersection(min, max, pt1, pt2, lineCoeff, blockFace); + res = cBoundingBox::CalcLineIntersection(*min, *max, *pt1, *pt2, lineCoeff, blockFace); } else { @@ -3543,7 +3543,7 @@ static int tolua_cBoundingBox_CalcLineIntersection(lua_State * a_LuaState) tolua_error(a_LuaState, "Invalid function params. Expected either bbox:CalcLineIntersection(pt1, pt2) or cBoundingBox:CalcLineIntersection(min, max, pt1, pt2).", nullptr); return 0; } - res = bbox->CalcLineIntersection(pt1, pt2, lineCoeff, blockFace); + res = bbox->CalcLineIntersection(*pt1, *pt2, lineCoeff, blockFace); } L.Push(res); if (res) diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index d1e101964..c2a1f782d 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -81,7 +81,7 @@ protected: { Vector3d Intersection = LineStart + m_Projectile->GetSpeed() * LineCoeff; // Point where projectile goes into the hit block - if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile, a_BlockX, a_BlockY, a_BlockZ, Face, &Intersection)) + if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile, a_BlockX, a_BlockY, a_BlockZ, Face, Intersection)) { return false; } diff --git a/src/Vector3.h b/src/Vector3.h index 732a65a1f..5c4839ab7 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -21,18 +21,17 @@ public: inline Vector3(T a_x, T a_y, T a_z) : x(a_x), y(a_y), z(a_z) {} - // Hardcoded copy constructors (tolua++ does not support function templates .. yet) - Vector3(const Vector3 & a_Rhs) : x(static_cast(a_Rhs.x)), y(static_cast(a_Rhs.y)), z(static_cast(a_Rhs.z)) {} - Vector3(const Vector3 & a_Rhs) : x(static_cast(a_Rhs.x)), y(static_cast(a_Rhs.y)), z(static_cast(a_Rhs.z)) {} - Vector3(const Vector3 & a_Rhs) : x(static_cast(a_Rhs.x)), y(static_cast(a_Rhs.y)), z(static_cast(a_Rhs.z)) {} + #if 0 // Hardcoded copy constructors (tolua++ does not support function templates .. yet) + Vector3(const Vector3 & a_Rhs); + Vector3(const Vector3 & a_Rhs); + Vector3(const Vector3 & a_Rhs); + #endif // tolua_end - template - Vector3(const Vector3<_T> & a_Rhs) : x(a_Rhs.x), y(a_Rhs.y), z(a_Rhs.z) {} - - template - Vector3(const Vector3<_T> * a_Rhs) : x(a_Rhs->x), y(a_Rhs->y), z(a_Rhs->z) {} + // Conversion constructors where U is not the same as T leaving the copy-constructor implicitly generated + template ::value>::type> + Vector3(const Vector3 & a_Rhs): x(static_cast(a_Rhs.x)), y(static_cast(a_Rhs.y)), z(static_cast(a_Rhs.z)) {} // tolua_begin inline void Set(T a_x, T a_y, T a_z) @@ -111,9 +110,9 @@ public: /** Updates each coord to its absolute value */ inline void Abs() { - x = (x < 0) ? -x : x; - y = (y < 0) ? -y : y; - z = (z < 0) ? -z : z; + x = std::abs(x); + y = std::abs(y); + z = std::abs(z); } /** Clamps each coord into the specified range. */ @@ -152,7 +151,7 @@ public: inline bool EqualsEps(const Vector3 & a_Rhs, T a_Eps) const { - return (Abs(x - a_Rhs.x) < a_Eps) && (Abs(y - a_Rhs.y) < a_Eps) && (Abs(z - a_Rhs.z) < a_Eps); + return (std::abs(x - a_Rhs.x) < a_Eps) && (std::abs(y - a_Rhs.y) < a_Eps) && (std::abs(z - a_Rhs.z) < a_Eps); } inline void Move(T a_X, T a_Y, T a_Z) @@ -229,14 +228,6 @@ public: z *= a_v; } - inline Vector3 & operator = (const Vector3 & a_Rhs) - { - x = a_Rhs.x; - y = a_Rhs.y; - z = a_Rhs.z; - return *this; - } - // tolua_begin inline Vector3 operator + (const Vector3& a_Rhs) const @@ -305,7 +296,7 @@ public: */ inline double LineCoeffToXYPlane(const Vector3 & a_OtherEnd, T a_Z) const { - if (Abs(z - a_OtherEnd.z) < EPS) + if (std::abs(z - a_OtherEnd.z) < EPS) { return NO_INTERSECTION; } @@ -320,7 +311,7 @@ public: */ inline double LineCoeffToXZPlane(const Vector3 & a_OtherEnd, T a_Y) const { - if (Abs(y - a_OtherEnd.y) < EPS) + if (std::abs(y - a_OtherEnd.y) < EPS) { return NO_INTERSECTION; } @@ -335,7 +326,7 @@ public: */ inline double LineCoeffToYZPlane(const Vector3 & a_OtherEnd, T a_X) const { - if (Abs(x - a_OtherEnd.x) < EPS) + if (std::abs(x - a_OtherEnd.x) < EPS) { return NO_INTERSECTION; } @@ -364,16 +355,6 @@ public: /** Return value of LineCoeffToPlane() if the line is parallel to the plane. */ static const double NO_INTERSECTION; - -protected: - - /** Returns the absolute value of the given argument. - Templatized because the standard library differentiates between abs() and fabs(). */ - static T Abs(T a_Value) - { - return (a_Value < 0) ? -a_Value : a_Value; - } - }; // tolua_end -- cgit v1.2.3 From f89becc7610af1ccf396831dd829fe6e04159e5b Mon Sep 17 00:00:00 2001 From: peterbell10 Date: Mon, 28 Aug 2017 12:49:33 +0100 Subject: cCuboid: restore default copy construct and assign. --- src/Cuboid.cpp | 22 ---------------------- src/Cuboid.h | 11 ++++------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/Cuboid.cpp b/src/Cuboid.cpp index c638eb636..7dc39f364 100644 --- a/src/Cuboid.cpp +++ b/src/Cuboid.cpp @@ -10,14 +10,6 @@ //////////////////////////////////////////////////////////////////////////////// // cCuboid: -cCuboid & cCuboid::operator =(cCuboid a_Other) -{ - std::swap(p1, a_Other.p1); - std::swap(p2, a_Other.p2); - return *this; -} - - void cCuboid::Assign(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2) { p1.x = a_X1; @@ -32,20 +24,6 @@ void cCuboid::Assign(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2) -void cCuboid::Assign(const cCuboid & a_SrcCuboid) -{ - p1.x = a_SrcCuboid.p1.x; - p1.y = a_SrcCuboid.p1.y; - p1.z = a_SrcCuboid.p1.z; - p2.x = a_SrcCuboid.p2.x; - p2.y = a_SrcCuboid.p2.y; - p2.z = a_SrcCuboid.p2.z; -} - - - - - void cCuboid::Sort(void) { if (p1.x > p2.x) diff --git a/src/Cuboid.h b/src/Cuboid.h index b9d5f8cfa..73edd31d9 100644 --- a/src/Cuboid.h +++ b/src/Cuboid.h @@ -13,15 +13,12 @@ public: Vector3i p1, p2; cCuboid(void) {} - cCuboid(const cCuboid & a_Cuboid) : p1(a_Cuboid.p1), p2(a_Cuboid.p2) {} cCuboid(const Vector3i & a_p1, const Vector3i & a_p2) : p1(a_p1), p2(a_p2) {} cCuboid(int a_X1, int a_Y1, int a_Z1) : p1(a_X1, a_Y1, a_Z1), p2(a_X1, a_Y1, a_Z1) {} - // tolua_end - - cCuboid & operator =(cCuboid a_Other); - - // tolua_begin + #if 0 // tolua isn't aware of implicitly generated copy constructors + cCuboid(const cCuboid & a_Cuboid); + #endif // DEPRECATED, use cCuboid(Vector3i, Vector3i) instead cCuboid(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2) : p1(a_X1, a_Y1, a_Z1), p2(a_X2, a_Y2, a_Z2) @@ -30,7 +27,7 @@ public: } void Assign(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2); - void Assign(const cCuboid & a_SrcCuboid); + void Assign(const cCuboid & a_SrcCuboid) { *this = a_SrcCuboid; } void Sort(void); -- cgit v1.2.3 From 96ce8414175e600285f2d965844bb141c5a9cf5c Mon Sep 17 00:00:00 2001 From: peterbell10 Date: Mon, 28 Aug 2017 14:36:23 +0100 Subject: Add TOLUA_EXPOSITION for readability --- src/Cuboid.h | 2 +- src/Globals.h | 4 ++++ src/Item.h | 14 ++------------ src/Vector3.h | 2 +- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Cuboid.h b/src/Cuboid.h index 73edd31d9..acb19d46b 100644 --- a/src/Cuboid.h +++ b/src/Cuboid.h @@ -16,7 +16,7 @@ public: cCuboid(const Vector3i & a_p1, const Vector3i & a_p2) : p1(a_p1), p2(a_p2) {} cCuboid(int a_X1, int a_Y1, int a_Z1) : p1(a_X1, a_Y1, a_Z1), p2(a_X1, a_Y1, a_Z1) {} - #if 0 // tolua isn't aware of implicitly generated copy constructors + #ifdef TOLUA_EXPOSITION // tolua isn't aware of implicitly generated copy constructors cCuboid(const cCuboid & a_Cuboid); #endif diff --git a/src/Globals.h b/src/Globals.h index 67f3cd284..0c48d2ad9 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -476,6 +476,10 @@ using cTickTimeLong = std::chrono::duration; #define TOLUA_TEMPLATE_BIND(x) #endif +#ifdef TOLUA_EXPOSITION + #error TOLUA_EXPOSITION should never actually be defined +#endif + diff --git a/src/Item.h b/src/Item.h index 493061d93..35c4e4582 100644 --- a/src/Item.h +++ b/src/Item.h @@ -80,20 +80,10 @@ public: // The constructor is disabled in code, because the compiler generates it anyway, // but it needs to stay because ToLua needs to generate the binding for it - #if 0 + #ifdef TOLUA_EXPOSITION /** Creates an exact copy of the item */ - cItem(const cItem & a_CopyFrom) : - m_ItemType (a_CopyFrom.m_ItemType), - m_ItemCount (a_CopyFrom.m_ItemCount), - m_ItemDamage (a_CopyFrom.m_ItemDamage), - m_Enchantments(a_CopyFrom.m_Enchantments), - m_CustomName (a_CopyFrom.m_CustomName), - m_Lore (a_CopyFrom.m_Lore), - m_RepairCost (a_CopyFrom.m_RepairCost), - m_FireworkItem(a_CopyFrom.m_FireworkItem) - { - } + cItem(const cItem & a_CopyFrom); #endif diff --git a/src/Vector3.h b/src/Vector3.h index 5c4839ab7..7c37c2601 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -21,7 +21,7 @@ public: inline Vector3(T a_x, T a_y, T a_z) : x(a_x), y(a_y), z(a_z) {} - #if 0 // Hardcoded copy constructors (tolua++ does not support function templates .. yet) + #ifdef TOLUA_EXPOSITION // Hardcoded copy constructors (tolua++ does not support function templates .. yet) Vector3(const Vector3 & a_Rhs); Vector3(const Vector3 & a_Rhs); Vector3(const Vector3 & a_Rhs); -- cgit v1.2.3 From 1f9788a80119814d1082015479731291a9cbfbad Mon Sep 17 00:00:00 2001 From: Lane Kolbly Date: Tue, 29 Aug 2017 18:35:53 -0500 Subject: Added ShouldSendRespawn parameter to ScheduleMoveToWorld (#3979) --- Server/Plugins/APIDump/APIDesc.lua | 7 ++++++- src/Entities/Entity.cpp | 5 +++-- src/Entities/Entity.h | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index 674729624..9a0b7a36e 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -3946,8 +3946,13 @@ local Hash = cCryptoHash.sha1HexString("DataToHash") Type = "boolean", IsOptional = true, }, + { + Name = "ShouldSendRespawn", + Type = "boolean", + IsOptional = true, + }, }, - Notes = "Schedules a MoveToWorld call to occur on the next Tick of the entity. If ShouldSetPortalCooldown is false (default), doesn't set any portal cooldown, if it is true, the default portal cooldown is applied to the entity.", + Notes = "Schedules a MoveToWorld call to occur on the next Tick of the entity. If ShouldSetPortalCooldown is false (default), doesn't set any portal cooldown, if it is true, the default portal cooldown is applied to the entity. If ShouldSendRespawn is false (default), no respawn packet is sent, if it is true then a respawn packet is sent to the client.", }, SetGravity = { diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 347c0ec91..836e69961 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1353,12 +1353,13 @@ void cEntity::DetectCacti(void) -void cEntity::ScheduleMoveToWorld(cWorld * a_World, Vector3d a_NewPosition, bool a_SetPortalCooldown) +void cEntity::ScheduleMoveToWorld(cWorld * a_World, Vector3d a_NewPosition, bool a_SetPortalCooldown, bool a_ShouldSendRespawn) { m_NewWorld = a_World; m_NewWorldPosition = a_NewPosition; m_IsWorldChangeScheduled = true; m_WorldChangeSetPortalCooldown = a_SetPortalCooldown; + m_WorldChangeSendRespawn = a_ShouldSendRespawn; } @@ -1378,7 +1379,7 @@ bool cEntity::DetectPortal() m_PortalCooldownData.m_ShouldPreventTeleportation = true; } - MoveToWorld(m_NewWorld, false, m_NewWorldPosition); + MoveToWorld(m_NewWorld, m_WorldChangeSendRespawn, m_NewWorldPosition); return true; } diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index ace2eb6d7..d143e3814 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -428,7 +428,7 @@ public: virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ); /** Schedules a MoveToWorld call to occur on the next Tick of the entity */ - void ScheduleMoveToWorld(cWorld * a_World, Vector3d a_NewPosition, bool a_ShouldSetPortalCooldown = false); + void ScheduleMoveToWorld(cWorld * a_World, Vector3d a_NewPosition, bool a_ShouldSetPortalCooldown = false, bool a_ShouldSendRespawn = false); bool MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_NewPosition); @@ -592,6 +592,7 @@ protected: /** State variables for ScheduleMoveToWorld. */ bool m_IsWorldChangeScheduled; bool m_WorldChangeSetPortalCooldown; + bool m_WorldChangeSendRespawn; cWorld * m_NewWorld; Vector3d m_NewWorldPosition; -- cgit v1.2.3 From c6bc822054f8d36f68a5ad906e90c91f9a7f47dc Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 30 Aug 2017 10:32:53 +0100 Subject: Update core plugins to latest version (#3951) * Update core plugins to latest version * Update Core again --- Server/Plugins/Core | 2 +- Server/Plugins/ProtectionAreas | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Server/Plugins/Core b/Server/Plugins/Core index 68430458a..c0509526b 160000 --- a/Server/Plugins/Core +++ b/Server/Plugins/Core @@ -1 +1 @@ -Subproject commit 68430458a3ea695cac85bc82136941bc83253e1e +Subproject commit c0509526be5569bbc52bbcd3d64c256b834c451c diff --git a/Server/Plugins/ProtectionAreas b/Server/Plugins/ProtectionAreas index 376b52df8..d08cf8fba 160000 --- a/Server/Plugins/ProtectionAreas +++ b/Server/Plugins/ProtectionAreas @@ -1 +1 @@ -Subproject commit 376b52df877f85c9d30c66eeb0a267cc956299ba +Subproject commit d08cf8fba9f700295ca0b54ee75aaec0b6b4b734 -- cgit v1.2.3 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 From 5d64451f74af1839177f9b93d76cd393b7a58ad1 Mon Sep 17 00:00:00 2001 From: Lane Kolbly Date: Wed, 30 Aug 2017 09:01:33 -0500 Subject: Protocol Spawn Position Should Use LastSentPosition (#3929) + Added GetLastSentPos * Fixed spawn position bug in 1.8. --- src/Entities/Entity.h | 4 ++++ src/Protocol/Protocol_1_8.cpp | 28 ++++++++++++++++------------ src/Protocol/Protocol_1_9.cpp | 28 ++++++++++++++++------------ 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index d143e3814..f39039183 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -306,6 +306,10 @@ public: /** Exported in ManualBindings */ const Vector3d & GetSpeed(void) const { return m_Speed; } + /** Returns the last position we sent to all the clients. Use this to + initialize clients with our position. */ + Vector3d GetLastSentPos(void) const { return m_LastSentPosition; } + /** Destroy the entity without scheduling memory freeing. This should only be used by cChunk or cClientHandle for internal memory management. */ void DestroyNoScheduling(bool a_ShouldBroadcast); diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index 7f4b074ce..b6e5b5a38 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -1077,9 +1077,10 @@ void cProtocol_1_8_0::SendPlayerSpawn(const cPlayer & a_Player) cPacketizer Pkt(*this, 0x0c); // Spawn Player packet Pkt.WriteVarInt32(a_Player.GetUniqueID()); Pkt.WriteUUID(a_Player.GetUUID()); - Pkt.WriteFPInt(a_Player.GetPosX()); - Pkt.WriteFPInt(a_Player.GetPosY() + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on. - Pkt.WriteFPInt(a_Player.GetPosZ()); + Vector3d LastSentPos = a_Player.GetLastSentPos(); + Pkt.WriteFPInt(LastSentPos.x); + Pkt.WriteFPInt(LastSentPos.y + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on. + Pkt.WriteFPInt(LastSentPos.z); Pkt.WriteByteAngle(a_Player.GetYaw()); Pkt.WriteByteAngle(a_Player.GetPitch()); short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType; @@ -1314,9 +1315,10 @@ void cProtocol_1_8_0::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock cPacketizer Pkt(*this, 0x0e); // Spawn Object packet Pkt.WriteVarInt32(a_FallingBlock.GetUniqueID()); Pkt.WriteBEUInt8(70); // Falling block - Pkt.WriteFPInt(a_FallingBlock.GetPosX()); - Pkt.WriteFPInt(a_FallingBlock.GetPosY()); - Pkt.WriteFPInt(a_FallingBlock.GetPosZ()); + Vector3d LastSentPos = a_FallingBlock.GetLastSentPos(); + Pkt.WriteFPInt(LastSentPos.x); + Pkt.WriteFPInt(LastSentPos.y); + Pkt.WriteFPInt(LastSentPos.z); Pkt.WriteByteAngle(a_FallingBlock.GetYaw()); Pkt.WriteByteAngle(a_FallingBlock.GetPitch()); Pkt.WriteBEInt32(static_cast(a_FallingBlock.GetBlockType()) | (static_cast(a_FallingBlock.GetBlockMeta()) << 12)); @@ -1336,9 +1338,10 @@ void cProtocol_1_8_0::SendSpawnMob(const cMonster & a_Mob) cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet Pkt.WriteVarInt32(a_Mob.GetUniqueID()); Pkt.WriteBEUInt8(static_cast(a_Mob.GetMobType())); - Pkt.WriteFPInt(a_Mob.GetPosX()); - Pkt.WriteFPInt(a_Mob.GetPosY()); - Pkt.WriteFPInt(a_Mob.GetPosZ()); + Vector3d LastSentPos = a_Mob.GetLastSentPos(); + Pkt.WriteFPInt(LastSentPos.x); + Pkt.WriteFPInt(LastSentPos.y); + Pkt.WriteFPInt(LastSentPos.z); Pkt.WriteByteAngle(a_Mob.GetPitch()); Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); Pkt.WriteByteAngle(a_Mob.GetYaw()); @@ -1392,9 +1395,10 @@ void cProtocol_1_8_0::SendSpawnVehicle(const cEntity & a_Vehicle, char a_Vehicle cPacketizer Pkt(*this, 0xe); // Spawn Object packet Pkt.WriteVarInt32(a_Vehicle.GetUniqueID()); Pkt.WriteBEUInt8(static_cast(a_VehicleType)); - Pkt.WriteFPInt(a_Vehicle.GetPosX()); - Pkt.WriteFPInt(a_Vehicle.GetPosY()); - Pkt.WriteFPInt(a_Vehicle.GetPosZ()); + Vector3d LastSentPos = a_Vehicle.GetLastSentPos(); + Pkt.WriteFPInt(LastSentPos.x); + Pkt.WriteFPInt(LastSentPos.y); + Pkt.WriteFPInt(LastSentPos.z); Pkt.WriteByteAngle(a_Vehicle.GetPitch()); Pkt.WriteByteAngle(a_Vehicle.GetYaw()); Pkt.WriteBEInt32(a_VehicleSubType); diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index c440a94ca..475047417 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -1124,9 +1124,10 @@ void cProtocol_1_9_0::SendPlayerSpawn(const cPlayer & a_Player) cPacketizer Pkt(*this, 0x05); // Spawn Player packet Pkt.WriteVarInt32(a_Player.GetUniqueID()); Pkt.WriteUUID(a_Player.GetUUID()); - Pkt.WriteBEDouble(a_Player.GetPosX()); - Pkt.WriteBEDouble(a_Player.GetPosY() + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on. - Pkt.WriteBEDouble(a_Player.GetPosZ()); + Vector3d LastSentPos = a_Player.GetLastSentPos(); + Pkt.WriteBEDouble(LastSentPos.x); + Pkt.WriteBEDouble(LastSentPos.y + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on. + Pkt.WriteBEDouble(LastSentPos.z); Pkt.WriteByteAngle(a_Player.GetYaw()); Pkt.WriteByteAngle(a_Player.GetPitch()); WriteEntityMetadata(Pkt, a_Player); @@ -1359,9 +1360,10 @@ void cProtocol_1_9_0::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock Pkt.WriteBEUInt64(0); Pkt.WriteBEUInt64(a_FallingBlock.GetUniqueID()); Pkt.WriteBEUInt8(70); // Falling block - Pkt.WriteBEDouble(a_FallingBlock.GetPosX()); - Pkt.WriteBEDouble(a_FallingBlock.GetPosY()); - Pkt.WriteBEDouble(a_FallingBlock.GetPosZ()); + Vector3d LastSentPos = a_FallingBlock.GetLastSentPos(); + Pkt.WriteBEDouble(LastSentPos.x); + Pkt.WriteBEDouble(LastSentPos.y); + Pkt.WriteBEDouble(LastSentPos.z); Pkt.WriteByteAngle(a_FallingBlock.GetYaw()); Pkt.WriteByteAngle(a_FallingBlock.GetPitch()); Pkt.WriteBEInt32(static_cast(a_FallingBlock.GetBlockType()) | (static_cast(a_FallingBlock.GetBlockMeta()) << 12)); @@ -1384,9 +1386,10 @@ void cProtocol_1_9_0::SendSpawnMob(const cMonster & a_Mob) Pkt.WriteBEUInt64(0); Pkt.WriteBEUInt64(a_Mob.GetUniqueID()); Pkt.WriteBEUInt8(static_cast(a_Mob.GetMobType())); - Pkt.WriteBEDouble(a_Mob.GetPosX()); - Pkt.WriteBEDouble(a_Mob.GetPosY()); - Pkt.WriteBEDouble(a_Mob.GetPosZ()); + Vector3d LastSentPos = a_Mob.GetLastSentPos(); + Pkt.WriteBEDouble(LastSentPos.x); + Pkt.WriteBEDouble(LastSentPos.y); + Pkt.WriteBEDouble(LastSentPos.z); Pkt.WriteByteAngle(a_Mob.GetPitch()); Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); Pkt.WriteByteAngle(a_Mob.GetYaw()); @@ -1443,9 +1446,10 @@ void cProtocol_1_9_0::SendSpawnVehicle(const cEntity & a_Vehicle, char a_Vehicle Pkt.WriteBEUInt64(0); Pkt.WriteBEUInt64(a_Vehicle.GetUniqueID()); Pkt.WriteBEUInt8(static_cast(a_VehicleType)); - Pkt.WriteBEDouble(a_Vehicle.GetPosX()); - Pkt.WriteBEDouble(a_Vehicle.GetPosY()); - Pkt.WriteBEDouble(a_Vehicle.GetPosZ()); + Vector3d LastSentPos = a_Vehicle.GetLastSentPos(); + Pkt.WriteBEDouble(LastSentPos.x); + Pkt.WriteBEDouble(LastSentPos.y); + Pkt.WriteBEDouble(LastSentPos.z); Pkt.WriteByteAngle(a_Vehicle.GetPitch()); Pkt.WriteByteAngle(a_Vehicle.GetYaw()); Pkt.WriteBEInt32(a_VehicleSubType); -- cgit v1.2.3