blob: 479bbb9f91f594d97101e99963092c211b9f7165 [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/*
Alexander Afanasyev09236c22020-06-03 13:42:38 -04003 * Copyright (c) 2013-2020 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"
Alexander Afanasyev7e721412017-01-11 13:36:08 -080023
Davide Pesavento7e780642018-11-24 15:51:34 -050024#include "ndn-cxx/face.hpp"
25#include "ndn-cxx/security/transform/public-key.hpp"
26#include "ndn-cxx/util/logger.hpp"
Alexander Afanasyev7e721412017-01-11 13:36:08 -080027
28namespace ndn {
29namespace security {
Alexander Afanasyev09236c22020-06-03 13:42:38 -040030inline namespace v2 {
Alexander Afanasyev7e721412017-01-11 13:36:08 -080031
Alexander Afanasyev09236c22020-06-03 13:42:38 -040032NDN_LOG_INIT(ndn.security.Validator);
Alexander Afanasyev7e721412017-01-11 13:36:08 -080033
34#define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << " " << x)
35#define NDN_LOG_TRACE_DEPTH(x) NDN_LOG_TRACE(std::string(state->getDepth() + 1, '>') << " " << x)
36
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -080037Validator::Validator(unique_ptr<ValidationPolicy> policy, unique_ptr<CertificateFetcher> certFetcher)
Alexander Afanasyev7e721412017-01-11 13:36:08 -080038 : m_policy(std::move(policy))
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -080039 , m_certFetcher(std::move(certFetcher))
Alexander Afanasyev7e721412017-01-11 13:36:08 -080040 , m_maxDepth(25)
41{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -080042 BOOST_ASSERT(m_policy != nullptr);
43 BOOST_ASSERT(m_certFetcher != nullptr);
Alexander Afanasyevb54aa572017-03-21 19:40:49 -050044 m_policy->setValidator(*this);
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -080045 m_certFetcher->setCertificateStorage(*this);
Alexander Afanasyev7e721412017-01-11 13:36:08 -080046}
47
48Validator::~Validator() = default;
49
Alexander Afanasyevb54aa572017-03-21 19:40:49 -050050ValidationPolicy&
51Validator::getPolicy()
52{
53 return *m_policy;
54}
55
56CertificateFetcher&
57Validator::getFetcher()
58{
59 return *m_certFetcher;
60}
61
Alexander Afanasyev7e721412017-01-11 13:36:08 -080062void
63Validator::setMaxDepth(size_t depth)
64{
65 m_maxDepth = depth;
66}
67
68size_t
69Validator::getMaxDepth() const
70{
71 return m_maxDepth;
72}
73
74void
75Validator::validate(const Data& data,
76 const DataValidationSuccessCallback& successCb,
77 const DataValidationFailureCallback& failureCb)
78{
79 auto state = make_shared<DataValidationState>(data, successCb, failureCb);
80 NDN_LOG_DEBUG_DEPTH("Start validating data " << data.getName());
81
82 m_policy->checkPolicy(data, state,
83 [this] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
84 if (certRequest == nullptr) {
85 state->bypassValidation();
86 }
87 else {
88 // need to fetch key and validate it
89 requestCertificate(certRequest, state);
90 }
91 });
92}
93
94void
95Validator::validate(const Interest& interest,
96 const InterestValidationSuccessCallback& successCb,
97 const InterestValidationFailureCallback& failureCb)
98{
99 auto state = make_shared<InterestValidationState>(interest, successCb, failureCb);
Eric Newberry17d7c472020-06-18 21:29:22 -0700100
101 auto fmt = interest.getSignatureInfo() ? SignedInterestFormat::V03 : SignedInterestFormat::V02;
102 state->setTag(make_shared<SignedInterestFormatTag>(fmt));
103
104 NDN_LOG_DEBUG_DEPTH("Start validating interest (" << fmt << ") " << interest.getName());
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800105
106 m_policy->checkPolicy(interest, state,
107 [this] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
108 if (certRequest == nullptr) {
109 state->bypassValidation();
110 }
111 else {
112 // need to fetch key and validate it
113 requestCertificate(certRequest, state);
114 }
115 });
116}
117
118void
119Validator::validate(const Certificate& cert, const shared_ptr<ValidationState>& state)
120{
121 NDN_LOG_DEBUG_DEPTH("Start validating certificate " << cert.getName());
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800122
123 if (!cert.isValid()) {
124 return state->fail({ValidationError::Code::EXPIRED_CERT, "Retrieved certificate is not yet valid or expired "
125 "`" + cert.getName().toUri() + "`"});
126 }
127
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800128 m_policy->checkPolicy(cert, state,
129 [this, cert] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
130 if (certRequest == nullptr) {
131 state->fail({ValidationError::POLICY_ERROR, "Validation policy is not allowed to designate `" +
132 cert.getName().toUri() + "` as a trust anchor"});
133 }
134 else {
135 // need to fetch key and validate it
136 state->addCertificate(cert);
137 requestCertificate(certRequest, state);
138 }
139 });
140}
141
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800142void
143Validator::requestCertificate(const shared_ptr<CertificateRequest>& certRequest,
144 const shared_ptr<ValidationState>& state)
145{
146 // TODO configurable check for the maximum number of steps
147 if (state->getDepth() >= m_maxDepth) {
148 state->fail({ValidationError::Code::EXCEEDED_DEPTH_LIMIT,
149 "Exceeded validation depth limit (" + to_string(m_maxDepth) + ")"});
150 return;
151 }
152
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500153 if (state->hasSeenCertificateName(certRequest->interest.getName())) {
Alexander Afanasyev5af04a72017-01-30 22:41:23 -0800154 state->fail({ValidationError::Code::LOOP_DETECTED,
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500155 "Validation loop detected for certificate `" + certRequest->interest.getName().toUri() + "`"});
Alexander Afanasyev5af04a72017-01-30 22:41:23 -0800156 return;
157 }
158
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500159 NDN_LOG_DEBUG_DEPTH("Retrieving " << certRequest->interest.getName());
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800160
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500161 auto cert = findTrustedCert(certRequest->interest);
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800162 if (cert != nullptr) {
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800163 NDN_LOG_TRACE_DEPTH("Found trusted certificate " << cert->getName());
164
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800165 cert = state->verifyCertificateChain(*cert);
166 if (cert != nullptr) {
167 state->verifyOriginalPacket(*cert);
168 }
169 for (auto trustedCert = std::make_move_iterator(state->m_certificateChain.begin());
170 trustedCert != std::make_move_iterator(state->m_certificateChain.end());
171 ++trustedCert) {
172 cacheVerifiedCertificate(*trustedCert);
173 }
174 return;
175 }
176
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800177 m_certFetcher->fetch(certRequest, state, [this] (const Certificate& cert, const shared_ptr<ValidationState>& state) {
178 validate(cert, state);
179 });
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800180}
181
182////////////////////////////////////////////////////////////////////////
183// Trust anchor management
184////////////////////////////////////////////////////////////////////////
185
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800186// to change visibility from protected to public
187
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800188void
189Validator::loadAnchor(const std::string& groupId, Certificate&& cert)
190{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800191 CertificateStorage::loadAnchor(groupId, std::move(cert));
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800192}
193
194void
195Validator::loadAnchor(const std::string& groupId, const std::string& certfilePath,
196 time::nanoseconds refreshPeriod, bool isDir)
197{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800198 CertificateStorage::loadAnchor(groupId, certfilePath, refreshPeriod, isDir);
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800199}
200
201void
Alexander Afanasyev6aff0242017-08-29 17:14:44 -0400202Validator::resetAnchors()
203{
204 CertificateStorage::resetAnchors();
205}
206
207void
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800208Validator::cacheVerifiedCertificate(Certificate&& cert)
209{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800210 CertificateStorage::cacheVerifiedCert(std::move(cert));
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800211}
212
Alexander Afanasyev6aff0242017-08-29 17:14:44 -0400213void
214Validator::resetVerifiedCertificates()
215{
216 CertificateStorage::resetVerifiedCerts();
217}
218
Alexander Afanasyev09236c22020-06-03 13:42:38 -0400219} // inline namespace v2
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800220} // namespace security
221} // namespace ndn