Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
uptane_init_test.cc
1 #include <gtest/gtest.h>
2 
3 #include <string>
4 
5 #include <boost/filesystem.hpp>
6 
7 #include "httpfake.h"
8 #include "primary/initializer.h"
9 #include "primary/sotauptaneclient.h"
10 #include "storage/invstorage.h"
11 #include "utilities/utils.h"
12 
13 /*
14  * Check that aktualizr creates provisioning data if they don't exist already.
15  */
16 TEST(Uptane, Initialize) {
17  RecordProperty("zephyr_key", "OTA-983,TST-153");
18  TemporaryDirectory temp_dir;
19  auto http = std::make_shared<HttpFake>(temp_dir.Path());
20  Config conf("tests/config/basic.toml");
21  conf.uptane.director_server = http->tls_server + "/director";
22  conf.uptane.repo_server = http->tls_server + "/repo";
23  conf.tls.server = http->tls_server;
24  conf.storage.path = temp_dir.Path();
25  conf.provision.primary_ecu_serial = "testecuserial";
26 
27  // First make sure nothing is already there.
28  auto storage = INvStorage::newStorage(conf.storage);
29  std::string pkey;
30  std::string cert;
31  std::string ca;
32  EXPECT_FALSE(storage->loadTlsCreds(&ca, &cert, &pkey));
33  std::string public_key;
34  std::string private_key;
35  EXPECT_FALSE(storage->loadPrimaryKeys(&public_key, &private_key));
36 
37  // Initialize.
38  KeyManager keys(storage, conf.keymanagerConfig());
39  Initializer initializer(conf.provision, storage, http, keys, {});
40  EXPECT_TRUE(initializer.isSuccessful());
41 
42  // Then verify that the storage contains what we expect.
43  EXPECT_TRUE(storage->loadTlsCreds(&ca, &cert, &pkey));
44  EXPECT_NE(ca, "");
45  EXPECT_NE(cert, "");
46  EXPECT_NE(pkey, "");
47  EXPECT_TRUE(storage->loadPrimaryKeys(&public_key, &private_key));
48  EXPECT_NE(public_key, "");
49  EXPECT_NE(private_key, "");
50 
51  const Json::Value ecu_data = Utils::parseJSONFile(temp_dir.Path() / "post.json");
52  EXPECT_EQ(ecu_data["ecus"].size(), 1);
53  EXPECT_EQ(ecu_data["ecus"][0]["clientKey"]["keyval"]["public"].asString(), public_key);
54  EXPECT_EQ(ecu_data["ecus"][0]["ecu_serial"].asString(), conf.provision.primary_ecu_serial);
55  EXPECT_NE(ecu_data["ecus"][0]["hardware_identifier"].asString(), "");
56  EXPECT_EQ(ecu_data["primary_ecu_serial"].asString(), conf.provision.primary_ecu_serial);
57 }
58 
59 /*
60  * Check that aktualizr does NOT change provisioning data if they DO exist
61  * already.
62  */
63 TEST(Uptane, InitializeTwice) {
64  RecordProperty("zephyr_key", "OTA-983,TST-154");
65  TemporaryDirectory temp_dir;
66  auto http = std::make_shared<HttpFake>(temp_dir.Path());
67  Config conf("tests/config/basic.toml");
68  conf.storage.path = temp_dir.Path();
69  conf.provision.primary_ecu_serial = "testecuserial";
70 
71  // First make sure nothing is already there.
72  auto storage = INvStorage::newStorage(conf.storage);
73  std::string pkey1;
74  std::string cert1;
75  std::string ca1;
76  EXPECT_FALSE(storage->loadTlsCreds(&ca1, &cert1, &pkey1));
77  std::string public_key1;
78  std::string private_key1;
79  EXPECT_FALSE(storage->loadPrimaryKeys(&public_key1, &private_key1));
80 
81  // Intialize and verify that the storage contains what we expect.
82  {
83  KeyManager keys(storage, conf.keymanagerConfig());
84  Initializer initializer(conf.provision, storage, http, keys, {});
85  EXPECT_TRUE(initializer.isSuccessful());
86 
87  EXPECT_TRUE(storage->loadTlsCreds(&ca1, &cert1, &pkey1));
88  EXPECT_NE(ca1, "");
89  EXPECT_NE(cert1, "");
90  EXPECT_NE(pkey1, "");
91  EXPECT_TRUE(storage->loadPrimaryKeys(&public_key1, &private_key1));
92  EXPECT_NE(public_key1, "");
93  EXPECT_NE(private_key1, "");
94  }
95 
96  // Intialize again and verify that nothing has changed.
97  {
98  KeyManager keys(storage, conf.keymanagerConfig());
99  Initializer initializer(conf.provision, storage, http, keys, {});
100  EXPECT_TRUE(initializer.isSuccessful());
101 
102  std::string pkey2;
103  std::string cert2;
104  std::string ca2;
105  EXPECT_TRUE(storage->loadTlsCreds(&ca2, &cert2, &pkey2));
106  std::string public_key2;
107  std::string private_key2;
108  EXPECT_TRUE(storage->loadPrimaryKeys(&public_key2, &private_key2));
109 
110  EXPECT_EQ(cert1, cert2);
111  EXPECT_EQ(ca1, ca2);
112  EXPECT_EQ(pkey1, pkey2);
113  EXPECT_EQ(public_key1, public_key2);
114  EXPECT_EQ(private_key1, private_key2);
115  }
116 }
117 
118 /**
119  * Check that aktualizr does not generate a pet name when device ID is
120  * specified.
121  */
122 TEST(Uptane, PetNameProvided) {
123  RecordProperty("zephyr_key", "OTA-985,TST-146");
124  TemporaryDirectory temp_dir;
125  const std::string test_name = "test-name-123";
126 
127  /* Make sure provided device ID is read as expected. */
128  Config conf("tests/config/device_id.toml");
129  conf.storage.path = temp_dir.Path();
130  conf.provision.primary_ecu_serial = "testecuserial";
131 
132  auto storage = INvStorage::newStorage(conf.storage);
133  auto http = std::make_shared<HttpFake>(temp_dir.Path());
134  KeyManager keys(storage, conf.keymanagerConfig());
135  Initializer initializer(conf.provision, storage, http, keys, {});
136  EXPECT_TRUE(initializer.isSuccessful());
137 
138  {
139  EXPECT_EQ(conf.provision.device_id, test_name);
140  std::string devid;
141  EXPECT_TRUE(storage->loadDeviceId(&devid));
142  EXPECT_EQ(devid, test_name);
143  }
144 
145  {
146  /* Make sure name is unchanged after re-initializing config. */
147  conf.postUpdateValues();
148  EXPECT_EQ(conf.provision.device_id, test_name);
149  std::string devid;
150  EXPECT_TRUE(storage->loadDeviceId(&devid));
151  EXPECT_EQ(devid, test_name);
152  }
153 }
154 
155 /**
156  * Check that aktualizr generates a pet name if no device ID is specified.
157  */
158 TEST(Uptane, PetNameCreation) {
159  RecordProperty("zephyr_key", "OTA-985,TST-145");
160  TemporaryDirectory temp_dir;
161 
162  // Make sure name is created.
163  Config conf("tests/config/basic.toml");
164  conf.storage.path = temp_dir.Path();
165  conf.provision.primary_ecu_serial = "testecuserial";
166  boost::filesystem::copy_file("tests/test_data/cred.zip", temp_dir.Path() / "cred.zip");
167  conf.provision.provision_path = temp_dir.Path() / "cred.zip";
168 
169  std::string test_name1, test_name2;
170  {
171  auto storage = INvStorage::newStorage(conf.storage);
172  auto http = std::make_shared<HttpFake>(temp_dir.Path());
173  KeyManager keys(storage, conf.keymanagerConfig());
174  Initializer initializer(conf.provision, storage, http, keys, {});
175  EXPECT_TRUE(initializer.isSuccessful());
176 
177  EXPECT_TRUE(storage->loadDeviceId(&test_name1));
178  EXPECT_NE(test_name1, "");
179  }
180 
181  // Make sure a new name is generated if the config does not specify a name and
182  // there is no device_id file.
183  TemporaryDirectory temp_dir2;
184  {
185  conf.storage.path = temp_dir2.Path();
186  boost::filesystem::copy_file("tests/test_data/cred.zip", temp_dir2.Path() / "cred.zip");
187  conf.provision.device_id = "";
188 
189  auto storage = INvStorage::newStorage(conf.storage);
190  auto http = std::make_shared<HttpFake>(temp_dir2.Path());
191  KeyManager keys(storage, conf.keymanagerConfig());
192  Initializer initializer(conf.provision, storage, http, keys, {});
193  EXPECT_TRUE(initializer.isSuccessful());
194 
195  EXPECT_TRUE(storage->loadDeviceId(&test_name2));
196  EXPECT_NE(test_name2, test_name1);
197  }
198 
199  // If the device_id is cleared in the config, but still present in the
200  // storage, re-initializing the config should read the device_id from storage.
201  {
202  conf.provision.device_id = "";
203  auto storage = INvStorage::newStorage(conf.storage);
204  auto http = std::make_shared<HttpFake>(temp_dir2.Path());
205  KeyManager keys(storage, conf.keymanagerConfig());
206  Initializer initializer(conf.provision, storage, http, keys, {});
207  EXPECT_TRUE(initializer.isSuccessful());
208 
209  std::string devid;
210  EXPECT_TRUE(storage->loadDeviceId(&devid));
211  EXPECT_EQ(devid, test_name2);
212  }
213 
214  // If the device_id is removed from storage, but the field is still present in
215  // the config, re-initializing the config should still read the device_id from
216  // config.
217  {
218  TemporaryDirectory temp_dir3;
219  conf.storage.path = temp_dir3.Path();
220  boost::filesystem::copy_file("tests/test_data/cred.zip", temp_dir3.Path() / "cred.zip");
221  conf.provision.device_id = test_name2;
222 
223  auto storage = INvStorage::newStorage(conf.storage);
224  auto http = std::make_shared<HttpFake>(temp_dir3.Path());
225  KeyManager keys(storage, conf.keymanagerConfig());
226  Initializer initializer(conf.provision, storage, http, keys, {});
227  EXPECT_TRUE(initializer.isSuccessful());
228 
229  std::string devid;
230  EXPECT_TRUE(storage->loadDeviceId(&devid));
231  EXPECT_EQ(devid, test_name2);
232  }
233 }
234 
235 /* Detect and recover from failed provisioning. */
236 TEST(Uptane, InitializeFail) {
237  TemporaryDirectory temp_dir;
238  auto http = std::make_shared<HttpFake>(temp_dir.Path());
239  Config conf("tests/config/basic.toml");
240  conf.uptane.director_server = http->tls_server + "/director";
241  conf.uptane.repo_server = http->tls_server + "/repo";
242  conf.tls.server = http->tls_server;
243  conf.storage.path = temp_dir.Path();
244  conf.provision.primary_ecu_serial = "testecuserial";
245 
246  auto storage = INvStorage::newStorage(conf.storage);
247  KeyManager keys(storage, conf.keymanagerConfig());
248 
249  // Force a failure from the fake server.
250  {
251  http->provisioningResponse = ProvisioningResult::kFailure;
252  Initializer initializer(conf.provision, storage, http, keys, {});
253  EXPECT_FALSE(initializer.isSuccessful());
254  }
255 
256  // Don't force a failure and make sure it actually works this time.
257  {
258  http->provisioningResponse = ProvisioningResult::kOK;
259  Initializer initializer(conf.provision, storage, http, keys, {});
260  EXPECT_TRUE(initializer.isSuccessful());
261  }
262 }
263 
264 /**
265  * Verifies if the system hostname is used as a primary ECU hardware ID
266  * if it's not specified in the configuration
267  *
268  * Checks actions:
269  *
270  * - [x] Use the system hostname as hardware ID if one is not provided
271  */
272 TEST(Uptane, HostnameAsHardwareID) {
273  TemporaryDirectory temp_dir;
274  Config conf("tests/config/basic.toml");
275  conf.storage.path = temp_dir.Path();
276 
277  boost::filesystem::copy_file("tests/test_data/cred.zip", temp_dir.Path() / "cred.zip");
278  conf.provision.provision_path = temp_dir.Path() / "cred.zip";
279 
280  {
281  auto storage = INvStorage::newStorage(conf.storage);
282  auto http = std::make_shared<HttpFake>(temp_dir.Path());
283  KeyManager keys(storage, conf.keymanagerConfig());
284 
285  EXPECT_TRUE(conf.provision.primary_ecu_hardware_id.empty());
286  Initializer initializer(conf.provision, storage, http, keys, {});
287  EXPECT_TRUE(initializer.isSuccessful());
288 
289  EcuSerials ecu_serials;
290  EXPECT_TRUE(storage->loadEcuSerials(&ecu_serials));
291  EXPECT_GE(ecu_serials.size(), 1);
292 
293  // A second element of the first tuple in ECU Serials tuple array is a primary hardware ID.
294  // Each client of the storage class needs to know this information.
295  // If it changes then corresponding changes should be done in each storage client.
296  // perhaps it makes sense to introduce get/setPrimaryHardwareID method and incapsulate
297  // this tech info within storage (or maybe some other entity)
298  auto primaryHardwareID = ecu_serials[0].second;
299  auto hostname = Utils::getHostname();
300  EXPECT_EQ(primaryHardwareID, Uptane::HardwareIdentifier(hostname));
301  }
302 }
303 
304 #ifndef __NO_MAIN__
305 int main(int argc, char** argv) {
306  ::testing::InitGoogleTest(&argc, argv);
307  logger_init();
308  logger_set_threshold(boost::log::trivial::trace);
309  return RUN_ALL_TESTS();
310 }
311 #endif
KeyManager
Definition: keymanager.h:13
Uptane::HardwareIdentifier
Definition: tuf.h:143
Config
Configuration object for an aktualizr instance running on a primary ECU.
Definition: config.h:74
TemporaryDirectory
Definition: utils.h:82
Initializer
Definition: initializer.h:13
Uptane
Base data types that are used in The Update Framework (TUF), part of UPTANE.
Definition: secondary_tcp_server.h:8