OpenTTD Source  20241121-master-g67a0fccfad
test_network_crypto.cpp
Go to the documentation of this file.
1 /*
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/>.
6  */
7 
10 #include "../stdafx.h"
11 
12 #include "../3rdparty/catch2/catch.hpp"
13 
14 #include "../core/format.hpp"
15 #include "../network/network_crypto_internal.h"
16 #include "../network/core/packet.h"
17 #include "../string_func.h"
18 
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);
22 
24 public:
25  MockNetworkSocketHandler(std::unique_ptr<NetworkEncryptionHandler> &&receive = {}, std::unique_ptr<NetworkEncryptionHandler> &&send = {})
26  {
27  this->receive_encryption_handler = std::move(receive);
28  this->send_encryption_handler = std::move(send);
29  }
30 };
31 
32 static MockNetworkSocketHandler mock_socket_handler;
33 
34 static std::tuple<Packet, bool> CreatePacketForReading(Packet &source, MockNetworkSocketHandler *socket_handler)
35 {
36  source.PrepareToSend();
37 
38  Packet dest(socket_handler, COMPAT_MTU, source.Size());
39 
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);
43  return length;
44  };
45  return source.TransferOutWithLimit(transfer_out, length, dest_data);
46  };
47  dest.TransferIn(transfer_in, source);
48 
49  bool valid = dest.PrepareToRead();
50  dest.Recv_uint8(); // Ignore the type
51  return { dest, valid };
52 }
53 
55 private:
56  std::string password;
57 public:
58  TestPasswordRequestHandler(std::string &password) : password(password) {}
59  void SendResponse() override {}
60  void AskUserForPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request) override { request->Reply(this->password); }
61 };
62 
63 static void TestAuthentication(NetworkAuthenticationServerHandler &server, NetworkAuthenticationClientHandler &client,
66 {
67  Packet request(&mock_socket_handler, PacketType{});
68  server.SendRequest(request);
69 
70  bool valid;
71  std::tie(request, valid) = CreatePacketForReading(request, &mock_socket_handler);
72  CHECK(valid);
73  CHECK(client.ReceiveRequest(request) == expected_request_result);
74 
75  Packet response(&mock_socket_handler, PacketType{});
76  client.SendResponse(response);
77 
78  std::tie(response, valid) = CreatePacketForReading(response, &mock_socket_handler);
79  CHECK(valid);
80  CHECK(server.ReceiveResponse(response) == expected_response_result);
81 }
82 
83 
84 TEST_CASE("Authentication_KeyExchangeOnly")
85 {
88 
90 }
91 
92 
93 static void TestAuthenticationPAKE(std::string server_password, std::string client_password,
95 {
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));
99 
100  TestAuthentication(server, client, expected_response_result, NetworkAuthenticationClientHandler::AWAIT_USER_INPUT);
101 }
102 
103 TEST_CASE("Authentication_PAKE")
104 {
105  SECTION("Correct password") {
106  TestAuthenticationPAKE("sikrit", "sikrit", NetworkAuthenticationServerHandler::AUTHENTICATED);
107  }
108 
109  SECTION("Empty password") {
110  TestAuthenticationPAKE("", "", NetworkAuthenticationServerHandler::AUTHENTICATED);
111  }
112 
113  SECTION("Wrong password") {
114  TestAuthenticationPAKE("sikrit", "secret", NetworkAuthenticationServerHandler::NOT_AUTHENTICATED);
115  }
116 }
117 
118 
119 static void TestAuthenticationAuthorizedKey(const X25519SecretKey &client_secret_key, const X25519PublicKey &server_expected_public_key,
121 {
122  NetworkAuthorizedKeys authorized_keys;
123  authorized_keys.Add(FormatArrayAsHex(server_expected_public_key));
124 
125  NetworkAuthenticationDefaultAuthorizedKeyHandler authorized_key_handler(authorized_keys);
126  X25519AuthorizedKeyServerHandler server(X25519SecretKey::CreateRandom(), &authorized_key_handler);
127  X25519AuthorizedKeyClientHandler client(client_secret_key);
128 
129  TestAuthentication(server, client, expected_response_result, NetworkAuthenticationClientHandler::READY_FOR_RESPONSE);
130 }
131 
132 TEST_CASE("Authentication_AuthorizedKey")
133 {
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();
137 
138  SECTION("Correct public key") {
139  TestAuthenticationAuthorizedKey(client_secret_key, valid_client_public_key, NetworkAuthenticationServerHandler::AUTHENTICATED);
140  }
141 
142  SECTION("Incorrect public key") {
143  TestAuthenticationAuthorizedKey(client_secret_key, invalid_client_public_key, NetworkAuthenticationServerHandler::NOT_AUTHENTICATED);
144  }
145 }
146 
147 
148 TEST_CASE("Authentication_Combined")
149 {
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);
154 
155  NetworkAuthorizedKeys valid_authorized_keys;
156  valid_authorized_keys.Add(client_public_key_str);
157  NetworkAuthenticationDefaultAuthorizedKeyHandler valid_authorized_key_handler(valid_authorized_keys);
158 
159  NetworkAuthorizedKeys invalid_authorized_keys;
160  invalid_authorized_keys.Add("not-a-valid-authorized-key");
161  NetworkAuthenticationDefaultAuthorizedKeyHandler invalid_authorized_key_handler(invalid_authorized_keys);
162 
163  NetworkAuthorizedKeys no_authorized_keys;
164  NetworkAuthenticationDefaultAuthorizedKeyHandler no_authorized_key_handler(no_authorized_keys);
165 
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);
172 
173  auto client = NetworkAuthenticationClientHandler::Create(std::make_shared<TestPasswordRequestHandler>(valid_password), client_secret_key_str, client_public_key_str);
174 
175  SECTION("Invalid authorized keys, invalid password") {
176  auto server = NetworkAuthenticationServerHandler::Create(&invalid_password_provider, &invalid_authorized_key_handler);
177 
180  }
181 
182  SECTION("Invalid authorized keys, valid password") {
183  auto server = NetworkAuthenticationServerHandler::Create(&valid_password_provider, &invalid_authorized_key_handler);
184 
187  }
188 
189  SECTION("Valid authorized keys, valid password") {
190  auto server = NetworkAuthenticationServerHandler::Create(&valid_password_provider, &valid_authorized_key_handler);
191 
193  }
194 
195  SECTION("No authorized keys, invalid password") {
196  auto server = NetworkAuthenticationServerHandler::Create(&invalid_password_provider, &no_authorized_key_handler);
197 
199  }
200 
201  SECTION("No authorized keys, valid password") {
202  auto server = NetworkAuthenticationServerHandler::Create(&valid_password_provider, &no_authorized_key_handler);
203 
205  }
206 
207  SECTION("No authorized keys, no password") {
208  auto server = NetworkAuthenticationServerHandler::Create(&no_password_provider, &no_authorized_key_handler);
209 
211  }
212 }
213 
214 
215 static void CheckEncryption(MockNetworkSocketHandler *sending_socket_handler, MockNetworkSocketHandler *receiving_socket_handler)
216 {
217  PacketType sent_packet_type{ 1 };
218  uint64_t sent_value = 0x1234567890ABCDEF;
219  std::set<PacketType> encrypted_packet_types;
220 
221  for (int i = 0; i < 10; i++) {
222  Packet request(sending_socket_handler, sent_packet_type);
223  request.Send_uint64(sent_value);
224 
225  auto [response, valid] = CreatePacketForReading(request, receiving_socket_handler);
226  CHECK(valid);
227  CHECK(response.Recv_uint64() == sent_value);
228 
229  encrypted_packet_types.insert(request.GetPacketType());
230  }
231  /*
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.
235  *
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.
241  */
242  CHECK(encrypted_packet_types.size() != 1);
243 
244 }
245 
246 TEST_CASE("Encryption handling")
247 {
250 
252 
253  Packet packet(&mock_socket_handler, PacketType{});
254  server.SendEnableEncryption(packet);
255 
256  bool valid;
257  std::tie(packet, valid) = CreatePacketForReading(packet, &mock_socket_handler);
258  CHECK(valid);
259  CHECK(client.ReceiveEnableEncryption(packet));
260 
263 
264  SECTION("Encyption happening client -> server") {
265  CheckEncryption(&client_socket_handler, &server_socket_handler);
266  }
267 
268  SECTION("Encyption happening server -> client") {
269  CheckEncryption(&server_socket_handler, &client_socket_handler);
270  }
271 
272  SECTION("Unencrypted packet sent causes invalid read packet") {
273  Packet request(&mock_socket_handler, PacketType{});
274  request.Send_uint64(0);
275 
276  auto [response, valid] = CreatePacketForReading(request, &client_socket_handler);
277  CHECK(!valid);
278  }
279 }
Base class for client side cryptographic authentication handlers.
virtual bool ReceiveEnableEncryption(struct Packet &p)=0
Read the request to enable encryption from the server.
virtual RequestResult ReceiveRequest(struct Packet &p)=0
Read a request from the server.
RequestResult
The processing result of receiving a request.
@ READY_FOR_RESPONSE
We do not have to wait for user input, and can immediately respond to the server.
@ AWAIT_USER_INPUT
We have requested some user input, but must wait on that.
virtual bool SendResponse(struct Packet &p)=0
Create the response to send to the server.
static std::unique_ptr< NetworkAuthenticationClientHandler > Create(std::shared_ptr< NetworkAuthenticationPasswordRequestHandler > password_handler, std::string &secret_key, std::string &public_key)
Create a NetworkAuthenticationClientHandler.
Default implementation for the authorized key handler.
Default implementation of the password provider.
virtual std::unique_ptr< NetworkEncryptionHandler > CreateClientToServerEncryptionHandler() const =0
Create a NetworkEncryptionHandler to encrypt or decrypt messages from the client to the server.
virtual std::unique_ptr< NetworkEncryptionHandler > CreateServerToClientEncryptionHandler() const =0
Create a NetworkEncryptionHandler to encrypt or decrypt messages from the server to the client.
Callback interface for client implementations to provide the handling of the password requests.
Base class for server side cryptographic authentication handlers.
static std::unique_ptr< NetworkAuthenticationServerHandler > Create(const NetworkAuthenticationPasswordProvider *password_provider, const NetworkAuthenticationAuthorizedKeyHandler *authorized_key_handler, NetworkAuthenticationMethodMask client_supported_method_mask=~static_cast< NetworkAuthenticationMethodMask >(0))
Create a NetworkAuthenticationServerHandler.
virtual ResponseResult ReceiveResponse(struct Packet &p)=0
Read the response from the client.
virtual void SendEnableEncryption(struct Packet &p)=0
Create the request to enable encryption to the client.
ResponseResult
The processing result of receiving a response.
@ RETRY_NEXT_METHOD
The client failed to authenticate, but there is another method to try.
@ AUTHENTICATED
The client was authenticated successfully.
@ NOT_AUTHENTICATED
All authentications for this handler have been exhausted.
virtual void SendRequest(struct Packet &p)=0
Create the request to send to the client.
Simple helper to (more easily) manage authorized keys.
Definition: network_type.h:148
bool Add(std::string_view key)
Add the given key to the authorized keys, when it is not already contained.
Definition: network.cpp:188
SocketHandler for all network sockets in OpenTTD.
Definition: core.h:43
std::unique_ptr< class NetworkEncryptionHandler > send_encryption_handler
The handler for encrypting sent packets.
Definition: core.h:50
std::unique_ptr< class NetworkEncryptionHandler > receive_encryption_handler
The handler for decrypting received packets.
Definition: core.h:49
void SendResponse() override
Callback to trigger sending the response for the password request.
void AskUserForPassword(std::shared_ptr< NetworkAuthenticationPasswordRequest > request) override
Callback to trigger asking the user for the password.
Handler for clients using a X25519 key exchange to perform authentication via a set of authorized (pu...
Handler for servers using a X25519 key exchange to perform authentication via a set of authorized (pu...
Client side handler for using X25519 without actual authentication.
Server side handler for using X25519 without actual authentication.
Client side handler for using X25519 with a password-authenticated key exchange.
Server side handler for using X25519 with a password-authenticated key exchange.
static const uint NETWORK_SECRET_KEY_LENGTH
The maximum length of the hexadecimal encoded secret keys, in bytes including '\0'.
Definition: config.h:96
static const size_t COMPAT_MTU
Number of bytes we can pack in a single packet for backward compatibility.
Definition: config.h:46
static const uint NETWORK_PUBLIC_KEY_LENGTH
The maximum length of the hexadecimal encoded public keys, in bytes including '\0'.
Definition: config.h:101
constexpr size_t X25519_KEY_SIZE
The number of bytes the public and secret keys are in X25519.
uint8_t valid
Bits indicating what variable is valid (for each bit, 0 is invalid, 1 is valid).
uint8_t PacketType
Identifier for the packet.
Definition: packet.h:21
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition: string.cpp:81
Internal entity of a packet.
Definition: packet.h:42
size_t Size() const
Get the number of bytes in the packet.
Definition: packet.cpp:250
ssize_t TransferOutWithLimit(F transfer_function, size_t limit, D destination, Args &&... args)
Transfer data from the packet to the given function.
Definition: packet.h:109
void PrepareToSend()
Writes the packet size from the raw packet from packet->size.
Definition: packet.cpp:66
void Send_uint64(uint64_t data)
Package a 64 bits integer in the packet.
Definition: packet.cpp:154
Container for a X25519 public key.
Container for a X25519 secret key.
X25519PublicKey CreatePublicKey() const
Create the public key associated with this secret key.
static X25519SecretKey CreateRandom()
Create a new secret key that's filled with random bytes.