Skip to content

Commit

Permalink
Merge pull request #1408 from adriendelsalle/get-pkg-mgr
Browse files Browse the repository at this point in the history
Generate `PkgMgr` TUF role from file
  • Loading branch information
wolfv authored Jan 28, 2022
2 parents abe9e61 + 74337f0 commit 32e5056
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 13 deletions.
3 changes: 2 additions & 1 deletion libmamba/include/mamba/api/configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -958,7 +958,8 @@ namespace mamba
template <class T>
auto Configurable<T>::set_default_value(const T& value) -> self_type&
{
m_value = m_default_value;
m_default_value = value;
m_value = value;
return *this;
};

Expand Down
3 changes: 2 additions & 1 deletion libmamba/include/mamba/core/validate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,8 @@ namespace validate
// std::set<std::string> roles() const override;
RoleFullKeys self_keys() const override;

PkgMgrRole create_pkg_mgr() const;
PkgMgrRole create_pkg_mgr(const fs::path& p) const;
PkgMgrRole create_pkg_mgr(const json& j) const;

/**
* Return a ``RepoIndexChecker`` implementation (derived class)
Expand Down
66 changes: 59 additions & 7 deletions libmamba/src/core/validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1380,7 +1380,7 @@ namespace validate

if ((result == CURLE_OK) && dl_target->finalize())
{
KeyMgrRole key_mgr(tmp_metadata_path, all_keys()["key_mgr"], spec_impl());
KeyMgrRole key_mgr = create_key_mgr(tmp_metadata_path);

// TUF spec 5.6.5 - Check for a freeze attack
// 'key_mgr' (equivalent of 'targets') role should not be expired
Expand All @@ -1407,7 +1407,7 @@ namespace validate
// Fallback to local cached-copy if existing
if (fs::exists(metadata_path))
{
KeyMgrRole key_mgr(metadata_path, all_keys()["key_mgr"], spec_impl());
KeyMgrRole key_mgr = create_key_mgr(metadata_path);
return key_mgr.build_index_checker(base_url, cache_path);
}

Expand Down Expand Up @@ -1504,16 +1504,68 @@ namespace validate
return m_keys;
}

PkgMgrRole KeyMgrRole::create_pkg_mgr() const
PkgMgrRole KeyMgrRole::create_pkg_mgr(const fs::path& p) const
{
return PkgMgrRole(all_keys().at("pkg_mgr"), spec_impl());
return PkgMgrRole(p, all_keys()["pkg_mgr"], spec_impl());
}

PkgMgrRole KeyMgrRole::create_pkg_mgr(const json& j) const
{
return PkgMgrRole(j, all_keys()["pkg_mgr"], spec_impl());
}

std::unique_ptr<RepoIndexChecker> KeyMgrRole::build_index_checker(
const std::string& url, const fs::path& cache_path) const
const std::string& base_url, const fs::path& cache_path) const
{
auto pkg_mgr = std::make_unique<PkgMgrRole>(create_pkg_mgr());
return pkg_mgr;
fs::path metadata_path = cache_path / "pkg_mgr.json";

auto tmp_dir = std::make_unique<mamba::TemporaryDirectory>();
auto tmp_metadata_path = tmp_dir->path() / "pkg_mgr.json";

mamba::URLHandler url(base_url + "/pkg_mgr.json");

auto dl_target = std::make_unique<mamba::DownloadTarget>(
"pkg_mgr.json", url.url(), tmp_metadata_path);

if (dl_target->resource_exists())
{
auto result = curl_easy_perform(dl_target->handle());
dl_target->set_result(result);

if ((result == CURLE_OK) && dl_target->finalize())
{
PkgMgrRole pkg_mgr = create_pkg_mgr(tmp_metadata_path);

// TUF spec 5.6.5 - Check for a freeze attack
// 'pkg_mgr' (equivalent of delegated 'targets') role should not be expired
// https://theupdateframework.github.io/specification/latest/#update-targets
if (pkg_mgr.expired())
{
LOG_ERROR << "Possible freeze attack of 'pkg_mgr' metadata.\nExpired: "
<< pkg_mgr.expires();
throw freeze_error();
}

// TUF spec 5.6.6 - Persist targets metadata
if (!cache_path.empty())
{
if (fs::exists(metadata_path))
fs::remove(metadata_path);
fs::copy(tmp_metadata_path, metadata_path);
}

return std::make_unique<PkgMgrRole>(pkg_mgr);
}
}

// Fallback to local cached-copy if existing
if (fs::exists(metadata_path))
{
return std::make_unique<PkgMgrRole>(create_pkg_mgr(metadata_path));
}

LOG_ERROR << "Error while fetching 'pkg_mgr' metadata";
throw fetching_error();
}

std::set<std::string> KeyMgrRole::mandatory_defined_roles() const
Expand Down
8 changes: 8 additions & 0 deletions libmamba/tests/test_configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ namespace mamba
.at("rc_files")
.get_wrapped<std::vector<fs::path>>()
.set_value({ fs::path(unique_location) });
mamba::Configuration::instance()
.at("show_banner")
.get_wrapped<bool>()
.set_default_value(false);
mamba::Configuration::instance().load();
}

Expand All @@ -59,6 +63,10 @@ namespace mamba
.at("rc_files")
.get_wrapped<std::vector<fs::path>>()
.set_value(sources);
mamba::Configuration::instance()
.at("show_banner")
.get_wrapped<bool>()
.set_default_value(false);
mamba::Configuration::instance().load();
}

Expand Down
72 changes: 68 additions & 4 deletions libmamba/tests/test_validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,7 @@ namespace validate
PkgMgrT_v06()
: KeyMgrT_v06()
{
sign_pkg_mgr();
generate_index_checkerdata();
root = std::make_unique<RootImpl>(root1_json);
};
Expand All @@ -1125,11 +1126,73 @@ namespace validate
return updated_repodata;
}

void sign_pkg_mgr()
{
std::vector<std::string> pkg_mgr_pks;
for (auto& secret : secrets.at("pkg_mgr"))
{
pkg_mgr_pks.push_back(secret.first);
}
pkg_mgr_json["signed"]["delegations"] = json::object();

pkg_mgr_json["signed"]["version"] = 1;
pkg_mgr_json["signed"]["metadata_spec_version"] = "0.6.0";
pkg_mgr_json["signed"]["type"] = "pkg_mgr";

pkg_mgr_json["signed"]["timestamp"] = timestamp(utc_time_now());
pkg_mgr_json["signed"]["expiration"] = timestamp(utc_time_now() + 3600);
pkg_mgr_json["signatures"] = sign_pkg_mgr_meta(pkg_mgr_json["signed"]);
}

json patched_pkg_mgr_json(const json& patch = json())
{
json update_pkg_mgr = pkg_mgr_json;

if (!patch.empty())
update_pkg_mgr = update_pkg_mgr.patch(patch);

json sig_patch = json::parse(
R"([
{ "op": "replace", "path": "/signatures", "value": )"
+ sign_pkg_mgr_meta(update_pkg_mgr.at("signed")).dump() + R"( }
])");
return update_pkg_mgr.patch(sig_patch);
}

fs::path write_pkg_mgr_file(const json& j,
const std::string& filename = "pkg_mgr.json")
{
fs::path p = channel_dir->path() / filename;

std::ofstream out_file(p, std::ofstream::out | std::ofstream::trunc);
out_file << j;
out_file.close();

return p;
}

protected:
json repodata_json, signed_repodata_json;
json pkg_mgr_json, repodata_json, signed_repodata_json;

std::unique_ptr<RootImpl> root;

json sign_pkg_mgr_meta(const json& meta)
{
std::map<std::string, std::map<std::string, std::string>> signatures;

unsigned char sig_bin[MAMBA_ED25519_SIGSIZE_BYTES];

for (auto& secret : secrets.at("pkg_mgr"))
{
sign(meta.dump(2), secret.second.data(), sig_bin);

auto sig_hex = ::mamba::hex_string(sig_bin, MAMBA_ED25519_SIGSIZE_BYTES);
signatures[secret.first].insert({ "signature", sig_hex });
}

return signatures;
}

void generate_index_checkerdata()
{
repodata_json = R"({
Expand Down Expand Up @@ -1182,15 +1245,15 @@ namespace validate
TEST_F(PkgMgrT_v06, verify_index)
{
auto key_mgr = root->create_key_mgr(key_mgr_json);
auto pkg_mgr = key_mgr.create_pkg_mgr();
auto pkg_mgr = key_mgr.create_pkg_mgr(pkg_mgr_json);

pkg_mgr.verify_index(signed_repodata_json);
}

TEST_F(PkgMgrT_v06, corrupted_repodata)
{
auto key_mgr = root->create_key_mgr(key_mgr_json);
auto pkg_mgr = key_mgr.create_pkg_mgr();
auto pkg_mgr = key_mgr.create_pkg_mgr(pkg_mgr_json);

json wrong_pkg_patch = R"([
{ "op": "replace", "path": "/packages/test-package1-0.1-0.tar.bz2/version", "value": "0.1.1" }
Expand All @@ -1202,7 +1265,7 @@ namespace validate
TEST_F(PkgMgrT_v06, illformed_repodata)
{
auto key_mgr = root->create_key_mgr(key_mgr_json);
auto pkg_mgr = key_mgr.create_pkg_mgr();
auto pkg_mgr = key_mgr.create_pkg_mgr(pkg_mgr_json);

json illformed_pkg_patch = R"([
{ "op": "remove", "path": "/signatures"}
Expand All @@ -1229,6 +1292,7 @@ namespace validate
write_role(create_root_update_json(patch), channel_dir->path() / "2.root.json");

write_role(key_mgr_json, channel_dir->path() / "key_mgr.json");
write_role(pkg_mgr_json, channel_dir->path() / "pkg_mgr.json");

spdlog::set_level(spdlog::level::debug);
}
Expand Down

0 comments on commit 32e5056

Please sign in to comment.