blob: 9e5f4df774a085c9f07826682d38767ffa641e27 [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#ifndef SYNC_VALIDATOR_H
23#define SYNC_VALIDATOR_H
24
25#include "sync-intro-certificate.h"
Yingdi Yu7c64e5c2014-04-30 14:06:37 -070026#include <ndn-cxx/security/validator.hpp>
27#include <ndn-cxx/security/key-chain.hpp>
28#include <ndn-cxx/security/sec-rule-relative.hpp>
29#include <ndn-cxx/security/certificate-cache.hpp>
Yingdi Yu0eee6002014-02-11 15:54:17 -080030#include <map>
31
32namespace Sync {
33
34class SyncValidator : public ndn::Validator
35{
36public:
Yingdi Yu3da10fe2014-02-27 16:37:34 -080037 typedef ndn::function< void (const uint8_t*, size_t, int) > PublishCertCallback;
38
Yingdi Yu0eee6002014-02-11 15:54:17 -080039 struct Error : public ndn::Validator::Error { Error(const std::string &what) : ndn::Validator::Error(what) {} };
40
41 static const ndn::shared_ptr<ndn::CertificateCache> DefaultCertificateCache;
42 static const ndn::shared_ptr<ndn::SecRuleRelative> DefaultDataRule;
43
44 SyncValidator(const ndn::Name& prefix,
45 const ndn::IdentityCertificate& anchor,
Yingdi Yua873d642014-04-15 21:31:33 -070046 ndn::Face& face,
Yingdi Yu3da10fe2014-02-27 16:37:34 -080047 const PublishCertCallback& publishCertCallback,
Yingdi Yu0eee6002014-02-11 15:54:17 -080048 ndn::shared_ptr<ndn::SecRuleRelative> rule = DefaultDataRule,
Yingdi Yua873d642014-04-15 21:31:33 -070049 ndn::shared_ptr<ndn::CertificateCache> certificateCache = DefaultCertificateCache,
Yingdi Yu0eee6002014-02-11 15:54:17 -080050 const int stepLimit = 10);
51
52 virtual
53 ~SyncValidator()
54 {
Yingdi Yua873d642014-04-15 21:31:33 -070055 m_face.unsetInterestFilter(m_prefixId);
Yingdi Yu0eee6002014-02-11 15:54:17 -080056 }
57
58 /**
59 * @brief Set the trust anchor
60 *
61 * The anchor should be the participant's own certificate.
62 * This anchor node is the origin of the derived trust graph.
63 * Once the new anchor is set, derive the TrustNode set.
Yingdi Yua873d642014-04-15 21:31:33 -070064 *
Yingdi Yu0eee6002014-02-11 15:54:17 -080065 * @param anchor.
66 */
67 inline void
68 setAnchor(const ndn::IdentityCertificate& anchor);
69
70 /**
71 * @brief Add a node into the trust graph.
Yingdi Yua873d642014-04-15 21:31:33 -070072 *
Yingdi Yu0eee6002014-02-11 15:54:17 -080073 * The method also create an edge from trust anchor to the node.
74 *
75 * @param introducee.
76 * @return IntroCertificate for the introducee.
77 */
78 inline ndn::shared_ptr<const IntroCertificate>
79 addParticipant(const ndn::IdentityCertificate& introducee);
80
81 /**
82 * @brief Add an edge into the trust graph.
83 *
84 * Create nodes if it is one of the edge's ends and does not exist in the graph.
85 *
86 * @param introCert.
87 */
88 inline void
89 addParticipant(const IntroCertificate& introCert);
90
Yingdi Yu3da10fe2014-02-27 16:37:34 -080091 inline void
92 getIntroCertNames(std::vector<ndn::Name>& list);
93
Yingdi Yuaed0f3e2014-02-28 14:54:16 -080094 inline const IntroCertificate&
95 getIntroCertificate(const ndn::Name& name);
96
Yingdi Yu0eee6002014-02-11 15:54:17 -080097#ifdef _TEST
98 bool
99 canTrust(const ndn::Name& certName)
100 {
101 return (m_trustedNodes.find(certName.getPrefix(-1)) != m_trustedNodes.end());
102 }
103#endif //_DEBUG
Yingdi Yua873d642014-04-15 21:31:33 -0700104
Yingdi Yu0eee6002014-02-11 15:54:17 -0800105protected:
106 /***********************
107 * From ndn::Validator *
108 ***********************/
109 virtual void
Yingdi Yua873d642014-04-15 21:31:33 -0700110 checkPolicy (const ndn::Data& data,
111 int stepCount,
112 const ndn::OnDataValidated& onValidated,
Yingdi Yu0eee6002014-02-11 15:54:17 -0800113 const ndn::OnDataValidationFailed& onValidationFailed,
114 std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps);
115
116 virtual void
Yingdi Yua873d642014-04-15 21:31:33 -0700117 checkPolicy (const ndn::Interest& interest,
118 int stepCount,
119 const ndn::OnInterestValidated& onValidated,
Yingdi Yu0eee6002014-02-11 15:54:17 -0800120 const ndn::OnInterestValidationFailed& onValidationFailed,
121 std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps);
122private:
123 void
124 deriveTrustNodes();
125
Yingdi Yua873d642014-04-15 21:31:33 -0700126
Yingdi Yu0eee6002014-02-11 15:54:17 -0800127 void
Yingdi Yua873d642014-04-15 21:31:33 -0700128 onCertificateValidated(const ndn::shared_ptr<const ndn::Data>& signCertificate,
129 const ndn::shared_ptr<const ndn::Data>& data,
130 const ndn::OnDataValidated& onValidated,
Yingdi Yu0eee6002014-02-11 15:54:17 -0800131 const ndn::OnDataValidationFailed& onValidationFailed);
Yingdi Yua873d642014-04-15 21:31:33 -0700132
Yingdi Yu0eee6002014-02-11 15:54:17 -0800133 void
134 onCertificateValidationFailed(const ndn::shared_ptr<const ndn::Data>& signCertificate,
135 const std::string& failureInfo,
Yingdi Yua873d642014-04-15 21:31:33 -0700136 const ndn::shared_ptr<const ndn::Data>& data,
Yingdi Yu0eee6002014-02-11 15:54:17 -0800137 const ndn::OnDataValidationFailed& onValidationFailed);
138
139 void
140 onCertInterest (const ndn::Name& prefix, const ndn::Interest& interest);
141
142 void
143 onCertRegisterFailed(const ndn::Name& prefix, const std::string& msg);
144
145private:
146 class IntroNode;
147
148 // Syncprefix
149 ndn::Name m_prefix;
Yingdi Yua873d642014-04-15 21:31:33 -0700150
Yingdi Yu0eee6002014-02-11 15:54:17 -0800151 // The map
152 typedef std::map<const ndn::Name, IntroNode> Nodes;
153 typedef std::map<const ndn::Name, IntroCertificate> Edges;
154 Nodes m_introNodes;
155 Edges m_introCerts;
156
157 // The derived trust info
158 typedef std::map<const ndn::Name, ndn::PublicKey> TrustNodes;
159 ndn::IdentityCertificate m_anchor;
160 TrustNodes m_trustedNodes;
Yingdi Yua873d642014-04-15 21:31:33 -0700161
Yingdi Yu0eee6002014-02-11 15:54:17 -0800162 // others
163 int m_stepLimit;
164 ndn::shared_ptr<ndn::CertificateCache> m_certificateCache;
165 ndn::KeyChain m_keychain;
166 const ndn::RegisteredPrefixId* m_prefixId;
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800167 PublishCertCallback m_publishCertCallback;
Yingdi Yu0eee6002014-02-11 15:54:17 -0800168 ndn::shared_ptr<ndn::SecRuleRelative> m_dataRule;
169
170 class IntroNode
171 {
172 public:
173 typedef std::vector<ndn::Name>::const_iterator const_iterator;
174
175 IntroNode()
176 {}
177
178 IntroNode(const ndn::IdentityCertificate& idCert)
179 : m_nodeName(idCert.getName().getPrefix(-1))
180 {}
Yingdi Yua873d642014-04-15 21:31:33 -0700181
Yingdi Yu0eee6002014-02-11 15:54:17 -0800182 IntroNode(const IntroCertificate& introCert, bool isIntroducer)
183 {
184 if(isIntroducer)
185 {
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800186 m_nodeName = introCert.getIntroducerCertName();
Yingdi Yu0eee6002014-02-11 15:54:17 -0800187 m_introduceeCerts.push_back(introCert.getName());
188 }
189 else
190 {
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800191 m_nodeName = introCert.getIntroduceeCertName();
Yingdi Yu0eee6002014-02-11 15:54:17 -0800192 m_introducerCerts.push_back(introCert.getName());
193 }
Yingdi Yua873d642014-04-15 21:31:33 -0700194 }
195
Yingdi Yu0eee6002014-02-11 15:54:17 -0800196 ~IntroNode()
197 {}
198
199 const ndn::Name&
200 name() const
201 {
202 return m_nodeName;
203 }
204
205 const_iterator
206 introducerBegin() const
207 {
208 return m_introducerCerts.begin();
209 }
210
211 const_iterator
212 introducerEnd() const
213 {
214 return m_introducerCerts.end();
215 }
216
217 const_iterator
218 introduceeBegin() const
219 {
220 return m_introduceeCerts.begin();
221 }
222
223 const_iterator
224 introduceeEnd() const
225 {
226 return m_introduceeCerts.end();
227 }
228
229 void
230 addIntroCertAsIntroducer(const ndn::Name& introCertName)
231 {
232 if(std::find(m_introduceeCerts.begin(), m_introduceeCerts.end(), introCertName) == m_introduceeCerts.end())
233 m_introduceeCerts.push_back(introCertName);
234 }
Yingdi Yua873d642014-04-15 21:31:33 -0700235
Yingdi Yu0eee6002014-02-11 15:54:17 -0800236 void
237 addIntroCertAsIntroducee(const ndn::Name& introCertName)
238 {
239 if(std::find(m_introducerCerts.begin(), m_introducerCerts.end(), introCertName) == m_introducerCerts.end())
240 m_introducerCerts.push_back(introCertName);
241 }
Yingdi Yua873d642014-04-15 21:31:33 -0700242
Yingdi Yu0eee6002014-02-11 15:54:17 -0800243 private:
244 ndn::Name m_nodeName;
245 std::vector<ndn::Name> m_introducerCerts;
246 std::vector<ndn::Name> m_introduceeCerts;
247 };
248
249};
250
251inline void
252SyncValidator::setAnchor(const ndn::IdentityCertificate& anchor)
253{
254 m_anchor = anchor;
Yingdi Yua873d642014-04-15 21:31:33 -0700255
Yingdi Yu0eee6002014-02-11 15:54:17 -0800256 // Add anchor into trust graph if it does not exist.
257 IntroNode origin(m_anchor);
258 Nodes::const_iterator nodeIt = m_introNodes.find(origin.name());
259 if(nodeIt == m_introNodes.end())
260 m_introNodes[origin.name()] = origin;
261
262 deriveTrustNodes();
263}
264
265inline void
266SyncValidator::addParticipant(const IntroCertificate& introCert)
267{
268 // Check if the edge has been added before.
269 ndn::Name certName = introCert.getName();
270 Edges::const_iterator edgeIt = m_introCerts.find(certName);
271 if(edgeIt != m_introCerts.end())
272 return; // the edge has been added before.
273
274 m_introCerts[certName] = introCert;
275
276 // Check if the introducer has been added.
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800277 Nodes::iterator nodeIt = m_introNodes.find(introCert.getIntroducerCertName());
Yingdi Yu0eee6002014-02-11 15:54:17 -0800278 if(nodeIt == m_introNodes.end())
279 {
280 IntroNode node(introCert, true);
281 m_introNodes[node.name()] = node;
282 }
283 else
284 nodeIt->second.addIntroCertAsIntroducer(certName);
285
286 // Check if the introducee has been added.
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800287 nodeIt = m_introNodes.find(introCert.getIntroduceeCertName());
Yingdi Yu0eee6002014-02-11 15:54:17 -0800288 if(nodeIt == m_introNodes.end())
289 {
290 IntroNode node(introCert, false);
291 m_introNodes[node.name()] = node;
292 }
293 else
294 nodeIt->second.addIntroCertAsIntroducee(certName);
295
296 // Check if the introducer is one of the trusted nodes.
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800297 TrustNodes::const_iterator trustNodeIt = m_trustedNodes.find(introCert.getIntroducerCertName());
Yingdi Yu0eee6002014-02-11 15:54:17 -0800298 if(trustNodeIt != m_trustedNodes.end() && verifySignature(introCert, trustNodeIt->second))
299 // If the introducee, add it into trusted node set.
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800300 m_trustedNodes[introCert.getIntroduceeCertName()] = introCert.getIntroduceeCert().getPublicKeyInfo();
Yingdi Yu0eee6002014-02-11 15:54:17 -0800301}
302
303inline ndn::shared_ptr<const IntroCertificate>
304SyncValidator::addParticipant(const ndn::IdentityCertificate& introducee)
305{
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800306 ndn::shared_ptr<IntroCertificate> introCert
307 = ndn::shared_ptr<IntroCertificate>(new IntroCertificate(m_prefix, introducee, m_anchor.getName().getPrefix(-1)));
Yingdi Yu0eee6002014-02-11 15:54:17 -0800308
309 m_keychain.sign(*introCert, m_anchor.getName());
Yingdi Yua873d642014-04-15 21:31:33 -0700310
Yingdi Yu0eee6002014-02-11 15:54:17 -0800311 addParticipant(*introCert);
312
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800313 // Publish certificate as normal data.
314 ndn::Block block = introCert->wireEncode();
315 m_publishCertCallback(block.wire(), block.size(), 1000);
316
Yingdi Yu0eee6002014-02-11 15:54:17 -0800317 return introCert;
318}
319
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800320inline void
321SyncValidator::getIntroCertNames(std::vector<ndn::Name>& list)
322{
323 Edges::const_iterator it = m_introCerts.begin();
324 Edges::const_iterator end = m_introCerts.end();
325 for(; it != end; it++)
326 list.push_back(it->first);
327}
328
Yingdi Yuaed0f3e2014-02-28 14:54:16 -0800329inline const IntroCertificate&
330SyncValidator::getIntroCertificate(const ndn::Name& name)
331{
332 Edges::const_iterator it = m_introCerts.find(name);
333 if(it != m_introCerts.end())
334 return it->second;
335 else
336 throw Error("No cert");
337}
338
Yingdi Yu0eee6002014-02-11 15:54:17 -0800339} // namespace Sync
340
341#endif //SYNC_VALIDATOR_H