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