blob: 9e5f4df774a085c9f07826682d38767ffa641e27 [file] [log] [blame]
/* -*- 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