blob: 99d1a6f47415ca46bf9bdf04e45f7e6a517470b4 [file] [log] [blame]
Alexander Afanasyev7e721412017-01-11 13:36:08 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyev6aff0242017-08-29 17:14:44 -04002/*
Davide Pesavento87208f92022-08-30 19:51:23 -04003 * Copyright (c) 2013-2022 Regents of the University of California.
Alexander Afanasyev7e721412017-01-11 13:36:08 -08004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * 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.
20 */
21
Alexander Afanasyev09236c22020-06-03 13:42:38 -040022#include "ndn-cxx/security/validator.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050023#include "ndn-cxx/util/logger.hpp"
Alexander Afanasyev7e721412017-01-11 13:36:08 -080024
Davide Pesavento87208f92022-08-30 19:51:23 -040025#include <boost/lexical_cast.hpp>
26
Alexander Afanasyev7e721412017-01-11 13:36:08 -080027namespace ndn {
28namespace security {
Alexander Afanasyev09236c22020-06-03 13:42:38 -040029inline namespace v2 {
Alexander Afanasyev7e721412017-01-11 13:36:08 -080030
Alexander Afanasyev09236c22020-06-03 13:42:38 -040031NDN_LOG_INIT(ndn.security.Validator);
Alexander Afanasyev7e721412017-01-11 13:36:08 -080032
33#define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << " " << x)
34#define NDN_LOG_TRACE_DEPTH(x) NDN_LOG_TRACE(std::string(state->getDepth() + 1, '>') << " " << x)
35
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -080036Validator::Validator(unique_ptr<ValidationPolicy> policy, unique_ptr<CertificateFetcher> certFetcher)
Alexander Afanasyev7e721412017-01-11 13:36:08 -080037 : m_policy(std::move(policy))
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -080038 , m_certFetcher(std::move(certFetcher))
Alexander Afanasyev7e721412017-01-11 13:36:08 -080039{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -080040 BOOST_ASSERT(m_policy != nullptr);
41 BOOST_ASSERT(m_certFetcher != nullptr);
Alexander Afanasyevb54aa572017-03-21 19:40:49 -050042 m_policy->setValidator(*this);
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -080043 m_certFetcher->setCertificateStorage(*this);
Alexander Afanasyev7e721412017-01-11 13:36:08 -080044}
45
Davide Pesavento87208f92022-08-30 19:51:23 -040046Validator::~Validator() noexcept = default;
Alexander Afanasyev7e721412017-01-11 13:36:08 -080047
48void
49Validator::validate(const Data& data,
50 const DataValidationSuccessCallback& successCb,
51 const DataValidationFailureCallback& failureCb)
52{
53 auto state = make_shared<DataValidationState>(data, successCb, failureCb);
54 NDN_LOG_DEBUG_DEPTH("Start validating data " << data.getName());
55
Davide Pesavento2acce252022-09-08 22:03:03 -040056 m_policy->checkPolicy(data, state, [this] (auto&&... args) {
57 continueValidation(std::forward<decltype(args)>(args)...);
58 });
Alexander Afanasyev7e721412017-01-11 13:36:08 -080059}
60
61void
62Validator::validate(const Interest& interest,
63 const InterestValidationSuccessCallback& successCb,
64 const InterestValidationFailureCallback& failureCb)
65{
66 auto state = make_shared<InterestValidationState>(interest, successCb, failureCb);
Davide Pesavento2acce252022-09-08 22:03:03 -040067 NDN_LOG_DEBUG_DEPTH("Start validating interest " << interest.getName());
Eric Newberry17d7c472020-06-18 21:29:22 -070068
Davide Pesavento2acce252022-09-08 22:03:03 -040069 try {
70 auto fmt = interest.getSignatureInfo() ? SignedInterestFormat::V03 : SignedInterestFormat::V02;
71 state->setTag(make_shared<SignedInterestFormatTag>(fmt));
72 }
73 catch (const tlv::Error& e) {
Davide Pesavento637ea3b2022-09-10 00:11:34 -040074 return state->fail({ValidationError::MALFORMED_SIGNATURE, "Malformed InterestSignatureInfo in `" +
Davide Pesavento2acce252022-09-08 22:03:03 -040075 interest.getName().toUri() + "`: " + e.what()});
76 }
Alexander Afanasyev7e721412017-01-11 13:36:08 -080077
Davide Pesavento2acce252022-09-08 22:03:03 -040078 m_policy->checkPolicy(interest, state, [this] (auto&&... args) {
79 continueValidation(std::forward<decltype(args)>(args)...);
80 });
Alexander Afanasyev7e721412017-01-11 13:36:08 -080081}
82
83void
84Validator::validate(const Certificate& cert, const shared_ptr<ValidationState>& state)
85{
86 NDN_LOG_DEBUG_DEPTH("Start validating certificate " << cert.getName());
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -080087
88 if (!cert.isValid()) {
Davide Pesavento87208f92022-08-30 19:51:23 -040089 return state->fail({ValidationError::EXPIRED_CERT, "`" + cert.getName().toUri() + "` is valid "
90 "between " + boost::lexical_cast<std::string>(cert.getValidityPeriod())});
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -080091 }
92
Alexander Afanasyev7e721412017-01-11 13:36:08 -080093 m_policy->checkPolicy(cert, state,
Davide Pesavento87208f92022-08-30 19:51:23 -040094 [this, cert] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
Alexander Afanasyev7e721412017-01-11 13:36:08 -080095 if (certRequest == nullptr) {
96 state->fail({ValidationError::POLICY_ERROR, "Validation policy is not allowed to designate `" +
97 cert.getName().toUri() + "` as a trust anchor"});
98 }
99 else {
100 // need to fetch key and validate it
101 state->addCertificate(cert);
102 requestCertificate(certRequest, state);
103 }
104 });
105}
106
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800107void
Davide Pesavento2acce252022-09-08 22:03:03 -0400108Validator::continueValidation(const shared_ptr<CertificateRequest>& certRequest,
109 const shared_ptr<ValidationState>& state)
110{
111 BOOST_ASSERT(state);
112
113 if (certRequest == nullptr) {
114 state->bypassValidation();
115 }
116 else {
117 // need to fetch key and validate it
118 requestCertificate(certRequest, state);
119 }
120}
121
122void
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800123Validator::requestCertificate(const shared_ptr<CertificateRequest>& certRequest,
124 const shared_ptr<ValidationState>& state)
125{
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800126 if (state->getDepth() >= m_maxDepth) {
Davide Pesavento87208f92022-08-30 19:51:23 -0400127 state->fail({ValidationError::EXCEEDED_DEPTH_LIMIT, to_string(m_maxDepth)});
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800128 return;
129 }
130
Justin Labryaef53b62021-03-10 06:07:27 +0000131 if (certRequest->interest.getName() == SigningInfo::getDigestSha256Identity()) {
132 state->verifyOriginalPacket(nullopt);
133 return;
134 }
135
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500136 if (state->hasSeenCertificateName(certRequest->interest.getName())) {
Davide Pesavento2acce252022-09-08 22:03:03 -0400137 state->fail({ValidationError::LOOP_DETECTED, certRequest->interest.getName().toUri()});
Alexander Afanasyev5af04a72017-01-30 22:41:23 -0800138 return;
139 }
140
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500141 NDN_LOG_DEBUG_DEPTH("Retrieving " << certRequest->interest.getName());
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800142
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500143 auto cert = findTrustedCert(certRequest->interest);
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800144 if (cert != nullptr) {
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800145 NDN_LOG_TRACE_DEPTH("Found trusted certificate " << cert->getName());
146
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800147 cert = state->verifyCertificateChain(*cert);
148 if (cert != nullptr) {
149 state->verifyOriginalPacket(*cert);
150 }
151 for (auto trustedCert = std::make_move_iterator(state->m_certificateChain.begin());
152 trustedCert != std::make_move_iterator(state->m_certificateChain.end());
153 ++trustedCert) {
154 cacheVerifiedCertificate(*trustedCert);
155 }
156 return;
157 }
158
Davide Pesavento87208f92022-08-30 19:51:23 -0400159 m_certFetcher->fetch(certRequest, state, [this] (auto&&... args) {
160 validate(std::forward<decltype(args)>(args)...);
161 });
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800162}
163
164////////////////////////////////////////////////////////////////////////
165// Trust anchor management
166////////////////////////////////////////////////////////////////////////
167
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800168// to change visibility from protected to public
169
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800170void
171Validator::loadAnchor(const std::string& groupId, Certificate&& cert)
172{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800173 CertificateStorage::loadAnchor(groupId, std::move(cert));
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800174}
175
176void
177Validator::loadAnchor(const std::string& groupId, const std::string& certfilePath,
178 time::nanoseconds refreshPeriod, bool isDir)
179{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800180 CertificateStorage::loadAnchor(groupId, certfilePath, refreshPeriod, isDir);
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800181}
182
183void
Alexander Afanasyev6aff0242017-08-29 17:14:44 -0400184Validator::resetAnchors()
185{
186 CertificateStorage::resetAnchors();
187}
188
189void
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800190Validator::cacheVerifiedCertificate(Certificate&& cert)
191{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800192 CertificateStorage::cacheVerifiedCert(std::move(cert));
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800193}
194
Alexander Afanasyev6aff0242017-08-29 17:14:44 -0400195void
196Validator::resetVerifiedCertificates()
197{
198 CertificateStorage::resetVerifiedCerts();
199}
200
Alexander Afanasyev09236c22020-06-03 13:42:38 -0400201} // inline namespace v2
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800202} // namespace security
203} // namespace ndn