blob: 1ec23236c50fc84c32e0e5730c0402a72e1908b4 [file] [log] [blame]
Yingdi Yu48e8c0c2014-03-19 12:01:55 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Yingdi Yu <yingdi@cs.ucla.edu>
5 * See COPYING for copyright and distribution information.
6 */
7
8#ifndef NDN_SECURITY_CONF_CHECKER_HPP
9#define NDN_SECURITY_CONF_CHECKER_HPP
10
11#include "key-locator-checker.hpp"
12#include "../../util/io.hpp"
13#include <boost/algorithm/string.hpp>
14
15#include "common.hpp"
16
17namespace ndn {
18namespace security {
19namespace conf {
20
21class Checker
22{
23public:
24 typedef function<void(const shared_ptr<const Interest>&)> OnInterestChecked;
25 typedef function<void(const shared_ptr<const Interest>&, const std::string&)> OnInterestCheckFailed;
26 typedef function<void(const shared_ptr<const Data>&)> OnDataChecked;
27 typedef function<void(const shared_ptr<const Data>&, const std::string&)> OnDataCheckFailed;
28
29
30 virtual
31 ~Checker()
32 {
33 }
34
35 /**
36 * @brief check if data satisfies condition defined in the specific checker implementation
37 *
38 * @param data Data packet
39 * @param onValidated Callback function which is called when data is immediately valid
40 * @param onValidationFailed Call function which is called when data is immediately invalid
41 * @return -1 if data is immediately invalid (onValidationFailed has been called)
42 * 1 if data is immediately valid (onValidated has been called)
43 * 0 if further signature verification is needed.
44 */
45 virtual int8_t
46 check(const Data& data,
47 const OnDataChecked& onValidated,
48 const OnDataCheckFailed& onValidationFailed) = 0;
49
50 /**
51 * @brief check if interest satisfies condition defined in the specific checker implementation
52 *
53 * @param interest Interest packet
54 * @param onValidated Callback function which is called when interest is immediately valid
55 * @param onValidationFailed Call function which is called when interest is immediately invalid
56 * @return -1 if interest is immediately invalid (onValidationFailed has been called)
57 * 1 if interest is immediately valid (onValidated has been called)
58 * 0 if further signature verification is needed.
59 */
60 virtual int8_t
61 check(const Interest& interest,
62 const OnInterestChecked& onValidated,
63 const OnInterestCheckFailed& onValidationFailed) = 0;
64};
65
66class CustomizedChecker : public Checker
67{
68 enum
69 {
70 INTEREST_SIG_VALUE = -1,
71 INTEREST_SIG_INFO = -2,
72 };
73
74public:
75 CustomizedChecker(uint32_t sigType,
76 shared_ptr<KeyLocatorChecker> keyLocatorChecker)
77 : m_sigType(sigType)
78 , m_keyLocatorChecker(keyLocatorChecker)
79 {
80 if (m_sigType == Signature::Sha256WithRsa && !static_cast<bool>(m_keyLocatorChecker))
81 throw Error("Strong signature requires KeyLocatorChecker");
82 }
83
84 virtual int8_t
85 check(const Data& data,
86 const OnDataChecked& onValidated,
87 const OnDataCheckFailed& onValidationFailed)
88 {
89 return check(data, data.getSignature(), onValidated, onValidationFailed);
90 }
91
92 virtual int8_t
93 check(const Interest& interest,
94 const OnInterestChecked& onValidated,
95 const OnInterestCheckFailed& onValidationFailed)
96 {
97 const Name& interestName = interest.getName();
98 Signature signature(interestName[INTEREST_SIG_INFO].blockFromValue(),
99 interestName[INTEREST_SIG_VALUE].blockFromValue());
100 return check(interest, signature, onValidated, onValidationFailed);
101 }
102
103private:
104 template<class Packet, class OnValidated, class OnFailed>
105 int8_t
106 check(const Packet& packet, const Signature& signature,
107 const OnValidated& onValidated,
108 const OnFailed& onValidationFailed)
109 {
110 if (m_sigType != signature.getType())
111 {
112 onValidationFailed(packet.shared_from_this(),
113 "Signature type does not match: " +
114 boost::lexical_cast<std::string>(m_sigType) +
115 "!=" +
116 boost::lexical_cast<std::string>(signature.getType()));
117 return -1;
118 }
119
120 switch (signature.getType())
121 {
122 case Signature::Sha256WithRsa:
123 {
124 try
125 {
126 SignatureSha256WithRsa sig(signature);
127
128 std::string failInfo;
129 if (m_keyLocatorChecker->check(packet, sig.getKeyLocator(), failInfo))
130 return 0;
131 else
132 {
133 onValidationFailed(packet.shared_from_this(), failInfo);
134 return -1;
135 }
136 }
137 catch (const SignatureSha256WithRsa::Error& e)
138 {
139 onValidationFailed(packet.shared_from_this(),
140 "Cannot decode Sha256WithRsa signature!");
141 return -1;
142 }
143 }
144 case Signature::Sha256:
145 return 0;
146 default:
147 {
148 onValidationFailed(packet.shared_from_this(),
149 "Unsupported signature type: " +
150 boost::lexical_cast<std::string>(signature.getType()));
151 return -1;
152 }
153 }
154 }
155
156private:
157 uint32_t m_sigType;
158 shared_ptr<KeyLocatorChecker> m_keyLocatorChecker;
159};
160
161class HierarchicalChecker : public CustomizedChecker
162{
163public:
164 HierarchicalChecker(uint32_t sigType)
165 : CustomizedChecker(sigType,
166 make_shared<HyperKeyLocatorNameChecker>("^(<>*)$", "\\1",
167 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
168 "\\1\\2",
169 KeyLocatorChecker::RELATION_IS_PREFIX_OF))
170 {
171 }
172};
173
174class FixedSignerChecker : public Checker
175{
176 enum
177 {
178 INTEREST_SIG_VALUE = -1,
179 INTEREST_SIG_INFO = -2,
180 };
181public:
182 FixedSignerChecker(uint32_t sigType,
183 const std::vector<shared_ptr<IdentityCertificate> >& signers)
184 : m_sigType(sigType)
185 {
186 for (std::vector<shared_ptr<IdentityCertificate> >::const_iterator it = signers.begin();
187 it != signers.end(); it++)
188 m_signers[(*it)->getName().getPrefix(-1)] = (*it);
189 }
190
191 virtual int8_t
192 check(const Data& data,
193 const OnDataChecked& onValidated,
194 const OnDataCheckFailed& onValidationFailed)
195 {
196 return check(data, data.getSignature(), onValidated, onValidationFailed);
197 }
198
199 virtual int8_t
200 check(const Interest& interest,
201 const OnInterestChecked& onValidated,
202 const OnInterestCheckFailed& onValidationFailed)
203 {
204 const Name& interestName = interest.getName();
205 Signature signature(interestName[INTEREST_SIG_INFO].blockFromValue(),
206 interestName[INTEREST_SIG_VALUE].blockFromValue());
207 return check(interest, signature, onValidated, onValidationFailed);
208 }
209
210private:
211 template<class Packet, class OnValidated, class OnFailed>
212 int8_t
213 check(const Packet& packet, const Signature& signature,
214 const OnValidated& onValidated,
215 const OnFailed& onValidationFailed)
216 {
217 if (m_sigType != signature.getType())
218 {
219 onValidationFailed(packet.shared_from_this(),
220 "Signature type does not match: "
221 + boost::lexical_cast<std::string>(m_sigType)
222 + "!="
223 + boost::lexical_cast<std::string>(signature.getType()));
224 return -1;
225 }
226
227 switch(signature.getType())
228 {
229 case Signature::Sha256WithRsa:
230 {
231 try
232 {
233 SignatureSha256WithRsa sig(signature);
234
235 const Name& keyLocatorName = sig.getKeyLocator().getName();
236 if (m_signers.find(keyLocatorName) == m_signers.end())
237 {
238 onValidationFailed(packet.shared_from_this(),
239 "Signer is not in the fixed signer list: "
240 + keyLocatorName.toUri());
241 return -1;
242 }
243
244 if (Validator::verifySignature(packet, sig,
245 m_signers[keyLocatorName]->getPublicKeyInfo()))
246 {
247 onValidated(packet.shared_from_this());
248 return 1;
249 }
250 else
251 {
252 onValidationFailed(packet.shared_from_this(),
253 "Signature cannot be validated!");
254 return -1;
255 }
256 }
257 catch (const KeyLocator::Error& e)
258 {
259 onValidationFailed(packet.shared_from_this(),
260 "KeyLocator does not have name!");
261 return -1;
262 }
263 catch (const SignatureSha256WithRsa::Error& e)
264 {
265 onValidationFailed(packet.shared_from_this(),
266 "Cannot decode signature!");
267 return -1;
268 }
269 }
270 case Signature::Sha256:
271 {
272 onValidationFailed(packet.shared_from_this(),
273 "FixedSigner does not allow Sha256 signature type!");
274 return -1;
275 }
276 default:
277 {
278 onValidationFailed(packet.shared_from_this(),
279 "Unsupported signature type: "
280 + boost::lexical_cast<std::string>(signature.getType()));
281 return -1;
282 }
283 }
284 }
285
286private:
287 typedef std::map<Name, shared_ptr<IdentityCertificate> > SignerList;
288
289 uint32_t m_sigType;
290 SignerList m_signers;
291};
292
293class CheckerFactory
294{
295public:
296 /**
297 * @brief create a checker from configuration file.
298 *
299 * @param configSection The section containing the definition of checker.
300 * @param configFilename The configuration file name.
301 * @return a shared pointer to the created checker.
302 */
303 static shared_ptr<Checker>
304 create(const ConfigSection& configSection, const std::string& configFilename)
305 {
306 ConfigSection::const_iterator propertyIt = configSection.begin();
307
308 // Get checker.type
309 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
310 throw Error("Expect <checker.type>!");
311
312 std::string type = propertyIt->second.data();
313
314 if (boost::iequals(type, "customized"))
315 return createCustomizedChecker(configSection, configFilename);
316 else if (boost::iequals(type, "hierarchical"))
317 return createHierarchicalChecker(configSection, configFilename);
318 else if (boost::iequals(type, "fixed-signer"))
319 return createFixedSignerChecker(configSection, configFilename);
320 else
321 throw Error("Unsupported checker type: " + type);
322 }
323
324private:
325 static shared_ptr<Checker>
326 createCustomizedChecker(const ConfigSection& configSection,
327 const std::string& configFilename)
328 {
329 ConfigSection::const_iterator propertyIt = configSection.begin();
330 propertyIt++;
331
332 // Get checker.sig-type
333 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type"))
334 throw Error("Expect <checker.sig-type>!");
335
336 std::string sigType = propertyIt->second.data();
337 propertyIt++;
338
339 // Get checker.key-locator
340 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator"))
341 throw Error("Expect <checker.key-locator>!");
342
343 shared_ptr<KeyLocatorChecker> keyLocatorChecker =
344 KeyLocatorCheckerFactory::create(propertyIt->second, configFilename);
345 propertyIt++;
346
347 if (propertyIt != configSection.end())
348 throw Error("Expect the end of checker!");
349
350 return make_shared<CustomizedChecker>(boost::cref(getSigType(sigType)),
351 boost::cref(keyLocatorChecker));
352 }
353
354 static shared_ptr<Checker>
355 createHierarchicalChecker(const ConfigSection& configSection,
356 const std::string& configFilename)
357 {
358 ConfigSection::const_iterator propertyIt = configSection.begin();
359 propertyIt++;
360
361 // Get checker.sig-type
362 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type"))
363 throw Error("Expect <checker.sig-type>!");
364
365 std::string sigType = propertyIt->second.data();
366 propertyIt++;
367
368 if (propertyIt != configSection.end())
369 throw Error("Expect the end of checker!");
370
371 return make_shared<HierarchicalChecker>(boost::cref(getSigType(sigType)));
372 }
373
374 static shared_ptr<Checker>
375 createFixedSignerChecker(const ConfigSection& configSection,
376 const std::string& configFilename)
377 {
378 ConfigSection::const_iterator propertyIt = configSection.begin();
379 propertyIt++;
380
381 // Get checker.sig-type
382 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type"))
383 throw Error("Expect <checker.sig-type>!");
384
385 std::string sigType = propertyIt->second.data();
386 propertyIt++;
387
388 std::vector<shared_ptr<IdentityCertificate> > signers;
389 for (; propertyIt != configSection.end(); propertyIt++)
390 {
391 if (!boost::iequals(propertyIt->first, "signer"))
392 throw Error("Expect <checker.signer> but get <checker."
393 + propertyIt->first + ">");
394
395 signers.push_back(getSigner(propertyIt->second, configFilename));
396 }
397
398 if (propertyIt != configSection.end())
399 throw Error("Expect the end of checker!");
400
401 return shared_ptr<FixedSignerChecker>(new FixedSignerChecker(getSigType(sigType),
402 signers));
403 }
404
405 static shared_ptr<IdentityCertificate>
406 getSigner(const ConfigSection& configSection, const std::string& configFilename)
407 {
408 using namespace boost::filesystem;
409
410 ConfigSection::const_iterator propertyIt = configSection.begin();
411
412 // Get checker.signer.type
413 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type"))
414 throw Error("Expect <checker.signer.type>!");
415
416 std::string type = propertyIt->second.data();
417 propertyIt++;
418
419 if (boost::iequals(type, "file"))
420 {
421 // Get checker.signer.file-name
422 if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name"))
423 throw Error("Expect <checker.signer.file-name>!");
424
425 path certfilePath = absolute(propertyIt->second.data(),
426 path(configFilename).parent_path());
427 propertyIt++;
428
429 if (propertyIt != configSection.end())
430 throw Error("Expect the end of checker.signer");
431
432 shared_ptr<IdentityCertificate> idCert
433 = io::load<IdentityCertificate>(certfilePath.c_str());
434
435 if (static_cast<bool>(idCert))
436 return idCert;
437 else
438 throw Error("Cannot read certificate from file: "
439 + certfilePath.native());
440 }
441 else if (boost::iequals(type, "base64"))
442 {
443 // Get checker.signer.base64-string
444 if (propertyIt == configSection.end() ||
445 !boost::iequals(propertyIt->first, "base64-string"))
446 throw Error("Expect <checker.signer.base64-string>!");
447
448 std::stringstream ss(propertyIt->second.data());
449 propertyIt++;
450
451 if (propertyIt != configSection.end())
452 throw Error("Expect the end of checker.signer");
453
454 shared_ptr<IdentityCertificate> idCert = io::load<IdentityCertificate>(ss);
455
456 if (static_cast<bool>(idCert))
457 return idCert;
458 else
459 throw Error("Cannot decode certificate from string");
460 }
461 else
462 throw Error("Unsupported checker.signer type: " + type);
463 }
464
465 static int32_t
466 getSigType(const std::string& sigType)
467 {
468 if (boost::iequals(sigType, "rsa-sha256"))
469 return Signature::Sha256WithRsa;
470 else if (boost::iequals(sigType, "sha256"))
471 return Signature::Sha256;
472 else
473 return -1;
474 }
475};
476
477} // namespace conf
478} // namespace security
479} // namespace ndn
480
481#endif // NDN_SECURITY_SEC_CONF_RULE_SIGNER_HPP