blob: b7c34945a52bfe0a31aeea9a169b071f5a8a0828 [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/**
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +02003 * Copyright (c) 2013-2016 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
Yingdi Yu0fc447c2014-04-29 19:38:32 -070063 /**
64 * @brief add an Interest rule that allows a specific certificate
65 *
66 * @param regex NDN Regex to match Interest Name
67 * @param certificate trusted certificate
68 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080069 void
70 addInterestRule(const std::string& regex, const IdentityCertificate& certificate);
71
Yingdi Yu0fc447c2014-04-29 19:38:32 -070072 /**
73 * @brief add an Interest rule that allows a specific public key
74 *
75 * @param regex NDN Regex to match Interest Name
76 * @param keyName KeyLocator.Name
77 * @param publicKey public key
78 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080079 void
80 addInterestRule(const std::string& regex, const Name& keyName, const PublicKey& publicKey);
81
Yingdi Yu0fc447c2014-04-29 19:38:32 -070082 /**
83 * @brief add an Interest rule that allows any signer
84 *
85 * @param regex NDN Regex to match Interest Name
86 * @note Command Interest matched by regex that is signed by any key will be accepted.
87 */
88 void
89 addInterestBypassRule(const std::string& regex);
90
Alexander Afanasyev285c2cf2014-06-02 19:22:10 +030091 /**
92 * @brief Remove all installed Interest rules (e.g., when reinitialization needed)
93 */
94 void
95 reset();
96
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080097protected:
98 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070099 checkPolicy(const Data& data,
100 int stepCount,
101 const OnDataValidated& onValidated,
102 const OnDataValidationFailed& onValidationFailed,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200103 std::vector<shared_ptr<ValidationRequest>>& nextSteps) override
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800104 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800105 onValidationFailed(data.shared_from_this(), "No policy for data checking");
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800106 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700107
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800108 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700109 checkPolicy(const Interest& interest,
110 int stepCount,
111 const OnInterestValidated& onValidated,
112 const OnInterestValidationFailed& onValidationFailed,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200113 std::vector<shared_ptr<ValidationRequest>>& nextSteps) override;
114
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800115private:
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700116 time::milliseconds m_graceInterval; //ms
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800117 std::map<Name, PublicKey> m_trustAnchorsForInterest;
118 std::list<SecRuleSpecific> m_trustScopeForInterest;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700119
120 typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
121 LastTimestampMap m_lastTimestamp;
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800122};
123
124inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700125CommandInterestValidator::addInterestRule(const std::string& regex,
126 const IdentityCertificate& certificate)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800127{
128 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
129 addInterestRule(regex, keyName, certificate.getPublicKeyInfo());
130}
131
132inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700133CommandInterestValidator::addInterestRule(const std::string& regex,
134 const Name& keyName,
135 const PublicKey& publicKey)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800136{
137 m_trustAnchorsForInterest[keyName] = publicKey;
138 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
139 shared_ptr<Regex> signerRegex = Regex::fromName(keyName, true);
140 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex, signerRegex));
141}
142
143inline void
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700144CommandInterestValidator::addInterestBypassRule(const std::string& regex)
145{
146 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
147 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex));
148}
149
150inline void
Alexander Afanasyev285c2cf2014-06-02 19:22:10 +0300151CommandInterestValidator::reset()
152{
153 m_trustAnchorsForInterest.clear();
154 m_trustScopeForInterest.clear();
155}
156
157inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700158CommandInterestValidator::checkPolicy(const Interest& interest,
159 int stepCount,
160 const OnInterestValidated& onValidated,
161 const OnInterestValidationFailed& onValidationFailed,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200162 std::vector<shared_ptr<ValidationRequest>>& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800163{
Yingdi Yu40587c02014-02-21 16:40:48 -0800164 const Name& interestName = interest.getName();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700165
166 //Prepare
Yingdi Yu449e1142014-03-28 18:54:42 -0700167 if (interestName.size() < MIN_LENGTH)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700168 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800169 "Interest is not signed: " + interest.getName().toUri());
Yingdi Yu449e1142014-03-28 18:54:42 -0700170 Name keyName;
171 try
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800172 {
Yingdi Yu449e1142014-03-28 18:54:42 -0700173 Signature signature(interestName[POS_SIG_INFO].blockFromValue(),
174 interestName[POS_SIG_VALUE].blockFromValue());
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700175
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600176 if (signature.getType() != tlv::SignatureSha256WithRsa)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700177 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu449e1142014-03-28 18:54:42 -0700178 "Require SignatureSha256WithRsa");
Yingdi Yu40587c02014-02-21 16:40:48 -0800179
Yingdi Yu449e1142014-03-28 18:54:42 -0700180 SignatureSha256WithRsa sig(signature);
Yingdi Yu40587c02014-02-21 16:40:48 -0800181
Yingdi Yu449e1142014-03-28 18:54:42 -0700182 const KeyLocator& keyLocator = sig.getKeyLocator();
183
184 if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
185 return onValidationFailed(interest.shared_from_this(),
186 "Key Locator is not a name");
187
188 keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
189
190 //Check if command is in the trusted scope
191 bool isInScope = false;
192 for (std::list<SecRuleSpecific>::iterator scopeIt = m_trustScopeForInterest.begin();
193 scopeIt != m_trustScopeForInterest.end();
194 ++scopeIt)
195 {
196 if (scopeIt->satisfy(interestName, keyName))
197 {
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700198 if (scopeIt->isExempted())
199 {
200 return onValidated(interest.shared_from_this());
201 }
202
Yingdi Yu449e1142014-03-28 18:54:42 -0700203 isInScope = true;
204 break;
205 }
206 }
207 if (isInScope == false)
208 return onValidationFailed(interest.shared_from_this(),
209 "Signer cannot be authorized for the command: " +
210 keyName.toUri());
211
212 //Check signature
213 if (!Validator::verifySignature(interestName.wireEncode().value(),
214 interestName.wireEncode().value_size() -
215 interestName[-1].size(),
216 sig, m_trustAnchorsForInterest[keyName]))
217 return onValidationFailed(interest.shared_from_this(),
218 "Signature cannot be validated: " +
219 interest.getName().toUri());
220
221 //Check if timestamp is valid
222 time::system_clock::TimePoint interestTime =
223 time::fromUnixTimestamp(time::milliseconds(interestName.get(POS_TIMESTAMP).toNumber()));
224
225 time::system_clock::TimePoint currentTime = time::system_clock::now();
226
227 LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
228 if (timestampIt == m_lastTimestamp.end())
229 {
230 if (!(currentTime - m_graceInterval <= interestTime &&
231 interestTime <= currentTime + m_graceInterval))
232 return onValidationFailed(interest.shared_from_this(),
233 "The command is not in grace interval: " +
234 interest.getName().toUri());
235 }
236 else
237 {
238 if (interestTime <= timestampIt->second)
239 return onValidationFailed(interest.shared_from_this(),
240 "The command is outdated: " +
241 interest.getName().toUri());
242 }
243
244 //Update timestamp
245 if (timestampIt == m_lastTimestamp.end())
246 {
247 m_lastTimestamp[keyName] = interestTime;
248 }
249 else
250 {
251 timestampIt->second = interestTime;
252 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700253 }
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200254 catch (const Signature::Error&)
Yingdi Yu449e1142014-03-28 18:54:42 -0700255 {
256 return onValidationFailed(interest.shared_from_this(),
257 "No valid signature");
258 }
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200259 catch (const IdentityCertificate::Error&)
Yingdi Yu449e1142014-03-28 18:54:42 -0700260 {
261 return onValidationFailed(interest.shared_from_this(),
262 "Cannot locate the signing key");
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700263 }
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200264 catch (const tlv::Error&)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700265 {
266 return onValidationFailed(interest.shared_from_this(),
267 "Cannot decode signature related TLVs");
268 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800269
270 return onValidated(interest.shared_from_this());
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800271}
272
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800273} // namespace ndn
274
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700275#endif // NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP