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