blob: 1ef7a05441df486c27e957a622bee382bbb3d5d6 [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/**
Teng Liange6f87512016-07-26 22:14:19 -07003 * Copyright (c) 2013-2016 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
Yingdi Yu6ac97982014-01-30 14:49:21 -080025#include "validator.hpp"
Yingdi Yu21157162014-02-28 13:02:34 -080026#include "../util/crypto.hpp"
Yingdi Yu6ac97982014-01-30 14:49:21 -080027
Junxiao Shi482ccc52014-03-31 13:05:24 -070028#include "cryptopp.hpp"
Yingdi Yu21157162014-02-28 13:02:34 -080029
Yingdi Yu6ac97982014-01-30 14:49:21 -080030namespace ndn {
31
Yingdi Yuc8f883c2014-06-20 23:25:22 -070032static OID SECP256R1("1.2.840.10045.3.1.7");
33static OID SECP384R1("1.3.132.0.34");
34
Yingdi Yu4e9b0692014-11-04 16:13:56 -080035Validator::Validator(Face* face)
36 : m_face(face)
Yingdi Yu96e64062014-04-15 19:57:33 -070037{
38}
Yingdi Yu6ac97982014-01-30 14:49:21 -080039
Yingdi Yu96e64062014-04-15 19:57:33 -070040Validator::Validator(Face& face)
Yingdi Yu4e9b0692014-11-04 16:13:56 -080041 : m_face(&face)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070042{
43}
Yingdi Yu6ac97982014-01-30 14:49:21 -080044
45void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070046Validator::validate(const Interest& interest,
47 const OnInterestValidated& onValidated,
48 const OnInterestValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070049 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080050{
Yingdi Yuc8f883c2014-06-20 23:25:22 -070051 std::vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070052 checkPolicy(interest, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070053
Yingdi Yu99b2a002015-08-12 12:47:44 -070054 if (nextSteps.empty()) {
55 // If there is no nextStep,
56 // that means InterestPolicy has already been able to verify the Interest.
57 // No more further processes.
58 return;
59 }
Yingdi Yud9006e72014-06-23 19:10:44 -070060
Yingdi Yud9006e72014-06-23 19:10:44 -070061 OnFailure onFailure = bind(onValidationFailed, interest.shared_from_this(), _1);
62 afterCheckPolicy(nextSteps, onFailure);
Yingdi Yu6ac97982014-01-30 14:49:21 -080063}
64
65void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070066Validator::validate(const Data& data,
67 const OnDataValidated& onValidated,
68 const OnDataValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070069 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080070{
Yingdi Yuc8f883c2014-06-20 23:25:22 -070071 std::vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070072 checkPolicy(data, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -080073
Yingdi Yu99b2a002015-08-12 12:47:44 -070074 if (nextSteps.empty()) {
75 // If there is no nextStep,
76 // that means Data Policy has already been able to verify the Interest.
77 // No more further processes.
78 return;
79 }
Yingdi Yud9006e72014-06-23 19:10:44 -070080
Yingdi Yud9006e72014-06-23 19:10:44 -070081 OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1);
82 afterCheckPolicy(nextSteps, onFailure);
Yingdi Yu6ac97982014-01-30 14:49:21 -080083}
84
85void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070086Validator::onData(const Interest& interest,
87 const Data& data,
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080088 const shared_ptr<ValidationRequest>& nextStep)
Yingdi Yu6ac97982014-01-30 14:49:21 -080089{
Yingdi Yud9006e72014-06-23 19:10:44 -070090 shared_ptr<const Data> certificateData = preCertificateValidation(data);
Yingdi Yu6ac97982014-01-30 14:49:21 -080091
Yingdi Yud9006e72014-06-23 19:10:44 -070092 if (!static_cast<bool>(certificateData))
93 return nextStep->m_onDataValidationFailed(data.shared_from_this(),
94 "Cannot decode cert: " + data.getName().toUri());
95
96 validate(*certificateData,
97 nextStep->m_onDataValidated, nextStep->m_onDataValidationFailed,
98 nextStep->m_nSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -080099}
100
101bool
102Validator::verifySignature(const Data& data, const PublicKey& key)
103{
Yingdi Yu4a557052014-07-09 16:40:37 -0700104 if (!data.getSignature().hasKeyLocator())
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700105 return false;
106
107 return verifySignature(data.wireEncode().value(),
108 data.wireEncode().value_size() -
109 data.getSignature().getValue().size(),
Yingdi Yu4a557052014-07-09 16:40:37 -0700110 data.getSignature(), key);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800111}
112
113bool
Yingdi Yu21157162014-02-28 13:02:34 -0800114Validator::verifySignature(const Interest& interest, const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800115{
Junxiao Shi198c3812016-08-12 19:24:18 +0000116 const Name& name = interest.getName();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800117
Junxiao Shi198c3812016-08-12 19:24:18 +0000118 if (name.size() < signed_interest::MIN_LENGTH_SIG_ONLY)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800119 return false;
120
Junxiao Shi198c3812016-08-12 19:24:18 +0000121 Signature sig;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700122 try {
Junxiao Shi198c3812016-08-12 19:24:18 +0000123 sig.setInfo(name[signed_interest::POS_SIG_INFO].blockFromValue());
124 sig.setValue(name[signed_interest::POS_SIG_VALUE].blockFromValue());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700125 }
Junxiao Shi198c3812016-08-12 19:24:18 +0000126 catch (const tlv::Error&) {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700127 return false;
128 }
Junxiao Shi198c3812016-08-12 19:24:18 +0000129
130 if (!sig.hasKeyLocator())
131 return false;
132
133 const Block& nameWire = name.wireEncode();
134 return verifySignature(nameWire.value(),
135 nameWire.value_size() - name[signed_interest::POS_SIG_VALUE].size(),
136 sig, key);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800137}
138
139bool
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700140Validator::verifySignature(const uint8_t* buf,
141 const size_t size,
Yingdi Yu4a557052014-07-09 16:40:37 -0700142 const Signature& sig,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700143 const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800144{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700145 try {
146 using namespace CryptoPP;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800147
Yingdi Yu99b2a002015-08-12 12:47:44 -0700148 switch (sig.getType()) {
149 case tlv::SignatureSha256WithRsa: {
150 if (key.getKeyType() != KeyType::RSA)
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700151 return false;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700152
153 RSA::PublicKey publicKey;
154 ByteQueue queue;
155
156 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
157 publicKey.Load(queue);
158
159 RSASS<PKCS1v15, SHA256>::Verifier verifier(publicKey);
160 return verifier.VerifyMessage(buf, size,
161 sig.getValue().value(), sig.getValue().value_size());
162 }
163
164 case tlv::SignatureSha256WithEcdsa: {
165 if (key.getKeyType() != KeyType::EC)
166 return false;
167
168 ECDSA<ECP, SHA256>::PublicKey publicKey;
169 ByteQueue queue;
170
171 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
172 publicKey.Load(queue);
173
174 ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
175
176 uint32_t length = 0;
177 StringSource src(key.get().buf(), key.get().size(), true);
178 BERSequenceDecoder subjectPublicKeyInfo(src);
179 {
180 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
181 {
182 OID algorithm;
183 algorithm.decode(algorithmInfo);
184
185 OID curveId;
186 curveId.decode(algorithmInfo);
187
188 if (curveId == SECP256R1)
189 length = 256;
190 else if (curveId == SECP384R1)
191 length = 384;
192 else
193 return false;
194 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700195 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700196
197 switch (length) {
198 case 256: {
199 uint8_t buffer[64];
200 size_t usedSize = DSAConvertSignatureFormat(buffer, sizeof(buffer), DSA_P1363,
201 sig.getValue().value(),
202 sig.getValue().value_size(),
203 DSA_DER);
204 return verifier.VerifyMessage(buf, size, buffer, usedSize);
205 }
206
207 case 384: {
208 uint8_t buffer[96];
209 size_t usedSize = DSAConvertSignatureFormat(buffer, sizeof(buffer), DSA_P1363,
210 sig.getValue().value(),
211 sig.getValue().value_size(),
212 DSA_DER);
213 return verifier.VerifyMessage(buf, size, buffer, usedSize);
214 }
215
216 default:
217 return false;
218 }
219 }
220
221 default:
222 // Unsupported sig type
223 return false;
Yingdi Yu40587c02014-02-21 16:40:48 -0800224 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700225 }
226 catch (const CryptoPP::Exception& e) {
227 return false;
228 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800229}
230
Yingdi Yu21157162014-02-28 13:02:34 -0800231bool
Yingdi Yubf6a2812014-06-17 15:32:11 -0700232Validator::verifySignature(const uint8_t* buf, const size_t size, const DigestSha256& sig)
Yingdi Yu21157162014-02-28 13:02:34 -0800233{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700234 try {
235 ConstBufferPtr buffer = crypto::sha256(buf, size);
236 const Block& sigValue = sig.getValue();
Yingdi Yu21157162014-02-28 13:02:34 -0800237
Yingdi Yu99b2a002015-08-12 12:47:44 -0700238 if (buffer != nullptr &&
239 buffer->size() == sigValue.value_size() &&
240 buffer->size() == crypto::SHA256_DIGEST_SIZE) {
241 const uint8_t* p1 = buffer->buf();
242 const uint8_t* p2 = sigValue.value();
Yingdi Yu21157162014-02-28 13:02:34 -0800243
Yingdi Yu99b2a002015-08-12 12:47:44 -0700244 return 0 == memcmp(p1, p2, crypto::SHA256_DIGEST_SIZE);
Yingdi Yu21157162014-02-28 13:02:34 -0800245 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700246 else
Yingdi Yu21157162014-02-28 13:02:34 -0800247 return false;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700248 }
249 catch (const CryptoPP::Exception& e) {
250 return false;
251 }
Yingdi Yu21157162014-02-28 13:02:34 -0800252}
253
Yingdi Yud9006e72014-06-23 19:10:44 -0700254void
Teng Liange6f87512016-07-26 22:14:19 -0700255Validator::onNack(const Interest& interest,
256 const lp::Nack& nack,
257 int remainingRetries,
258 const OnFailure& onFailure,
259 const shared_ptr<ValidationRequest>& validationRequest)
260{
261 if (remainingRetries > 0) {
262 Interest newInterest = Interest(interest);
263 newInterest.refreshNonce();
264
265 //Express the same interest with different nonce and decremented remainingRetries.
266 m_face->expressInterest(newInterest,
267 bind(&Validator::onData, this, _1, _2, validationRequest),
268 bind(&Validator::onNack, this, _1, _2,
269 remainingRetries - 1, onFailure, validationRequest),
270 bind(&Validator::onTimeout, this, _1,
271 remainingRetries - 1, onFailure, validationRequest));
272 }
273 else {
274 onFailure("Cannot fetch cert: " + interest.getName().toUri());
275 }
276}
277
278void
Yingdi Yud9006e72014-06-23 19:10:44 -0700279Validator::onTimeout(const Interest& interest,
280 int remainingRetries,
281 const OnFailure& onFailure,
282 const shared_ptr<ValidationRequest>& validationRequest)
283{
Teng Liange6f87512016-07-26 22:14:19 -0700284 if (remainingRetries > 0) {
285 Interest newInterest = Interest(interest);
286 newInterest.refreshNonce();
287
288 // Express the same interest with different nonce and decremented remainingRetries.
289 m_face->expressInterest(newInterest,
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800290 bind(&Validator::onData, this, _1, _2, validationRequest),
Teng Liange6f87512016-07-26 22:14:19 -0700291 bind(&Validator::onNack, this, _1, _2,
292 remainingRetries - 1, onFailure, validationRequest),
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800293 bind(&Validator::onTimeout, this, _1,
294 remainingRetries - 1, onFailure, validationRequest));
Teng Liange6f87512016-07-26 22:14:19 -0700295 }
296 else {
Yingdi Yud9006e72014-06-23 19:10:44 -0700297 onFailure("Cannot fetch cert: " + interest.getName().toUri());
Teng Liange6f87512016-07-26 22:14:19 -0700298 }
Yingdi Yud9006e72014-06-23 19:10:44 -0700299}
300
Yingdi Yud9006e72014-06-23 19:10:44 -0700301void
Yingdi Yu99b2a002015-08-12 12:47:44 -0700302Validator::afterCheckPolicy(const std::vector<shared_ptr<ValidationRequest>>& nextSteps,
Yingdi Yud9006e72014-06-23 19:10:44 -0700303 const OnFailure& onFailure)
304{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700305 if (m_face == nullptr) {
306 onFailure("Require more information to validate the packet!");
307 return;
308 }
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800309
Yingdi Yu99b2a002015-08-12 12:47:44 -0700310 for (shared_ptr<ValidationRequest> step : nextSteps) {
311 m_face->expressInterest(step->m_interest,
312 bind(&Validator::onData, this, _1, _2, step),
313 bind(&Validator::onNack, this, _1, _2,
314 step->m_nRetries, onFailure, step),
315 bind(&Validator::onTimeout,
316 this, _1, step->m_nRetries,
317 onFailure,
318 step));
319 }
Yingdi Yud9006e72014-06-23 19:10:44 -0700320}
321
Yingdi Yufc40d872014-02-18 12:56:04 -0800322} // namespace ndn