blob: 84aaa0f748b73a1838719bfea9c30c963c8791fd [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
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070028#include "v1/cryptopp.hpp"
Yingdi Yu21157162014-02-28 13:02:34 -080029
Yingdi Yu6ac97982014-01-30 14:49:21 -080030namespace ndn {
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070031namespace security {
Yingdi Yu6ac97982014-01-30 14:49:21 -080032
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070033static Oid SECP256R1("1.2.840.10045.3.1.7");
34static Oid SECP384R1("1.3.132.0.34");
Yingdi Yuc8f883c2014-06-20 23:25:22 -070035
Yingdi Yu4e9b0692014-11-04 16:13:56 -080036Validator::Validator(Face* face)
37 : m_face(face)
Yingdi Yu96e64062014-04-15 19:57:33 -070038{
39}
Yingdi Yu6ac97982014-01-30 14:49:21 -080040
Yingdi Yu96e64062014-04-15 19:57:33 -070041Validator::Validator(Face& face)
Yingdi Yu4e9b0692014-11-04 16:13:56 -080042 : m_face(&face)
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070043{
44}
Yingdi Yu6ac97982014-01-30 14:49:21 -080045
Davide Pesaventoc152e6f2016-08-14 02:54:48 +020046Validator::~Validator() = default;
47
Yingdi Yu6ac97982014-01-30 14:49:21 -080048void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070049Validator::validate(const Interest& interest,
50 const OnInterestValidated& onValidated,
51 const OnInterestValidationFailed& onValidationFailed,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070052 int nSteps)
Yingdi Yu6ac97982014-01-30 14:49:21 -080053{
Yingdi Yuc8f883c2014-06-20 23:25:22 -070054 std::vector<shared_ptr<ValidationRequest> > nextSteps;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070055 checkPolicy(interest, nSteps, onValidated, onValidationFailed, nextSteps);
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070056
Yingdi Yu99b2a002015-08-12 12:47:44 -070057 if (nextSteps.empty()) {
58 // If there is no nextStep,
59 // that means InterestPolicy has already been able to verify the Interest.
60 // No more further processes.
61 return;
62 }
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 Yu99b2a002015-08-12 12:47:44 -070077 if (nextSteps.empty()) {
78 // If there is no nextStep,
79 // that means Data Policy has already been able to verify the Interest.
80 // No more further processes.
81 return;
82 }
Yingdi Yud9006e72014-06-23 19:10:44 -070083
Yingdi Yud9006e72014-06-23 19:10:44 -070084 OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1);
85 afterCheckPolicy(nextSteps, onFailure);
Yingdi Yu6ac97982014-01-30 14:49:21 -080086}
87
88void
Yingdi Yu48e8c0c2014-03-19 12:01:55 -070089Validator::onData(const Interest& interest,
90 const Data& data,
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080091 const shared_ptr<ValidationRequest>& nextStep)
Yingdi Yu6ac97982014-01-30 14:49:21 -080092{
Yingdi Yud9006e72014-06-23 19:10:44 -070093 shared_ptr<const Data> certificateData = preCertificateValidation(data);
Yingdi Yu6ac97982014-01-30 14:49:21 -080094
Yingdi Yud9006e72014-06-23 19:10:44 -070095 if (!static_cast<bool>(certificateData))
96 return nextStep->m_onDataValidationFailed(data.shared_from_this(),
97 "Cannot decode cert: " + data.getName().toUri());
98
99 validate(*certificateData,
100 nextStep->m_onDataValidated, nextStep->m_onDataValidationFailed,
101 nextStep->m_nSteps);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800102}
103
104bool
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700105Validator::verifySignature(const Data& data, const v1::PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800106{
Yingdi Yu4a557052014-07-09 16:40:37 -0700107 if (!data.getSignature().hasKeyLocator())
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700108 return false;
109
110 return verifySignature(data.wireEncode().value(),
111 data.wireEncode().value_size() -
112 data.getSignature().getValue().size(),
Yingdi Yu4a557052014-07-09 16:40:37 -0700113 data.getSignature(), key);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800114}
115
116bool
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700117Validator::verifySignature(const Interest& interest, const v1::PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800118{
Junxiao Shi198c3812016-08-12 19:24:18 +0000119 const Name& name = interest.getName();
Yingdi Yu6ac97982014-01-30 14:49:21 -0800120
Junxiao Shi198c3812016-08-12 19:24:18 +0000121 if (name.size() < signed_interest::MIN_LENGTH_SIG_ONLY)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800122 return false;
123
Junxiao Shi198c3812016-08-12 19:24:18 +0000124 Signature sig;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700125 try {
Junxiao Shi198c3812016-08-12 19:24:18 +0000126 sig.setInfo(name[signed_interest::POS_SIG_INFO].blockFromValue());
127 sig.setValue(name[signed_interest::POS_SIG_VALUE].blockFromValue());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700128 }
Junxiao Shi198c3812016-08-12 19:24:18 +0000129 catch (const tlv::Error&) {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700130 return false;
131 }
Junxiao Shi198c3812016-08-12 19:24:18 +0000132
133 if (!sig.hasKeyLocator())
134 return false;
135
136 const Block& nameWire = name.wireEncode();
137 return verifySignature(nameWire.value(),
138 nameWire.value_size() - name[signed_interest::POS_SIG_VALUE].size(),
139 sig, key);
Yingdi Yu6ac97982014-01-30 14:49:21 -0800140}
141
142bool
Yingdi Yu48e8c0c2014-03-19 12:01:55 -0700143Validator::verifySignature(const uint8_t* buf,
144 const size_t size,
Yingdi Yu4a557052014-07-09 16:40:37 -0700145 const Signature& sig,
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700146 const v1::PublicKey& key)
Yingdi Yu6ac97982014-01-30 14:49:21 -0800147{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700148 try {
149 using namespace CryptoPP;
Yingdi Yu6ac97982014-01-30 14:49:21 -0800150
Yingdi Yu99b2a002015-08-12 12:47:44 -0700151 switch (sig.getType()) {
152 case tlv::SignatureSha256WithRsa: {
153 if (key.getKeyType() != KeyType::RSA)
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700154 return false;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700155
156 RSA::PublicKey publicKey;
157 ByteQueue queue;
158
159 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
160 publicKey.Load(queue);
161
162 RSASS<PKCS1v15, SHA256>::Verifier verifier(publicKey);
163 return verifier.VerifyMessage(buf, size,
164 sig.getValue().value(), sig.getValue().value_size());
165 }
166
167 case tlv::SignatureSha256WithEcdsa: {
168 if (key.getKeyType() != KeyType::EC)
169 return false;
170
171 ECDSA<ECP, SHA256>::PublicKey publicKey;
172 ByteQueue queue;
173
174 queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
175 publicKey.Load(queue);
176
177 ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
178
179 uint32_t length = 0;
180 StringSource src(key.get().buf(), key.get().size(), true);
181 BERSequenceDecoder subjectPublicKeyInfo(src);
182 {
183 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
184 {
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700185 Oid algorithm;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700186 algorithm.decode(algorithmInfo);
187
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700188 Oid curveId;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700189 curveId.decode(algorithmInfo);
190
191 if (curveId == SECP256R1)
192 length = 256;
193 else if (curveId == SECP384R1)
194 length = 384;
195 else
196 return false;
197 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700198 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700199
200 switch (length) {
201 case 256: {
202 uint8_t buffer[64];
203 size_t usedSize = DSAConvertSignatureFormat(buffer, sizeof(buffer), DSA_P1363,
204 sig.getValue().value(),
205 sig.getValue().value_size(),
206 DSA_DER);
207 return verifier.VerifyMessage(buf, size, buffer, usedSize);
208 }
209
210 case 384: {
211 uint8_t buffer[96];
212 size_t usedSize = DSAConvertSignatureFormat(buffer, sizeof(buffer), DSA_P1363,
213 sig.getValue().value(),
214 sig.getValue().value_size(),
215 DSA_DER);
216 return verifier.VerifyMessage(buf, size, buffer, usedSize);
217 }
218
219 default:
220 return false;
221 }
222 }
223
224 default:
225 // Unsupported sig type
226 return false;
Yingdi Yu40587c02014-02-21 16:40:48 -0800227 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700228 }
229 catch (const CryptoPP::Exception& e) {
230 return false;
231 }
Yingdi Yu6ac97982014-01-30 14:49:21 -0800232}
233
Yingdi Yu21157162014-02-28 13:02:34 -0800234bool
Yingdi Yubf6a2812014-06-17 15:32:11 -0700235Validator::verifySignature(const uint8_t* buf, const size_t size, const DigestSha256& sig)
Yingdi Yu21157162014-02-28 13:02:34 -0800236{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700237 try {
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700238 ConstBufferPtr buffer = crypto::computeSha256Digest(buf, size);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700239 const Block& sigValue = sig.getValue();
Yingdi Yu21157162014-02-28 13:02:34 -0800240
Yingdi Yu99b2a002015-08-12 12:47:44 -0700241 if (buffer != nullptr &&
242 buffer->size() == sigValue.value_size() &&
243 buffer->size() == crypto::SHA256_DIGEST_SIZE) {
244 const uint8_t* p1 = buffer->buf();
245 const uint8_t* p2 = sigValue.value();
Yingdi Yu21157162014-02-28 13:02:34 -0800246
Yingdi Yu99b2a002015-08-12 12:47:44 -0700247 return 0 == memcmp(p1, p2, crypto::SHA256_DIGEST_SIZE);
Yingdi Yu21157162014-02-28 13:02:34 -0800248 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700249 else
Yingdi Yu21157162014-02-28 13:02:34 -0800250 return false;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700251 }
252 catch (const CryptoPP::Exception& e) {
253 return false;
254 }
Yingdi Yu21157162014-02-28 13:02:34 -0800255}
256
Yingdi Yud9006e72014-06-23 19:10:44 -0700257void
Teng Liange6f87512016-07-26 22:14:19 -0700258Validator::onNack(const Interest& interest,
259 const lp::Nack& nack,
260 int remainingRetries,
261 const OnFailure& onFailure,
262 const shared_ptr<ValidationRequest>& validationRequest)
263{
264 if (remainingRetries > 0) {
265 Interest newInterest = Interest(interest);
266 newInterest.refreshNonce();
267
268 //Express the same interest with different nonce and decremented remainingRetries.
269 m_face->expressInterest(newInterest,
270 bind(&Validator::onData, this, _1, _2, validationRequest),
271 bind(&Validator::onNack, this, _1, _2,
272 remainingRetries - 1, onFailure, validationRequest),
273 bind(&Validator::onTimeout, this, _1,
274 remainingRetries - 1, onFailure, validationRequest));
275 }
276 else {
277 onFailure("Cannot fetch cert: " + interest.getName().toUri());
278 }
279}
280
281void
Yingdi Yud9006e72014-06-23 19:10:44 -0700282Validator::onTimeout(const Interest& interest,
283 int remainingRetries,
284 const OnFailure& onFailure,
285 const shared_ptr<ValidationRequest>& validationRequest)
286{
Teng Liange6f87512016-07-26 22:14:19 -0700287 if (remainingRetries > 0) {
288 Interest newInterest = Interest(interest);
289 newInterest.refreshNonce();
290
291 // Express the same interest with different nonce and decremented remainingRetries.
292 m_face->expressInterest(newInterest,
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800293 bind(&Validator::onData, this, _1, _2, validationRequest),
Teng Liange6f87512016-07-26 22:14:19 -0700294 bind(&Validator::onNack, this, _1, _2,
295 remainingRetries - 1, onFailure, validationRequest),
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800296 bind(&Validator::onTimeout, this, _1,
297 remainingRetries - 1, onFailure, validationRequest));
Teng Liange6f87512016-07-26 22:14:19 -0700298 }
299 else {
Yingdi Yud9006e72014-06-23 19:10:44 -0700300 onFailure("Cannot fetch cert: " + interest.getName().toUri());
Teng Liange6f87512016-07-26 22:14:19 -0700301 }
Yingdi Yud9006e72014-06-23 19:10:44 -0700302}
303
Yingdi Yud9006e72014-06-23 19:10:44 -0700304void
Yingdi Yu99b2a002015-08-12 12:47:44 -0700305Validator::afterCheckPolicy(const std::vector<shared_ptr<ValidationRequest>>& nextSteps,
Yingdi Yud9006e72014-06-23 19:10:44 -0700306 const OnFailure& onFailure)
307{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700308 if (m_face == nullptr) {
309 onFailure("Require more information to validate the packet!");
310 return;
311 }
Yingdi Yu4e9b0692014-11-04 16:13:56 -0800312
Yingdi Yu99b2a002015-08-12 12:47:44 -0700313 for (shared_ptr<ValidationRequest> step : nextSteps) {
314 m_face->expressInterest(step->m_interest,
315 bind(&Validator::onData, this, _1, _2, step),
316 bind(&Validator::onNack, this, _1, _2,
317 step->m_nRetries, onFailure, step),
318 bind(&Validator::onTimeout,
319 this, _1, step->m_nRetries,
320 onFailure,
321 step));
322 }
Yingdi Yud9006e72014-06-23 19:10:44 -0700323}
324
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700325} // namespace security
Yingdi Yufc40d872014-02-18 12:56:04 -0800326} // namespace ndn