blob: ffb95016c5444940516422cdd4ccf2ee7a6e4dcc [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
Davide Pesaventoc152e6f2016-08-14 02:54:48 +020045Validator::~Validator() = default;
46
Yingdi Yu6ac97982014-01-30 14:49:21 -080047void
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 Yu99b2a002015-08-12 12:47:44 -070056 if (nextSteps.empty()) {
57 // If there is no nextStep,
58 // that means InterestPolicy has already been able to verify the Interest.
59 // No more further processes.
60 return;
61 }
Yingdi Yud9006e72014-06-23 19:10:44 -070062
Yingdi Yud9006e72014-06-23 19:10:44 -070063 OnFailure onFailure = bind(onValidationFailed, interest.shared_from_this(), _1);
64 afterCheckPolicy(nextSteps, onFailure);
Yingdi Yu6ac97982014-01-30 14:49:21 -080065}
66
67void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070068Validator::validate(const Data& data,
69 const OnDataValidated& onValidated,
70 const OnDataValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070071 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080072{
Yingdi Yuc8f883c2014-06-20 23:25:22 -070073 std::vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070074 checkPolicy(data, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -080075
Yingdi Yu99b2a002015-08-12 12:47:44 -070076 if (nextSteps.empty()) {
77 // If there is no nextStep,
78 // that means Data Policy has already been able to verify the Interest.
79 // No more further processes.
80 return;
81 }
Yingdi Yud9006e72014-06-23 19:10:44 -070082
Yingdi Yud9006e72014-06-23 19:10:44 -070083 OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1);
84 afterCheckPolicy(nextSteps, onFailure);
Yingdi Yu6ac97982014-01-30 14:49:21 -080085}
86
87void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070088Validator::onData(const Interest& interest,
89 const Data& data,
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080090 const shared_ptr<ValidationRequest>& nextStep)
Yingdi Yu6ac97982014-01-30 14:49:21 -080091{
Yingdi Yud9006e72014-06-23 19:10:44 -070092 shared_ptr<const Data> certificateData = preCertificateValidation(data);
Yingdi Yu6ac97982014-01-30 14:49:21 -080093
Yingdi Yud9006e72014-06-23 19:10:44 -070094 if (!static_cast<bool>(certificateData))
95 return nextStep->m_onDataValidationFailed(data.shared_from_this(),
96 "Cannot decode cert: " + data.getName().toUri());
97
98 validate(*certificateData,
99 nextStep->m_onDataValidated, nextStep->m_onDataValidationFailed,
100 nextStep->m_nSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800101}
102
103bool
104Validator::verifySignature(const Data& data, const PublicKey& key)
105{
Yingdi Yu4a557052014-07-09 16:40:37 -0700106 if (!data.getSignature().hasKeyLocator())
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700107 return false;
108
109 return verifySignature(data.wireEncode().value(),
110 data.wireEncode().value_size() -
111 data.getSignature().getValue().size(),
Yingdi Yu4a557052014-07-09 16:40:37 -0700112 data.getSignature(), key);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800113}
114
115bool
Yingdi Yu21157162014-02-28 13:02:34 -0800116Validator::verifySignature(const Interest& interest, const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800117{
Junxiao Shi198c3812016-08-12 19:24:18 +0000118 const Name& name = interest.getName();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800119
Junxiao Shi198c3812016-08-12 19:24:18 +0000120 if (name.size() < signed_interest::MIN_LENGTH_SIG_ONLY)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800121 return false;
122
Junxiao Shi198c3812016-08-12 19:24:18 +0000123 Signature sig;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700124 try {
Junxiao Shi198c3812016-08-12 19:24:18 +0000125 sig.setInfo(name[signed_interest::POS_SIG_INFO].blockFromValue());
126 sig.setValue(name[signed_interest::POS_SIG_VALUE].blockFromValue());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700127 }
Junxiao Shi198c3812016-08-12 19:24:18 +0000128 catch (const tlv::Error&) {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700129 return false;
130 }
Junxiao Shi198c3812016-08-12 19:24:18 +0000131
132 if (!sig.hasKeyLocator())
133 return false;
134
135 const Block& nameWire = name.wireEncode();
136 return verifySignature(nameWire.value(),
137 nameWire.value_size() - name[signed_interest::POS_SIG_VALUE].size(),
138 sig, key);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800139}
140
141bool
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700142Validator::verifySignature(const uint8_t* buf,
143 const size_t size,
Yingdi Yu4a557052014-07-09 16:40:37 -0700144 const Signature& sig,
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700145 const PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800146{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700147 try {
148 using namespace CryptoPP;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800149
Yingdi Yu99b2a002015-08-12 12:47:44 -0700150 switch (sig.getType()) {
151 case tlv::SignatureSha256WithRsa: {
152 if (key.getKeyType() != KeyType::RSA)
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700153 return false;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700154
155 RSA::PublicKey publicKey;
156 ByteQueue queue;
157
158 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
159 publicKey.Load(queue);
160
161 RSASS<PKCS1v15, SHA256>::Verifier verifier(publicKey);
162 return verifier.VerifyMessage(buf, size,
163 sig.getValue().value(), sig.getValue().value_size());
164 }
165
166 case tlv::SignatureSha256WithEcdsa: {
167 if (key.getKeyType() != KeyType::EC)
168 return false;
169
170 ECDSA<ECP, SHA256>::PublicKey publicKey;
171 ByteQueue queue;
172
173 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
174 publicKey.Load(queue);
175
176 ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
177
178 uint32_t length = 0;
179 StringSource src(key.get().buf(), key.get().size(), true);
180 BERSequenceDecoder subjectPublicKeyInfo(src);
181 {
182 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
183 {
184 OID algorithm;
185 algorithm.decode(algorithmInfo);
186
187 OID curveId;
188 curveId.decode(algorithmInfo);
189
190 if (curveId == SECP256R1)
191 length = 256;
192 else if (curveId == SECP384R1)
193 length = 384;
194 else
195 return false;
196 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700197 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700198
199 switch (length) {
200 case 256: {
201 uint8_t buffer[64];
202 size_t usedSize = DSAConvertSignatureFormat(buffer, sizeof(buffer), DSA_P1363,
203 sig.getValue().value(),
204 sig.getValue().value_size(),
205 DSA_DER);
206 return verifier.VerifyMessage(buf, size, buffer, usedSize);
207 }
208
209 case 384: {
210 uint8_t buffer[96];
211 size_t usedSize = DSAConvertSignatureFormat(buffer, sizeof(buffer), DSA_P1363,
212 sig.getValue().value(),
213 sig.getValue().value_size(),
214 DSA_DER);
215 return verifier.VerifyMessage(buf, size, buffer, usedSize);
216 }
217
218 default:
219 return false;
220 }
221 }
222
223 default:
224 // Unsupported sig type
225 return false;
Yingdi Yu40587c02014-02-21 16:40:48 -0800226 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700227 }
228 catch (const CryptoPP::Exception& e) {
229 return false;
230 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800231}
232
Yingdi Yu21157162014-02-28 13:02:34 -0800233bool
Yingdi Yubf6a2812014-06-17 15:32:11 -0700234Validator::verifySignature(const uint8_t* buf, const size_t size, const DigestSha256& sig)
Yingdi Yu21157162014-02-28 13:02:34 -0800235{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700236 try {
237 ConstBufferPtr buffer = crypto::sha256(buf, size);
238 const Block& sigValue = sig.getValue();
Yingdi Yu21157162014-02-28 13:02:34 -0800239
Yingdi Yu99b2a002015-08-12 12:47:44 -0700240 if (buffer != nullptr &&
241 buffer->size() == sigValue.value_size() &&
242 buffer->size() == crypto::SHA256_DIGEST_SIZE) {
243 const uint8_t* p1 = buffer->buf();
244 const uint8_t* p2 = sigValue.value();
Yingdi Yu21157162014-02-28 13:02:34 -0800245
Yingdi Yu99b2a002015-08-12 12:47:44 -0700246 return 0 == memcmp(p1, p2, crypto::SHA256_DIGEST_SIZE);
Yingdi Yu21157162014-02-28 13:02:34 -0800247 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700248 else
Yingdi Yu21157162014-02-28 13:02:34 -0800249 return false;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700250 }
251 catch (const CryptoPP::Exception& e) {
252 return false;
253 }
Yingdi Yu21157162014-02-28 13:02:34 -0800254}
255
Yingdi Yud9006e72014-06-23 19:10:44 -0700256void
Teng Liange6f87512016-07-26 22:14:19 -0700257Validator::onNack(const Interest& interest,
258 const lp::Nack& nack,
259 int remainingRetries,
260 const OnFailure& onFailure,
261 const shared_ptr<ValidationRequest>& validationRequest)
262{
263 if (remainingRetries > 0) {
264 Interest newInterest = Interest(interest);
265 newInterest.refreshNonce();
266
267 //Express the same interest with different nonce and decremented remainingRetries.
268 m_face->expressInterest(newInterest,
269 bind(&Validator::onData, this, _1, _2, validationRequest),
270 bind(&Validator::onNack, this, _1, _2,
271 remainingRetries - 1, onFailure, validationRequest),
272 bind(&Validator::onTimeout, this, _1,
273 remainingRetries - 1, onFailure, validationRequest));
274 }
275 else {
276 onFailure("Cannot fetch cert: " + interest.getName().toUri());
277 }
278}
279
280void
Yingdi Yud9006e72014-06-23 19:10:44 -0700281Validator::onTimeout(const Interest& interest,
282 int remainingRetries,
283 const OnFailure& onFailure,
284 const shared_ptr<ValidationRequest>& validationRequest)
285{
Teng Liange6f87512016-07-26 22:14:19 -0700286 if (remainingRetries > 0) {
287 Interest newInterest = Interest(interest);
288 newInterest.refreshNonce();
289
290 // Express the same interest with different nonce and decremented remainingRetries.
291 m_face->expressInterest(newInterest,
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800292 bind(&Validator::onData, this, _1, _2, validationRequest),
Teng Liange6f87512016-07-26 22:14:19 -0700293 bind(&Validator::onNack, this, _1, _2,
294 remainingRetries - 1, onFailure, validationRequest),
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800295 bind(&Validator::onTimeout, this, _1,
296 remainingRetries - 1, onFailure, validationRequest));
Teng Liange6f87512016-07-26 22:14:19 -0700297 }
298 else {
Yingdi Yud9006e72014-06-23 19:10:44 -0700299 onFailure("Cannot fetch cert: " + interest.getName().toUri());
Teng Liange6f87512016-07-26 22:14:19 -0700300 }
Yingdi Yud9006e72014-06-23 19:10:44 -0700301}
302
Yingdi Yud9006e72014-06-23 19:10:44 -0700303void
Yingdi Yu99b2a002015-08-12 12:47:44 -0700304Validator::afterCheckPolicy(const std::vector<shared_ptr<ValidationRequest>>& nextSteps,
Yingdi Yud9006e72014-06-23 19:10:44 -0700305 const OnFailure& onFailure)
306{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700307 if (m_face == nullptr) {
308 onFailure("Require more information to validate the packet!");
309 return;
310 }
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800311
Yingdi Yu99b2a002015-08-12 12:47:44 -0700312 for (shared_ptr<ValidationRequest> step : nextSteps) {
313 m_face->expressInterest(step->m_interest,
314 bind(&Validator::onData, this, _1, _2, step),
315 bind(&Validator::onNack, this, _1, _2,
316 step->m_nRetries, onFailure, step),
317 bind(&Validator::onTimeout,
318 this, _1, step->m_nRetries,
319 onFailure,
320 step));
321 }
Yingdi Yud9006e72014-06-23 19:10:44 -0700322}
323
Yingdi Yufc40d872014-02-18 12:56:04 -0800324} // namespace ndn