blob: 2d86dbef45cf28b1faee68e5acf2727354911050 [file] [log] [blame]
Yingdi Yu0eee6002014-02-11 15:54:17 -08001/* -*- 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
16using namespace ndn;
17using namespace std;
18
19INIT_LOGGER ("SyncValidator");
20
21namespace Sync {
22
23const shared_ptr<CertificateCache> SyncValidator::DefaultCertificateCache = shared_ptr<CertificateCache>();
24const shared_ptr<SecRuleRelative> SyncValidator::DefaultDataRule = shared_ptr<SecRuleRelative>();
25
26SyncValidator::SyncValidator(const Name& prefix,
27 const IdentityCertificate& anchor,
28 shared_ptr<Face> face,
Yingdi Yu3da10fe2014-02-27 16:37:34 -080029 const PublishCertCallback& publishCertCallback,
Yingdi Yu0eee6002014-02-11 15:54:17 -080030 shared_ptr<SecRuleRelative> rule,
31 shared_ptr<CertificateCache> certificateCache,
32 const int stepLimit)
33 : Validator(face)
34 , m_prefix(prefix)
35 , m_anchor(anchor)
36 , m_stepLimit(stepLimit)
37 , m_certificateCache(certificateCache)
Yingdi Yu3da10fe2014-02-27 16:37:34 -080038 , m_publishCertCallback(publishCertCallback)
Yingdi Yu0eee6002014-02-11 15:54:17 -080039 , m_dataRule(rule)
40{
41 if(!static_cast<bool>(face))
42 throw Error("Face is not set!");
43
44 if(!static_cast<bool>(m_certificateCache))
45 m_certificateCache = make_shared<CertificateCacheTtl>(m_face->ioService());
46
47 Name certPrefix = prefix;
Yingdi Yu3da10fe2014-02-27 16:37:34 -080048 certPrefix.append("CHRONOS-INTRO-CERT");
49 m_prefixId = m_face->setInterestFilter(certPrefix,
50 bind(&SyncValidator::onCertInterest, this, _1, _2),
51 bind(&SyncValidator::onCertRegisterFailed, this, _1, _2));
Yingdi Yu0eee6002014-02-11 15:54:17 -080052
53 setAnchor(m_anchor);
54}
55
56void
57SyncValidator::deriveTrustNodes()
58{
59 queue<Name> nodeQueue;
60
61 // Clear existing trust nodes.
62 m_trustedNodes.clear();
63
64 // Add the trust anchor.
65 IntroNode origin(m_anchor);
66 m_trustedNodes[origin.name()] = m_anchor.getPublicKeyInfo();
67 nodeQueue.push(origin.name());
68
69 // BFS trusted nodes.
70 while(!nodeQueue.empty())
71 {
72 // Get next trusted node to process.
73 Nodes::const_iterator it = m_introNodes.find(nodeQueue.front());
74 const PublicKey& publicKey = m_trustedNodes[nodeQueue.front()];
75
76 if(it != m_introNodes.end())
77 {
78 // If the trusted node exists in the graph.
79 IntroNode::const_iterator eeIt = it->second.introduceeBegin();
80 IntroNode::const_iterator eeEnd = it->second.introduceeEnd();
81 for(; eeIt != eeEnd; eeIt++)
82 {
83 // Check the nodes introduced by the trusted node.
84 Edges::const_iterator edgeIt = m_introCerts.find(*eeIt);
85 if(edgeIt != m_introCerts.end()
Yingdi Yu3da10fe2014-02-27 16:37:34 -080086 && m_trustedNodes.find(edgeIt->second.getIntroduceeCertName()) == m_trustedNodes.end()
Yingdi Yu0eee6002014-02-11 15:54:17 -080087 && verifySignature(edgeIt->second, publicKey))
88 {
89 // If the introduced node can be validated, add it into trusted node set and the node queue.
Yingdi Yu3da10fe2014-02-27 16:37:34 -080090 m_trustedNodes[edgeIt->second.getIntroduceeCertName()] = edgeIt->second.getIntroduceeCert().getPublicKeyInfo();
91 nodeQueue.push(edgeIt->second.getIntroduceeCertName());
Yingdi Yu0eee6002014-02-11 15:54:17 -080092 }
93 }
94 }
95 nodeQueue.pop();
96 }
97}
98
99void
100SyncValidator::checkPolicy (const Data& data,
101 int stepCount,
102 const OnDataValidated& onValidated,
103 const OnDataValidationFailed& onValidationFailed,
104 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
105{
106 if(m_stepLimit == stepCount)
107 return onValidationFailed(data.shared_from_this(),
108 "Maximum steps of validation reached: " + data.getName().toUri());
109
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800110 if(m_prefix.isPrefixOf(data.getName()) || (static_cast<bool>(m_dataRule) && m_dataRule->satisfy(data)))
Yingdi Yu0eee6002014-02-11 15:54:17 -0800111 {
112 try
113 {
114 SignatureSha256WithRsa sig(data.getSignature());
115 Name keyLocatorName = sig.getKeyLocator().getName();
116
117 TrustNodes::const_iterator it = m_trustedNodes.find(keyLocatorName);
118 if(m_trustedNodes.end() != it)
119 {
120 if(verifySignature(data, sig, it->second))
121 return onValidated(data.shared_from_this());
122 else
123 return onValidationFailed(data.shared_from_this(),
124 "Cannot verify signature: " + data.getName().toUri());
125 }
126 else
127 {
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800128 _LOG_DEBUG("I am: " << m_anchor.getName().get(0).toEscapedString() << " for " << data.getName());
129
Yingdi Yu0eee6002014-02-11 15:54:17 -0800130 Name interestName = m_prefix;
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800131 interestName.append("CHRONOS-INTRO-CERT").append(keyLocatorName.wireEncode());
Yingdi Yu0eee6002014-02-11 15:54:17 -0800132 Interest interest(interestName);
133 interest.setInterestLifetime(500);
134
135 OnDataValidated onKeyValidated = bind(&SyncValidator::onCertificateValidated, this,
136 _1, data.shared_from_this(), onValidated, onValidationFailed);
137
138 OnDataValidationFailed onKeyValidationFailed = bind(&SyncValidator::onCertificateValidationFailed, this,
139 _1, _2, data.shared_from_this(), onValidationFailed);
140
141 shared_ptr<ValidationRequest> nextStep = make_shared<ValidationRequest>(interest,
142 onKeyValidated,
143 onKeyValidationFailed,
144 1,
145 stepCount + 1);
146 nextSteps.push_back(nextStep);
147
148 return;
149 }
150 }
151 catch(SignatureSha256WithRsa::Error& e)
152 {
153 return onValidationFailed(data.shared_from_this(),
154 "Not SignatureSha256WithRsa signature: " + string(e.what()));
155 }
156 catch(KeyLocator::Error& e)
157 {
158 return onValidationFailed(data.shared_from_this(),
159 "Key Locator is not a name: " + data.getName().toUri());
160 }
161 }
Yingdi Yu0eee6002014-02-11 15:54:17 -0800162 else
163 return onValidationFailed(data.shared_from_this(),
Yingdi Yu3da10fe2014-02-27 16:37:34 -0800164 "No rule or rule is not satisfied: " + data.getName().toUri());
Yingdi Yu0eee6002014-02-11 15:54:17 -0800165}
166
167void
168SyncValidator::checkPolicy (const Interest& interest,
169 int stepCount,
170 const OnInterestValidated& onValidated,
171 const OnInterestValidationFailed& onValidationFailed,
172 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
173{
174 onValidationFailed(interest.shared_from_this(), "No policy for signed interest checking");
175}
176
177void
178SyncValidator::onCertificateValidated(const shared_ptr<const Data>& signCertificate,
179 const shared_ptr<const Data>& data,
180 const OnDataValidated& onValidated,
181 const OnDataValidationFailed& onValidationFailed)
182{
183 try
184 {
185 IntroCertificate introCert(*signCertificate);
186 addParticipant(introCert);
187
188 if(verifySignature(*data, introCert.getIntroduceeCert().getPublicKeyInfo()))
189 return onValidated(data);
190 else
191 return onValidationFailed(data,
192 "Cannot verify signature: " + data->getName().toUri());
193 }
194 catch(IntroCertificate::Error& e)
195 {
196 return onValidationFailed(data,
197 "Intro cert decoding error: " + string(e.what()));
198 }
199}
200
201void
202SyncValidator::onCertificateValidationFailed(const shared_ptr<const Data>& signCertificate,
203 const string& failureInfo,
204 const shared_ptr<const Data>& data,
205 const OnDataValidationFailed& onValidationFailed)
206{
207 onValidationFailed(data, failureInfo);
208}
209
210void
211SyncValidator::onCertInterest(const Name& prefix, const Interest& interest)
212{
213 Name name = interest.getName();
214 Edges::const_iterator it = m_introCerts.begin();
215 for(; it != m_introCerts.end(); it++)
216 {
217 if(name.isPrefixOf(it->first))
218 {
219 m_face->put(it->second);
220 return;
221 }
222 }
223}
224
225void
226SyncValidator::onCertRegisterFailed(const Name& prefix, const string& msg)
227{
228 _LOG_DEBUG("SyncValidator::onCertRegisterFailed: " << msg);
229}
230
231} // namespace Sync