blob: 2e1e63787ed715683d8265429c1156c51502b1a3 [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 Yu4e9b0692014-11-04 16:13:56 -080037Validator::Validator(Face* face)
38 : m_face(face)
Yingdi Yu96e64062014-04-15 19:57:33 -070039{
40}
Yingdi Yu6ac97982014-01-30 14:49:21 -080041
Yingdi Yu96e64062014-04-15 19:57:33 -070042Validator::Validator(Face& face)
Yingdi Yu4e9b0692014-11-04 16:13:56 -080043 : m_face(&face)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070044{
45}
Yingdi Yu6ac97982014-01-30 14:49:21 -080046
47void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070048Validator::validate(const Interest& interest,
49 const OnInterestValidated& onValidated,
50 const OnInterestValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070051 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080052{
Yingdi Yuc8f883c2014-06-20 23:25:22 -070053 std::vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070054 checkPolicy(interest, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070055
Yingdi Yud9006e72014-06-23 19:10:44 -070056 if (nextSteps.empty())
Yingdi Yu6ac97982014-01-30 14:49:21 -080057 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070058 // If there is no nextStep,
59 // that means InterestPolicy has already been able to verify the Interest.
60 // No more further processes.
Yingdi Yud9006e72014-06-23 19:10:44 -070061 return;
Yingdi Yu6ac97982014-01-30 14:49:21 -080062 }
Yingdi Yud9006e72014-06-23 19:10:44 -070063
Yingdi Yud9006e72014-06-23 19:10:44 -070064 OnFailure onFailure = bind(onValidationFailed, interest.shared_from_this(), _1);
65 afterCheckPolicy(nextSteps, onFailure);
Yingdi Yu6ac97982014-01-30 14:49:21 -080066}
67
68void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070069Validator::validate(const Data& data,
70 const OnDataValidated& onValidated,
71 const OnDataValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070072 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080073{
Yingdi Yuc8f883c2014-06-20 23:25:22 -070074 std::vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070075 checkPolicy(data, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -080076
Yingdi Yud9006e72014-06-23 19:10:44 -070077 if (nextSteps.empty())
Yingdi Yu6ac97982014-01-30 14:49:21 -080078 {
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070079 // If there is no nextStep,
80 // that means Data Policy has already been able to verify the Interest.
81 // No more further processes.
Yingdi Yud9006e72014-06-23 19:10:44 -070082 return;
Yingdi Yu6ac97982014-01-30 14:49:21 -080083 }
Yingdi Yud9006e72014-06-23 19:10:44 -070084
Yingdi Yud9006e72014-06-23 19:10:44 -070085 OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1);
86 afterCheckPolicy(nextSteps, onFailure);
Yingdi Yu6ac97982014-01-30 14:49:21 -080087}
88
89void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070090Validator::onData(const Interest& interest,
91 const Data& data,
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080092 const shared_ptr<ValidationRequest>& nextStep)
Yingdi Yu6ac97982014-01-30 14:49:21 -080093{
Yingdi Yud9006e72014-06-23 19:10:44 -070094 shared_ptr<const Data> certificateData = preCertificateValidation(data);
Yingdi Yu6ac97982014-01-30 14:49:21 -080095
Yingdi Yud9006e72014-06-23 19:10:44 -070096 if (!static_cast<bool>(certificateData))
97 return nextStep->m_onDataValidationFailed(data.shared_from_this(),
98 "Cannot decode cert: " + data.getName().toUri());
99
100 validate(*certificateData,
101 nextStep->m_onDataValidated, nextStep->m_onDataValidationFailed,
102 nextStep->m_nSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800103}
104
105bool
106Validator::verifySignature(const Data& data, const PublicKey& key)
107{
Yingdi Yu4a557052014-07-09 16:40:37 -0700108 if (!data.getSignature().hasKeyLocator())
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700109 return false;
110
111 return verifySignature(data.wireEncode().value(),
112 data.wireEncode().value_size() -
113 data.getSignature().getValue().size(),
Yingdi Yu4a557052014-07-09 16:40:37 -0700114 data.getSignature(), key);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800115}
116
117bool
Yingdi Yu21157162014-02-28 13:02:34 -0800118Validator::verifySignature(const Interest& interest, const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800119{
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700120 const Name& interestName = interest.getName();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800121
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700122 if (interestName.size() < 2)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800123 return false;
124
Yingdi Yu40587c02014-02-21 16:40:48 -0800125 try
126 {
127 const Block& nameBlock = interestName.wireEncode();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800128
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700129 Signature sig(interestName[-2].blockFromValue(),
Yingdi Yu40587c02014-02-21 16:40:48 -0800130 interestName[-1].blockFromValue());
Yingdi Yu6ac97982014-01-30 14:49:21 -0800131
Yingdi Yu4a557052014-07-09 16:40:37 -0700132 if (!sig.hasKeyLocator())
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700133 return false;
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700134
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700135 return verifySignature(nameBlock.value(),
136 nameBlock.value_size() - interestName[-1].size(),
Yingdi Yu4a557052014-07-09 16:40:37 -0700137 sig, key);
Yingdi Yu40587c02014-02-21 16:40:48 -0800138 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700139 catch (Block::Error& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800140 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800141 return false;
142 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800143}
144
145bool
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700146Validator::verifySignature(const uint8_t* buf,
147 const size_t size,
Yingdi Yu4a557052014-07-09 16:40:37 -0700148 const Signature& sig,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700149 const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800150{
Yingdi Yu40587c02014-02-21 16:40:48 -0800151 try
152 {
153 using namespace CryptoPP;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800154
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700155 switch (sig.getType())
156 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600157 case tlv::SignatureSha256WithRsa:
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700158 {
159 if (key.getKeyType() != KEY_TYPE_RSA)
160 return false;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800161
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700162 RSA::PublicKey publicKey;
163 ByteQueue queue;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800164
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700165 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
166 publicKey.Load(queue);
167
168 RSASS<PKCS1v15, SHA256>::Verifier verifier(publicKey);
169 return verifier.VerifyMessage(buf, size,
170 sig.getValue().value(), sig.getValue().value_size());
171 }
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600172 case tlv::SignatureSha256WithEcdsa:
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700173 {
174 if (key.getKeyType() != KEY_TYPE_ECDSA)
175 return false;
176
177 ECDSA<ECP, SHA256>::PublicKey publicKey;
178 ByteQueue queue;
179
180 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
181 publicKey.Load(queue);
182
183 ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
184
185 uint32_t length = 0;
186 StringSource src(key.get().buf(), key.get().size(), true);
187 BERSequenceDecoder subjectPublicKeyInfo(src);
188 {
189 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
190 {
191 OID algorithm;
192 algorithm.decode(algorithmInfo);
193
194 OID curveId;
195 curveId.decode(algorithmInfo);
196
197 if (curveId == SECP256R1)
198 length = 256;
199 else if (curveId == SECP384R1)
200 length = 384;
201 else
202 return false;
203 }
204 }
205
206 switch (length)
207 {
208 case 256:
209 {
210 uint8_t buffer[64];
211 size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363,
212 sig.getValue().value(),
213 sig.getValue().value_size(),
214 DSA_DER);
215 return verifier.VerifyMessage(buf, size, buffer, usedSize);
216 }
217 case 384:
218 {
219 uint8_t buffer[96];
220 size_t usedSize = DSAConvertSignatureFormat(buffer, 96, DSA_P1363,
221 sig.getValue().value(),
222 sig.getValue().value_size(),
223 DSA_DER);
224 return verifier.VerifyMessage(buf, size, buffer, usedSize);
225 }
226 default:
227 return false;
228 }
229 }
230 default:
231 // Unsupported sig type
232 return false;
233 }
Yingdi Yu40587c02014-02-21 16:40:48 -0800234 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700235 catch (CryptoPP::Exception& e)
Yingdi Yu40587c02014-02-21 16:40:48 -0800236 {
Yingdi Yu40587c02014-02-21 16:40:48 -0800237 return false;
238 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800239}
240
Yingdi Yu21157162014-02-28 13:02:34 -0800241bool
Yingdi Yubf6a2812014-06-17 15:32:11 -0700242Validator::verifySignature(const uint8_t* buf, const size_t size, const DigestSha256& sig)
Yingdi Yu21157162014-02-28 13:02:34 -0800243{
244 try
245 {
246 ConstBufferPtr buffer = crypto::sha256(buf, size);
247 const Block& sigValue = sig.getValue();
248
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700249 if (static_cast<bool>(buffer) &&
250 buffer->size() == sigValue.value_size() &&
251 buffer->size() == crypto::SHA256_DIGEST_SIZE)
Yingdi Yu21157162014-02-28 13:02:34 -0800252 {
253
254 const uint8_t* p1 = buffer->buf();
255 const uint8_t* p2 = sigValue.value();
256
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700257 return 0 == memcmp(p1, p2, crypto::SHA256_DIGEST_SIZE);
Yingdi Yu21157162014-02-28 13:02:34 -0800258 }
259 else
260 return false;
261 }
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700262 catch (CryptoPP::Exception& e)
Yingdi Yu21157162014-02-28 13:02:34 -0800263 {
Yingdi Yu21157162014-02-28 13:02:34 -0800264 return false;
265 }
266}
267
Yingdi Yud9006e72014-06-23 19:10:44 -0700268void
269Validator::onTimeout(const Interest& interest,
270 int remainingRetries,
271 const OnFailure& onFailure,
272 const shared_ptr<ValidationRequest>& validationRequest)
273{
274 if (remainingRetries > 0)
275 // Issue the same expressInterest except decrement nRetrials.
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800276 m_face->expressInterest(interest,
277 bind(&Validator::onData, this, _1, _2, validationRequest),
278 bind(&Validator::onTimeout, this, _1,
279 remainingRetries - 1, onFailure, validationRequest));
Yingdi Yud9006e72014-06-23 19:10:44 -0700280 else
281 onFailure("Cannot fetch cert: " + interest.getName().toUri());
282}
283
284
285void
286Validator::afterCheckPolicy(const std::vector<shared_ptr<ValidationRequest> >& nextSteps,
287 const OnFailure& onFailure)
288{
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800289 if (m_face == nullptr)
290 {
291 onFailure("Require more information to validate the packet!");
292 return;
293 }
294
Yingdi Yud9006e72014-06-23 19:10:44 -0700295 for (std::vector<shared_ptr<ValidationRequest> >::const_iterator it = nextSteps.begin();
296 it != nextSteps.end(); it++)
297 {
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800298 m_face->expressInterest((*it)->m_interest,
299 bind(&Validator::onData, this, _1, _2, *it),
300 bind(&Validator::onTimeout,
301 this, _1, (*it)->m_nRetries,
302 onFailure,
303 *it));
Yingdi Yud9006e72014-06-23 19:10:44 -0700304 }
305}
306
Yingdi Yufc40d872014-02-18 12:56:04 -0800307} // namespace ndn