blob: d3e4be498b19e41163546e287c9e2380bea9cee4 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yingdi Yu48e8c0c2014-03-19 12:01:55 -07002/**
Alexander Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070022 */
23
24#ifndef NDN_SECURITY_VALIDATOR_CONFIG_HPP
25#define NDN_SECURITY_VALIDATOR_CONFIG_HPP
26
27#include "validator.hpp"
28#include "certificate-cache.hpp"
29#include "conf/rule.hpp"
30#include "conf/common.hpp"
31
32namespace ndn {
33
34class ValidatorConfig : public Validator
35{
Yingdi Yub4650652014-04-17 10:19:59 -070036
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070037public:
38 class Error : public Validator::Error
39 {
40 public:
41 explicit
42 Error(const std::string& what)
43 : Validator::Error(what)
44 {
45 }
46 };
47
48 static const shared_ptr<CertificateCache> DEFAULT_CERTIFICATE_CACHE;
Yingdi Yu0f5fb692014-06-10 12:07:28 -070049 static const time::milliseconds DEFAULT_GRACE_INTERVAL;
50 static const time::system_clock::Duration DEFAULT_KEY_TIMESTAMP_TTL;
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070051
Yingdi Yu96e64062014-04-15 19:57:33 -070052 explicit
53 ValidatorConfig(Face& face,
54 const shared_ptr<CertificateCache>& certificateCache = DEFAULT_CERTIFICATE_CACHE,
Yingdi Yu0f5fb692014-06-10 12:07:28 -070055 const time::milliseconds& graceInterval = DEFAULT_GRACE_INTERVAL,
56 const size_t stepLimit = 10,
57 const size_t maxTrackedKeys = 1000,
58 const time::system_clock::Duration& keyTimestampTtl = DEFAULT_KEY_TIMESTAMP_TTL);
Yingdi Yu96e64062014-04-15 19:57:33 -070059
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070060 virtual
61 ~ValidatorConfig()
62 {
63 }
64
65 void
66 load(const std::string& filename);
67
68 void
69 load(const std::string& input, const std::string& filename);
70
71 void
72 load(std::istream& input, const std::string& filename);
73
Yingdi Yudfa9d732014-04-09 09:53:01 -070074 void
75 load(const security::conf::ConfigSection& configSection,
76 const std::string& filename);
77
Yingdi Yu58f33712014-04-16 16:57:47 -070078 inline void
79 reset();
80
81 inline bool
82 isEmpty();
83
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070084protected:
85 virtual void
86 checkPolicy(const Data& data,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070087 int nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070088 const OnDataValidated& onValidated,
89 const OnDataValidationFailed& onValidationFailed,
90 std::vector<shared_ptr<ValidationRequest> >& nextSteps);
91
92 virtual void
93 checkPolicy(const Interest& interest,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070094 int nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070095 const OnInterestValidated& onValidated,
96 const OnInterestValidationFailed& onValidationFailed,
97 std::vector<shared_ptr<ValidationRequest> >& nextSteps);
98
99private:
100 template<class Packet, class OnValidated, class OnFailed>
101 void
102 checkSignature(const Packet& packet,
103 const Signature& signature,
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700104 size_t nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700105 const OnValidated& onValidated,
106 const OnFailed& onValidationFailed,
107 std::vector<shared_ptr<ValidationRequest> >& nextSteps);
108
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700109 void
110 checkTimestamp(const shared_ptr<const Interest>& interest,
111 const Name& keyName,
112 const OnInterestValidated& onValidated,
113 const OnInterestValidationFailed& onValidationFailed);
114
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700115 template<class Packet, class OnValidated, class OnFailed>
116 void
117 onCertValidated(const shared_ptr<const Data>& signCertificate,
118 const shared_ptr<const Packet>& packet,
119 const OnValidated& onValidated,
120 const OnFailed& onValidationFailed);
121
122 template<class Packet, class OnFailed>
123 void
124 onCertFailed(const shared_ptr<const Data>& signCertificate,
125 const std::string& failureInfo,
126 const shared_ptr<const Packet>& packet,
127 const OnFailed& onValidationFailed);
128
129 void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700130 onConfigRule(const security::conf::ConfigSection& section,
131 const std::string& filename);
132
133 void
134 onConfigTrustAnchor(const security::conf::ConfigSection& section,
135 const std::string& filename);
136
Yingdi Yub4650652014-04-17 10:19:59 -0700137 time::nanoseconds
138 getRefreshPeriod(std::string refreshString);
139
140 inline time::nanoseconds
141 getDefaultRefreshPeriod();
142
143 void
144 refreshAnchors();
145
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700146 void
147 cleanOldKeys();
148
149#ifdef NDN_CXX_HAVE_TESTS
150 size_t
151 getTimestampMapSize()
152 {
153 return m_lastTimestamp.size();
154 }
155#endif
156
Yingdi Yub4650652014-04-17 10:19:59 -0700157
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700158private:
Yingdi Yub4650652014-04-17 10:19:59 -0700159
160 class TrustAnchorContainer
161 {
162 public:
163 TrustAnchorContainer()
164 {
165 }
166
167 const std::list<shared_ptr<IdentityCertificate> >&
168 getAll() const
169 {
170 return m_certificates;
171 }
172
173 void
174 add(shared_ptr<IdentityCertificate> certificate)
175 {
176 m_certificates.push_back(certificate);
177 }
178
179 protected:
180 std::list<shared_ptr<IdentityCertificate> > m_certificates;
181 };
182
183 class DynamicTrustAnchorContainer : public TrustAnchorContainer
184 {
185 public:
186 DynamicTrustAnchorContainer(const boost::filesystem::path& path, bool isDir,
187 time::nanoseconds refreshPeriod)
188 : m_path(path)
189 , m_isDir(isDir)
190 , m_refreshPeriod(refreshPeriod)
191 {
192 }
193
194 void
195 setLastRefresh(const time::system_clock::TimePoint& lastRefresh)
196 {
197 m_lastRefresh = lastRefresh;
198 }
199
200 const time::system_clock::TimePoint&
201 getLastRefresh() const
202 {
203 return m_lastRefresh;
204 }
205
206 const time::nanoseconds&
207 getRefreshPeriod() const
208 {
209 return m_refreshPeriod;
210 }
211
212 void
213 refresh();
214
215 private:
216 boost::filesystem::path m_path;
217 bool m_isDir;
218
219 time::system_clock::TimePoint m_lastRefresh;
220 time::nanoseconds m_refreshPeriod;
221 };
222
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700223 typedef security::conf::Rule<Interest> InterestRule;
224 typedef security::conf::Rule<Data> DataRule;
225 typedef std::vector<shared_ptr<InterestRule> > InterestRuleList;
226 typedef std::vector<shared_ptr<DataRule> > DataRuleList;
227 typedef std::map<Name, shared_ptr<IdentityCertificate> > AnchorList;
Yingdi Yub4650652014-04-17 10:19:59 -0700228 typedef std::list<DynamicTrustAnchorContainer> DynamicContainers; // sorted by m_lastRefresh
229 typedef std::list<shared_ptr<IdentityCertificate> > CertificateList;
230
231 static inline bool
232 compareDynamicContainer(const DynamicTrustAnchorContainer& containerA,
233 const DynamicTrustAnchorContainer& containerB)
234 {
235 return (containerA.getLastRefresh() < containerB.getLastRefresh());
236 }
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700237
Yingdi Yu44d190c2014-04-16 17:05:46 -0700238 /**
239 * @brief gives whether validation should be preformed
240 *
241 * If false, no validation occurs, and any packet is considered validated immediately.
242 */
243 bool m_shouldValidate;
244
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700245 size_t m_stepLimit;
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700246 shared_ptr<CertificateCache> m_certificateCache;
247
248 InterestRuleList m_interestRules;
249 DataRuleList m_dataRules;
Yingdi Yub4650652014-04-17 10:19:59 -0700250
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700251 AnchorList m_anchors;
Yingdi Yub4650652014-04-17 10:19:59 -0700252 TrustAnchorContainer m_staticContainer;
253 DynamicContainers m_dynamicContainers;
254
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700255 time::milliseconds m_graceInterval;
256 size_t m_maxTrackedKeys;
257 typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
258 LastTimestampMap m_lastTimestamp;
259 const time::system_clock::Duration& m_keyTimestampTtl;
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700260};
261
Yingdi Yu58f33712014-04-16 16:57:47 -0700262inline void
263ValidatorConfig::reset()
264{
265 m_certificateCache->reset();
266 m_interestRules.clear();
267 m_dataRules.clear();
Yingdi Yub4650652014-04-17 10:19:59 -0700268
Yingdi Yu58f33712014-04-16 16:57:47 -0700269 m_anchors.clear();
Yingdi Yub4650652014-04-17 10:19:59 -0700270
271 m_staticContainer = TrustAnchorContainer();
272
273 m_dynamicContainers.clear();
Yingdi Yu58f33712014-04-16 16:57:47 -0700274}
275
276inline bool
277ValidatorConfig::isEmpty()
278{
279 if (m_certificateCache->isEmpty() &&
280 m_interestRules.empty() &&
281 m_dataRules.empty() &&
282 m_anchors.empty())
283 return true;
284 return false;
285}
286
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700287template<class Packet, class OnValidated, class OnFailed>
288void
289ValidatorConfig::checkSignature(const Packet& packet,
290 const Signature& signature,
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700291 size_t nSteps,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700292 const OnValidated& onValidated,
293 const OnFailed& onValidationFailed,
294 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
295{
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700296 if (signature.getType() == Tlv::DigestSha256)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700297 {
Yingdi Yubf6a2812014-06-17 15:32:11 -0700298 DigestSha256 sigSha256(signature);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700299
300 if (verifySignature(packet, sigSha256))
301 return onValidated(packet.shared_from_this());
302 else
303 return onValidationFailed(packet.shared_from_this(),
304 "Sha256 Signature cannot be verified!");
305 }
306
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700307 try {
308 switch (signature.getType()) {
309 case Tlv::SignatureSha256WithRsa:
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700310 case Tlv::SignatureSha256WithEcdsa:
311 {
Yingdi Yu4a557052014-07-09 16:40:37 -0700312 if (!signature.hasKeyLocator()) {
313 return onValidationFailed(packet.shared_from_this(),
314 "Missing KeyLocator in SignatureInfo");
315 }
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700316 break;
317 }
318 default:
319 return onValidationFailed(packet.shared_from_this(),
320 "Unsupported signature type");
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700321 }
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700322 }
323 catch (Tlv::Error& e) {
324 return onValidationFailed(packet.shared_from_this(),
325 "Cannot decode public key signature");
326 }
327 catch (KeyLocator::Error& e) {
328 return onValidationFailed(packet.shared_from_this(),
329 "Cannot decode KeyLocator in public key signature");
330 }
331
Yingdi Yu4a557052014-07-09 16:40:37 -0700332 if (signature.getKeyLocator().getType() != KeyLocator::KeyLocator_Name) {
333 return onValidationFailed(packet.shared_from_this(), "Unsupported KeyLocator type");
334 }
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700335
Yingdi Yu4a557052014-07-09 16:40:37 -0700336 const Name& keyLocatorName = signature.getKeyLocator().getName();
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700337
338 shared_ptr<const Certificate> trustedCert;
339
340 refreshAnchors();
341
342 AnchorList::const_iterator it = m_anchors.find(keyLocatorName);
343 if (m_anchors.end() == it)
344 trustedCert = m_certificateCache->getCertificate(keyLocatorName);
345 else
346 trustedCert = it->second;
347
348 if (static_cast<bool>(trustedCert))
349 {
Yingdi Yu4a557052014-07-09 16:40:37 -0700350 if (verifySignature(packet, signature, trustedCert->getPublicKeyInfo()))
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700351 return onValidated(packet.shared_from_this());
352 else
353 return onValidationFailed(packet.shared_from_this(),
354 "Cannot verify signature");
355 }
356 else
357 {
358 if (m_stepLimit == nSteps)
359 return onValidationFailed(packet.shared_from_this(),
360 "Maximum steps of validation reached");
361
362 OnDataValidated onCertValidated =
363 bind(&ValidatorConfig::onCertValidated<Packet, OnValidated, OnFailed>,
364 this, _1, packet.shared_from_this(), onValidated, onValidationFailed);
365
366 OnDataValidationFailed onCertValidationFailed =
367 bind(&ValidatorConfig::onCertFailed<Packet, OnFailed>,
368 this, _1, _2, packet.shared_from_this(), onValidationFailed);
369
370 Interest certInterest(keyLocatorName);
371
372 shared_ptr<ValidationRequest> nextStep =
373 make_shared<ValidationRequest>(certInterest,
374 onCertValidated,
375 onCertValidationFailed,
376 1, nSteps + 1);
377
378 nextSteps.push_back(nextStep);
379 return;
380 }
381
Yingdi Yu4a557052014-07-09 16:40:37 -0700382 return onValidationFailed(packet.shared_from_this(), "Unsupported Signature Type");
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700383}
384
385template<class Packet, class OnValidated, class OnFailed>
386void
387ValidatorConfig::onCertValidated(const shared_ptr<const Data>& signCertificate,
388 const shared_ptr<const Packet>& packet,
389 const OnValidated& onValidated,
390 const OnFailed& onValidationFailed)
391{
392 shared_ptr<IdentityCertificate> certificate =
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700393 make_shared<IdentityCertificate>(*signCertificate);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700394
395 if (!certificate->isTooLate() && !certificate->isTooEarly())
396 {
397 m_certificateCache->insertCertificate(certificate);
398
399 if (verifySignature(*packet, certificate->getPublicKeyInfo()))
400 return onValidated(packet);
401 else
402 return onValidationFailed(packet,
403 "Cannot verify signature: " +
404 packet->getName().toUri());
405 }
406 else
407 {
408 return onValidationFailed(packet,
409 "Signing certificate " +
410 signCertificate->getName().toUri() +
411 " is no longer valid.");
412 }
413}
414
415template<class Packet, class OnFailed>
416void
417ValidatorConfig::onCertFailed(const shared_ptr<const Data>& signCertificate,
418 const std::string& failureInfo,
419 const shared_ptr<const Packet>& packet,
420 const OnFailed& onValidationFailed)
421{
422 onValidationFailed(packet, failureInfo);
423}
424
Yingdi Yub4650652014-04-17 10:19:59 -0700425inline time::nanoseconds
426ValidatorConfig::getDefaultRefreshPeriod()
427{
428 return time::duration_cast<time::nanoseconds>(time::seconds(3600));
429}
430
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700431} // namespace ndn
432
433#endif // NDN_SECURITY_VALIDATOR_CONFIG_HPP