2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 /** @file test_network_crypto.cpp Tests for network related crypto functions. */
10 #include "../stdafx.h"
12 #include "../3rdparty/catch2/catch.hpp"
14 #include "../core/format.hpp"
15 #include "../network/network_crypto_internal.h"
16 #include "../network/core/packet.h"
17 #include "../string_func.h"
19 /* The length of the hexadecimal representation of a X25519 key must fit in the key length. */
20 static_assert(NETWORK_SECRET_KEY_LENGTH
>= X25519_KEY_SIZE
* 2 + 1);
21 static_assert(NETWORK_PUBLIC_KEY_LENGTH
>= X25519_KEY_SIZE
* 2 + 1);
23 class MockNetworkSocketHandler
: public NetworkSocketHandler
{
25 MockNetworkSocketHandler(std::unique_ptr
<NetworkEncryptionHandler
> &&receive
= {}, std::unique_ptr
<NetworkEncryptionHandler
> &&send
= {})
27 this->receive_encryption_handler
= std::move(receive
);
28 this->send_encryption_handler
= std::move(send
);
32 static MockNetworkSocketHandler mock_socket_handler
;
34 static std::tuple
<Packet
, bool> CreatePacketForReading(Packet
&source
, MockNetworkSocketHandler
*socket_handler
)
36 source
.PrepareToSend();
38 Packet
dest(socket_handler
, COMPAT_MTU
, source
.Size());
40 auto transfer_in
= [](Packet
&source
, char *dest_data
, size_t length
) {
41 auto transfer_out
= [](char *dest_data
, const char *source_data
, size_t length
) {
42 std::copy(source_data
, source_data
+ length
, dest_data
);
45 return source
.TransferOutWithLimit(transfer_out
, length
, dest_data
);
47 dest
.TransferIn(transfer_in
, source
);
49 bool valid
= dest
.PrepareToRead();
50 dest
.Recv_uint8(); // Ignore the type
51 return { dest
, valid
};
54 class TestPasswordRequestHandler
: public NetworkAuthenticationPasswordRequestHandler
{
58 TestPasswordRequestHandler(std::string
&password
) : password(password
) {}
59 void SendResponse() override
{}
60 void AskUserForPassword(std::shared_ptr
<NetworkAuthenticationPasswordRequest
> request
) override
{ request
->Reply(this->password
); }
63 static void TestAuthentication(NetworkAuthenticationServerHandler
&server
, NetworkAuthenticationClientHandler
&client
,
64 NetworkAuthenticationServerHandler::ResponseResult expected_response_result
,
65 NetworkAuthenticationClientHandler::RequestResult expected_request_result
)
67 Packet
request(&mock_socket_handler
, PacketType
{});
68 server
.SendRequest(request
);
71 std::tie(request
, valid
) = CreatePacketForReading(request
, &mock_socket_handler
);
73 CHECK(client
.ReceiveRequest(request
) == expected_request_result
);
75 Packet
response(&mock_socket_handler
, PacketType
{});
76 client
.SendResponse(response
);
78 std::tie(response
, valid
) = CreatePacketForReading(response
, &mock_socket_handler
);
80 CHECK(server
.ReceiveResponse(response
) == expected_response_result
);
84 TEST_CASE("Authentication_KeyExchangeOnly")
86 X25519KeyExchangeOnlyServerHandler
server(X25519SecretKey::CreateRandom());
87 X25519KeyExchangeOnlyClientHandler
client(X25519SecretKey::CreateRandom());
89 TestAuthentication(server
, client
, NetworkAuthenticationServerHandler::AUTHENTICATED
, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE
);
93 static void TestAuthenticationPAKE(std::string server_password
, std::string client_password
,
94 NetworkAuthenticationServerHandler::ResponseResult expected_response_result
)
96 NetworkAuthenticationDefaultPasswordProvider
server_password_provider(server_password
);
97 X25519PAKEServerHandler
server(X25519SecretKey::CreateRandom(), &server_password_provider
);
98 X25519PAKEClientHandler
client(X25519SecretKey::CreateRandom(), std::make_shared
<TestPasswordRequestHandler
>(client_password
));
100 TestAuthentication(server
, client
, expected_response_result
, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT
);
103 TEST_CASE("Authentication_PAKE")
105 SECTION("Correct password") {
106 TestAuthenticationPAKE("sikrit", "sikrit", NetworkAuthenticationServerHandler::AUTHENTICATED
);
109 SECTION("Empty password") {
110 TestAuthenticationPAKE("", "", NetworkAuthenticationServerHandler::AUTHENTICATED
);
113 SECTION("Wrong password") {
114 TestAuthenticationPAKE("sikrit", "secret", NetworkAuthenticationServerHandler::NOT_AUTHENTICATED
);
119 static void TestAuthenticationAuthorizedKey(const X25519SecretKey
&client_secret_key
, const X25519PublicKey
&server_expected_public_key
,
120 NetworkAuthenticationServerHandler::ResponseResult expected_response_result
)
122 NetworkAuthorizedKeys authorized_keys
;
123 authorized_keys
.Add(FormatArrayAsHex(server_expected_public_key
));
125 NetworkAuthenticationDefaultAuthorizedKeyHandler
authorized_key_handler(authorized_keys
);
126 X25519AuthorizedKeyServerHandler
server(X25519SecretKey::CreateRandom(), &authorized_key_handler
);
127 X25519AuthorizedKeyClientHandler
client(client_secret_key
);
129 TestAuthentication(server
, client
, expected_response_result
, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE
);
132 TEST_CASE("Authentication_AuthorizedKey")
134 auto client_secret_key
= X25519SecretKey::CreateRandom();
135 auto valid_client_public_key
= client_secret_key
.CreatePublicKey();
136 auto invalid_client_public_key
= X25519SecretKey::CreateRandom().CreatePublicKey();
138 SECTION("Correct public key") {
139 TestAuthenticationAuthorizedKey(client_secret_key
, valid_client_public_key
, NetworkAuthenticationServerHandler::AUTHENTICATED
);
142 SECTION("Incorrect public key") {
143 TestAuthenticationAuthorizedKey(client_secret_key
, invalid_client_public_key
, NetworkAuthenticationServerHandler::NOT_AUTHENTICATED
);
148 TEST_CASE("Authentication_Combined")
150 auto client_secret_key
= X25519SecretKey::CreateRandom();
151 std::string client_secret_key_str
= FormatArrayAsHex(client_secret_key
);
152 auto client_public_key
= client_secret_key
.CreatePublicKey();
153 std::string client_public_key_str
= FormatArrayAsHex(client_public_key
);
155 NetworkAuthorizedKeys valid_authorized_keys
;
156 valid_authorized_keys
.Add(client_public_key_str
);
157 NetworkAuthenticationDefaultAuthorizedKeyHandler
valid_authorized_key_handler(valid_authorized_keys
);
159 NetworkAuthorizedKeys invalid_authorized_keys
;
160 invalid_authorized_keys
.Add("not-a-valid-authorized-key");
161 NetworkAuthenticationDefaultAuthorizedKeyHandler
invalid_authorized_key_handler(invalid_authorized_keys
);
163 NetworkAuthorizedKeys no_authorized_keys
;
164 NetworkAuthenticationDefaultAuthorizedKeyHandler
no_authorized_key_handler(no_authorized_keys
);
166 std::string no_password
= "";
167 NetworkAuthenticationDefaultPasswordProvider
no_password_provider(no_password
);
168 std::string valid_password
= "sikrit";
169 NetworkAuthenticationDefaultPasswordProvider
valid_password_provider(valid_password
);
170 std::string invalid_password
= "secret";
171 NetworkAuthenticationDefaultPasswordProvider
invalid_password_provider(invalid_password
);
173 auto client
= NetworkAuthenticationClientHandler::Create(std::make_shared
<TestPasswordRequestHandler
>(valid_password
), client_secret_key_str
, client_public_key_str
);
175 SECTION("Invalid authorized keys, invalid password") {
176 auto server
= NetworkAuthenticationServerHandler::Create(&invalid_password_provider
, &invalid_authorized_key_handler
);
178 TestAuthentication(*server
, *client
, NetworkAuthenticationServerHandler::RETRY_NEXT_METHOD
, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE
);
179 TestAuthentication(*server
, *client
, NetworkAuthenticationServerHandler::NOT_AUTHENTICATED
, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT
);
182 SECTION("Invalid authorized keys, valid password") {
183 auto server
= NetworkAuthenticationServerHandler::Create(&valid_password_provider
, &invalid_authorized_key_handler
);
185 TestAuthentication(*server
, *client
, NetworkAuthenticationServerHandler::RETRY_NEXT_METHOD
, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE
);
186 TestAuthentication(*server
, *client
, NetworkAuthenticationServerHandler::AUTHENTICATED
, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT
);
189 SECTION("Valid authorized keys, valid password") {
190 auto server
= NetworkAuthenticationServerHandler::Create(&valid_password_provider
, &valid_authorized_key_handler
);
192 TestAuthentication(*server
, *client
, NetworkAuthenticationServerHandler::AUTHENTICATED
, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE
);
195 SECTION("No authorized keys, invalid password") {
196 auto server
= NetworkAuthenticationServerHandler::Create(&invalid_password_provider
, &no_authorized_key_handler
);
198 TestAuthentication(*server
, *client
, NetworkAuthenticationServerHandler::NOT_AUTHENTICATED
, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT
);
201 SECTION("No authorized keys, valid password") {
202 auto server
= NetworkAuthenticationServerHandler::Create(&valid_password_provider
, &no_authorized_key_handler
);
204 TestAuthentication(*server
, *client
, NetworkAuthenticationServerHandler::AUTHENTICATED
, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT
);
207 SECTION("No authorized keys, no password") {
208 auto server
= NetworkAuthenticationServerHandler::Create(&no_password_provider
, &no_authorized_key_handler
);
210 TestAuthentication(*server
, *client
, NetworkAuthenticationServerHandler::AUTHENTICATED
, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE
);
215 static void CheckEncryption(MockNetworkSocketHandler
*sending_socket_handler
, MockNetworkSocketHandler
*receiving_socket_handler
)
217 PacketType sent_packet_type
{ 1 };
218 uint64_t sent_value
= 0x1234567890ABCDEF;
219 std::set
<PacketType
> encrypted_packet_types
;
221 for (int i
= 0; i
< 10; i
++) {
222 Packet
request(sending_socket_handler
, sent_packet_type
);
223 request
.Send_uint64(sent_value
);
225 auto [response
, valid
] = CreatePacketForReading(request
, receiving_socket_handler
);
227 CHECK(response
.Recv_uint64() == sent_value
);
229 encrypted_packet_types
.insert(request
.GetPacketType());
232 * Check whether it looks like encryption has happened. This is done by checking the value
233 * of the packet type after encryption. If after a few iterations more than one encrypted
234 * value has been seen, then we know that some type of encryption/scrambling is happening.
236 * Technically this check could fail erroneously when 16 subsequent encryptions yield the
237 * same encrypted packet type. However, with encryption that byte should have random value
238 * value, so the chance of this happening are tiny given enough iterations.
239 * Roughly in the order of 2**((iterations - 1) * 8), which with 10 iterations is in the
240 * one-in-sextillion (10**21) order of magnitude.
242 CHECK(encrypted_packet_types
.size() != 1);
246 TEST_CASE("Encryption handling")
248 X25519KeyExchangeOnlyServerHandler
server(X25519SecretKey::CreateRandom());
249 X25519KeyExchangeOnlyClientHandler
client(X25519SecretKey::CreateRandom());
251 TestAuthentication(server
, client
, NetworkAuthenticationServerHandler::AUTHENTICATED
, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE
);
253 Packet
packet(&mock_socket_handler
, PacketType
{});
254 server
.SendEnableEncryption(packet
);
257 std::tie(packet
, valid
) = CreatePacketForReading(packet
, &mock_socket_handler
);
259 CHECK(client
.ReceiveEnableEncryption(packet
));
261 MockNetworkSocketHandler
server_socket_handler(server
.CreateClientToServerEncryptionHandler(), server
.CreateServerToClientEncryptionHandler());
262 MockNetworkSocketHandler
client_socket_handler(client
.CreateServerToClientEncryptionHandler(), client
.CreateClientToServerEncryptionHandler());
264 SECTION("Encyption happening client -> server") {
265 CheckEncryption(&client_socket_handler
, &server_socket_handler
);
268 SECTION("Encyption happening server -> client") {
269 CheckEncryption(&server_socket_handler
, &client_socket_handler
);
272 SECTION("Unencrypted packet sent causes invalid read packet") {
273 Packet
request(&mock_socket_handler
, PacketType
{});
274 request
.Send_uint64(0);
276 auto [response
, valid
] = CreatePacketForReading(request
, &client_socket_handler
);