blob: 7d179a043df34440ce5a23dc4abb616a8ee28648 [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
33class CommandInterestValidator : public Validator
34{
35public:
36 enum {
37 POS_SIG_VALUE = -1,
38 POS_SIG_INFO = -2,
39 POS_RANDOM_VAL = -3,
40 POS_TIMESTAMP = -4,
41
Yingdi Yu449e1142014-03-28 18:54:42 -070042 MIN_LENGTH = 4,
43
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080044 GRACE_INTERVAL = 3000 // ms
45 };
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070046
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070047 CommandInterestValidator(const time::milliseconds& graceInterval =
48 time::milliseconds(static_cast<int>(GRACE_INTERVAL)))
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070049 : m_graceInterval(graceInterval < time::milliseconds::zero() ?
50 time::milliseconds(static_cast<int>(GRACE_INTERVAL)) : graceInterval)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080051 {
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080052 }
53
54 virtual
55 ~CommandInterestValidator()
56 {
57 }
58
Yingdi Yu0fc447c2014-04-29 19:38:32 -070059 /**
60 * @brief add an Interest rule that allows a specific certificate
61 *
62 * @param regex NDN Regex to match Interest Name
63 * @param certificate trusted certificate
64 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080065 void
66 addInterestRule(const std::string& regex, const IdentityCertificate& certificate);
67
Yingdi Yu0fc447c2014-04-29 19:38:32 -070068 /**
69 * @brief add an Interest rule that allows a specific public key
70 *
71 * @param regex NDN Regex to match Interest Name
72 * @param keyName KeyLocator.Name
73 * @param publicKey public key
74 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080075 void
76 addInterestRule(const std::string& regex, const Name& keyName, const PublicKey& publicKey);
77
Yingdi Yu0fc447c2014-04-29 19:38:32 -070078 /**
79 * @brief add an Interest rule that allows any signer
80 *
81 * @param regex NDN Regex to match Interest Name
82 * @note Command Interest matched by regex that is signed by any key will be accepted.
83 */
84 void
85 addInterestBypassRule(const std::string& regex);
86
Alexander Afanasyev285c2cf2014-06-02 19:22:10 +030087 /**
88 * @brief Remove all installed Interest rules (e.g., when reinitialization needed)
89 */
90 void
91 reset();
92
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080093protected:
94 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070095 checkPolicy(const Data& data,
96 int stepCount,
97 const OnDataValidated& onValidated,
98 const OnDataValidationFailed& onValidationFailed,
99 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800100 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800101 onValidationFailed(data.shared_from_this(), "No policy for data checking");
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800102 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700103
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800104 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700105 checkPolicy(const Interest& interest,
106 int stepCount,
107 const OnInterestValidated& onValidated,
108 const OnInterestValidationFailed& onValidationFailed,
109 std::vector<shared_ptr<ValidationRequest> >& nextSteps);
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800110private:
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700111 time::milliseconds m_graceInterval; //ms
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800112 std::map<Name, PublicKey> m_trustAnchorsForInterest;
113 std::list<SecRuleSpecific> m_trustScopeForInterest;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700114
115 typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
116 LastTimestampMap m_lastTimestamp;
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800117};
118
119inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700120CommandInterestValidator::addInterestRule(const std::string& regex,
121 const IdentityCertificate& certificate)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800122{
123 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
124 addInterestRule(regex, keyName, certificate.getPublicKeyInfo());
125}
126
127inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700128CommandInterestValidator::addInterestRule(const std::string& regex,
129 const Name& keyName,
130 const PublicKey& publicKey)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800131{
132 m_trustAnchorsForInterest[keyName] = publicKey;
133 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
134 shared_ptr<Regex> signerRegex = Regex::fromName(keyName, true);
135 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex, signerRegex));
136}
137
138inline void
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700139CommandInterestValidator::addInterestBypassRule(const std::string& regex)
140{
141 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
142 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex));
143}
144
145inline void
Alexander Afanasyev285c2cf2014-06-02 19:22:10 +0300146CommandInterestValidator::reset()
147{
148 m_trustAnchorsForInterest.clear();
149 m_trustScopeForInterest.clear();
150}
151
152inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700153CommandInterestValidator::checkPolicy(const Interest& interest,
154 int stepCount,
155 const OnInterestValidated& onValidated,
156 const OnInterestValidationFailed& onValidationFailed,
157 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800158{
Yingdi Yu40587c02014-02-21 16:40:48 -0800159 const Name& interestName = interest.getName();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700160
161 //Prepare
Yingdi Yu449e1142014-03-28 18:54:42 -0700162 if (interestName.size() < MIN_LENGTH)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700163 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800164 "Interest is not signed: " + interest.getName().toUri());
Yingdi Yu449e1142014-03-28 18:54:42 -0700165 Name keyName;
166 try
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800167 {
Yingdi Yu449e1142014-03-28 18:54:42 -0700168 Signature signature(interestName[POS_SIG_INFO].blockFromValue(),
169 interestName[POS_SIG_VALUE].blockFromValue());
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700170
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700171 if (signature.getType() != Tlv::SignatureSha256WithRsa)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700172 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu449e1142014-03-28 18:54:42 -0700173 "Require SignatureSha256WithRsa");
Yingdi Yu40587c02014-02-21 16:40:48 -0800174
Yingdi Yu449e1142014-03-28 18:54:42 -0700175 SignatureSha256WithRsa sig(signature);
Yingdi Yu40587c02014-02-21 16:40:48 -0800176
Yingdi Yu449e1142014-03-28 18:54:42 -0700177 const KeyLocator& keyLocator = sig.getKeyLocator();
178
179 if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
180 return onValidationFailed(interest.shared_from_this(),
181 "Key Locator is not a name");
182
183 keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
184
185 //Check if command is in the trusted scope
186 bool isInScope = false;
187 for (std::list<SecRuleSpecific>::iterator scopeIt = m_trustScopeForInterest.begin();
188 scopeIt != m_trustScopeForInterest.end();
189 ++scopeIt)
190 {
191 if (scopeIt->satisfy(interestName, keyName))
192 {
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700193 if (scopeIt->isExempted())
194 {
195 return onValidated(interest.shared_from_this());
196 }
197
Yingdi Yu449e1142014-03-28 18:54:42 -0700198 isInScope = true;
199 break;
200 }
201 }
202 if (isInScope == false)
203 return onValidationFailed(interest.shared_from_this(),
204 "Signer cannot be authorized for the command: " +
205 keyName.toUri());
206
207 //Check signature
208 if (!Validator::verifySignature(interestName.wireEncode().value(),
209 interestName.wireEncode().value_size() -
210 interestName[-1].size(),
211 sig, m_trustAnchorsForInterest[keyName]))
212 return onValidationFailed(interest.shared_from_this(),
213 "Signature cannot be validated: " +
214 interest.getName().toUri());
215
216 //Check if timestamp is valid
217 time::system_clock::TimePoint interestTime =
218 time::fromUnixTimestamp(time::milliseconds(interestName.get(POS_TIMESTAMP).toNumber()));
219
220 time::system_clock::TimePoint currentTime = time::system_clock::now();
221
222 LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
223 if (timestampIt == m_lastTimestamp.end())
224 {
225 if (!(currentTime - m_graceInterval <= interestTime &&
226 interestTime <= currentTime + m_graceInterval))
227 return onValidationFailed(interest.shared_from_this(),
228 "The command is not in grace interval: " +
229 interest.getName().toUri());
230 }
231 else
232 {
233 if (interestTime <= timestampIt->second)
234 return onValidationFailed(interest.shared_from_this(),
235 "The command is outdated: " +
236 interest.getName().toUri());
237 }
238
239 //Update timestamp
240 if (timestampIt == m_lastTimestamp.end())
241 {
242 m_lastTimestamp[keyName] = interestTime;
243 }
244 else
245 {
246 timestampIt->second = interestTime;
247 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700248 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700249 catch (Signature::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700250 {
251 return onValidationFailed(interest.shared_from_this(),
252 "No valid signature");
253 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700254 catch (IdentityCertificate::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700255 {
256 return onValidationFailed(interest.shared_from_this(),
257 "Cannot locate the signing key");
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700258 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700259 catch (Tlv::Error& e)
260 {
261 return onValidationFailed(interest.shared_from_this(),
262 "Cannot decode signature related TLVs");
263 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800264
265 return onValidated(interest.shared_from_this());
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800266}
267
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800268} // namespace ndn
269
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700270#endif // NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP