Skip to content

Commit

Permalink
Enable verifying packages signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
Hind-M committed Feb 19, 2024
1 parent a310d31 commit b9a2850
Show file tree
Hide file tree
Showing 22 changed files with 458 additions and 88 deletions.
2 changes: 2 additions & 0 deletions libmamba/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ set(
${LIBMAMBA_SOURCE_DIR}/core/activation.cpp
${LIBMAMBA_SOURCE_DIR}/core/channel_context.cpp
${LIBMAMBA_SOURCE_DIR}/core/context.cpp
${LIBMAMBA_SOURCE_DIR}/core/repo_checker_store.cpp
${LIBMAMBA_SOURCE_DIR}/core/download.cpp
${LIBMAMBA_SOURCE_DIR}/core/download_progress_bar.cpp
${LIBMAMBA_SOURCE_DIR}/core/environments_manager.cpp
Expand Down Expand Up @@ -325,6 +326,7 @@ set(
${LIBMAMBA_INCLUDE_DIR}/mamba/core/channel_context.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/palette.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/context.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/repo_checker_store.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/download.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/download_progress_bar.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/environments_manager.hpp
Expand Down
8 changes: 8 additions & 0 deletions libmamba/include/mamba/core/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ namespace mamba
VerificationLevel safety_checks = VerificationLevel::Warn;
bool extra_safety_checks = false;
bool verify_artifacts = false;
// Leave this empty?
// Need to populate from server? from config?.... to think about it (TODO)
// if we just specify "channel0" it becomes "https://conda.anaconda.org/channel0" ...
// TODO test with multiple channels in there and check behavior: like uncommenting
// conda-forge as first channel
std::vector<std::string> trusted_channels = {
/*"conda-forge", */ "http://127.0.0.1:8000/get/channel0"
};
};


Expand Down
46 changes: 46 additions & 0 deletions libmamba/include/mamba/core/repo_checker_store.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2024, QuantStack and Mamba Contributors
//
// Distributed under the terms of the BSD 3-Clause License.
//
// The full license is in the file LICENSE, distributed with this software.

#ifndef MAMBA_CORE_REPO_CHECKER_STORE_HPP
#define MAMBA_CORE_REPO_CHECKER_STORE_HPP

#include <utility>
#include <vector>

#include "mamba/specs/channel.hpp"
#include "mamba/validation/repo_checker.hpp"

namespace mamba
{
class Context;
class ChannelContext;
class MultiPackageCache;

class RepoCheckerStore
{
public:

using Channel = specs::Channel;
using RepoChecker = validation::RepoChecker;
using repo_checker_list = std::vector<std::pair<Channel, RepoChecker>>;

[[nodiscard]] static auto
make(const Context& ctx, ChannelContext& cc, MultiPackageCache& caches) -> RepoCheckerStore;

explicit RepoCheckerStore(repo_checker_list checkers);

[[nodiscard]] auto find_checker(const Channel& chan) const -> const RepoChecker*;

[[nodiscard]] auto contains_checker(const Channel& chan) const -> bool;

[[nodiscard]] auto at_checker(const Channel& chan) const -> const RepoChecker&;

private:

repo_checker_list m_repo_checkers = {};
};
}
#endif
11 changes: 11 additions & 0 deletions libmamba/include/mamba/validation/errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,5 +142,16 @@ namespace mamba::validation
index_error();
~index_error() override = default;
};

/**
* Error raised when the given signatures of a package are empty/invalid.
*/
class signatures_error : public trust_error
{
public:

signatures_error();
~signatures_error() override = default;
};
}
#endif
21 changes: 16 additions & 5 deletions libmamba/include/mamba/validation/repo_checker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <memory>
#include <string>
#include <string_view>

#include <nlohmann/json_fwd.hpp>

Expand Down Expand Up @@ -41,14 +42,23 @@ namespace mamba::validation
* @param ref_path Path to the reference directory, hosting trusted root metadata
* @param cache_path Path to the cache directory
*/
RepoChecker(Context& context, std::string base_url, fs::u8path ref_path, fs::u8path cache_path = "");
RepoChecker(
const Context& context,
std::string base_url,
fs::u8path ref_path,
fs::u8path cache_path = ""
);
RepoChecker(RepoChecker&&) noexcept;
~RepoChecker();

auto operator=(RepoChecker&&) noexcept -> RepoChecker&;

// Forwarding to a ``RepoIndexChecker`` implementation
void verify_index(const nlohmann::json& j) const;
void verify_index(const fs::u8path& p) const;
void
verify_package(const nlohmann::json& signed_data, const nlohmann::json& signatures) const;
void verify_package(const nlohmann::json& signed_data, std::string_view signatures) const;

void generate_index_checker();

Expand All @@ -58,20 +68,21 @@ namespace mamba::validation

private:

std::unique_ptr<RepoIndexChecker> p_index_checker;
std::reference_wrapper<const Context> m_context;

std::string m_base_url;
std::size_t m_root_version = 0;
fs::u8path m_ref_path;
fs::u8path m_cache_path;
Context& m_context;

std::size_t m_root_version;

auto initial_trusted_root() -> fs::u8path;
auto ref_root() -> fs::u8path;
auto cached_root() -> fs::u8path;

void persist_file(const fs::u8path& file_path);

std::unique_ptr<RepoIndexChecker> p_index_checker;

