blob: 24542bb9d11152ef8f984440fb4373e775a49c83 [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/*
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -05003 * Copyright (c) 2013-2018 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
22#include "validator.hpp"
23
24#include "face.hpp"
25#include "security/transform/public-key.hpp"
26#include "util/logger.hpp"
27
28namespace ndn {
29namespace security {
30namespace v2 {
31
32NDN_LOG_INIT(ndn.security.v2.Validator);
33
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);
100 NDN_LOG_DEBUG_DEPTH("Start validating interest " << interest.getName());
101
102 m_policy->checkPolicy(interest, state,
103 [this] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
104 if (certRequest == nullptr) {
105 state->bypassValidation();
106 }
107 else {
108 // need to fetch key and validate it
109 requestCertificate(certRequest, state);
110 }
111 });
112}
113
114void
115Validator::validate(const Certificate& cert, const shared_ptr<ValidationState>& state)
116{
117 NDN_LOG_DEBUG_DEPTH("Start validating certificate " << cert.getName());
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800118
119 if (!cert.isValid()) {
120 return state->fail({ValidationError::Code::EXPIRED_CERT, "Retrieved certificate is not yet valid or expired "
121 "`" + cert.getName().toUri() + "`"});
122 }
123
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800124 m_policy->checkPolicy(cert, state,
125 [this, cert] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
126 if (certRequest == nullptr) {
127 state->fail({ValidationError::POLICY_ERROR, "Validation policy is not allowed to designate `" +
128 cert.getName().toUri() + "` as a trust anchor"});
129 }
130 else {
131 // need to fetch key and validate it
132 state->addCertificate(cert);
133 requestCertificate(certRequest, state);
134 }
135 });
136}
137
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800138void
139Validator::requestCertificate(const shared_ptr<CertificateRequest>& certRequest,
140 const shared_ptr<ValidationState>& state)
141{
142 // TODO configurable check for the maximum number of steps
143 if (state->getDepth() >= m_maxDepth) {
144 state->fail({ValidationError::Code::EXCEEDED_DEPTH_LIMIT,
145 "Exceeded validation depth limit (" + to_string(m_maxDepth) + ")"});
146 return;
147 }
148
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500149 if (state->hasSeenCertificateName(certRequest->interest.getName())) {
Alexander Afanasyev5af04a72017-01-30 22:41:23 -0800150 state->fail({ValidationError::Code::LOOP_DETECTED,
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500151 "Validation loop detected for certificate `" + certRequest->interest.getName().toUri() + "`"});
Alexander Afanasyev5af04a72017-01-30 22:41:23 -0800152 return;
153 }
154
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500155 NDN_LOG_DEBUG_DEPTH("Retrieving " << certRequest->interest.getName());
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800156
Ashlesh Gawande3e39a4d2018-08-30 16:49:13 -0500157 auto cert = findTrustedCert(certRequest->interest);
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800158 if (cert != nullptr) {
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800159 NDN_LOG_TRACE_DEPTH("Found trusted certificate " << cert->getName());
160
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800161 cert = state->verifyCertificateChain(*cert);
162 if (cert != nullptr) {
163 state->verifyOriginalPacket(*cert);
164 }
165 for (auto trustedCert = std::make_move_iterator(state->m_certificateChain.begin());
166 trustedCert != std::make_move_iterator(state->m_certificateChain.end());
167 ++trustedCert) {
168 cacheVerifiedCertificate(*trustedCert);
169 }
170 return;
171 }
172
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800173 m_certFetcher->fetch(certRequest, state, [this] (const Certificate& cert, const shared_ptr<ValidationState>& state) {
174 validate(cert, state);
175 });
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800176}
177
178////////////////////////////////////////////////////////////////////////
179// Trust anchor management
180////////////////////////////////////////////////////////////////////////
181
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800182// to change visibility from protected to public
183
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800184void
185Validator::loadAnchor(const std::string& groupId, Certificate&& cert)
186{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800187 CertificateStorage::loadAnchor(groupId, std::move(cert));
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800188}
189
190void
191Validator::loadAnchor(const std::string& groupId, const std::string& certfilePath,
192 time::nanoseconds refreshPeriod, bool isDir)
193{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800194 CertificateStorage::loadAnchor(groupId, certfilePath, refreshPeriod, isDir);
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800195}
196
197void
Alexander Afanasyev6aff0242017-08-29 17:14:44 -0400198Validator::resetAnchors()
199{
200 CertificateStorage::resetAnchors();
201}
202
203void
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800204Validator::cacheVerifiedCertificate(Certificate&& cert)
205{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800206 CertificateStorage::cacheVerifiedCert(std::move(cert));
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800207}
208
Alexander Afanasyev6aff0242017-08-29 17:14:44 -0400209void
210Validator::resetVerifiedCertificates()
211{
212 CertificateStorage::resetVerifiedCerts();
213}
214
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800215} // namespace v2
216} // namespace security
217} // namespace ndn