blob: d132231d15cd7f7c79006429737fbb0c11405044 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -08002/**
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 Afanasyev9cbf70a2014-02-17 18:07:51 -080020 */
21
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070022#ifndef NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP
23#define NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080024
25#include "../security/validator.hpp"
26#include "../security/identity-certificate.hpp"
27#include "../security/sec-rule-specific.hpp"
28
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070029#include <list>
30
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080031namespace ndn {
32
Yingdi Yu50b13902014-07-09 15:05:46 -070033/**
34 * @brief Helper class to validate CommandInterests
35 *
36 * @deprecated Use ValidatorConfig instead.
37 * See http://redmine.named-data.net/projects/ndn-cxx/wiki/CommandValidatorConf
38 * for more details about the configuration format of ValidatorConfig.
39 *
40 * @see http://redmine.named-data.net/projects/nfd/wiki/Command_Interests
41 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080042class CommandInterestValidator : public Validator
43{
44public:
45 enum {
46 POS_SIG_VALUE = -1,
47 POS_SIG_INFO = -2,
48 POS_RANDOM_VAL = -3,
49 POS_TIMESTAMP = -4,
50
Yingdi Yu449e1142014-03-28 18:54:42 -070051 MIN_LENGTH = 4,
52
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080053 GRACE_INTERVAL = 3000 // ms
54 };
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070055
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070056 CommandInterestValidator(const time::milliseconds& graceInterval =
57 time::milliseconds(static_cast<int>(GRACE_INTERVAL)))
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070058 : m_graceInterval(graceInterval < time::milliseconds::zero() ?
59 time::milliseconds(static_cast<int>(GRACE_INTERVAL)) : graceInterval)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080060 {
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080061 }
62
63 virtual
64 ~CommandInterestValidator()
65 {
66 }
67
Yingdi Yu0fc447c2014-04-29 19:38:32 -070068 /**
69 * @brief add an Interest rule that allows a specific certificate
70 *
71 * @param regex NDN Regex to match Interest Name
72 * @param certificate trusted certificate
73 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080074 void
75 addInterestRule(const std::string& regex, const IdentityCertificate& certificate);
76
Yingdi Yu0fc447c2014-04-29 19:38:32 -070077 /**
78 * @brief add an Interest rule that allows a specific public key
79 *
80 * @param regex NDN Regex to match Interest Name
81 * @param keyName KeyLocator.Name
82 * @param publicKey public key
83 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080084 void
85 addInterestRule(const std::string& regex, const Name& keyName, const PublicKey& publicKey);
86
Yingdi Yu0fc447c2014-04-29 19:38:32 -070087 /**
88 * @brief add an Interest rule that allows any signer
89 *
90 * @param regex NDN Regex to match Interest Name
91 * @note Command Interest matched by regex that is signed by any key will be accepted.
92 */
93 void
94 addInterestBypassRule(const std::string& regex);
95
Alexander Afanasyev285c2cf2014-06-02 19:22:10 +030096 /**
97 * @brief Remove all installed Interest rules (e.g., when reinitialization needed)
98 */
99 void
100 reset();
101
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800102protected:
103 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700104 checkPolicy(const Data& data,
105 int stepCount,
106 const OnDataValidated& onValidated,
107 const OnDataValidationFailed& onValidationFailed,
108 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800109 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800110 onValidationFailed(data.shared_from_this(), "No policy for data checking");
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800111 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700112
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800113 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700114 checkPolicy(const Interest& interest,
115 int stepCount,
116 const OnInterestValidated& onValidated,
117 const OnInterestValidationFailed& onValidationFailed,
118 std::vector<shared_ptr<ValidationRequest> >& nextSteps);
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800119private:
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700120 time::milliseconds m_graceInterval; //ms
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800121 std::map<Name, PublicKey> m_trustAnchorsForInterest;
122 std::list<SecRuleSpecific> m_trustScopeForInterest;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700123
124 typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
125 LastTimestampMap m_lastTimestamp;
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800126};
127
128inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700129CommandInterestValidator::addInterestRule(const std::string& regex,
130 const IdentityCertificate& certificate)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800131{
132 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
133 addInterestRule(regex, keyName, certificate.getPublicKeyInfo());
134}
135
136inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700137CommandInterestValidator::addInterestRule(const std::string& regex,
138 const Name& keyName,
139 const PublicKey& publicKey)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800140{
141 m_trustAnchorsForInterest[keyName] = publicKey;
142 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
143 shared_ptr<Regex> signerRegex = Regex::fromName(keyName, true);
144 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex, signerRegex));
145}
146
147inline void
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700148CommandInterestValidator::addInterestBypassRule(const std::string& regex)
149{
150 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
151 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex));
152}
153
154inline void
Alexander Afanasyev285c2cf2014-06-02 19:22:10 +0300155CommandInterestValidator::reset()
156{
157 m_trustAnchorsForInterest.clear();
158 m_trustScopeForInterest.clear();
159}
160
161inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700162CommandInterestValidator::checkPolicy(const Interest& interest,
163 int stepCount,
164 const OnInterestValidated& onValidated,
165 const OnInterestValidationFailed& onValidationFailed,
166 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800167{
Yingdi Yu40587c02014-02-21 16:40:48 -0800168 const Name& interestName = interest.getName();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700169
170 //Prepare
Yingdi Yu449e1142014-03-28 18:54:42 -0700171 if (interestName.size() < MIN_LENGTH)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700172 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800173 "Interest is not signed: " + interest.getName().toUri());
Yingdi Yu449e1142014-03-28 18:54:42 -0700174 Name keyName;
175 try
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800176 {
Yingdi Yu449e1142014-03-28 18:54:42 -0700177 Signature signature(interestName[POS_SIG_INFO].blockFromValue(),
178 interestName[POS_SIG_VALUE].blockFromValue());
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700179
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700180 if (signature.getType() != Tlv::SignatureSha256WithRsa)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700181 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu449e1142014-03-28 18:54:42 -0700182 "Require SignatureSha256WithRsa");
Yingdi Yu40587c02014-02-21 16:40:48 -0800183
Yingdi Yu449e1142014-03-28 18:54:42 -0700184 SignatureSha256WithRsa sig(signature);
Yingdi Yu40587c02014-02-21 16:40:48 -0800185
Yingdi Yu449e1142014-03-28 18:54:42 -0700186 const KeyLocator& keyLocator = sig.getKeyLocator();
187
188 if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
189 return onValidationFailed(interest.shared_from_this(),
190 "Key Locator is not a name");
191
192 keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
193
194 //Check if command is in the trusted scope
195 bool isInScope = false;
196 for (std::list<SecRuleSpecific>::iterator scopeIt = m_trustScopeForInterest.begin();
197 scopeIt != m_trustScopeForInterest.end();
198 ++scopeIt)
199 {
200 if (scopeIt->satisfy(interestName, keyName))
201 {
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700202 if (scopeIt->isExempted())
203 {
204 return onValidated(interest.shared_from_this());
205 }
206
Yingdi Yu449e1142014-03-28 18:54:42 -0700207 isInScope = true;
208 break;
209 }
210 }
211 if (isInScope == false)
212 return onValidationFailed(interest.shared_from_this(),
213 "Signer cannot be authorized for the command: " +
214 keyName.toUri());
215
216 //Check signature
217 if (!Validator::verifySignature(interestName.wireEncode().value(),
218 interestName.wireEncode().value_size() -
219 interestName[-1].size(),
220 sig, m_trustAnchorsForInterest[keyName]))
221 return onValidationFailed(interest.shared_from_this(),
222 "Signature cannot be validated: " +
223 interest.getName().toUri());
224
225 //Check if timestamp is valid
226 time::system_clock::TimePoint interestTime =
227 time::fromUnixTimestamp(time::milliseconds(interestName.get(POS_TIMESTAMP).toNumber()));
228
229 time::system_clock::TimePoint currentTime = time::system_clock::now();
230
231 LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
232 if (timestampIt == m_lastTimestamp.end())
233 {
234 if (!(currentTime - m_graceInterval <= interestTime &&
235 interestTime <= currentTime + m_graceInterval))
236 return onValidationFailed(interest.shared_from_this(),
237 "The command is not in grace interval: " +
238 interest.getName().toUri());
239 }
240 else
241 {
242 if (interestTime <= timestampIt->second)
243 return onValidationFailed(interest.shared_from_this(),
244 "The command is outdated: " +
245 interest.getName().toUri());
246 }
247
248 //Update timestamp
249 if (timestampIt == m_lastTimestamp.end())
250 {
251 m_lastTimestamp[keyName] = interestTime;
252 }
253 else
254 {
255 timestampIt->second = interestTime;
256 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700257 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700258 catch (Signature::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700259 {
260 return onValidationFailed(interest.shared_from_this(),
261 "No valid signature");
262 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700263 catch (IdentityCertificate::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700264 {
265 return onValidationFailed(interest.shared_from_this(),
266 "Cannot locate the signing key");
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700267 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700268 catch (Tlv::Error& e)
269 {
270 return onValidationFailed(interest.shared_from_this(),
271 "Cannot decode signature related TLVs");
272 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800273
274 return onValidated(interest.shared_from_this());
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800275}
276
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800277} // namespace ndn
278
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700279#endif // NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP