blob: 07e164ff63f75345dd7a297610b3da45dd562532 [file] [log] [blame]
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * See COPYING for copyright and distribution information.
5 */
6
Yingdi Yu48e8c0c2014-03-19 12:01:55 -07007#ifndef NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP
8#define NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -08009
10#include "../security/validator.hpp"
11#include "../security/identity-certificate.hpp"
12#include "../security/sec-rule-specific.hpp"
13
14namespace ndn {
15
16class CommandInterestValidator : public Validator
17{
18public:
19 enum {
20 POS_SIG_VALUE = -1,
21 POS_SIG_INFO = -2,
22 POS_RANDOM_VAL = -3,
23 POS_TIMESTAMP = -4,
24
Yingdi Yu449e1142014-03-28 18:54:42 -070025 MIN_LENGTH = 4,
26
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080027 GRACE_INTERVAL = 3000 // ms
28 };
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070029
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070030 CommandInterestValidator(const time::milliseconds& graceInterval =
31 time::milliseconds(static_cast<int>(GRACE_INTERVAL)))
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070032 : m_graceInterval(graceInterval < time::milliseconds::zero() ?
33 time::milliseconds(static_cast<int>(GRACE_INTERVAL)) : graceInterval)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080034 {
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080035 }
36
37 virtual
38 ~CommandInterestValidator()
39 {
40 }
41
42 void
43 addInterestRule(const std::string& regex, const IdentityCertificate& certificate);
44
45 void
46 addInterestRule(const std::string& regex, const Name& keyName, const PublicKey& publicKey);
47
48protected:
49 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070050 checkPolicy(const Data& data,
51 int stepCount,
52 const OnDataValidated& onValidated,
53 const OnDataValidationFailed& onValidationFailed,
54 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080055 {
Yingdi Yu40587c02014-02-21 16:40:48 -080056 onValidationFailed(data.shared_from_this(), "No policy for data checking");
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080057 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070058
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080059 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070060 checkPolicy(const Interest& interest,
61 int stepCount,
62 const OnInterestValidated& onValidated,
63 const OnInterestValidationFailed& onValidationFailed,
64 std::vector<shared_ptr<ValidationRequest> >& nextSteps);
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080065private:
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070066 time::milliseconds m_graceInterval; //ms
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080067 std::map<Name, PublicKey> m_trustAnchorsForInterest;
68 std::list<SecRuleSpecific> m_trustScopeForInterest;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070069
70 typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
71 LastTimestampMap m_lastTimestamp;
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080072};
73
74inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070075CommandInterestValidator::addInterestRule(const std::string& regex,
76 const IdentityCertificate& certificate)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080077{
78 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
79 addInterestRule(regex, keyName, certificate.getPublicKeyInfo());
80}
81
82inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070083CommandInterestValidator::addInterestRule(const std::string& regex,
84 const Name& keyName,
85 const PublicKey& publicKey)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080086{
87 m_trustAnchorsForInterest[keyName] = publicKey;
88 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
89 shared_ptr<Regex> signerRegex = Regex::fromName(keyName, true);
90 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex, signerRegex));
91}
92
93inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070094CommandInterestValidator::checkPolicy(const Interest& interest,
95 int stepCount,
96 const OnInterestValidated& onValidated,
97 const OnInterestValidationFailed& onValidationFailed,
98 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080099{
Yingdi Yu40587c02014-02-21 16:40:48 -0800100 const Name& interestName = interest.getName();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700101
102 //Prepare
Yingdi Yu449e1142014-03-28 18:54:42 -0700103 if (interestName.size() < MIN_LENGTH)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700104 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800105 "Interest is not signed: " + interest.getName().toUri());
Yingdi Yu449e1142014-03-28 18:54:42 -0700106 Name keyName;
107 try
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800108 {
Yingdi Yu449e1142014-03-28 18:54:42 -0700109 Signature signature(interestName[POS_SIG_INFO].blockFromValue(),
110 interestName[POS_SIG_VALUE].blockFromValue());
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700111
Yingdi Yu449e1142014-03-28 18:54:42 -0700112 if (signature.getType() != Signature::Sha256WithRsa)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700113 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu449e1142014-03-28 18:54:42 -0700114 "Require SignatureSha256WithRsa");
Yingdi Yu40587c02014-02-21 16:40:48 -0800115
Yingdi Yu449e1142014-03-28 18:54:42 -0700116 SignatureSha256WithRsa sig(signature);
Yingdi Yu40587c02014-02-21 16:40:48 -0800117
Yingdi Yu449e1142014-03-28 18:54:42 -0700118 const KeyLocator& keyLocator = sig.getKeyLocator();
119
120 if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
121 return onValidationFailed(interest.shared_from_this(),
122 "Key Locator is not a name");
123
124 keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
125
126 //Check if command is in the trusted scope
127 bool isInScope = false;
128 for (std::list<SecRuleSpecific>::iterator scopeIt = m_trustScopeForInterest.begin();
129 scopeIt != m_trustScopeForInterest.end();
130 ++scopeIt)
131 {
132 if (scopeIt->satisfy(interestName, keyName))
133 {
134 isInScope = true;
135 break;
136 }
137 }
138 if (isInScope == false)
139 return onValidationFailed(interest.shared_from_this(),
140 "Signer cannot be authorized for the command: " +
141 keyName.toUri());
142
143 //Check signature
144 if (!Validator::verifySignature(interestName.wireEncode().value(),
145 interestName.wireEncode().value_size() -
146 interestName[-1].size(),
147 sig, m_trustAnchorsForInterest[keyName]))
148 return onValidationFailed(interest.shared_from_this(),
149 "Signature cannot be validated: " +
150 interest.getName().toUri());
151
152 //Check if timestamp is valid
153 time::system_clock::TimePoint interestTime =
154 time::fromUnixTimestamp(time::milliseconds(interestName.get(POS_TIMESTAMP).toNumber()));
155
156 time::system_clock::TimePoint currentTime = time::system_clock::now();
157
158 LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
159 if (timestampIt == m_lastTimestamp.end())
160 {
161 if (!(currentTime - m_graceInterval <= interestTime &&
162 interestTime <= currentTime + m_graceInterval))
163 return onValidationFailed(interest.shared_from_this(),
164 "The command is not in grace interval: " +
165 interest.getName().toUri());
166 }
167 else
168 {
169 if (interestTime <= timestampIt->second)
170 return onValidationFailed(interest.shared_from_this(),
171 "The command is outdated: " +
172 interest.getName().toUri());
173 }
174
175 //Update timestamp
176 if (timestampIt == m_lastTimestamp.end())
177 {
178 m_lastTimestamp[keyName] = interestTime;
179 }
180 else
181 {
182 timestampIt->second = interestTime;
183 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700184 }
Yingdi Yu449e1142014-03-28 18:54:42 -0700185 catch (const Tlv::Error& e)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700186 {
Yingdi Yu449e1142014-03-28 18:54:42 -0700187 return onValidationFailed(interest.shared_from_this(),
188 "Cannot decode signature related TLVs");
189 }
190 catch (const Signature::Error& e)
191 {
192 return onValidationFailed(interest.shared_from_this(),
193 "No valid signature");
194 }
195 catch (const IdentityCertificate::Error& e)
196 {
197 return onValidationFailed(interest.shared_from_this(),
198 "Cannot locate the signing key");
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700199 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800200
201 return onValidated(interest.shared_from_this());
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800202}
203
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800204} // namespace ndn
205
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700206#endif // NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP