blob: 2dcc947a31a920fb1fc6f851d66fa9c50a409798 [file] [log] [blame]
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080011 */
12
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070013#ifndef NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP
14#define NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080015
16#include "../security/validator.hpp"
17#include "../security/identity-certificate.hpp"
18#include "../security/sec-rule-specific.hpp"
19
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070020#include <list>
21
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080022namespace ndn {
23
24class CommandInterestValidator : public Validator
25{
26public:
27 enum {
28 POS_SIG_VALUE = -1,
29 POS_SIG_INFO = -2,
30 POS_RANDOM_VAL = -3,
31 POS_TIMESTAMP = -4,
32
Yingdi Yu449e1142014-03-28 18:54:42 -070033 MIN_LENGTH = 4,
34
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080035 GRACE_INTERVAL = 3000 // ms
36 };
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070037
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070038 CommandInterestValidator(const time::milliseconds& graceInterval =
39 time::milliseconds(static_cast<int>(GRACE_INTERVAL)))
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070040 : m_graceInterval(graceInterval < time::milliseconds::zero() ?
41 time::milliseconds(static_cast<int>(GRACE_INTERVAL)) : graceInterval)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080042 {
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080043 }
44
45 virtual
46 ~CommandInterestValidator()
47 {
48 }
49
Yingdi Yu0fc447c2014-04-29 19:38:32 -070050 /**
51 * @brief add an Interest rule that allows a specific certificate
52 *
53 * @param regex NDN Regex to match Interest Name
54 * @param certificate trusted certificate
55 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080056 void
57 addInterestRule(const std::string& regex, const IdentityCertificate& certificate);
58
Yingdi Yu0fc447c2014-04-29 19:38:32 -070059 /**
60 * @brief add an Interest rule that allows a specific public key
61 *
62 * @param regex NDN Regex to match Interest Name
63 * @param keyName KeyLocator.Name
64 * @param publicKey public key
65 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080066 void
67 addInterestRule(const std::string& regex, const Name& keyName, const PublicKey& publicKey);
68
Yingdi Yu0fc447c2014-04-29 19:38:32 -070069 /**
70 * @brief add an Interest rule that allows any signer
71 *
72 * @param regex NDN Regex to match Interest Name
73 * @note Command Interest matched by regex that is signed by any key will be accepted.
74 */
75 void
76 addInterestBypassRule(const std::string& regex);
77
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080078protected:
79 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070080 checkPolicy(const Data& data,
81 int stepCount,
82 const OnDataValidated& onValidated,
83 const OnDataValidationFailed& onValidationFailed,
84 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080085 {
Yingdi Yu40587c02014-02-21 16:40:48 -080086 onValidationFailed(data.shared_from_this(), "No policy for data checking");
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080087 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070088
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080089 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070090 checkPolicy(const Interest& interest,
91 int stepCount,
92 const OnInterestValidated& onValidated,
93 const OnInterestValidationFailed& onValidationFailed,
94 std::vector<shared_ptr<ValidationRequest> >& nextSteps);
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080095private:
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070096 time::milliseconds m_graceInterval; //ms
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080097 std::map<Name, PublicKey> m_trustAnchorsForInterest;
98 std::list<SecRuleSpecific> m_trustScopeForInterest;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070099
100 typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
101 LastTimestampMap m_lastTimestamp;
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800102};
103
104inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700105CommandInterestValidator::addInterestRule(const std::string& regex,
106 const IdentityCertificate& certificate)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800107{
108 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
109 addInterestRule(regex, keyName, certificate.getPublicKeyInfo());
110}
111
112inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700113CommandInterestValidator::addInterestRule(const std::string& regex,
114 const Name& keyName,
115 const PublicKey& publicKey)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800116{
117 m_trustAnchorsForInterest[keyName] = publicKey;
118 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
119 shared_ptr<Regex> signerRegex = Regex::fromName(keyName, true);
120 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex, signerRegex));
121}
122
123inline void
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700124CommandInterestValidator::addInterestBypassRule(const std::string& regex)
125{
126 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
127 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex));
128}
129
130inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700131CommandInterestValidator::checkPolicy(const Interest& interest,
132 int stepCount,
133 const OnInterestValidated& onValidated,
134 const OnInterestValidationFailed& onValidationFailed,
135 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800136{
Yingdi Yu40587c02014-02-21 16:40:48 -0800137 const Name& interestName = interest.getName();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700138
139 //Prepare
Yingdi Yu449e1142014-03-28 18:54:42 -0700140 if (interestName.size() < MIN_LENGTH)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700141 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800142 "Interest is not signed: " + interest.getName().toUri());
Yingdi Yu449e1142014-03-28 18:54:42 -0700143 Name keyName;
144 try
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800145 {
Yingdi Yu449e1142014-03-28 18:54:42 -0700146 Signature signature(interestName[POS_SIG_INFO].blockFromValue(),
147 interestName[POS_SIG_VALUE].blockFromValue());
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700148
Yingdi Yu449e1142014-03-28 18:54:42 -0700149 if (signature.getType() != Signature::Sha256WithRsa)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700150 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu449e1142014-03-28 18:54:42 -0700151 "Require SignatureSha256WithRsa");
Yingdi Yu40587c02014-02-21 16:40:48 -0800152
Yingdi Yu449e1142014-03-28 18:54:42 -0700153 SignatureSha256WithRsa sig(signature);
Yingdi Yu40587c02014-02-21 16:40:48 -0800154
Yingdi Yu449e1142014-03-28 18:54:42 -0700155 const KeyLocator& keyLocator = sig.getKeyLocator();
156
157 if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
158 return onValidationFailed(interest.shared_from_this(),
159 "Key Locator is not a name");
160
161 keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
162
163 //Check if command is in the trusted scope
164 bool isInScope = false;
165 for (std::list<SecRuleSpecific>::iterator scopeIt = m_trustScopeForInterest.begin();
166 scopeIt != m_trustScopeForInterest.end();
167 ++scopeIt)
168 {
169 if (scopeIt->satisfy(interestName, keyName))
170 {
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700171 if (scopeIt->isExempted())
172 {
173 return onValidated(interest.shared_from_this());
174 }
175
Yingdi Yu449e1142014-03-28 18:54:42 -0700176 isInScope = true;
177 break;
178 }
179 }
180 if (isInScope == false)
181 return onValidationFailed(interest.shared_from_this(),
182 "Signer cannot be authorized for the command: " +
183 keyName.toUri());
184
185 //Check signature
186 if (!Validator::verifySignature(interestName.wireEncode().value(),
187 interestName.wireEncode().value_size() -
188 interestName[-1].size(),
189 sig, m_trustAnchorsForInterest[keyName]))
190 return onValidationFailed(interest.shared_from_this(),
191 "Signature cannot be validated: " +
192 interest.getName().toUri());
193
194 //Check if timestamp is valid
195 time::system_clock::TimePoint interestTime =
196 time::fromUnixTimestamp(time::milliseconds(interestName.get(POS_TIMESTAMP).toNumber()));
197
198 time::system_clock::TimePoint currentTime = time::system_clock::now();
199
200 LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
201 if (timestampIt == m_lastTimestamp.end())
202 {
203 if (!(currentTime - m_graceInterval <= interestTime &&
204 interestTime <= currentTime + m_graceInterval))
205 return onValidationFailed(interest.shared_from_this(),
206 "The command is not in grace interval: " +
207 interest.getName().toUri());
208 }
209 else
210 {
211 if (interestTime <= timestampIt->second)
212 return onValidationFailed(interest.shared_from_this(),
213 "The command is outdated: " +
214 interest.getName().toUri());
215 }
216
217 //Update timestamp
218 if (timestampIt == m_lastTimestamp.end())
219 {
220 m_lastTimestamp[keyName] = interestTime;
221 }
222 else
223 {
224 timestampIt->second = interestTime;
225 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700226 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700227 catch (Signature::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700228 {
229 return onValidationFailed(interest.shared_from_this(),
230 "No valid signature");
231 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700232 catch (IdentityCertificate::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700233 {
234 return onValidationFailed(interest.shared_from_this(),
235 "Cannot locate the signing key");
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700236 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700237 catch (Tlv::Error& e)
238 {
239 return onValidationFailed(interest.shared_from_this(),
240 "Cannot decode signature related TLVs");
241 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800242
243 return onValidated(interest.shared_from_this());
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800244}
245
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800246} // namespace ndn
247
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700248#endif // NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP