blob: 6bd32508a1f65e65ba92bcf38026c82c10e09f28 [file] [log] [blame]
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080011 */
12
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070013#ifndef NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP
14#define NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080015
16#include "../security/validator.hpp"
17#include "../security/identity-certificate.hpp"
18#include "../security/sec-rule-specific.hpp"
19
20namespace ndn {
21
22class CommandInterestValidator : public Validator
23{
24public:
25 enum {
26 POS_SIG_VALUE = -1,
27 POS_SIG_INFO = -2,
28 POS_RANDOM_VAL = -3,
29 POS_TIMESTAMP = -4,
30
Yingdi Yu449e1142014-03-28 18:54:42 -070031 MIN_LENGTH = 4,
32
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080033 GRACE_INTERVAL = 3000 // ms
34 };
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070035
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070036 CommandInterestValidator(const time::milliseconds& graceInterval =
37 time::milliseconds(static_cast<int>(GRACE_INTERVAL)))
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070038 : m_graceInterval(graceInterval < time::milliseconds::zero() ?
39 time::milliseconds(static_cast<int>(GRACE_INTERVAL)) : graceInterval)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080040 {
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080041 }
42
43 virtual
44 ~CommandInterestValidator()
45 {
46 }
47
Yingdi Yu0fc447c2014-04-29 19:38:32 -070048 /**
49 * @brief add an Interest rule that allows a specific certificate
50 *
51 * @param regex NDN Regex to match Interest Name
52 * @param certificate trusted certificate
53 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080054 void
55 addInterestRule(const std::string& regex, const IdentityCertificate& certificate);
56
Yingdi Yu0fc447c2014-04-29 19:38:32 -070057 /**
58 * @brief add an Interest rule that allows a specific public key
59 *
60 * @param regex NDN Regex to match Interest Name
61 * @param keyName KeyLocator.Name
62 * @param publicKey public key
63 */
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080064 void
65 addInterestRule(const std::string& regex, const Name& keyName, const PublicKey& publicKey);
66
Yingdi Yu0fc447c2014-04-29 19:38:32 -070067 /**
68 * @brief add an Interest rule that allows any signer
69 *
70 * @param regex NDN Regex to match Interest Name
71 * @note Command Interest matched by regex that is signed by any key will be accepted.
72 */
73 void
74 addInterestBypassRule(const std::string& regex);
75
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080076protected:
77 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070078 checkPolicy(const Data& data,
79 int stepCount,
80 const OnDataValidated& onValidated,
81 const OnDataValidationFailed& onValidationFailed,
82 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080083 {
Yingdi Yu40587c02014-02-21 16:40:48 -080084 onValidationFailed(data.shared_from_this(), "No policy for data checking");
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080085 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070086
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080087 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070088 checkPolicy(const Interest& interest,
89 int stepCount,
90 const OnInterestValidated& onValidated,
91 const OnInterestValidationFailed& onValidationFailed,
92 std::vector<shared_ptr<ValidationRequest> >& nextSteps);
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080093private:
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070094 time::milliseconds m_graceInterval; //ms
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080095 std::map<Name, PublicKey> m_trustAnchorsForInterest;
96 std::list<SecRuleSpecific> m_trustScopeForInterest;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070097
98 typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
99 LastTimestampMap m_lastTimestamp;
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800100};
101
102inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700103CommandInterestValidator::addInterestRule(const std::string& regex,
104 const IdentityCertificate& certificate)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800105{
106 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
107 addInterestRule(regex, keyName, certificate.getPublicKeyInfo());
108}
109
110inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700111CommandInterestValidator::addInterestRule(const std::string& regex,
112 const Name& keyName,
113 const PublicKey& publicKey)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800114{
115 m_trustAnchorsForInterest[keyName] = publicKey;
116 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
117 shared_ptr<Regex> signerRegex = Regex::fromName(keyName, true);
118 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex, signerRegex));
119}
120
121inline void
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700122CommandInterestValidator::addInterestBypassRule(const std::string& regex)
123{
124 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
125 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex));
126}
127
128inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700129CommandInterestValidator::checkPolicy(const Interest& interest,
130 int stepCount,
131 const OnInterestValidated& onValidated,
132 const OnInterestValidationFailed& onValidationFailed,
133 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800134{
Yingdi Yu40587c02014-02-21 16:40:48 -0800135 const Name& interestName = interest.getName();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700136
137 //Prepare
Yingdi Yu449e1142014-03-28 18:54:42 -0700138 if (interestName.size() < MIN_LENGTH)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700139 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800140 "Interest is not signed: " + interest.getName().toUri());
Yingdi Yu449e1142014-03-28 18:54:42 -0700141 Name keyName;
142 try
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800143 {
Yingdi Yu449e1142014-03-28 18:54:42 -0700144 Signature signature(interestName[POS_SIG_INFO].blockFromValue(),
145 interestName[POS_SIG_VALUE].blockFromValue());
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700146
Yingdi Yu449e1142014-03-28 18:54:42 -0700147 if (signature.getType() != Signature::Sha256WithRsa)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700148 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu449e1142014-03-28 18:54:42 -0700149 "Require SignatureSha256WithRsa");
Yingdi Yu40587c02014-02-21 16:40:48 -0800150
Yingdi Yu449e1142014-03-28 18:54:42 -0700151 SignatureSha256WithRsa sig(signature);
Yingdi Yu40587c02014-02-21 16:40:48 -0800152
Yingdi Yu449e1142014-03-28 18:54:42 -0700153 const KeyLocator& keyLocator = sig.getKeyLocator();
154
155 if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
156 return onValidationFailed(interest.shared_from_this(),
157 "Key Locator is not a name");
158
159 keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
160
161 //Check if command is in the trusted scope
162 bool isInScope = false;
163 for (std::list<SecRuleSpecific>::iterator scopeIt = m_trustScopeForInterest.begin();
164 scopeIt != m_trustScopeForInterest.end();
165 ++scopeIt)
166 {
167 if (scopeIt->satisfy(interestName, keyName))
168 {
Yingdi Yu0fc447c2014-04-29 19:38:32 -0700169 if (scopeIt->isExempted())
170 {
171 return onValidated(interest.shared_from_this());
172 }
173
Yingdi Yu449e1142014-03-28 18:54:42 -0700174 isInScope = true;
175 break;
176 }
177 }
178 if (isInScope == false)
179 return onValidationFailed(interest.shared_from_this(),
180 "Signer cannot be authorized for the command: " +
181 keyName.toUri());
182
183 //Check signature
184 if (!Validator::verifySignature(interestName.wireEncode().value(),
185 interestName.wireEncode().value_size() -
186 interestName[-1].size(),
187 sig, m_trustAnchorsForInterest[keyName]))
188 return onValidationFailed(interest.shared_from_this(),
189 "Signature cannot be validated: " +
190 interest.getName().toUri());
191
192 //Check if timestamp is valid
193 time::system_clock::TimePoint interestTime =
194 time::fromUnixTimestamp(time::milliseconds(interestName.get(POS_TIMESTAMP).toNumber()));
195
196 time::system_clock::TimePoint currentTime = time::system_clock::now();
197
198 LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
199 if (timestampIt == m_lastTimestamp.end())
200 {
201 if (!(currentTime - m_graceInterval <= interestTime &&
202 interestTime <= currentTime + m_graceInterval))
203 return onValidationFailed(interest.shared_from_this(),
204 "The command is not in grace interval: " +
205 interest.getName().toUri());
206 }
207 else
208 {
209 if (interestTime <= timestampIt->second)
210 return onValidationFailed(interest.shared_from_this(),
211 "The command is outdated: " +
212 interest.getName().toUri());
213 }
214
215 //Update timestamp
216 if (timestampIt == m_lastTimestamp.end())
217 {
218 m_lastTimestamp[keyName] = interestTime;
219 }
220 else
221 {
222 timestampIt->second = interestTime;
223 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700224 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700225 catch (Signature::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700226 {
227 return onValidationFailed(interest.shared_from_this(),
228 "No valid signature");
229 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700230 catch (IdentityCertificate::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700231 {
232 return onValidationFailed(interest.shared_from_this(),
233 "Cannot locate the signing key");
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700234 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700235 catch (Tlv::Error& e)
236 {
237 return onValidationFailed(interest.shared_from_this(),
238 "Cannot decode signature related TLVs");
239 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800240
241 return onValidated(interest.shared_from_this());
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800242}
243
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800244} // namespace ndn
245
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700246#endif // NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP