blob: df7b0e6ad3e25d78099745af42c38f8a8cabb7d3 [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 Yu6ac97982014-01-30 14:49:21 -080058 if (!nextSteps.empty())
59 {
Yingdi Yu96e64062014-04-15 19:57:33 -070060 if (!m_hasFace)
61 {
62 onValidationFailed(interest.shared_from_this(),
63 "Require more information to validate the interest!");
64 return;
65 }
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070066
Yingdi Yuc8f883c2014-06-20 23:25:22 -070067 std::vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
Yingdi Yu40587c02014-02-21 16:40:48 -080068 OnFailure onFailure = bind(onValidationFailed, interest.shared_from_this(), _1);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070069 for (; it != nextSteps.end(); it++)
Yingdi Yu96e64062014-04-15 19:57:33 -070070 m_face.expressInterest((*it)->m_interest,
71 bind(&Validator::onData, this, _1, _2, *it),
72 bind(&Validator::onTimeout,
73 this, _1, (*it)->m_nRetrials,
74 onFailure,
75 *it));
Yingdi Yu6ac97982014-01-30 14:49:21 -080076 }
77 else
78 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070079 // If there is no nextStep,
80 // that means InterestPolicy has already been able to verify the Interest.
81 // No more further processes.
Yingdi Yu6ac97982014-01-30 14:49:21 -080082 }
83}
84
85void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070086Validator::validate(const Data& data,
87 const OnDataValidated& onValidated,
88 const OnDataValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070089 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080090{
Yingdi Yuc8f883c2014-06-20 23:25:22 -070091 std::vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070092 checkPolicy(data, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -080093
94 if (!nextSteps.empty())
95 {
Yingdi Yu96e64062014-04-15 19:57:33 -070096 if (!m_hasFace)
97 {
98 onValidationFailed(data.shared_from_this(),
99 "Require more information to validate the data!");
100 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800101
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700102 std::vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
Yingdi Yu40587c02014-02-21 16:40:48 -0800103 OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700104 for (; it != nextSteps.end(); it++)
Yingdi Yu96e64062014-04-15 19:57:33 -0700105 m_face.expressInterest((*it)->m_interest,
106 bind(&Validator::onData, this, _1, _2, *it),
107 bind(&Validator::onTimeout,
108 this, _1, (*it)->m_nRetrials,
109 onFailure,
110 *it));
Yingdi Yu6ac97982014-01-30 14:49:21 -0800111 }
112 else
113 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700114 // If there is no nextStep,
115 // that means Data Policy has already been able to verify the Interest.
116 // No more further processes.
Yingdi Yu6ac97982014-01-30 14:49:21 -0800117 }
118}
119
120void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700121Validator::onData(const Interest& interest,
122 const Data& data,
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800123 const shared_ptr<ValidationRequest>& nextStep)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800124{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700125 validate(data, nextStep->m_onValidated, nextStep->m_onDataValidated, nextStep->m_nSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800126}
127
128void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700129Validator::onTimeout(const Interest& interest,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700130 int nRetrials,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700131 const OnFailure& onFailure,
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800132 const shared_ptr<ValidationRequest>& nextStep)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800133{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700134 if (nRetrials > 0)
135 // Issue the same expressInterest except decrement nRetrials.
Yingdi Yu96e64062014-04-15 19:57:33 -0700136 m_face.expressInterest(interest,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700137 bind(&Validator::onData, this, _1, _2, nextStep),
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700138 bind(&Validator::onTimeout, this, _1,
139 nRetrials - 1, onFailure, nextStep));
Yingdi Yu6ac97982014-01-30 14:49:21 -0800140 else
Yingdi Yu40587c02014-02-21 16:40:48 -0800141 onFailure("Cannot fetch cert: " + interest.getName().toUri());
Yingdi Yu6ac97982014-01-30 14:49:21 -0800142}
143
144bool
145Validator::verifySignature(const Data& data, const PublicKey& key)
146{
Yingdi Yu40587c02014-02-21 16:40:48 -0800147 try
148 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700149 switch (data.getSignature().getType())
Yingdi Yu40587c02014-02-21 16:40:48 -0800150 {
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700151 case Tlv::SignatureSha256WithRsa:
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700152 {
153 SignatureSha256WithRsa sigSha256Rsa(data.getSignature());
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700154 return verifySignature(data.wireEncode().value(),
155 data.wireEncode().value_size() -
156 data.getSignature().getValue().size(),
157 sigSha256Rsa, key);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700158 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700159 case Tlv::SignatureSha256WithEcdsa:
160 {
161 SignatureSha256WithEcdsa sigSha256Ecdsa(data.getSignature());
162 return verifySignature(data.wireEncode().value(),
163 data.wireEncode().value_size() -
164 data.getSignature().getValue().size(),
165 sigSha256Ecdsa, key);
166 }
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700167 default:
168 {
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700169 // Unsupported sig type
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700170 return false;
171 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800172 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800173 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700174 catch (Signature::Error& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800175 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800176 return false;
177 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800178 return false;
179}
180
181bool
Yingdi Yu21157162014-02-28 13:02:34 -0800182Validator::verifySignature(const Interest& interest, const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800183{
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700184 const Name& interestName = interest.getName();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800185
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700186 if (interestName.size() < 2)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800187 return false;
188
Yingdi Yu40587c02014-02-21 16:40:48 -0800189 try
190 {
191 const Block& nameBlock = interestName.wireEncode();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800192
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700193 Signature sig(interestName[-2].blockFromValue(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800194 interestName[-1].blockFromValue());
Yingdi Yu6ac97982014-01-30 14:49:21 -0800195
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700196 switch (sig.getType())
Yingdi Yu40587c02014-02-21 16:40:48 -0800197 {
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700198 case Tlv::SignatureSha256WithRsa:
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700199 {
200 SignatureSha256WithRsa sigSha256Rsa(sig);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800201
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700202 return verifySignature(nameBlock.value(),
203 nameBlock.value_size() - interestName[-1].size(),
204 sigSha256Rsa, key);
205 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700206 case Tlv::SignatureSha256WithEcdsa:
207 {
208 SignatureSha256WithEcdsa sigSha256Ecdsa(sig);
209
210 return verifySignature(nameBlock.value(),
211 nameBlock.value_size() - interestName[-1].size(),
212 sigSha256Ecdsa, key);
213 }
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700214 default:
215 {
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700216 // Unsupported sig type
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700217 return false;
218 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800219 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800220 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700221 catch (Signature::Error& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800222 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800223 return false;
224 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700225 catch (Block::Error& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800226 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800227 return false;
228 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800229 return false;
230}
231
232bool
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700233Validator::verifySignature(const uint8_t* buf,
234 const size_t size,
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700235 const SignatureWithPublicKey& sig,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700236 const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800237{
Yingdi Yu40587c02014-02-21 16:40:48 -0800238 try
239 {
240 using namespace CryptoPP;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800241
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700242 switch (sig.getType())
243 {
244 case Tlv::SignatureSha256WithRsa:
245 {
246 if (key.getKeyType() != KEY_TYPE_RSA)
247 return false;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800248
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700249 RSA::PublicKey publicKey;
250 ByteQueue queue;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800251
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700252 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
253 publicKey.Load(queue);
254
255 RSASS<PKCS1v15, SHA256>::Verifier verifier(publicKey);
256 return verifier.VerifyMessage(buf, size,
257 sig.getValue().value(), sig.getValue().value_size());
258 }
259 case Tlv::SignatureSha256WithEcdsa:
260 {
261 if (key.getKeyType() != KEY_TYPE_ECDSA)
262 return false;
263
264 ECDSA<ECP, SHA256>::PublicKey publicKey;
265 ByteQueue queue;
266
267 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
268 publicKey.Load(queue);
269
270 ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
271
272 uint32_t length = 0;
273 StringSource src(key.get().buf(), key.get().size(), true);
274 BERSequenceDecoder subjectPublicKeyInfo(src);
275 {
276 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
277 {
278 OID algorithm;
279 algorithm.decode(algorithmInfo);
280
281 OID curveId;
282 curveId.decode(algorithmInfo);
283
284 if (curveId == SECP256R1)
285 length = 256;
286 else if (curveId == SECP384R1)
287 length = 384;
288 else
289 return false;
290 }
291 }
292
293 switch (length)
294 {
295 case 256:
296 {
297 uint8_t buffer[64];
298 size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363,
299 sig.getValue().value(),
300 sig.getValue().value_size(),
301 DSA_DER);
302 return verifier.VerifyMessage(buf, size, buffer, usedSize);
303 }
304 case 384:
305 {
306 uint8_t buffer[96];
307 size_t usedSize = DSAConvertSignatureFormat(buffer, 96, DSA_P1363,
308 sig.getValue().value(),
309 sig.getValue().value_size(),
310 DSA_DER);
311 return verifier.VerifyMessage(buf, size, buffer, usedSize);
312 }
313 default:
314 return false;
315 }
316 }
317 default:
318 // Unsupported sig type
319 return false;
320 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800321 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700322 catch (CryptoPP::Exception& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800323 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800324 return false;
325 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800326}
327
Yingdi Yu21157162014-02-28 13:02:34 -0800328bool
Yingdi Yubf6a2812014-06-17 15:32:11 -0700329Validator::verifySignature(const uint8_t* buf, const size_t size, const DigestSha256& sig)
Yingdi Yu21157162014-02-28 13:02:34 -0800330{
331 try
332 {
333 ConstBufferPtr buffer = crypto::sha256(buf, size);
334 const Block& sigValue = sig.getValue();
335
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700336 if (static_cast<bool>(buffer) &&
337 buffer->size() == sigValue.value_size() &&
338 buffer->size() == crypto::SHA256_DIGEST_SIZE)
Yingdi Yu21157162014-02-28 13:02:34 -0800339 {
340
341 const uint8_t* p1 = buffer->buf();
342 const uint8_t* p2 = sigValue.value();
343
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700344 return 0 == memcmp(p1, p2, crypto::SHA256_DIGEST_SIZE);
Yingdi Yu21157162014-02-28 13:02:34 -0800345 }
346 else
347 return false;
348 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700349 catch (CryptoPP::Exception& e)
Yingdi Yu21157162014-02-28 13:02:34 -0800350 {
Yingdi Yu21157162014-02-28 13:02:34 -0800351 return false;
352 }
353}
354
Yingdi Yufc40d872014-02-18 12:56:04 -0800355} // namespace ndn