2 #include "logging/logging.h" 3 #include "uptane/exceptions.h" 4 #include "uptane/tuf.h" 8 Root::Root(RepositoryType repo,
const Json::Value &json,
Root &root) :
Root(repo, json) {
10 this->UnpackSignedObject(repo, json);
14 if (!json.isObject() || !json.isMember(
"signed")) {
18 version_ = json[
"signed"][
"version"].asInt();
21 original_object_ = json;
23 if (!json.isObject() || !json[
"signed"].isMember(
"keys") || !json[
"signed"].isMember(
"roles")) {
24 throw InvalidMetadata(RepoString(repo),
"root",
"missing keys/roles field");
27 Json::Value keys = json[
"signed"][
"keys"];
28 for (Json::ValueIterator it = keys.begin(); it != keys.end(); ++it) {
29 std::string key_type = boost::algorithm::to_lower_copy((*it)[
"keytype"].asString());
30 if (key_type !=
"rsa" && key_type !=
"ed25519") {
31 throw SecurityException(RepoString(repo),
"Unsupported key type: " + (*it)[
"keytype"].asString());
33 KeyId keyid = it.key().asString();
38 Json::Value roles = json[
"signed"][
"roles"];
39 for (Json::ValueIterator it = roles.begin(); it != roles.end(); it++) {
40 std::string role_name = it.key().asString();
42 if (role == Role::InvalidRole()) {
43 LOG_WARNING <<
"Invalid role in root.json";
44 LOG_TRACE <<
"Role name:" << role_name;
45 LOG_TRACE <<
"root.json is:" << json;
49 int64_t requiredThreshold = (*it)[
"threshold"].asInt64();
50 if (requiredThreshold < kMinSignatures) {
54 LOG_DEBUG <<
"Failing with threshold for role " << role <<
" too small: " << requiredThreshold <<
" < " 55 <<
static_cast<int64_t
>(kMinSignatures);
56 throw IllegalThreshold(RepoString(repo),
"The role " + role_name +
" had an illegal signature threshold.");
58 if (kMaxSignatures < requiredThreshold) {
62 LOG_DEBUG <<
"Failing with threshold for role " << role <<
" too large: " <<
static_cast<int>(kMaxSignatures)
63 <<
" < " << requiredThreshold;
64 throw IllegalThreshold(RepoString(repo),
"root.json contains a role that requires too many signatures");
66 thresholds_for_role_[role] = requiredThreshold;
69 Json::Value keyids = (*it)[
"keyids"];
70 for (Json::ValueIterator itk = keyids.begin(); itk != keyids.end(); ++itk) {
71 keys_for_role_.insert(std::make_pair(role, (*itk).asString()));
77 std::string repository = RepoString(repo);
79 Uptane::Role role(signed_object[
"signed"][
"_type"].asString());
80 if (policy_ == Policy::kAcceptAll) {
83 if (policy_ == Policy::kRejectAll) {
86 assert(policy_ == Policy::kCheck);
88 std::string canonical = Json::FastWriter().write(signed_object[
"signed"]);
89 Json::Value signatures = signed_object[
"signatures"];
90 int valid_signatures = 0;
92 std::set<std::string> used_keyids;
93 for (Json::ValueIterator sig = signatures.begin(); sig != signatures.end(); ++sig) {
94 std::string keyid = (*sig)[
"keyid"].asString();
95 if (used_keyids.count(keyid) != 0) {
98 used_keyids.insert(keyid);
100 std::string method((*sig)[
"method"].asString());
101 std::transform(method.begin(), method.end(), method.begin(), ::tolower);
103 if (method !=
"rsassa-pss" && method !=
"rsassa-pss-sha256" && method !=
"ed25519") {
104 throw SecurityException(repository, std::string(
"Unsupported sign method: ") + (*sig)[
"method"].asString());
107 if (keys_.count(keyid) == 0u) {
108 LOG_DEBUG <<
"Signed by unknown KeyId: " << keyid <<
". Skipping.";
112 if (keys_for_role_.count(std::make_pair(role, keyid)) == 0u) {
113 LOG_WARNING <<
"KeyId " << keyid <<
" is not valid to sign for this role (" << role.ToString() <<
").";
116 std::string signature = (*sig)[
"sig"].asString();
117 if (keys_[keyid].VerifySignature(signature, canonical)) {
120 LOG_WARNING <<
"Signature was present but invalid: " << signature <<
" with KeyId: " << keyid;
123 int64_t threshold = thresholds_for_role_[role];
124 if (threshold < kMinSignatures || kMaxSignatures < threshold) {
129 if (signatures.size() == 1 && valid_signatures == 0) {
132 if (valid_signatures < threshold) {
137 if (role != actual_role) {
138 LOG_ERROR <<
"Object was signed for a different role";
139 LOG_TRACE <<
" role:" << role;
140 LOG_TRACE <<
" actual_role:" << actual_role;
Root(Policy policy=Policy::kRejectAll)
An empty Root, that either accepts or rejects everything.
RepositoryType
This must match the repo_type table in sqlstorage.
void UnpackSignedObject(RepositoryType repo, const Json::Value &signed_object)
Take a JSON blob that contains a signatures/signed component that is supposedly for a given role...