Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 1 | /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */ |
| 2 | /* |
| 3 | * Copyright (c) 2013, Regents of the University of California |
| 4 | * Yingdi Yu |
| 5 | * |
| 6 | * BSD license, See the LICENSE file for more information |
| 7 | * |
| 8 | * Author: Yingdi Yu <yingdi@cs.ucla.edu> |
| 9 | */ |
| 10 | |
| 11 | #include "sync-validator.h" |
| 12 | #include "sync-logging.h" |
| 13 | #include <ndn-cpp-dev/security/certificate-cache-ttl.hpp> |
| 14 | #include <queue> |
| 15 | |
| 16 | using namespace ndn; |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 17 | |
| 18 | INIT_LOGGER ("SyncValidator"); |
| 19 | |
| 20 | namespace Sync { |
| 21 | |
Yingdi Yu | 68bc51a | 2014-03-25 16:02:12 -0700 | [diff] [blame^] | 22 | using ndn::shared_ptr; |
| 23 | |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 24 | const shared_ptr<CertificateCache> SyncValidator::DefaultCertificateCache = shared_ptr<CertificateCache>(); |
| 25 | const shared_ptr<SecRuleRelative> SyncValidator::DefaultDataRule = shared_ptr<SecRuleRelative>(); |
| 26 | |
| 27 | SyncValidator::SyncValidator(const Name& prefix, |
| 28 | const IdentityCertificate& anchor, |
| 29 | shared_ptr<Face> face, |
Yingdi Yu | 3da10fe | 2014-02-27 16:37:34 -0800 | [diff] [blame] | 30 | const PublishCertCallback& publishCertCallback, |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 31 | shared_ptr<SecRuleRelative> rule, |
| 32 | shared_ptr<CertificateCache> certificateCache, |
| 33 | const int stepLimit) |
| 34 | : Validator(face) |
| 35 | , m_prefix(prefix) |
| 36 | , m_anchor(anchor) |
| 37 | , m_stepLimit(stepLimit) |
| 38 | , m_certificateCache(certificateCache) |
Yingdi Yu | 3da10fe | 2014-02-27 16:37:34 -0800 | [diff] [blame] | 39 | , m_publishCertCallback(publishCertCallback) |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 40 | , m_dataRule(rule) |
| 41 | { |
| 42 | if(!static_cast<bool>(face)) |
| 43 | throw Error("Face is not set!"); |
| 44 | |
| 45 | if(!static_cast<bool>(m_certificateCache)) |
| 46 | m_certificateCache = make_shared<CertificateCacheTtl>(m_face->ioService()); |
| 47 | |
| 48 | Name certPrefix = prefix; |
Yingdi Yu | 3da10fe | 2014-02-27 16:37:34 -0800 | [diff] [blame] | 49 | certPrefix.append("CHRONOS-INTRO-CERT"); |
| 50 | m_prefixId = m_face->setInterestFilter(certPrefix, |
| 51 | bind(&SyncValidator::onCertInterest, this, _1, _2), |
| 52 | bind(&SyncValidator::onCertRegisterFailed, this, _1, _2)); |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 53 | |
| 54 | setAnchor(m_anchor); |
| 55 | } |
| 56 | |
| 57 | void |
| 58 | SyncValidator::deriveTrustNodes() |
| 59 | { |
Yingdi Yu | 68bc51a | 2014-03-25 16:02:12 -0700 | [diff] [blame^] | 60 | std::queue<Name> nodeQueue; |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 61 | |
| 62 | // Clear existing trust nodes. |
| 63 | m_trustedNodes.clear(); |
| 64 | |
| 65 | // Add the trust anchor. |
| 66 | IntroNode origin(m_anchor); |
| 67 | m_trustedNodes[origin.name()] = m_anchor.getPublicKeyInfo(); |
| 68 | nodeQueue.push(origin.name()); |
| 69 | |
| 70 | // BFS trusted nodes. |
| 71 | while(!nodeQueue.empty()) |
| 72 | { |
| 73 | // Get next trusted node to process. |
| 74 | Nodes::const_iterator it = m_introNodes.find(nodeQueue.front()); |
| 75 | const PublicKey& publicKey = m_trustedNodes[nodeQueue.front()]; |
| 76 | |
| 77 | if(it != m_introNodes.end()) |
| 78 | { |
| 79 | // If the trusted node exists in the graph. |
| 80 | IntroNode::const_iterator eeIt = it->second.introduceeBegin(); |
| 81 | IntroNode::const_iterator eeEnd = it->second.introduceeEnd(); |
| 82 | for(; eeIt != eeEnd; eeIt++) |
| 83 | { |
| 84 | // Check the nodes introduced by the trusted node. |
| 85 | Edges::const_iterator edgeIt = m_introCerts.find(*eeIt); |
| 86 | if(edgeIt != m_introCerts.end() |
Yingdi Yu | 3da10fe | 2014-02-27 16:37:34 -0800 | [diff] [blame] | 87 | && m_trustedNodes.find(edgeIt->second.getIntroduceeCertName()) == m_trustedNodes.end() |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 88 | && verifySignature(edgeIt->second, publicKey)) |
| 89 | { |
| 90 | // If the introduced node can be validated, add it into trusted node set and the node queue. |
Yingdi Yu | 3da10fe | 2014-02-27 16:37:34 -0800 | [diff] [blame] | 91 | m_trustedNodes[edgeIt->second.getIntroduceeCertName()] = edgeIt->second.getIntroduceeCert().getPublicKeyInfo(); |
| 92 | nodeQueue.push(edgeIt->second.getIntroduceeCertName()); |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 93 | } |
| 94 | } |
| 95 | } |
| 96 | nodeQueue.pop(); |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | void |
| 101 | SyncValidator::checkPolicy (const Data& data, |
| 102 | int stepCount, |
| 103 | const OnDataValidated& onValidated, |
| 104 | const OnDataValidationFailed& onValidationFailed, |
| 105 | std::vector<shared_ptr<ValidationRequest> >& nextSteps) |
| 106 | { |
| 107 | if(m_stepLimit == stepCount) |
| 108 | return onValidationFailed(data.shared_from_this(), |
| 109 | "Maximum steps of validation reached: " + data.getName().toUri()); |
| 110 | |
Yingdi Yu | 3da10fe | 2014-02-27 16:37:34 -0800 | [diff] [blame] | 111 | if(m_prefix.isPrefixOf(data.getName()) || (static_cast<bool>(m_dataRule) && m_dataRule->satisfy(data))) |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 112 | { |
| 113 | try |
| 114 | { |
| 115 | SignatureSha256WithRsa sig(data.getSignature()); |
| 116 | Name keyLocatorName = sig.getKeyLocator().getName(); |
| 117 | |
| 118 | TrustNodes::const_iterator it = m_trustedNodes.find(keyLocatorName); |
| 119 | if(m_trustedNodes.end() != it) |
| 120 | { |
| 121 | if(verifySignature(data, sig, it->second)) |
| 122 | return onValidated(data.shared_from_this()); |
| 123 | else |
| 124 | return onValidationFailed(data.shared_from_this(), |
| 125 | "Cannot verify signature: " + data.getName().toUri()); |
| 126 | } |
| 127 | else |
| 128 | { |
Yingdi Yu | 3da10fe | 2014-02-27 16:37:34 -0800 | [diff] [blame] | 129 | _LOG_DEBUG("I am: " << m_anchor.getName().get(0).toEscapedString() << " for " << data.getName()); |
| 130 | |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 131 | Name interestName = m_prefix; |
Yingdi Yu | 3da10fe | 2014-02-27 16:37:34 -0800 | [diff] [blame] | 132 | interestName.append("CHRONOS-INTRO-CERT").append(keyLocatorName.wireEncode()); |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 133 | Interest interest(interestName); |
Yingdi Yu | 6e1c9cd | 2014-03-25 10:26:54 -0700 | [diff] [blame] | 134 | interest.setInterestLifetime(time::milliseconds(500)); |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 135 | |
| 136 | OnDataValidated onKeyValidated = bind(&SyncValidator::onCertificateValidated, this, |
| 137 | _1, data.shared_from_this(), onValidated, onValidationFailed); |
| 138 | |
| 139 | OnDataValidationFailed onKeyValidationFailed = bind(&SyncValidator::onCertificateValidationFailed, this, |
| 140 | _1, _2, data.shared_from_this(), onValidationFailed); |
| 141 | |
| 142 | shared_ptr<ValidationRequest> nextStep = make_shared<ValidationRequest>(interest, |
| 143 | onKeyValidated, |
| 144 | onKeyValidationFailed, |
| 145 | 1, |
| 146 | stepCount + 1); |
| 147 | nextSteps.push_back(nextStep); |
| 148 | |
| 149 | return; |
| 150 | } |
| 151 | } |
| 152 | catch(SignatureSha256WithRsa::Error& e) |
| 153 | { |
| 154 | return onValidationFailed(data.shared_from_this(), |
Yingdi Yu | 68bc51a | 2014-03-25 16:02:12 -0700 | [diff] [blame^] | 155 | "Not SignatureSha256WithRsa signature: " + std::string(e.what())); |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 156 | } |
| 157 | catch(KeyLocator::Error& e) |
| 158 | { |
| 159 | return onValidationFailed(data.shared_from_this(), |
| 160 | "Key Locator is not a name: " + data.getName().toUri()); |
| 161 | } |
| 162 | } |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 163 | else |
| 164 | return onValidationFailed(data.shared_from_this(), |
Yingdi Yu | 3da10fe | 2014-02-27 16:37:34 -0800 | [diff] [blame] | 165 | "No rule or rule is not satisfied: " + data.getName().toUri()); |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | void |
| 169 | SyncValidator::checkPolicy (const Interest& interest, |
| 170 | int stepCount, |
| 171 | const OnInterestValidated& onValidated, |
| 172 | const OnInterestValidationFailed& onValidationFailed, |
| 173 | std::vector<shared_ptr<ValidationRequest> >& nextSteps) |
| 174 | { |
| 175 | onValidationFailed(interest.shared_from_this(), "No policy for signed interest checking"); |
| 176 | } |
| 177 | |
| 178 | void |
| 179 | SyncValidator::onCertificateValidated(const shared_ptr<const Data>& signCertificate, |
| 180 | const shared_ptr<const Data>& data, |
| 181 | const OnDataValidated& onValidated, |
| 182 | const OnDataValidationFailed& onValidationFailed) |
| 183 | { |
| 184 | try |
| 185 | { |
| 186 | IntroCertificate introCert(*signCertificate); |
| 187 | addParticipant(introCert); |
| 188 | |
| 189 | if(verifySignature(*data, introCert.getIntroduceeCert().getPublicKeyInfo())) |
| 190 | return onValidated(data); |
| 191 | else |
| 192 | return onValidationFailed(data, |
| 193 | "Cannot verify signature: " + data->getName().toUri()); |
| 194 | } |
| 195 | catch(IntroCertificate::Error& e) |
| 196 | { |
| 197 | return onValidationFailed(data, |
Yingdi Yu | 68bc51a | 2014-03-25 16:02:12 -0700 | [diff] [blame^] | 198 | "Intro cert decoding error: " + std::string(e.what())); |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 199 | } |
| 200 | } |
| 201 | |
| 202 | void |
| 203 | SyncValidator::onCertificateValidationFailed(const shared_ptr<const Data>& signCertificate, |
Yingdi Yu | 68bc51a | 2014-03-25 16:02:12 -0700 | [diff] [blame^] | 204 | const std::string& failureInfo, |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 205 | const shared_ptr<const Data>& data, |
| 206 | const OnDataValidationFailed& onValidationFailed) |
| 207 | { |
| 208 | onValidationFailed(data, failureInfo); |
| 209 | } |
| 210 | |
| 211 | void |
| 212 | SyncValidator::onCertInterest(const Name& prefix, const Interest& interest) |
| 213 | { |
| 214 | Name name = interest.getName(); |
| 215 | Edges::const_iterator it = m_introCerts.begin(); |
| 216 | for(; it != m_introCerts.end(); it++) |
| 217 | { |
| 218 | if(name.isPrefixOf(it->first)) |
| 219 | { |
| 220 | m_face->put(it->second); |
| 221 | return; |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | void |
Yingdi Yu | 68bc51a | 2014-03-25 16:02:12 -0700 | [diff] [blame^] | 227 | SyncValidator::onCertRegisterFailed(const Name& prefix, const std::string& msg) |
Yingdi Yu | 0eee600 | 2014-02-11 15:54:17 -0800 | [diff] [blame] | 228 | { |
| 229 | _LOG_DEBUG("SyncValidator::onCertRegisterFailed: " << msg); |
| 230 | } |
| 231 | |
| 232 | } // namespace Sync |