blob: 6dc1f91dd7e34d51ab607b41f920e76d21a787be [file] [log] [blame]
Alexander Afanasyev7e721412017-01-11 13:36:08 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2017 Regents of the University of California.
4 *
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);
44 m_certFetcher->setCertificateStorage(*this);
Alexander Afanasyev7e721412017-01-11 13:36:08 -080045}
46
47Validator::~Validator() = default;
48
49void
50Validator::setMaxDepth(size_t depth)
51{
52 m_maxDepth = depth;
53}
54
55size_t
56Validator::getMaxDepth() const
57{
58 return m_maxDepth;
59}
60
61void
62Validator::validate(const Data& data,
63 const DataValidationSuccessCallback& successCb,
64 const DataValidationFailureCallback& failureCb)
65{
66 auto state = make_shared<DataValidationState>(data, successCb, failureCb);
67 NDN_LOG_DEBUG_DEPTH("Start validating data " << data.getName());
68
69 m_policy->checkPolicy(data, state,
70 [this] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
71 if (certRequest == nullptr) {
72 state->bypassValidation();
73 }
74 else {
75 // need to fetch key and validate it
76 requestCertificate(certRequest, state);
77 }
78 });
79}
80
81void
82Validator::validate(const Interest& interest,
83 const InterestValidationSuccessCallback& successCb,
84 const InterestValidationFailureCallback& failureCb)
85{
86 auto state = make_shared<InterestValidationState>(interest, successCb, failureCb);
87 NDN_LOG_DEBUG_DEPTH("Start validating interest " << interest.getName());
88
89 m_policy->checkPolicy(interest, state,
90 [this] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
91 if (certRequest == nullptr) {
92 state->bypassValidation();
93 }
94 else {
95 // need to fetch key and validate it
96 requestCertificate(certRequest, state);
97 }
98 });
99}
100
101void
102Validator::validate(const Certificate& cert, const shared_ptr<ValidationState>& state)
103{
104 NDN_LOG_DEBUG_DEPTH("Start validating certificate " << cert.getName());
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800105
106 if (!cert.isValid()) {
107 return state->fail({ValidationError::Code::EXPIRED_CERT, "Retrieved certificate is not yet valid or expired "
108 "`" + cert.getName().toUri() + "`"});
109 }
110
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800111 m_policy->checkPolicy(cert, state,
112 [this, cert] (const shared_ptr<CertificateRequest>& certRequest, const shared_ptr<ValidationState>& state) {
113 if (certRequest == nullptr) {
114 state->fail({ValidationError::POLICY_ERROR, "Validation policy is not allowed to designate `" +
115 cert.getName().toUri() + "` as a trust anchor"});
116 }
117 else {
118 // need to fetch key and validate it
119 state->addCertificate(cert);
120 requestCertificate(certRequest, state);
121 }
122 });
123}
124
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800125void
126Validator::requestCertificate(const shared_ptr<CertificateRequest>& certRequest,
127 const shared_ptr<ValidationState>& state)
128{
129 // TODO configurable check for the maximum number of steps
130 if (state->getDepth() >= m_maxDepth) {
131 state->fail({ValidationError::Code::EXCEEDED_DEPTH_LIMIT,
132 "Exceeded validation depth limit (" + to_string(m_maxDepth) + ")"});
133 return;
134 }
135
Alexander Afanasyev5af04a72017-01-30 22:41:23 -0800136 if (state->hasSeenCertificateName(certRequest->m_interest.getName())) {
137 state->fail({ValidationError::Code::LOOP_DETECTED,
138 "Validation loop detected for certificate `" + certRequest->m_interest.getName().toUri() + "`"});
139 return;
140 }
141
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800142 NDN_LOG_DEBUG_DEPTH("Retrieving " << certRequest->m_interest.getName());
143
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800144 auto cert = findTrustedCert(certRequest->m_interest);
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800145 if (cert != nullptr) {
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800146 NDN_LOG_TRACE_DEPTH("Found trusted certificate " << cert->getName());
147
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800148 cert = state->verifyCertificateChain(*cert);
149 if (cert != nullptr) {
150 state->verifyOriginalPacket(*cert);
151 }
152 for (auto trustedCert = std::make_move_iterator(state->m_certificateChain.begin());
153 trustedCert != std::make_move_iterator(state->m_certificateChain.end());
154 ++trustedCert) {
155 cacheVerifiedCertificate(*trustedCert);
156 }
157 return;
158 }
159
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800160 m_certFetcher->fetch(certRequest, state, [this] (const Certificate& cert, const shared_ptr<ValidationState>& state) {
161 validate(cert, state);
162 });
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800163}
164
165////////////////////////////////////////////////////////////////////////
166// Trust anchor management
167////////////////////////////////////////////////////////////////////////
168
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800169// to change visibility from protected to public
170
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800171void
172Validator::loadAnchor(const std::string& groupId, Certificate&& cert)
173{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800174 CertificateStorage::loadAnchor(groupId, std::move(cert));
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800175}
176
177void
178Validator::loadAnchor(const std::string& groupId, const std::string& certfilePath,
179 time::nanoseconds refreshPeriod, bool isDir)
180{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800181 CertificateStorage::loadAnchor(groupId, certfilePath, refreshPeriod, isDir);
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800182}
183
184void
185Validator::cacheVerifiedCertificate(Certificate&& cert)
186{
Alexander Afanasyev7bc10fa2017-01-13 16:56:26 -0800187 CertificateStorage::cacheVerifiedCert(std::move(cert));
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800188}
189
190} // namespace v2
191} // namespace security
192} // namespace ndn