blob: 06e5d77338d1120428a71af19410d467d866ef99 [file] [log] [blame]
Alexander Afanasyev8722d872014-07-02 13:00:29 -07001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
Yingdi Yu0eee6002014-02-11 15:54:17 -08002/*
Alexander Afanasyev8722d872014-07-02 13:00:29 -07003 * Copyright (c) 2012-2014 University of California, Los Angeles
Yingdi Yu0eee6002014-02-11 15:54:17 -08004 *
Alexander Afanasyev8722d872014-07-02 13:00:29 -07005 * This file is part of ChronoSync, synchronization library for distributed realtime
6 * applications for NDN.
Yingdi Yu0eee6002014-02-11 15:54:17 -08007 *
Alexander Afanasyev8722d872014-07-02 13:00:29 -07008 * 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 Yu0eee6002014-02-11 15:54:17 -080020 */
21
22#include "sync-validator.h"
23#include "sync-logging.h"
Yingdi Yu7c64e5c2014-04-30 14:06:37 -070024#include <ndn-cxx/security/certificate-cache-ttl.hpp>
Yingdi Yu0eee6002014-02-11 15:54:17 -080025#include <queue>
26
27using namespace ndn;
Yingdi Yu0eee6002014-02-11 15:54:17 -080028
29INIT_LOGGER ("SyncValidator");
30
31namespace Sync {
32
Yingdi Yu68bc51a2014-03-25 16:02:12 -070033using ndn::shared_ptr;
34
Yingdi Yu0eee6002014-02-11 15:54:17 -080035const shared_ptr<CertificateCache> SyncValidator::DefaultCertificateCache = shared_ptr<CertificateCache>();
36const shared_ptr<SecRuleRelative> SyncValidator::DefaultDataRule = shared_ptr<SecRuleRelative>();
37
38SyncValidator::SyncValidator(const Name& prefix,
39 const IdentityCertificate& anchor,
Yingdi Yua873d642014-04-15 21:31:33 -070040 Face& face,
Yingdi Yu3da10fe2014-02-27 16:37:34 -080041 const PublishCertCallback& publishCertCallback,
Yingdi Yu0eee6002014-02-11 15:54:17 -080042 shared_ptr<SecRuleRelative> rule,
Yingdi Yua873d642014-04-15 21:31:33 -070043 shared_ptr<CertificateCache> certificateCache,
Yingdi Yu0eee6002014-02-11 15:54:17 -080044 const int stepLimit)
45 : Validator(face)
46 , m_prefix(prefix)
47 , m_anchor(anchor)
48 , m_stepLimit(stepLimit)
49 , m_certificateCache(certificateCache)
Yingdi Yu3da10fe2014-02-27 16:37:34 -080050 , m_publishCertCallback(publishCertCallback)
Yingdi Yu0eee6002014-02-11 15:54:17 -080051 , m_dataRule(rule)
52{
Yingdi Yu0eee6002014-02-11 15:54:17 -080053 if(!static_cast<bool>(m_certificateCache))
Yingdi Yu7c64e5c2014-04-30 14:06:37 -070054 m_certificateCache = make_shared<CertificateCacheTtl>(boost::ref(m_face.getIoService()));
Yingdi Yu0eee6002014-02-11 15:54:17 -080055
56 Name certPrefix = prefix;
Yingdi Yu3da10fe2014-02-27 16:37:34 -080057 certPrefix.append("CHRONOS-INTRO-CERT");
Yingdi Yua873d642014-04-15 21:31:33 -070058 m_prefixId = m_face.setInterestFilter(certPrefix,
59 bind(&SyncValidator::onCertInterest, this, _1, _2),
Yingdi Yu3da10fe2014-02-27 16:37:34 -080060 bind(&SyncValidator::onCertRegisterFailed, this, _1, _2));
Yingdi Yu0eee6002014-02-11 15:54:17 -080061
62 setAnchor(m_anchor);
63}
64
65void
66SyncValidator::deriveTrustNodes()
67{
Yingdi Yu68bc51a2014-03-25 16:02:12 -070068 std::queue<Name> nodeQueue;
Yingdi Yu0eee6002014-02-11 15:54:17 -080069
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 Yua873d642014-04-15 21:31:33 -070094 if(edgeIt != m_introCerts.end()
Yingdi Yu3da10fe2014-02-27 16:37:34 -080095 && m_trustedNodes.find(edgeIt->second.getIntroduceeCertName()) == m_trustedNodes.end()
Yingdi Yu0eee6002014-02-11 15:54:17 -080096 && verifySignature(edgeIt->second, publicKey))
97 {
98 // If the introduced node can be validated, add it into trusted node set and the node queue.
Yingdi Yu3da10fe2014-02-27 16:37:34 -080099 m_trustedNodes[edgeIt->second.getIntroduceeCertName()] = edgeIt->second.getIntroduceeCert().getPublicKeyInfo();
100 nodeQueue.push(edgeIt->second.getIntroduceeCertName());
Yingdi Yu0eee6002014-02-11 15:54:17 -0800101 }
102 }
103 }
104 nodeQueue.pop();
105 }
106}
107
108void
Yingdi Yua873d642014-04-15 21:31:33 -0700109SyncValidator::checkPolicy (const Data& data,
110 int stepCount,
111 const OnDataValidated& onValidated,
Yingdi Yu0eee6002014-02-11 15:54:17 -0800112 const OnDataValidationFailed& onValidationFailed,
113 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
114{
115 if(m_stepLimit == stepCount)
Yingdi Yua873d642014-04-15 21:31:33 -0700116 return onValidationFailed(data.shared_from_this(),
Yingdi Yu0eee6002014-02-11 15:54:17 -0800117 "Maximum steps of validation reached: " + data.getName().toUri());
118
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800119 if(m_prefix.isPrefixOf(data.getName()) || (static_cast<bool>(m_dataRule) && m_dataRule->satisfy(data)))
Yingdi Yu0eee6002014-02-11 15:54:17 -0800120 {
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 Yua873d642014-04-15 21:31:33 -0700132 return onValidationFailed(data.shared_from_this(),
Yingdi Yu0eee6002014-02-11 15:54:17 -0800133 "Cannot verify signature: " + data.getName().toUri());
134 }
135 else
136 {
Yingdi Yua873d642014-04-15 21:31:33 -0700137 _LOG_DEBUG("I am: " << m_anchor.getName().get(0).toEscapedString() << " for " << data.getName());
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800138
Yingdi Yu0eee6002014-02-11 15:54:17 -0800139 Name interestName = m_prefix;
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800140 interestName.append("CHRONOS-INTRO-CERT").append(keyLocatorName.wireEncode());
Yingdi Yu0eee6002014-02-11 15:54:17 -0800141 Interest interest(interestName);
Yingdi Yu6e1c9cd2014-03-25 10:26:54 -0700142 interest.setInterestLifetime(time::milliseconds(500));
Yingdi Yu0eee6002014-02-11 15:54:17 -0800143
Yingdi Yua873d642014-04-15 21:31:33 -0700144 OnDataValidated onKeyValidated = bind(&SyncValidator::onCertificateValidated, this,
Yingdi Yu0eee6002014-02-11 15:54:17 -0800145 _1, data.shared_from_this(), onValidated, onValidationFailed);
Yingdi Yu0eee6002014-02-11 15:54:17 -0800146
Yingdi Yua873d642014-04-15 21:31:33 -0700147 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 Yu0eee6002014-02-11 15:54:17 -0800151 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 Yua873d642014-04-15 21:31:33 -0700162 return onValidationFailed(data.shared_from_this(),
Yingdi Yu68bc51a2014-03-25 16:02:12 -0700163 "Not SignatureSha256WithRsa signature: " + std::string(e.what()));
Yingdi Yu0eee6002014-02-11 15:54:17 -0800164 }
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 Yu0eee6002014-02-11 15:54:17 -0800171 else
172 return onValidationFailed(data.shared_from_this(),
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800173 "No rule or rule is not satisfied: " + data.getName().toUri());
Yingdi Yu0eee6002014-02-11 15:54:17 -0800174}
175
176void
Yingdi Yua873d642014-04-15 21:31:33 -0700177SyncValidator::checkPolicy (const Interest& interest,
178 int stepCount,
179 const OnInterestValidated& onValidated,
Yingdi Yu0eee6002014-02-11 15:54:17 -0800180 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
186void
Yingdi Yua873d642014-04-15 21:31:33 -0700187SyncValidator::onCertificateValidated(const shared_ptr<const Data>& signCertificate,
188 const shared_ptr<const Data>& data,
189 const OnDataValidated& onValidated,
Yingdi Yu0eee6002014-02-11 15:54:17 -0800190 const OnDataValidationFailed& onValidationFailed)
191{
192 try
193 {
194 IntroCertificate introCert(*signCertificate);
195 addParticipant(introCert);
Yingdi Yua873d642014-04-15 21:31:33 -0700196
Yingdi Yu0eee6002014-02-11 15:54:17 -0800197 if(verifySignature(*data, introCert.getIntroduceeCert().getPublicKeyInfo()))
198 return onValidated(data);
199 else
Yingdi Yua873d642014-04-15 21:31:33 -0700200 return onValidationFailed(data,
Yingdi Yu0eee6002014-02-11 15:54:17 -0800201 "Cannot verify signature: " + data->getName().toUri());
202 }
203 catch(IntroCertificate::Error& e)
204 {
Yingdi Yua873d642014-04-15 21:31:33 -0700205 return onValidationFailed(data,
Yingdi Yu68bc51a2014-03-25 16:02:12 -0700206 "Intro cert decoding error: " + std::string(e.what()));
Yingdi Yu0eee6002014-02-11 15:54:17 -0800207 }
208}
209
210void
Yingdi Yua873d642014-04-15 21:31:33 -0700211SyncValidator::onCertificateValidationFailed(const shared_ptr<const Data>& signCertificate,
Yingdi Yu68bc51a2014-03-25 16:02:12 -0700212 const std::string& failureInfo,
Yingdi Yua873d642014-04-15 21:31:33 -0700213 const shared_ptr<const Data>& data,
Yingdi Yu0eee6002014-02-11 15:54:17 -0800214 const OnDataValidationFailed& onValidationFailed)
215{
216 onValidationFailed(data, failureInfo);
217}
218
219void
220SyncValidator::onCertInterest(const Name& prefix, const Interest& interest)
221{
Yingdi Yua873d642014-04-15 21:31:33 -0700222 Name name = interest.getName();
Yingdi Yu0eee6002014-02-11 15:54:17 -0800223 Edges::const_iterator it = m_introCerts.begin();
224 for(; it != m_introCerts.end(); it++)
225 {
226 if(name.isPrefixOf(it->first))
227 {
Yingdi Yua873d642014-04-15 21:31:33 -0700228 m_face.put(it->second);
Yingdi Yu0eee6002014-02-11 15:54:17 -0800229 return;
230 }
231 }
232}
233
234void
Yingdi Yu68bc51a2014-03-25 16:02:12 -0700235SyncValidator::onCertRegisterFailed(const Name& prefix, const std::string& msg)
Yingdi Yu0eee6002014-02-11 15:54:17 -0800236{
237 _LOG_DEBUG("SyncValidator::onCertRegisterFailed: " << msg);
238}
239
240} // namespace Sync