blob: 9a077b13123dd4bf384771b43cd60e5c3c08da76 [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 Afanasyev9cbf70a2014-02-17 18:07:51 -080087protected:
88 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070089 checkPolicy(const Data& data,
90 int stepCount,
91 const OnDataValidated& onValidated,
92 const OnDataValidationFailed& onValidationFailed,
93 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080094 {
Yingdi Yu40587c02014-02-21 16:40:48 -080095 onValidationFailed(data.shared_from_this(), "No policy for data checking");
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080096 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070097
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080098 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070099 checkPolicy(const Interest& interest,
100 int stepCount,
101 const OnInterestValidated& onValidated,
102 const OnInterestValidationFailed& onValidationFailed,
103 std::vector<shared_ptr<ValidationRequest> >& nextSteps);
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800104private:
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700105 time::milliseconds m_graceInterval; //ms
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800106 std::map<Name, PublicKey> m_trustAnchorsForInterest;
107 std::list<SecRuleSpecific> m_trustScopeForInterest;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700108
109 typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
110 LastTimestampMap m_lastTimestamp;
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800111};
112
113inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700114CommandInterestValidator::addInterestRule(const std::string& regex,
115 const IdentityCertificate& certificate)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800116{
117 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
118 addInterestRule(regex, keyName, certificate.getPublicKeyInfo());
119}
120
121inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700122CommandInterestValidator::addInterestRule(const std::string& regex,
123 const Name& keyName,
124 const PublicKey& publicKey)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800125{
126 m_trustAnchorsForInterest[keyName] = publicKey;
127 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
128 shared_ptr<Regex> signerRegex = Regex::fromName(keyName, true);
129 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex, signerRegex));
130}
131
132inline void
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700133CommandInterestValidator::addInterestBypassRule(const std::string& regex)
134{
135 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
136 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex));
137}
138
139inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700140CommandInterestValidator::checkPolicy(const Interest& interest,
141 int stepCount,
142 const OnInterestValidated& onValidated,
143 const OnInterestValidationFailed& onValidationFailed,
144 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800145{
Yingdi Yu40587c02014-02-21 16:40:48 -0800146 const Name& interestName = interest.getName();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700147
148 //Prepare
Yingdi Yu449e1142014-03-28 18:54:42 -0700149 if (interestName.size() < MIN_LENGTH)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700150 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800151 "Interest is not signed: " + interest.getName().toUri());
Yingdi Yu449e1142014-03-28 18:54:42 -0700152 Name keyName;
153 try
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800154 {
Yingdi Yu449e1142014-03-28 18:54:42 -0700155 Signature signature(interestName[POS_SIG_INFO].blockFromValue(),
156 interestName[POS_SIG_VALUE].blockFromValue());
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700157
Yingdi Yu449e1142014-03-28 18:54:42 -0700158 if (signature.getType() != Signature::Sha256WithRsa)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700159 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu449e1142014-03-28 18:54:42 -0700160 "Require SignatureSha256WithRsa");
Yingdi Yu40587c02014-02-21 16:40:48 -0800161
Yingdi Yu449e1142014-03-28 18:54:42 -0700162 SignatureSha256WithRsa sig(signature);
Yingdi Yu40587c02014-02-21 16:40:48 -0800163
Yingdi Yu449e1142014-03-28 18:54:42 -0700164 const KeyLocator& keyLocator = sig.getKeyLocator();
165
166 if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
167 return onValidationFailed(interest.shared_from_this(),
168 "Key Locator is not a name");
169
170 keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
171
172 //Check if command is in the trusted scope
173 bool isInScope = false;
174 for (std::list<SecRuleSpecific>::iterator scopeIt = m_trustScopeForInterest.begin();
175 scopeIt != m_trustScopeForInterest.end();
176 ++scopeIt)
177 {
178 if (scopeIt->satisfy(interestName, keyName))
179 {
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700180 if (scopeIt->isExempted())
181 {
182 return onValidated(interest.shared_from_this());
183 }
184
Yingdi Yu449e1142014-03-28 18:54:42 -0700185 isInScope = true;
186 break;
187 }
188 }
189 if (isInScope == false)
190 return onValidationFailed(interest.shared_from_this(),
191 "Signer cannot be authorized for the command: " +
192 keyName.toUri());
193
194 //Check signature
195 if (!Validator::verifySignature(interestName.wireEncode().value(),
196 interestName.wireEncode().value_size() -
197 interestName[-1].size(),
198 sig, m_trustAnchorsForInterest[keyName]))
199 return onValidationFailed(interest.shared_from_this(),
200 "Signature cannot be validated: " +
201 interest.getName().toUri());
202
203 //Check if timestamp is valid
204 time::system_clock::TimePoint interestTime =
205 time::fromUnixTimestamp(time::milliseconds(interestName.get(POS_TIMESTAMP).toNumber()));
206
207 time::system_clock::TimePoint currentTime = time::system_clock::now();
208
209 LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
210 if (timestampIt == m_lastTimestamp.end())
211 {
212 if (!(currentTime - m_graceInterval <= interestTime &&
213 interestTime <= currentTime + m_graceInterval))
214 return onValidationFailed(interest.shared_from_this(),
215 "The command is not in grace interval: " +
216 interest.getName().toUri());
217 }
218 else
219 {
220 if (interestTime <= timestampIt->second)
221 return onValidationFailed(interest.shared_from_this(),
222 "The command is outdated: " +
223 interest.getName().toUri());
224 }
225
226 //Update timestamp
227 if (timestampIt == m_lastTimestamp.end())
228 {
229 m_lastTimestamp[keyName] = interestTime;
230 }
231 else
232 {
233 timestampIt->second = interestTime;
234 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700235 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700236 catch (Signature::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700237 {
238 return onValidationFailed(interest.shared_from_this(),
239 "No valid signature");
240 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700241 catch (IdentityCertificate::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700242 {
243 return onValidationFailed(interest.shared_from_this(),
244 "Cannot locate the signing key");
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700245 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700246 catch (Tlv::Error& e)
247 {
248 return onValidationFailed(interest.shared_from_this(),
249 "Cannot decode signature related TLVs");
250 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800251
252 return onValidated(interest.shared_from_this());
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800253}
254
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800255} // namespace ndn
256
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700257#endif // NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP