blob: 17d264b0e1e74b42c20297ee293876d6650a3963 [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
48 void
49 addInterestRule(const std::string& regex, const IdentityCertificate& certificate);
50
51 void
52 addInterestRule(const std::string& regex, const Name& keyName, const PublicKey& publicKey);
53
54protected:
55 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070056 checkPolicy(const Data& data,
57 int stepCount,
58 const OnDataValidated& onValidated,
59 const OnDataValidationFailed& onValidationFailed,
60 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080061 {
Yingdi Yu40587c02014-02-21 16:40:48 -080062 onValidationFailed(data.shared_from_this(), "No policy for data checking");
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080063 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070064
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080065 virtual void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070066 checkPolicy(const Interest& interest,
67 int stepCount,
68 const OnInterestValidated& onValidated,
69 const OnInterestValidationFailed& onValidationFailed,
70 std::vector<shared_ptr<ValidationRequest> >& nextSteps);
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080071private:
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070072 time::milliseconds m_graceInterval; //ms
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080073 std::map<Name, PublicKey> m_trustAnchorsForInterest;
74 std::list<SecRuleSpecific> m_trustScopeForInterest;
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070075
76 typedef std::map<Name, time::system_clock::TimePoint> LastTimestampMap;
77 LastTimestampMap m_lastTimestamp;
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080078};
79
80inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070081CommandInterestValidator::addInterestRule(const std::string& regex,
82 const IdentityCertificate& certificate)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080083{
84 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
85 addInterestRule(regex, keyName, certificate.getPublicKeyInfo());
86}
87
88inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070089CommandInterestValidator::addInterestRule(const std::string& regex,
90 const Name& keyName,
91 const PublicKey& publicKey)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -080092{
93 m_trustAnchorsForInterest[keyName] = publicKey;
94 shared_ptr<Regex> interestRegex = make_shared<Regex>(regex);
95 shared_ptr<Regex> signerRegex = Regex::fromName(keyName, true);
96 m_trustScopeForInterest.push_back(SecRuleSpecific(interestRegex, signerRegex));
97}
98
99inline void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700100CommandInterestValidator::checkPolicy(const Interest& interest,
101 int stepCount,
102 const OnInterestValidated& onValidated,
103 const OnInterestValidationFailed& onValidationFailed,
104 std::vector<shared_ptr<ValidationRequest> >& nextSteps)
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800105{
Yingdi Yu40587c02014-02-21 16:40:48 -0800106 const Name& interestName = interest.getName();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700107
108 //Prepare
Yingdi Yu449e1142014-03-28 18:54:42 -0700109 if (interestName.size() < MIN_LENGTH)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700110 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800111 "Interest is not signed: " + interest.getName().toUri());
Yingdi Yu449e1142014-03-28 18:54:42 -0700112 Name keyName;
113 try
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800114 {
Yingdi Yu449e1142014-03-28 18:54:42 -0700115 Signature signature(interestName[POS_SIG_INFO].blockFromValue(),
116 interestName[POS_SIG_VALUE].blockFromValue());
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700117
Yingdi Yu449e1142014-03-28 18:54:42 -0700118 if (signature.getType() != Signature::Sha256WithRsa)
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700119 return onValidationFailed(interest.shared_from_this(),
Yingdi Yu449e1142014-03-28 18:54:42 -0700120 "Require SignatureSha256WithRsa");
Yingdi Yu40587c02014-02-21 16:40:48 -0800121
Yingdi Yu449e1142014-03-28 18:54:42 -0700122 SignatureSha256WithRsa sig(signature);
Yingdi Yu40587c02014-02-21 16:40:48 -0800123
Yingdi Yu449e1142014-03-28 18:54:42 -0700124 const KeyLocator& keyLocator = sig.getKeyLocator();
125
126 if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
127 return onValidationFailed(interest.shared_from_this(),
128 "Key Locator is not a name");
129
130 keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
131
132 //Check if command is in the trusted scope
133 bool isInScope = false;
134 for (std::list<SecRuleSpecific>::iterator scopeIt = m_trustScopeForInterest.begin();
135 scopeIt != m_trustScopeForInterest.end();
136 ++scopeIt)
137 {
138 if (scopeIt->satisfy(interestName, keyName))
139 {
140 isInScope = true;
141 break;
142 }
143 }
144 if (isInScope == false)
145 return onValidationFailed(interest.shared_from_this(),
146 "Signer cannot be authorized for the command: " +
147 keyName.toUri());
148
149 //Check signature
150 if (!Validator::verifySignature(interestName.wireEncode().value(),
151 interestName.wireEncode().value_size() -
152 interestName[-1].size(),
153 sig, m_trustAnchorsForInterest[keyName]))
154 return onValidationFailed(interest.shared_from_this(),
155 "Signature cannot be validated: " +
156 interest.getName().toUri());
157
158 //Check if timestamp is valid
159 time::system_clock::TimePoint interestTime =
160 time::fromUnixTimestamp(time::milliseconds(interestName.get(POS_TIMESTAMP).toNumber()));
161
162 time::system_clock::TimePoint currentTime = time::system_clock::now();
163
164 LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName);
165 if (timestampIt == m_lastTimestamp.end())
166 {
167 if (!(currentTime - m_graceInterval <= interestTime &&
168 interestTime <= currentTime + m_graceInterval))
169 return onValidationFailed(interest.shared_from_this(),
170 "The command is not in grace interval: " +
171 interest.getName().toUri());
172 }
173 else
174 {
175 if (interestTime <= timestampIt->second)
176 return onValidationFailed(interest.shared_from_this(),
177 "The command is outdated: " +
178 interest.getName().toUri());
179 }
180
181 //Update timestamp
182 if (timestampIt == m_lastTimestamp.end())
183 {
184 m_lastTimestamp[keyName] = interestTime;
185 }
186 else
187 {
188 timestampIt->second = interestTime;
189 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700190 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700191 catch (Signature::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700192 {
193 return onValidationFailed(interest.shared_from_this(),
194 "No valid signature");
195 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700196 catch (IdentityCertificate::Error& e)
Yingdi Yu449e1142014-03-28 18:54:42 -0700197 {
198 return onValidationFailed(interest.shared_from_this(),
199 "Cannot locate the signing key");
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700200 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700201 catch (Tlv::Error& e)
202 {
203 return onValidationFailed(interest.shared_from_this(),
204 "Cannot decode signature related TLVs");
205 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800206
207 return onValidated(interest.shared_from_this());
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800208}
209
Alexander Afanasyev9cbf70a2014-02-17 18:07:51 -0800210} // namespace ndn
211
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700212#endif // NDN_UTIL_COMMAND_INTEREST_VALIDATOR_HPP