blob: de8c311d498cb48c64c117302d80f33b367f5a4b [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 Yu4a557052014-07-09 16:40:37 -0700124 if (!data.getSignature().hasKeyLocator())
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700125 return false;
126
127 return verifySignature(data.wireEncode().value(),
128 data.wireEncode().value_size() -
129 data.getSignature().getValue().size(),
Yingdi Yu4a557052014-07-09 16:40:37 -0700130 data.getSignature(), key);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800131}
132
133bool
Yingdi Yu21157162014-02-28 13:02:34 -0800134Validator::verifySignature(const Interest& interest, const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800135{
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700136 const Name& interestName = interest.getName();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800137
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700138 if (interestName.size() < 2)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800139 return false;
140
Yingdi Yu40587c02014-02-21 16:40:48 -0800141 try
142 {
143 const Block& nameBlock = interestName.wireEncode();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800144
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700145 Signature sig(interestName[-2].blockFromValue(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800146 interestName[-1].blockFromValue());
Yingdi Yu6ac97982014-01-30 14:49:21 -0800147
Yingdi Yu4a557052014-07-09 16:40:37 -0700148 if (!sig.hasKeyLocator())
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700149 return false;
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700150
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700151 return verifySignature(nameBlock.value(),
152 nameBlock.value_size() - interestName[-1].size(),
Yingdi Yu4a557052014-07-09 16:40:37 -0700153 sig, key);
Yingdi Yu40587c02014-02-21 16:40:48 -0800154 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700155 catch (Block::Error& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800156 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800157 return false;
158 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800159}
160
161bool
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700162Validator::verifySignature(const uint8_t* buf,
163 const size_t size,
Yingdi Yu4a557052014-07-09 16:40:37 -0700164 const Signature& sig,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700165 const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800166{
Yingdi Yu40587c02014-02-21 16:40:48 -0800167 try
168 {
169 using namespace CryptoPP;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800170
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700171 switch (sig.getType())
172 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600173 case tlv::SignatureSha256WithRsa:
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700174 {
175 if (key.getKeyType() != KEY_TYPE_RSA)
176 return false;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800177
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700178 RSA::PublicKey publicKey;
179 ByteQueue queue;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800180
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700181 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
182 publicKey.Load(queue);
183
184 RSASS<PKCS1v15, SHA256>::Verifier verifier(publicKey);
185 return verifier.VerifyMessage(buf, size,
186 sig.getValue().value(), sig.getValue().value_size());
187 }
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600188 case tlv::SignatureSha256WithEcdsa:
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700189 {
190 if (key.getKeyType() != KEY_TYPE_ECDSA)
191 return false;
192
193 ECDSA<ECP, SHA256>::PublicKey publicKey;
194 ByteQueue queue;
195
196 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
197 publicKey.Load(queue);
198
199 ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
200
201 uint32_t length = 0;
202 StringSource src(key.get().buf(), key.get().size(), true);
203 BERSequenceDecoder subjectPublicKeyInfo(src);
204 {
205 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
206 {
207 OID algorithm;
208 algorithm.decode(algorithmInfo);
209
210 OID curveId;
211 curveId.decode(algorithmInfo);
212
213 if (curveId == SECP256R1)
214 length = 256;
215 else if (curveId == SECP384R1)
216 length = 384;
217 else
218 return false;
219 }
220 }
221
222 switch (length)
223 {
224 case 256:
225 {
226 uint8_t buffer[64];
227 size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363,
228 sig.getValue().value(),
229 sig.getValue().value_size(),
230 DSA_DER);
231 return verifier.VerifyMessage(buf, size, buffer, usedSize);
232 }
233 case 384:
234 {
235 uint8_t buffer[96];
236 size_t usedSize = DSAConvertSignatureFormat(buffer, 96, DSA_P1363,
237 sig.getValue().value(),
238 sig.getValue().value_size(),
239 DSA_DER);
240 return verifier.VerifyMessage(buf, size, buffer, usedSize);
241 }
242 default:
243 return false;
244 }
245 }
246 default:
247 // Unsupported sig type
248 return false;
249 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800250 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700251 catch (CryptoPP::Exception& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800252 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800253 return false;
254 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800255}
256
Yingdi Yu21157162014-02-28 13:02:34 -0800257bool
Yingdi Yubf6a2812014-06-17 15:32:11 -0700258Validator::verifySignature(const uint8_t* buf, const size_t size, const DigestSha256& sig)
Yingdi Yu21157162014-02-28 13:02:34 -0800259{
260 try
261 {
262 ConstBufferPtr buffer = crypto::sha256(buf, size);
263 const Block& sigValue = sig.getValue();
264
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700265 if (static_cast<bool>(buffer) &&
266 buffer->size() == sigValue.value_size() &&
267 buffer->size() == crypto::SHA256_DIGEST_SIZE)
Yingdi Yu21157162014-02-28 13:02:34 -0800268 {
269
270 const uint8_t* p1 = buffer->buf();
271 const uint8_t* p2 = sigValue.value();
272
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700273 return 0 == memcmp(p1, p2, crypto::SHA256_DIGEST_SIZE);
Yingdi Yu21157162014-02-28 13:02:34 -0800274 }
275 else
276 return false;
277 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700278 catch (CryptoPP::Exception& e)
Yingdi Yu21157162014-02-28 13:02:34 -0800279 {
Yingdi Yu21157162014-02-28 13:02:34 -0800280 return false;
281 }
282}
283
Yingdi Yud9006e72014-06-23 19:10:44 -0700284void
285Validator::onTimeout(const Interest& interest,
286 int remainingRetries,
287 const OnFailure& onFailure,
288 const shared_ptr<ValidationRequest>& validationRequest)
289{
290 if (remainingRetries > 0)
291 // Issue the same expressInterest except decrement nRetrials.
292 m_face.expressInterest(interest,
293 bind(&Validator::onData, this, _1, _2, validationRequest),
294 bind(&Validator::onTimeout, this, _1,
295 remainingRetries - 1, onFailure, validationRequest));
296 else
297 onFailure("Cannot fetch cert: " + interest.getName().toUri());
298}
299
300
301void
302Validator::afterCheckPolicy(const std::vector<shared_ptr<ValidationRequest> >& nextSteps,
303 const OnFailure& onFailure)
304{
305 for (std::vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
306 it != nextSteps.end(); it++)
307 {
308 m_face.expressInterest((*it)->m_interest,
309 bind(&Validator::onData, this, _1, _2, *it),
310 bind(&Validator::onTimeout,
311 this, _1, (*it)->m_nRetries,
312 onFailure,
313 *it));
314 }
315}
316
Yingdi Yufc40d872014-02-18 12:56:04 -0800317} // namespace ndn