1 #include "uptane/managedsecondary.h" 3 #include <boost/algorithm/hex.hpp> 4 #include <boost/filesystem.hpp> 6 #include "crypto/crypto.h" 7 #include "logging/logging.h" 11 ManagedSecondary::ManagedSecondary(
const SecondaryConfig &sconfig_in) : SecondaryInterface(sconfig_in) {
12 boost::filesystem::create_directories(sconfig.metadata_path);
16 std::string public_key_string;
18 if (!loadKeys(&public_key_string, &private_key)) {
19 if (!Crypto::generateKeyPair(sconfig.key_type, &public_key_string, &private_key)) {
20 LOG_ERROR <<
"Could not generate rsa keys for secondary " << ManagedSecondary::getSerial() <<
"@" 21 << sconfig.ecu_hardware_id;
22 throw std::runtime_error(
"Unable to generate secondary rsa keys");
24 storeKeys(public_key_string, private_key);
26 public_key_ =
PublicKey(public_key_string, sconfig.key_type);
29 void ManagedSecondary::rawToMeta() {
31 current_meta.director_root =
Uptane::Root(RepositoryType::Director, Utils::parseJSON(current_raw_meta.director_root));
32 current_meta.director_targets =
Uptane::Targets(Utils::parseJSON(current_raw_meta.director_targets));
33 current_meta.image_root =
Uptane::Root(RepositoryType::Images, Utils::parseJSON(current_raw_meta.image_root));
34 current_meta.image_targets =
Uptane::Targets(Utils::parseJSON(current_raw_meta.image_targets));
35 current_meta.image_timestamp =
Uptane::TimestampMeta(Utils::parseJSON(current_raw_meta.image_timestamp));
36 current_meta.image_snapshot =
Uptane::Snapshot(Utils::parseJSON(current_raw_meta.image_snapshot));
39 bool ManagedSecondary::putMetadata(
const RawMetaPack &meta_pack) {
43 current_raw_meta = meta_pack;
45 if (!current_meta.isConsistent()) {
48 storeMetadata(current_raw_meta);
50 expected_target_name =
"";
51 expected_target_hashes.clear();
52 expected_target_length = 0;
54 bool target_found =
false;
56 std::vector<Uptane::Target>::const_iterator it;
57 for (it = current_meta.director_targets.targets.begin(); it != current_meta.director_targets.targets.end(); ++it) {
59 if (it->ecus().find(getSerial()) != it->ecus().end()) {
61 detected_attack =
"Duplicate entry for this ECU";
64 expected_target_name = it->filename();
65 expected_target_hashes = it->hashes();
66 expected_target_length = it->length();
72 detected_attack =
"No update for this ECU";
78 int ManagedSecondary::getRootVersion(
const bool director) {
80 return current_meta.director_root.version();
82 return current_meta.image_root.version();
85 bool ManagedSecondary::putRoot(
const std::string &root,
const bool director) {
86 Uptane::Root &prev_root = (director) ? current_meta.director_root : current_meta.image_root;
87 std::string &prev_raw_root = (director) ? current_raw_meta.director_root : current_raw_meta.image_root;
89 Uptane::Root((director) ? RepositoryType::Director : RepositoryType::Images, Utils::parseJSON(root));
92 if (new_root.version() == prev_root.version() + 1) {
96 detected_attack =
"Tried to update root version " + std::to_string(prev_root.version()) +
" with version " +
97 std::to_string(new_root.version());
100 if (!current_meta.isConsistent()) {
103 storeMetadata(current_raw_meta);
107 bool ManagedSecondary::sendFirmwareAsync(
const std::shared_ptr<std::string> &
data) {
108 if (!install_future.valid() || install_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
109 install_future = std::async(std::launch::async, &ManagedSecondary::sendFirmware,
this,
data);
115 bool ManagedSecondary::sendFirmware(
const std::shared_ptr<std::string> &
data) {
116 sendEvent(std::make_shared<event::InstallStarted>(getSerial()));
118 if (expected_target_name.empty()) {
119 sendEvent(std::make_shared<event::InstallComplete>(getSerial()));
122 if (!detected_attack.empty()) {
123 sendEvent(std::make_shared<event::InstallComplete>(getSerial()));
127 if (
data->size() >
static_cast<size_t>(expected_target_length)) {
128 detected_attack =
"overflow";
129 sendEvent(std::make_shared<event::InstallComplete>(getSerial()));
133 std::vector<Hash>::const_iterator it;
134 for (it = expected_target_hashes.begin(); it != expected_target_hashes.end(); it++) {
135 if (it->TypeString() ==
"sha256") {
136 if (boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(*
data))) !=
137 boost::algorithm::to_lower_copy(it->HashString())) {
138 detected_attack =
"wrong_hash";
139 sendEvent(std::make_shared<event::InstallComplete>(getSerial()));
142 }
else if (it->TypeString() ==
"sha512") {
143 if (boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha512digest(*
data))) !=
144 boost::algorithm::to_lower_copy(it->HashString())) {
145 detected_attack =
"wrong_hash";
146 sendEvent(std::make_shared<event::InstallComplete>(getSerial()));
151 detected_attack =
"";
152 bool result = storeFirmware(expected_target_name, *
data);
153 sendEvent(std::make_shared<event::InstallComplete>(getSerial()));
157 Json::Value ManagedSecondary::getManifest() {
159 std::string targetname;
161 if (!getFirmwareInfo(&targetname, target_len, &hash)) {
162 return Json::nullValue;
165 Json::Value manifest;
168 Json::Value installed_image;
169 installed_image[
"filepath"] = targetname;
171 installed_image[
"fileinfo"][
"hashes"][
"sha256"] = hash;
172 installed_image[
"fileinfo"][
"length"] =
static_cast<Json::Int64
>(target_len);
174 manifest[
"attacks_detected"] = detected_attack;
175 manifest[
"installed_image"] = installed_image;
176 manifest[
"ecu_serial"] = getSerial().ToString();
177 manifest[
"previous_timeserver_time"] =
"1970-01-01T00:00:00Z";
178 manifest[
"timeserver_time"] =
"1970-01-01T00:00:00Z";
180 Json::Value signed_ecu_version;
182 std::string b64sig = Utils::toBase64(Crypto::RSAPSSSign(
nullptr, private_key, Json::FastWriter().write(manifest)));
183 Json::Value signature;
184 signature[
"method"] =
"rsassa-pss";
185 signature[
"sig"] = b64sig;
187 signature[
"keyid"] = public_key_.KeyId();
188 signed_ecu_version[
"signed"] = manifest;
189 signed_ecu_version[
"signatures"] = Json::Value(Json::arrayValue);
190 signed_ecu_version[
"signatures"].append(signature);
192 return signed_ecu_version;
195 void ManagedSecondary::storeKeys(
const std::string &pub_key,
const std::string &priv_key) {
196 Utils::writeFile((sconfig.full_client_dir / sconfig.ecu_private_key), priv_key);
197 Utils::writeFile((sconfig.full_client_dir / sconfig.ecu_public_key), pub_key);
200 bool ManagedSecondary::loadKeys(std::string *pub_key, std::string *priv_key) {
201 boost::filesystem::path public_key_path = sconfig.full_client_dir / sconfig.ecu_public_key;
202 boost::filesystem::path private_key_path = sconfig.full_client_dir / sconfig.ecu_private_key;
204 if (!boost::filesystem::exists(public_key_path) || !boost::filesystem::exists(private_key_path)) {
208 *priv_key = Utils::readFile(private_key_path.string());
209 *pub_key = Utils::readFile(public_key_path.string());
Base data types that are used in The Update Framework (TUF), part of UPTANE.