auto get_root_role(const TimeRef& time_reference) -> std::unique_ptr<RootRole>;
};
}
Expand Down
2 changes: 1 addition & 1 deletion libmamba/include/mamba/validation/update_framework.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ namespace mamba::validation
auto possible_update_files() -> std::vector<fs::u8path>;

virtual auto build_index_checker(
Context& context,
const Context& context,
const TimeRef& time_reference,
const std::string& url,
const fs::u8path& cache_path
Expand Down
4 changes: 2 additions & 2 deletions libmamba/include/mamba/validation/update_framework_v0_6.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ namespace mamba::validation::v0_6
* Return a ``RepoIndexChecker`` implementation (derived class) from repository base URL.
*/
auto build_index_checker(
Context& context,
const Context& context,
const TimeRef& time_reference,
const std::string& url,
const fs::u8path& cache_path
Expand Down Expand Up @@ -131,7 +131,7 @@ namespace mamba::validation::v0_6
* Return a ``RepoIndexChecker`` implementation (derived class) from repository base URL.
*/
auto build_index_checker(
Context& context,
const Context& context,
const TimeRef& time_reference,
const std::string& url,
const fs::u8path& cache_path
Expand Down
2 changes: 1 addition & 1 deletion libmamba/include/mamba/validation/update_framework_v1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ namespace mamba::validation::v1
[[nodiscard]] auto self_keys() const -> RoleFullKeys override;

auto build_index_checker(
Context& context,
const Context& context,
const TimeRef& time_reference,
const std::string& url,
const fs::u8path& cache_path
Expand Down
9 changes: 7 additions & 2 deletions libmamba/src/api/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1224,9 +1224,14 @@ namespace mamba

insert(Configurable("experimental_repodata_parsing", &m_context.experimental_repodata_parsing)
.group("Basic")
.description("Enable experimental parsing of repodata.json using nl::json")
.description( //
"Enable experimental parsing of `repodata.json` using simdjson.\n"
"Default is `true`. `false` means libsolv is used.\n"
"This feature may be still under active development and not stable yet.\n"
)
.set_rc_configurable()
.set_env_var_names());
.set_env_var_names()
.set_post_merge_hook(detail::experimental_hook));

insert(Configurable("debug", &m_context.debug)
.group("Basic")
Expand Down
10 changes: 8 additions & 2 deletions libmamba/src/core/pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,16 @@ namespace mamba
repo,
path,
std::string(url),
context().use_only_tar_bz2
context().use_only_tar_bz2,
context().validation_params.verify_artifacts
);
}
return solver::libsolv::libsolv_read_json(repo, path, context().use_only_tar_bz2)
return solver::libsolv::libsolv_read_json(
repo,
path,
context().use_only_tar_bz2,
context().validation_params.verify_artifacts
)
.transform(
[&url](solv::ObjRepoView repo)
{
Expand Down
83 changes: 83 additions & 0 deletions libmamba/src/core/repo_checker_store.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) 2024, QuantStack and Mamba Contributors
//
// Distributed under the terms of the BSD 3-Clause License.
//
// The full license is in the file LICENSE, distributed with this software.

#include "mamba/core/channel_context.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/package_cache.hpp"
#include "mamba/core/repo_checker_store.hpp"
#include "mamba/core/subdirdata.hpp"

namespace mamba
{

auto RepoCheckerStore::make(const Context& ctx, ChannelContext& cc, MultiPackageCache& caches)
-> RepoCheckerStore
{
if (!ctx.validation_params.verify_artifacts)
{
return RepoCheckerStore({});
}

auto repo_checkers = repo_checker_list();
repo_checkers.reserve(ctx.validation_params.trusted_channels.size());
for (const auto& location : ctx.validation_params.trusted_channels)
{
for (auto& chan : cc.make_channel(location))
{
// Parametrization
auto url = chan.url().str(specs::CondaURL::Credentials::Show);
auto url_id = cache_name_from_url(url);
// TODO make these configurable?
auto ref_path = ctx.prefix_params.root_prefix / "etc" / "trusted-repos" / url_id;
auto cache_path = caches.first_writable_path() / "cache" / url_id;

LOG_INFO << "Creating RepoChecker with base_url: " << url
<< ", ref_path: " << ref_path << ", and cache_path: " << cache_path;

auto checker = RepoChecker(ctx, std::move(url), std::move(ref_path), cache_path);

// Initialization
fs::create_directories(checker.cache_path());
checker.generate_index_checker();

repo_checkers.emplace_back(std::move(chan), std::move(checker));
}
}
return RepoCheckerStore(std::move(repo_checkers));
}

RepoCheckerStore::RepoCheckerStore(repo_checker_list checkers)
: m_repo_checkers(std::move(checkers))
{
}

auto RepoCheckerStore::find_checker(const Channel& chan) const -> const RepoChecker*
{
for (auto& [candidate_chan, checker] : m_repo_checkers)
{
if (candidate_chan.contains_equivalent(chan))
{
return &checker;
}
}
return nullptr;
}

auto RepoCheckerStore::contains_checker(const Channel& chan) const -> bool
{
return find_checker(chan) != nullptr;
}

auto RepoCheckerStore::at_checker(const Channel& chan) const -> const RepoChecker&
{
if (auto ptr = find_checker(chan))
{
return *ptr;
}
throw std::range_error("Checker not found");
}
}
Loading

0 comments on commit b9a2850

Please sign in to comment.