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