blob: 5edb85230b5e6f9f7514dce246fc526e6774b072 [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 -080032namespace ndn {
33
Yingdi Yuc8f883c2014-06-20 23:25:22 -070034static OID SECP256R1("1.2.840.10045.3.1.7");
35static OID SECP384R1("1.3.132.0.34");
36
Yingdi Yu96e64062014-04-15 19:57:33 -070037Validator::Validator()
38 : m_hasFace(false)
39 , m_face(*static_cast<Face*>(0))
40{
41}
Yingdi Yu6ac97982014-01-30 14:49:21 -080042
Yingdi Yu96e64062014-04-15 19:57:33 -070043Validator::Validator(Face& face)
44 : m_hasFace(true)
45 , m_face(face)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070046{
47}
Yingdi Yu6ac97982014-01-30 14:49:21 -080048
49void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070050Validator::validate(const Interest& interest,
51 const OnInterestValidated& onValidated,
52 const OnInterestValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070053 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080054{
Yingdi Yuc8f883c2014-06-20 23:25:22 -070055 std::vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070056 checkPolicy(interest, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070057
Yingdi Yud9006e72014-06-23 19:10:44 -070058 if (nextSteps.empty())
Yingdi Yu6ac97982014-01-30 14:49:21 -080059 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070060 // If there is no nextStep,
61 // that means InterestPolicy has already been able to verify the Interest.
62 // No more further processes.
Yingdi Yud9006e72014-06-23 19:10:44 -070063 return;
Yingdi Yu6ac97982014-01-30 14:49:21 -080064 }
Yingdi Yud9006e72014-06-23 19:10:44 -070065
66 if (!m_hasFace)
67 {
68 onValidationFailed(interest.shared_from_this(),
69 "Require more information to validate the interest!");
70 return;
71 }
72
73 OnFailure onFailure = bind(onValidationFailed, interest.shared_from_this(), _1);
74 afterCheckPolicy(nextSteps, onFailure);
Yingdi Yu6ac97982014-01-30 14:49:21 -080075}
76
77void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070078Validator::validate(const Data& data,
79 const OnDataValidated& onValidated,
80 const OnDataValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070081 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080082{
Yingdi Yuc8f883c2014-06-20 23:25:22 -070083 std::vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070084 checkPolicy(data, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -080085
Yingdi Yud9006e72014-06-23 19:10:44 -070086 if (nextSteps.empty())
Yingdi Yu6ac97982014-01-30 14:49:21 -080087 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070088 // If there is no nextStep,
89 // that means Data Policy has already been able to verify the Interest.
90 // No more further processes.
Yingdi Yud9006e72014-06-23 19:10:44 -070091 return;
Yingdi Yu6ac97982014-01-30 14:49:21 -080092 }
Yingdi Yud9006e72014-06-23 19:10:44 -070093
94 if (!m_hasFace)
95 {
96 onValidationFailed(data.shared_from_this(),
97 "Require more information to validate the data!");
98 return;
99 }
100
101 OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1);
102 afterCheckPolicy(nextSteps, onFailure);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800103}
104
105void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700106Validator::onData(const Interest& interest,
107 const Data& data,
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800108 const shared_ptr<ValidationRequest>& nextStep)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800109{
Yingdi Yud9006e72014-06-23 19:10:44 -0700110 shared_ptr<const Data> certificateData = preCertificateValidation(data);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800111
Yingdi Yud9006e72014-06-23 19:10:44 -0700112 if (!static_cast<bool>(certificateData))
113 return nextStep->m_onDataValidationFailed(data.shared_from_this(),
114 "Cannot decode cert: " + data.getName().toUri());
115
116 validate(*certificateData,
117 nextStep->m_onDataValidated, nextStep->m_onDataValidationFailed,
118 nextStep->m_nSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800119}
120
121bool
122Validator::verifySignature(const Data& data, const PublicKey& key)
123{
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700124 shared_ptr<SignatureWithPublicKey> publicKeySig =
125 determineSignatureWithPublicKey(data.getSignature());
126
127 if (!static_cast<bool>(publicKeySig))
128 return false;
129
130 return verifySignature(data.wireEncode().value(),
131 data.wireEncode().value_size() -
132 data.getSignature().getValue().size(),
133 *publicKeySig, key);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800134}
135
136bool
Yingdi Yu21157162014-02-28 13:02:34 -0800137Validator::verifySignature(const Interest& interest, const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800138{
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700139 const Name& interestName = interest.getName();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800140
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700141 if (interestName.size() < 2)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800142 return false;
143
Yingdi Yu40587c02014-02-21 16:40:48 -0800144 try
145 {
146 const Block& nameBlock = interestName.wireEncode();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800147
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700148 Signature sig(interestName[-2].blockFromValue(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800149 interestName[-1].blockFromValue());
Yingdi Yu6ac97982014-01-30 14:49:21 -0800150
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700151 shared_ptr<SignatureWithPublicKey> publicKeySig = determineSignatureWithPublicKey(sig);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800152
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700153 if (!static_cast<bool>(publicKeySig))
154 return false;
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700155
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700156 return verifySignature(nameBlock.value(),
157 nameBlock.value_size() - interestName[-1].size(),
158 *publicKeySig, key);
Yingdi Yu40587c02014-02-21 16:40:48 -0800159 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700160 catch (Block::Error& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800161 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800162 return false;
163 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800164}
165
166bool
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700167Validator::verifySignature(const uint8_t* buf,
168 const size_t size,
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700169 const SignatureWithPublicKey& sig,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700170 const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800171{
Yingdi Yu40587c02014-02-21 16:40:48 -0800172 try
173 {
174 using namespace CryptoPP;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800175
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700176 switch (sig.getType())
177 {
178 case Tlv::SignatureSha256WithRsa:
179 {
180 if (key.getKeyType() != KEY_TYPE_RSA)
181 return false;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800182
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700183 RSA::PublicKey publicKey;
184 ByteQueue queue;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800185
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700186 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
187 publicKey.Load(queue);
188
189 RSASS<PKCS1v15, SHA256>::Verifier verifier(publicKey);
190 return verifier.VerifyMessage(buf, size,
191 sig.getValue().value(), sig.getValue().value_size());
192 }
193 case Tlv::SignatureSha256WithEcdsa:
194 {
195 if (key.getKeyType() != KEY_TYPE_ECDSA)
196 return false;
197
198 ECDSA<ECP, SHA256>::PublicKey publicKey;
199 ByteQueue queue;
200
201 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
202 publicKey.Load(queue);
203
204 ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
205
206 uint32_t length = 0;
207 StringSource src(key.get().buf(), key.get().size(), true);
208 BERSequenceDecoder subjectPublicKeyInfo(src);
209 {
210 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
211 {
212 OID algorithm;
213 algorithm.decode(algorithmInfo);
214
215 OID curveId;
216 curveId.decode(algorithmInfo);
217
218 if (curveId == SECP256R1)
219 length = 256;
220 else if (curveId == SECP384R1)
221 length = 384;
222 else
223 return false;
224 }
225 }
226
227 switch (length)
228 {
229 case 256:
230 {
231 uint8_t buffer[64];
232 size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363,
233 sig.getValue().value(),
234 sig.getValue().value_size(),
235 DSA_DER);
236 return verifier.VerifyMessage(buf, size, buffer, usedSize);
237 }
238 case 384:
239 {
240 uint8_t buffer[96];
241 size_t usedSize = DSAConvertSignatureFormat(buffer, 96, DSA_P1363,
242 sig.getValue().value(),
243 sig.getValue().value_size(),
244 DSA_DER);
245 return verifier.VerifyMessage(buf, size, buffer, usedSize);
246 }
247 default:
248 return false;
249 }
250 }
251 default:
252 // Unsupported sig type
253 return false;
254 }
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
Yingdi Yubf6a2812014-06-17 15:32:11 -0700263Validator::verifySignature(const uint8_t* buf, const size_t size, const DigestSha256& sig)
Yingdi Yu21157162014-02-28 13:02:34 -0800264{
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 Yu5ec0ee32014-06-24 16:26:09 -0700289shared_ptr<SignatureWithPublicKey>
290Validator::determineSignatureWithPublicKey(const Signature& signature)
291{
292 try {
293 switch (signature.getType())
294 {
295 case Tlv::SignatureSha256WithRsa:
296 return make_shared<SignatureSha256WithRsa>(signature);
297 case Tlv::SignatureSha256WithEcdsa:
298 return make_shared<SignatureSha256WithEcdsa>(signature);
299 default:
300 return shared_ptr<SignatureWithPublicKey>();
301 }
302 }
303 catch (Tlv::Error& e) {
304 return shared_ptr<SignatureWithPublicKey>();
305 }
306 catch (KeyLocator::Error& e) {
307 return shared_ptr<SignatureWithPublicKey>();
308 }
309}
310
Yingdi Yud9006e72014-06-23 19:10:44 -0700311void
312Validator::onTimeout(const Interest& interest,
313 int remainingRetries,
314 const OnFailure& onFailure,
315 const shared_ptr<ValidationRequest>& validationRequest)
316{
317 if (remainingRetries > 0)
318 // Issue the same expressInterest except decrement nRetrials.
319 m_face.expressInterest(interest,
320 bind(&Validator::onData, this, _1, _2, validationRequest),
321 bind(&Validator::onTimeout, this, _1,
322 remainingRetries - 1, onFailure, validationRequest));
323 else
324 onFailure("Cannot fetch cert: " + interest.getName().toUri());
325}
326
327
328void
329Validator::afterCheckPolicy(const std::vector<shared_ptr<ValidationRequest> >& nextSteps,
330 const OnFailure& onFailure)
331{
332 for (std::vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
333 it != nextSteps.end(); it++)
334 {
335 m_face.expressInterest((*it)->m_interest,
336 bind(&Validator::onData, this, _1, _2, *it),
337 bind(&Validator::onTimeout,
338 this, _1, (*it)->m_nRetries,
339 onFailure,
340 *it));
341 }
342}
343
Yingdi Yufc40d872014-02-18 12:56:04 -0800344} // namespace ndn