blob: a6cd465acacfb1cb8d09b413b7b2caefdf4ff6cc [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"
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080026#include "../security/sec-rule-specific.hpp"
27
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070028#include <list>
29
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080030namespace ndn {
31
Yingdi Yu50b13902014-07-09 15:05:46 -070032/**
33 * @brief Helper class to validate CommandInterests
34 *
35 * @deprecated Use ValidatorConfig instead.
36 * See http://redmine.named-data.net/projects/ndn-cxx/wiki/CommandValidatorConf
37 * for more details about the configuration format of ValidatorConfig.
38 *
39 * @see http://redmine.named-data.net/projects/nfd/wiki/Command_Interests
40 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080041class CommandInterestValidator : public Validator
42{
43public:
44 enum {
45 POS_SIG_VALUE = -1,
46 POS_SIG_INFO = -2,
47 POS_RANDOM_VAL = -3,
48 POS_TIMESTAMP = -4,
49
Yingdi Yu449e1142014-03-28 18:54:42 -070050 MIN_LENGTH = 4,
51
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080052 GRACE_INTERVAL = 3000 // ms
53 };
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070054
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070055 CommandInterestValidator(const time::milliseconds& graceInterval =
56 time::milliseconds(static_cast<int>(GRACE_INTERVAL)))
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070057 : m_graceInterval(graceInterval < time::milliseconds::zero() ?
58 time::milliseconds(static_cast<int>(GRACE_INTERVAL)) : graceInterval)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080059 {
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080060 }
61
Yingdi Yu0fc447c2014-04-29 19:38:32 -070062 /**
63 * @brief add an Interest rule that allows a specific certificate
64 *
65 * @param regex NDN Regex to match Interest Name
66 * @param certificate trusted certificate
67 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080068 void
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070069 addInterestRule(const std::string& regex, const security::v1::IdentityCertificate& certificate);
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080070
Yingdi Yu0fc447c2014-04-29 19:38:32 -070071 /**
72 * @brief add an Interest rule that allows a specific public key
73 *
74 * @param regex NDN Regex to match Interest Name
75 * @param keyName KeyLocator.Name
76 * @param publicKey public key
77 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080078 void
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070079 addInterestRule(const std::string& regex, const Name& keyName, const security::v1::PublicKey& publicKey);
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080080
Yingdi Yu0fc447c2014-04-29 19:38:32 -070081 /**
82 * @brief add an Interest rule that allows any signer
83 *
84 * @param regex NDN Regex to match Interest Name
85 * @note Command Interest matched by regex that is signed by any key will be accepted.
86 */
87 void
88 addInterestBypassRule(const std::string& regex);
89
Alexander Afanasyev285c2cf2014-06-02 19:22:10 +030090 /**
91 * @brief Remove all installed Interest rules (e.g., when reinitialization needed)
92 */
93 void
94 reset();
95
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080096protected:
97 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070098 checkPolicy(const Data& data,
99 int stepCount,
100 const OnDataValidated& onValidated,
101 const OnDataValidationFailed& onValidationFailed,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200102 std::vector<shared_ptr<ValidationRequest>>& nextSteps) override
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800103 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800104 onValidationFailed(data.shared_from_this(), "No policy for data checking");
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800105 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700106
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800107 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700108 checkPolicy(const Interest& interest,
109 int stepCount,
110 const OnInterestValidated& onValidated,
111 const OnInterestValidationFailed& onValidationFailed,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200112 std::vector<shared_ptr<ValidationRequest>>& nextSteps) override;
113
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800114private:
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700115 time::milliseconds m_graceInterval; //ms
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700116 std::map<Name, security::v1::PublicKey> m_trustAnchorsForInterest;
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800117 std::list<SecRuleSpecific> m_trustScopeForInterest;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700118
119 typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
120 LastTimestampMap m_lastTimestamp;
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800121};
122
123inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700124CommandInterestValidator::addInterestRule(const std::string& regex,
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700125 const security::v1::IdentityCertificate& certificate)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800126{
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700127 Name keyName = security::v1::IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800128 addInterestRule(regex, keyName, certificate.getPublicKeyInfo());
129}
130
131inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700132CommandInterestValidator::addInterestRule(const std::string& regex,
133 const Name& keyName,
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700134 const security::v1::PublicKey& publicKey)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800135{
136 m_trustAnchorsForInterest[keyName] = publicKey;
137 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
138 shared_ptr<Regex> signerRegex = Regex::fromName(keyName, true);
139 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex, signerRegex));
140}
141
142inline void
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700143CommandInterestValidator::addInterestBypassRule(const std::string& regex)
144{
145 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
146 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex));
147}
148
149inline void
Alexander Afanasyev285c2cf2014-06-02 19:22:10 +0300150CommandInterestValidator::reset()
151{
152 m_trustAnchorsForInterest.clear();
153 m_trustScopeForInterest.clear();
154}
155
156inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700157CommandInterestValidator::checkPolicy(const Interest& interest,
158 int stepCount,
159 const OnInterestValidated& onValidated,
160 const OnInterestValidationFailed& onValidationFailed,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200161 std::vector<shared_ptr<ValidationRequest>>& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800162{
Yingdi Yu40587c02014-02-21 16:40:48 -0800163 const Name& interestName = interest.getName();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700164
165 //Prepare
Yingdi Yu449e1142014-03-28 18:54:42 -0700166 if (interestName.size() < MIN_LENGTH)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700167 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800168 "Interest is not signed: " + interest.getName().toUri());
Yingdi Yu449e1142014-03-28 18:54:42 -0700169 Name keyName;
170 try
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800171 {
Yingdi Yu449e1142014-03-28 18:54:42 -0700172 Signature signature(interestName[POS_SIG_INFO].blockFromValue(),
173 interestName[POS_SIG_VALUE].blockFromValue());
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700174
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600175 if (signature.getType() != tlv::SignatureSha256WithRsa)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700176 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu449e1142014-03-28 18:54:42 -0700177 "Require SignatureSha256WithRsa");
Yingdi Yu40587c02014-02-21 16:40:48 -0800178
Yingdi Yu449e1142014-03-28 18:54:42 -0700179 SignatureSha256WithRsa sig(signature);
Yingdi Yu40587c02014-02-21 16:40:48 -0800180
Yingdi Yu449e1142014-03-28 18:54:42 -0700181 const KeyLocator& keyLocator = sig.getKeyLocator();
182
183 if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
184 return onValidationFailed(interest.shared_from_this(),
185 "Key Locator is not a name");
186
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700187 keyName = security::v1::IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
Yingdi Yu449e1142014-03-28 18:54:42 -0700188
189 //Check if command is in the trusted scope
190 bool isInScope = false;
191 for (std::list<SecRuleSpecific>::iterator scopeIt = m_trustScopeForInterest.begin();
192 scopeIt != m_trustScopeForInterest.end();
193 ++scopeIt)
194 {
195 if (scopeIt->satisfy(interestName, keyName))
196 {
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700197 if (scopeIt->isExempted())
198 {
199 return onValidated(interest.shared_from_this());
200 }
201
Yingdi Yu449e1142014-03-28 18:54:42 -0700202 isInScope = true;
203 break;
204 }
205 }
206 if (isInScope == false)
207 return onValidationFailed(interest.shared_from_this(),
208 "Signer cannot be authorized for the command: " +
209 keyName.toUri());
210
211 //Check signature
212 if (!Validator::verifySignature(interestName.wireEncode().value(),
213 interestName.wireEncode().value_size() -
214 interestName[-1].size(),
215 sig, m_trustAnchorsForInterest[keyName]))
216 return onValidationFailed(interest.shared_from_this(),
217 "Signature cannot be validated: " +
218 interest.getName().toUri());
219
220 //Check if timestamp is valid
221 time::system_clock::TimePoint interestTime =
222 time::fromUnixTimestamp(time::milliseconds(interestName.get(POS_TIMESTAMP).toNumber()));
223
224 time::system_clock::TimePoint currentTime = time::system_clock::now();
225
226 LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
227 if (timestampIt == m_lastTimestamp.end())
228 {
229 if (!(currentTime - m_graceInterval <= interestTime &&
230 interestTime <= currentTime + m_graceInterval))
231 return onValidationFailed(interest.shared_from_this(),
232 "The command is not in grace interval: " +
233 interest.getName().toUri());
234 }
235 else
236 {
237 if (interestTime <= timestampIt->second)
238 return onValidationFailed(interest.shared_from_this(),
239 "The command is outdated: " +
240 interest.getName().toUri());
241 }
242
243 //Update timestamp
244 if (timestampIt == m_lastTimestamp.end())
245 {
246 m_lastTimestamp[keyName] = interestTime;
247 }
248 else
249 {
250 timestampIt->second = interestTime;
251 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700252 }
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200253 catch (const Signature::Error&)
Yingdi Yu449e1142014-03-28 18:54:42 -0700254 {
255 return onValidationFailed(interest.shared_from_this(),
256 "No valid signature");
257 }
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700258 catch (const security::v1::IdentityCertificate::Error&)
Yingdi Yu449e1142014-03-28 18:54:42 -0700259 {
260 return onValidationFailed(interest.shared_from_this(),
261 "Cannot locate the signing key");
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700262 }
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200263 catch (const tlv::Error&)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700264 {
265 return onValidationFailed(interest.shared_from_this(),
266 "Cannot decode signature related TLVs");
267 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800268
269 return onValidated(interest.shared_from_this());
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800270}
271
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800272} // namespace ndn
273
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700274#endif // NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP