Aktualizr
C++ SOTA Client
metawithkeys.cc
1 #include "logging/logging.h"
2 #include "uptane/exceptions.h"
3 #include "uptane/tuf.h"
4 
6 
7 MetaWithKeys::MetaWithKeys(const Json::Value &json) : BaseMeta(json) {}
8 MetaWithKeys::MetaWithKeys(RepositoryType repo, const Role &role, const Json::Value &json,
9  const std::shared_ptr<MetaWithKeys> &signer)
10  : BaseMeta(repo, role, json, signer) {}
11 
12 void Uptane::MetaWithKeys::ParseKeys(const RepositoryType repo, const Json::Value &keys) {
13  for (auto it = keys.begin(); it != keys.end(); ++it) {
14  const std::string key_type = boost::algorithm::to_lower_copy((*it)["keytype"].asString());
15  if (key_type != "rsa" && key_type != "ed25519") {
16  throw SecurityException(repo, "Unsupported key type: " + (*it)["keytype"].asString());
17  }
18  const KeyId keyid = it.key().asString();
19  PublicKey key(*it);
20  keys_[keyid] = key;
21  }
22 }
23 
24 void Uptane::MetaWithKeys::ParseRole(const RepositoryType repo, const Json::ValueConstIterator &it, const Role &role,
25  const std::string &meta_role) {
26  if (role == Role::InvalidRole()) {
27  LOG_WARNING << "Invalid role in " << meta_role << ".json";
28  LOG_TRACE << "Role name:" << role.ToString();
29  return;
30  }
31  // Threshold
32  const int64_t requiredThreshold = (*it)["threshold"].asInt64();
33  if (requiredThreshold < kMinSignatures) {
34  // static_cast<int64_t> is to stop << taking a reference to kMinSignatures
35  // http://www.stroustrup.com/bs_faq2.html#in-class
36  // this occurs in Boost 1.62 (and possibly other versions)
37  LOG_DEBUG << "Failing with threshold for role " << role << " too small: " << requiredThreshold << " < "
38  << static_cast<int64_t>(kMinSignatures);
39  throw IllegalThreshold(repo, "The role " + role.ToString() + " had an illegal signature threshold.");
40  }
41  if (kMaxSignatures < requiredThreshold) {
42  // static_cast<int> is to stop << taking a reference to kMaxSignatures
43  // http://www.stroustrup.com/bs_faq2.html#in-class
44  // this occurs in Boost 1.62 (and possibly other versions)
45  LOG_DEBUG << "Failing with threshold for role " << role << " too large: " << static_cast<int>(kMaxSignatures)
46  << " < " << requiredThreshold;
47  throw IllegalThreshold(repo, meta_role + ".json contains a role that requires too many signatures");
48  }
49  thresholds_for_role_[role] = requiredThreshold;
50 
51  // KeyIds
52  const Json::Value keyids = (*it)["keyids"];
53  for (auto itk = keyids.begin(); itk != keyids.end(); ++itk) {
54  keys_for_role_.insert(std::make_pair(role, (*itk).asString()));
55  }
56 }
57 
59  const Json::Value &signed_object) {
60  const std::string repository = repo;
61 
62  const Uptane::Role type(signed_object["signed"]["_type"].asString());
63  if (role.IsDelegation()) {
64  if (type != Uptane::Role::Targets()) {
65  LOG_ERROR << "Delegated role " << role << " has an invalid type: " << type;
66  throw SecurityException(repo, "Delegated role " + role.ToString() + " has invalid type " + type.ToString());
67  }
68  } else if (role != type) {
69  LOG_ERROR << "Metadata type " << type << " does not match expected role: " << role;
70  throw SecurityException(repo,
71  "Metadata type " + type.ToString() + " does not match expected role " + role.ToString());
72  }
73 
74  const std::string canonical = Utils::jsonToCanonicalStr(signed_object["signed"]);
75  const Json::Value signatures = signed_object["signatures"];
76  int valid_signatures = 0;
77 
78  std::set<std::string> used_keyids;
79  for (auto sig = signatures.begin(); sig != signatures.end(); ++sig) {
80  const std::string keyid = (*sig)["keyid"].asString();
81  if (used_keyids.count(keyid) != 0) {
82  throw NonUniqueSignatures(repository, role.ToString());
83  }
84  used_keyids.insert(keyid);
85 
86  std::string method((*sig)["method"].asString());
87  std::transform(method.begin(), method.end(), method.begin(), ::tolower);
88 
89  if (method != "rsassa-pss" && method != "rsassa-pss-sha256" && method != "ed25519") {
90  throw SecurityException(repository, std::string("Unsupported sign method: ") + (*sig)["method"].asString());
91  }
92 
93  if (keys_.count(keyid) == 0U) {
94  LOG_DEBUG << "Signed by unknown KeyId: " << keyid << ". Skipping.";
95  continue;
96  }
97 
98  if (keys_for_role_.count(std::make_pair(role, keyid)) == 0U) {
99  LOG_WARNING << "KeyId " << keyid << " is not valid to sign for this role (" << role.ToString() << ").";
100  continue;
101  }
102  const std::string signature = (*sig)["sig"].asString();
103  if (keys_[keyid].VerifySignature(signature, canonical)) {
104  valid_signatures++;
105  } else {
106  LOG_WARNING << "Signature was present but invalid: " << signature << " with KeyId: " << keyid;
107  }
108  }
109  const int64_t threshold = thresholds_for_role_[role];
110  if (threshold < kMinSignatures || kMaxSignatures < threshold) {
111  throw IllegalThreshold(repository, "Invalid signature threshold");
112  }
113  // One signature and it is bad: throw bad key ID.
114  // Multiple signatures but not enough good ones to pass threshold: throw unmet threshold.
115  if (signatures.size() == 1 && valid_signatures == 0) {
116  throw BadKeyId(repository);
117  }
118  if (valid_signatures < threshold) {
119  throw UnmetThreshold(repository, role.ToString());
120  }
121 }
Uptane::UnmetThreshold
Definition: exceptions.h:67
Uptane::NonUniqueSignatures
Definition: exceptions.h:95
Uptane::MetaWithKeys::MetaWithKeys
MetaWithKeys()
An empty metadata object that could contain keys.
Definition: tuf.h:167
Uptane::RepositoryType
Definition: tuf.h:21
Uptane::BaseMeta
Definition: tuf.h:140
Uptane::MetaWithKeys
Definition: tuf.h:161
PublicKey
Definition: types.h:119
Uptane::IllegalThreshold
Definition: exceptions.h:55
Uptane::BadKeyId
Definition: exceptions.h:102
Uptane::Role
TUF Roles.
Definition: tuf.h:61
Uptane::MetaWithKeys::UnpackSignedObject
virtual void UnpackSignedObject(RepositoryType repo, const Role &role, const Json::Value &signed_object)
Take a JSON blob that contains a signatures/signed component that is supposedly for a given role,...
Definition: metawithkeys.cc:58
Uptane::SecurityException
Definition: exceptions.h:28