blob: 4962779d8bcb9ad11c48021ecdb700ca4dcd620e [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yingdi Yu6ac97982014-01-30 14:49:21 -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 Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
22 * @author Jeff Thompson <jefft0@remap.ucla.edu>
Yingdi Yu6ac97982014-01-30 14:49:21 -080023 */
24
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080025#include "common.hpp"
26
Yingdi Yu6ac97982014-01-30 14:49:21 -080027#include "validator.hpp"
Yingdi Yu21157162014-02-28 13:02:34 -080028#include "../util/crypto.hpp"
Yingdi Yu6ac97982014-01-30 14:49:21 -080029
Junxiao Shi482ccc52014-03-31 13:05:24 -070030#include "cryptopp.hpp"
Yingdi Yu21157162014-02-28 13:02:34 -080031
Yingdi Yu6ac97982014-01-30 14:49:21 -080032using namespace std;
33
Yingdi Yu6ac97982014-01-30 14:49:21 -080034namespace ndn {
35
Yingdi Yu96e64062014-04-15 19:57:33 -070036Validator::Validator()
37 : m_hasFace(false)
38 , m_face(*static_cast<Face*>(0))
39{
40}
Yingdi Yu6ac97982014-01-30 14:49:21 -080041
Yingdi Yu96e64062014-04-15 19:57:33 -070042Validator::Validator(Face& face)
43 : m_hasFace(true)
44 , m_face(face)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070045{
46}
Yingdi Yu6ac97982014-01-30 14:49:21 -080047
48void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070049Validator::validate(const Interest& interest,
50 const OnInterestValidated& onValidated,
51 const OnInterestValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070052 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080053{
54 vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070055 checkPolicy(interest, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070056
Yingdi Yu6ac97982014-01-30 14:49:21 -080057 if (!nextSteps.empty())
58 {
Yingdi Yu96e64062014-04-15 19:57:33 -070059 if (!m_hasFace)
60 {
61 onValidationFailed(interest.shared_from_this(),
62 "Require more information to validate the interest!");
63 return;
64 }
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070065
Yingdi Yu6ac97982014-01-30 14:49:21 -080066 vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
Yingdi Yu40587c02014-02-21 16:40:48 -080067 OnFailure onFailure = bind(onValidationFailed, interest.shared_from_this(), _1);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070068 for (; it != nextSteps.end(); it++)
Yingdi Yu96e64062014-04-15 19:57:33 -070069 m_face.expressInterest((*it)->m_interest,
70 bind(&Validator::onData, this, _1, _2, *it),
71 bind(&Validator::onTimeout,
72 this, _1, (*it)->m_nRetrials,
73 onFailure,
74 *it));
Yingdi Yu6ac97982014-01-30 14:49:21 -080075 }
76 else
77 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070078 // If there is no nextStep,
79 // that means InterestPolicy has already been able to verify the Interest.
80 // No more further processes.
Yingdi Yu6ac97982014-01-30 14:49:21 -080081 }
82}
83
84void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070085Validator::validate(const Data& data,
86 const OnDataValidated& onValidated,
87 const OnDataValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070088 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080089{
90 vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070091 checkPolicy(data, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -080092
93 if (!nextSteps.empty())
94 {
Yingdi Yu96e64062014-04-15 19:57:33 -070095 if (!m_hasFace)
96 {
97 onValidationFailed(data.shared_from_this(),
98 "Require more information to validate the data!");
99 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800100
101 vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
Yingdi Yu40587c02014-02-21 16:40:48 -0800102 OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700103 for (; it != nextSteps.end(); it++)
Yingdi Yu96e64062014-04-15 19:57:33 -0700104 m_face.expressInterest((*it)->m_interest,
105 bind(&Validator::onData, this, _1, _2, *it),
106 bind(&Validator::onTimeout,
107 this, _1, (*it)->m_nRetrials,
108 onFailure,
109 *it));
Yingdi Yu6ac97982014-01-30 14:49:21 -0800110 }
111 else
112 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700113 // If there is no nextStep,
114 // that means Data Policy has already been able to verify the Interest.
115 // No more further processes.
Yingdi Yu6ac97982014-01-30 14:49:21 -0800116 }
117}
118
119void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700120Validator::onData(const Interest& interest,
121 const Data& data,
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800122 const shared_ptr<ValidationRequest>& nextStep)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800123{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700124 validate(data, nextStep->m_onValidated, nextStep->m_onDataValidated, nextStep->m_nSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800125}
126
127void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700128Validator::onTimeout(const Interest& interest,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700129 int nRetrials,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700130 const OnFailure& onFailure,
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800131 const shared_ptr<ValidationRequest>& nextStep)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800132{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700133 if (nRetrials > 0)
134 // Issue the same expressInterest except decrement nRetrials.
Yingdi Yu96e64062014-04-15 19:57:33 -0700135 m_face.expressInterest(interest,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700136 bind(&Validator::onData, this, _1, _2, nextStep),
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700137 bind(&Validator::onTimeout, this, _1,
138 nRetrials - 1, onFailure, nextStep));
Yingdi Yu6ac97982014-01-30 14:49:21 -0800139 else
Yingdi Yu40587c02014-02-21 16:40:48 -0800140 onFailure("Cannot fetch cert: " + interest.getName().toUri());
Yingdi Yu6ac97982014-01-30 14:49:21 -0800141}
142
143bool
144Validator::verifySignature(const Data& data, const PublicKey& key)
145{
Yingdi Yu40587c02014-02-21 16:40:48 -0800146 try
147 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700148 switch (data.getSignature().getType())
Yingdi Yu40587c02014-02-21 16:40:48 -0800149 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700150 case Signature::Sha256WithRsa:
151 {
152 SignatureSha256WithRsa sigSha256Rsa(data.getSignature());
153 return verifySignature(data, sigSha256Rsa, key);
154 }
155 default:
156 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700157 return false;
158 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800159 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800160 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700161 catch (Signature::Error& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800162 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800163 return false;
164 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800165 return false;
166}
167
168bool
Yingdi Yu21157162014-02-28 13:02:34 -0800169Validator::verifySignature(const Interest& interest, const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800170{
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700171 const Name& interestName = interest.getName();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800172
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700173 if (interestName.size() < 2)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800174 return false;
175
Yingdi Yu40587c02014-02-21 16:40:48 -0800176 try
177 {
178 const Block& nameBlock = interestName.wireEncode();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800179
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700180 Signature sig(interestName[-2].blockFromValue(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800181 interestName[-1].blockFromValue());
Yingdi Yu6ac97982014-01-30 14:49:21 -0800182
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700183 switch (sig.getType())
Yingdi Yu40587c02014-02-21 16:40:48 -0800184 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700185 case Signature::Sha256WithRsa:
186 {
187 SignatureSha256WithRsa sigSha256Rsa(sig);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800188
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700189 return verifySignature(nameBlock.value(),
190 nameBlock.value_size() - interestName[-1].size(),
191 sigSha256Rsa, key);
192 }
193 default:
194 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700195 return false;
196 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800197 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800198 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700199 catch (Signature::Error& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800200 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800201 return false;
202 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700203 catch (Block::Error& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800204 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800205 return false;
206 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800207 return false;
208}
209
210bool
Yingdi Yu21157162014-02-28 13:02:34 -0800211Validator::verifySignature(const Buffer& data, const Signature& sig, const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800212{
Yingdi Yu40587c02014-02-21 16:40:48 -0800213 try
214 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700215 switch (sig.getType())
Yingdi Yu40587c02014-02-21 16:40:48 -0800216 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700217 case Signature::Sha256WithRsa:
218 {
219 SignatureSha256WithRsa sigSha256Rsa(sig);
220 return verifySignature(data, sigSha256Rsa, key);
221 }
222 default:
223 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700224 return false;
225 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800226 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800227 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700228 catch (Signature::Error& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800229 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800230 return false;
231 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800232 return false;
233}
234
235bool
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700236Validator::verifySignature(const uint8_t* buf,
237 const size_t size,
238 const SignatureSha256WithRsa& sig,
239 const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800240{
Yingdi Yu40587c02014-02-21 16:40:48 -0800241 try
242 {
243 using namespace CryptoPP;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800244
Yingdi Yu40587c02014-02-21 16:40:48 -0800245 RSA::PublicKey publicKey;
246 ByteQueue queue;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800247
Yingdi Yu40587c02014-02-21 16:40:48 -0800248 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
249 publicKey.Load(queue);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800250
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700251 RSASS<PKCS1v15, SHA256>::Verifier verifier(publicKey);
252 return verifier.VerifyMessage(buf, size,
253 sig.getValue().value(),
254 sig.getValue().value_size());
Yingdi Yu40587c02014-02-21 16:40:48 -0800255 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700256 catch (CryptoPP::Exception& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800257 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800258 return false;
259 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800260}
261
Yingdi Yu21157162014-02-28 13:02:34 -0800262bool
263Validator::verifySignature(const uint8_t* buf, const size_t size, const SignatureSha256& sig)
264{
265 try
266 {
267 ConstBufferPtr buffer = crypto::sha256(buf, size);
268 const Block& sigValue = sig.getValue();
269
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700270 if (static_cast<bool>(buffer) &&
271 buffer->size() == sigValue.value_size() &&
272 buffer->size() == crypto::SHA256_DIGEST_SIZE)
Yingdi Yu21157162014-02-28 13:02:34 -0800273 {
274
275 const uint8_t* p1 = buffer->buf();
276 const uint8_t* p2 = sigValue.value();
277
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700278 return 0 == memcmp(p1, p2, crypto::SHA256_DIGEST_SIZE);
Yingdi Yu21157162014-02-28 13:02:34 -0800279 }
280 else
281 return false;
282 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700283 catch (CryptoPP::Exception& e)
Yingdi Yu21157162014-02-28 13:02:34 -0800284 {
Yingdi Yu21157162014-02-28 13:02:34 -0800285 return false;
286 }
287}
288
Yingdi Yufc40d872014-02-18 12:56:04 -0800289} // namespace ndn