| /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */ |
| /* |
| * Copyright (c) 2012-2014 University of California, Los Angeles |
| * |
| * This file is part of ChronoSync, synchronization library for distributed realtime |
| * applications for NDN. |
| * |
| * ChronoSync is free software: you can redistribute it and/or modify it under the terms |
| * of the GNU General Public License as published by the Free Software Foundation, either |
| * version 3 of the License, or (at your option) any later version. |
| * |
| * ChronoSync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; |
| * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
| * PURPOSE. See the GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along with |
| * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>. |
| * |
| * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/web/index.html> |
| */ |
| |
| #ifndef SYNC_VALIDATOR_H |
| #define SYNC_VALIDATOR_H |
| |
| #include "sync-intro-certificate.h" |
| #include <ndn-cxx/security/validator.hpp> |
| #include <ndn-cxx/security/key-chain.hpp> |
| #include <ndn-cxx/security/sec-rule-relative.hpp> |
| #include <ndn-cxx/security/certificate-cache.hpp> |
| #include <map> |
| |
| namespace Sync { |
| |
| class SyncValidator : public ndn::Validator |
| { |
| public: |
| typedef ndn::function< void (const uint8_t*, size_t, int) > PublishCertCallback; |
| |
| struct Error : public ndn::Validator::Error { Error(const std::string &what) : ndn::Validator::Error(what) {} }; |
| |
| static const ndn::shared_ptr<ndn::CertificateCache> DefaultCertificateCache; |
| static const ndn::shared_ptr<ndn::SecRuleRelative> DefaultDataRule; |
| |
| SyncValidator(const ndn::Name& prefix, |
| const ndn::IdentityCertificate& anchor, |
| ndn::Face& face, |
| const PublishCertCallback& publishCertCallback, |
| ndn::shared_ptr<ndn::SecRuleRelative> rule = DefaultDataRule, |
| ndn::shared_ptr<ndn::CertificateCache> certificateCache = DefaultCertificateCache, |
| const int stepLimit = 10); |
| |
| virtual |
| ~SyncValidator() |
| { |
| m_face.unsetInterestFilter(m_prefixId); |
| } |
| |
| /** |
| * @brief Set the trust anchor |
| * |
| * The anchor should be the participant's own certificate. |
| * This anchor node is the origin of the derived trust graph. |
| * Once the new anchor is set, derive the TrustNode set. |
| * |
| * @param anchor. |
| */ |
| inline void |
| setAnchor(const ndn::IdentityCertificate& anchor); |
| |
| /** |
| * @brief Add a node into the trust graph. |
| * |
| * The method also create an edge from trust anchor to the node. |
| * |
| * @param introducee. |
| * @return IntroCertificate for the introducee. |
| */ |
| inline ndn::shared_ptr<const IntroCertificate> |
| addParticipant(const ndn::IdentityCertificate& introducee); |
| |
| /** |
| * @brief Add an edge into the trust graph. |
| * |
| * Create nodes if it is one of the edge's ends and does not exist in the graph. |
| * |
| * @param introCert. |
| */ |
| inline void |
| addParticipant(const IntroCertificate& introCert); |
| |
| inline void |
| getIntroCertNames(std::vector<ndn::Name>& list); |
| |
| inline const IntroCertificate& |
| getIntroCertificate(const ndn::Name& name); |
| |
| #ifdef _TEST |
| bool |
| canTrust(const ndn::Name& certName) |
| { |
| return (m_trustedNodes.find(certName.getPrefix(-1)) != m_trustedNodes.end()); |
| } |
| #endif //_DEBUG |
| |
| protected: |
| /*********************** |
| * From ndn::Validator * |
| ***********************/ |
| virtual void |
| checkPolicy (const ndn::Data& data, |
| int stepCount, |
| const ndn::OnDataValidated& onValidated, |
| const ndn::OnDataValidationFailed& onValidationFailed, |
| std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps); |
| |
| virtual void |
| checkPolicy (const ndn::Interest& interest, |
| int stepCount, |
| const ndn::OnInterestValidated& onValidated, |
| const ndn::OnInterestValidationFailed& onValidationFailed, |
| std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps); |
| private: |
| void |
| deriveTrustNodes(); |
| |
| |
| void |
| onCertificateValidated(const ndn::shared_ptr<const ndn::Data>& signCertificate, |
| const ndn::shared_ptr<const ndn::Data>& data, |
| const ndn::OnDataValidated& onValidated, |
| const ndn::OnDataValidationFailed& onValidationFailed); |
| |
| void |
| onCertificateValidationFailed(const ndn::shared_ptr<const ndn::Data>& signCertificate, |
| const std::string& failureInfo, |
| const ndn::shared_ptr<const ndn::Data>& data, |
| const ndn::OnDataValidationFailed& onValidationFailed); |
| |
| void |
| onCertInterest (const ndn::Name& prefix, const ndn::Interest& interest); |
| |
| void |
| onCertRegisterFailed(const ndn::Name& prefix, const std::string& msg); |
| |
| private: |
| class IntroNode; |
| |
| // Syncprefix |
| ndn::Name m_prefix; |
| |
| // The map |
| typedef std::map<const ndn::Name, IntroNode> Nodes; |
| typedef std::map<const ndn::Name, IntroCertificate> Edges; |
| Nodes m_introNodes; |
| Edges m_introCerts; |
| |
| // The derived trust info |
| typedef std::map<const ndn::Name, ndn::PublicKey> TrustNodes; |
| ndn::IdentityCertificate m_anchor; |
| TrustNodes m_trustedNodes; |
| |
| // others |
| int m_stepLimit; |
| ndn::shared_ptr<ndn::CertificateCache> m_certificateCache; |
| ndn::KeyChain m_keychain; |
| const ndn::RegisteredPrefixId* m_prefixId; |
| PublishCertCallback m_publishCertCallback; |
| ndn::shared_ptr<ndn::SecRuleRelative> m_dataRule; |
| |
| class IntroNode |
| { |
| public: |
| typedef std::vector<ndn::Name>::const_iterator const_iterator; |
| |
| IntroNode() |
| {} |
| |
| IntroNode(const ndn::IdentityCertificate& idCert) |
| : m_nodeName(idCert.getName().getPrefix(-1)) |
| {} |
| |
| IntroNode(const IntroCertificate& introCert, bool isIntroducer) |
| { |
| if(isIntroducer) |
| { |
| m_nodeName = introCert.getIntroducerCertName(); |
| m_introduceeCerts.push_back(introCert.getName()); |
| } |
| else |
| { |
| m_nodeName = introCert.getIntroduceeCertName(); |
| m_introducerCerts.push_back(introCert.getName()); |
| } |
| } |
| |
| ~IntroNode() |
| {} |
| |
| const ndn::Name& |
| name() const |
| { |
| return m_nodeName; |
| } |
| |
| const_iterator |
| introducerBegin() const |
| { |
| return m_introducerCerts.begin(); |
| } |
| |
| const_iterator |
| introducerEnd() const |
| { |
| return m_introducerCerts.end(); |
| } |
| |
| const_iterator |
| introduceeBegin() const |
| { |
| return m_introduceeCerts.begin(); |
| } |
| |
| const_iterator |
| introduceeEnd() const |
| { |
| return m_introduceeCerts.end(); |
| } |
| |
| void |
| addIntroCertAsIntroducer(const ndn::Name& introCertName) |
| { |
| if(std::find(m_introduceeCerts.begin(), m_introduceeCerts.end(), introCertName) == m_introduceeCerts.end()) |
| m_introduceeCerts.push_back(introCertName); |
| } |
| |
| void |
| addIntroCertAsIntroducee(const ndn::Name& introCertName) |
| { |
| if(std::find(m_introducerCerts.begin(), m_introducerCerts.end(), introCertName) == m_introducerCerts.end()) |
| m_introducerCerts.push_back(introCertName); |
| } |
| |
| private: |
| ndn::Name m_nodeName; |
| std::vector<ndn::Name> m_introducerCerts; |
| std::vector<ndn::Name> m_introduceeCerts; |
| }; |
| |
| }; |
| |
| inline void |
| SyncValidator::setAnchor(const ndn::IdentityCertificate& anchor) |
| { |
| m_anchor = anchor; |
| |
| // Add anchor into trust graph if it does not exist. |
| IntroNode origin(m_anchor); |
| Nodes::const_iterator nodeIt = m_introNodes.find(origin.name()); |
| if(nodeIt == m_introNodes.end()) |
| m_introNodes[origin.name()] = origin; |
| |
| deriveTrustNodes(); |
| } |
| |
| inline void |
| SyncValidator::addParticipant(const IntroCertificate& introCert) |
| { |
| // Check if the edge has been added before. |
| ndn::Name certName = introCert.getName(); |
| Edges::const_iterator edgeIt = m_introCerts.find(certName); |
| if(edgeIt != m_introCerts.end()) |
| return; // the edge has been added before. |
| |
| m_introCerts[certName] = introCert; |
| |
| // Check if the introducer has been added. |
| Nodes::iterator nodeIt = m_introNodes.find(introCert.getIntroducerCertName()); |
| if(nodeIt == m_introNodes.end()) |
| { |
| IntroNode node(introCert, true); |
| m_introNodes[node.name()] = node; |
| } |
| else |
| nodeIt->second.addIntroCertAsIntroducer(certName); |
| |
| // Check if the introducee has been added. |
| nodeIt = m_introNodes.find(introCert.getIntroduceeCertName()); |
| if(nodeIt == m_introNodes.end()) |
| { |
| IntroNode node(introCert, false); |
| m_introNodes[node.name()] = node; |
| } |
| else |
| nodeIt->second.addIntroCertAsIntroducee(certName); |
| |
| // Check if the introducer is one of the trusted nodes. |
| TrustNodes::const_iterator trustNodeIt = m_trustedNodes.find(introCert.getIntroducerCertName()); |
| if(trustNodeIt != m_trustedNodes.end() && verifySignature(introCert, trustNodeIt->second)) |
| // If the introducee, add it into trusted node set. |
| m_trustedNodes[introCert.getIntroduceeCertName()] = introCert.getIntroduceeCert().getPublicKeyInfo(); |
| } |
| |
| inline ndn::shared_ptr<const IntroCertificate> |
| SyncValidator::addParticipant(const ndn::IdentityCertificate& introducee) |
| { |
| ndn::shared_ptr<IntroCertificate> introCert |
| = ndn::shared_ptr<IntroCertificate>(new IntroCertificate(m_prefix, introducee, m_anchor.getName().getPrefix(-1))); |
| |
| m_keychain.sign(*introCert, m_anchor.getName()); |
| |
| addParticipant(*introCert); |
| |
| // Publish certificate as normal data. |
| ndn::Block block = introCert->wireEncode(); |
| m_publishCertCallback(block.wire(), block.size(), 1000); |
| |
| return introCert; |
| } |
| |
| inline void |
| SyncValidator::getIntroCertNames(std::vector<ndn::Name>& list) |
| { |
| Edges::const_iterator it = m_introCerts.begin(); |
| Edges::const_iterator end = m_introCerts.end(); |
| for(; it != end; it++) |
| list.push_back(it->first); |
| } |
| |
| inline const IntroCertificate& |
| SyncValidator::getIntroCertificate(const ndn::Name& name) |
| { |
| Edges::const_iterator it = m_introCerts.find(name); |
| if(it != m_introCerts.end()) |
| return it->second; |
| else |
| throw Error("No cert"); |
| } |
| |
| } // namespace Sync |
| |
| #endif //SYNC_VALIDATOR_H |