blob: 10fe352868dba35db21b0151e7979bf545c4e39b [file] [log] [blame]
Zhiyi Zhang9829da92020-09-30 16:19:34 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2017-2020, Regents of the University of California.
4 *
5 * This file is part of ndncert, a certificate management system based on NDN.
6 *
7 * ndncert is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * ndncert 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 General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License along with
16 * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ndncert authors and contributors.
19 */
20
21#include "configuration.hpp"
22#include "challenge-module.hpp"
23#include <ndn-cxx/util/io.hpp>
24#include <boost/filesystem.hpp>
25
26namespace ndn {
27namespace ndncert {
28
29void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -070030CaProfile::parse(const JsonSection& configJson)
Zhiyi Zhang9829da92020-09-30 16:19:34 -070031{
32 // CA prefix
33 m_caPrefix = Name(configJson.get(CONFIG_CA_PREFIX, ""));
34 if (m_caPrefix.empty()) {
35 BOOST_THROW_EXCEPTION(std::runtime_error("Cannot parse ca-prefix from the config file"));
36 }
37 // CA info
38 m_caInfo = configJson.get(CONFIG_CA_INFO, "");
39 // CA max validity period
40 m_maxValidityPeriod = time::seconds(configJson.get(CONFIG_MAX_VALIDITY_PERIOD, 86400));
41 // CA max suffix length
42 m_maxSuffixLength = configJson.get_optional<size_t>(CONFIG_MAX_SUFFIX_LENGTH);
43 // probe parameter keys
44 m_probeParameterKeys.clear();
45 auto probeParametersJson = configJson.get_child_optional(CONFIG_PROBE_PARAMETERS);
46 if (probeParametersJson) {
47 for (const auto item : *probeParametersJson) {
48 auto probeParameter = item.second.get(CONFIG_PROBE_PARAMETER, "");
49 probeParameter = boost::algorithm::to_lower_copy(probeParameter);
50 if (probeParameter == "") {
51 BOOST_THROW_EXCEPTION(std::runtime_error("Probe parameter key cannot be empty."));
52 }
53 m_probeParameterKeys.push_back(probeParameter);
54 }
55 }
56 // supported challenges
57 m_supportedChallenges.clear();
58 auto challengeListJson = configJson.get_child_optional(CONFIG_SUPPORTED_CHALLENGES);
59 if (challengeListJson) {
60 for (const auto item : *challengeListJson) {
61 auto challengeType = item.second.get(CONFIG_CHALLENGE, "");
62 challengeType = boost::algorithm::to_lower_copy(challengeType);
63 if (challengeType == "") {
64 BOOST_THROW_EXCEPTION(std::runtime_error("Challenge type canont be empty."));
65 }
66 if (!ChallengeModule::isChallengeSupported(challengeType)) {
67 BOOST_THROW_EXCEPTION(std::runtime_error("Challenge " + challengeType + " is not supported."));
68 }
69 m_supportedChallenges.push_back(challengeType);
70 }
71 }
72 // anchor certificate
73 m_cert = nullptr;
Zhiyi Zhangfde50112020-10-01 16:36:33 -070074 auto certificateStr = configJson.get(CONFIG_CERTIFICATE, "");
Zhiyi Zhang9829da92020-09-30 16:19:34 -070075 if (certificateStr != "") {
76 std::istringstream ss(certificateStr);
77 m_cert = io::load<security::v2::Certificate>(ss);
78 }
79}
80
81JsonSection
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -070082CaProfile::toJson() const
Zhiyi Zhang9829da92020-09-30 16:19:34 -070083{
84 JsonSection caItem;
85 caItem.put(CONFIG_CA_PREFIX, m_caPrefix.toUri());
86 caItem.put(CONFIG_CA_INFO, m_caInfo);
87 caItem.put(CONFIG_MAX_VALIDITY_PERIOD, m_maxValidityPeriod.count());
88 caItem.put(CONFIG_MAX_SUFFIX_LENGTH, m_maxSuffixLength);
89 if (!m_probeParameterKeys.empty()) {
90 JsonSection probeParametersJson;
91 for (const auto& key : m_probeParameterKeys) {
92 JsonSection keyJson;
93 keyJson.put(CONFIG_PROBE_PARAMETER, key);
94 probeParametersJson.push_back(std::make_pair("", keyJson));
95 }
96 caItem.add_child("", probeParametersJson);
97 }
98 if (!m_supportedChallenges.empty()) {
99 JsonSection challengeListJson;
100 for (const auto& challenge : m_supportedChallenges) {
101 JsonSection challengeJson;
102 challengeJson.put(CONFIG_CHALLENGE, challenge);
103 challengeListJson.push_back(std::make_pair("", challengeJson));
104 }
105 caItem.add_child("", challengeListJson);
106 }
107 if (m_cert != nullptr) {
108 std::stringstream ss;
109 io::save(*m_cert, ss);
110 caItem.put("certificate", ss.str());
111 }
112 return caItem;
113}
114
115void
116CaConfig::load(const std::string& fileName)
117{
118 JsonSection configJson;
119 try {
120 boost::property_tree::read_json(fileName, configJson);
121 }
122 catch (const std::exception& error) {
123 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to parse configuration file " + fileName + ", " + error.what()));
124 }
125 if (configJson.begin() == configJson.end()) {
126 BOOST_THROW_EXCEPTION(std::runtime_error("No JSON configuration found in file: " + fileName));
127 }
128 m_caItem.parse(configJson);
129 if (m_caItem.m_supportedChallenges.size() == 0) {
130 BOOST_THROW_EXCEPTION(std::runtime_error("At least one challenge should be specified."));
131 }
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700132 // parse redirection section if appears
133 m_redirection = boost::none;
134 auto redirectionItems = configJson.get_child_optional(CONFIG_REDIRECTION);
135 if (redirectionItems) {
136 for (const auto item : *redirectionItems) {
137 auto caPrefixStr = item.second.get(CONFIG_CA_PREFIX, "");
138 auto caCertStr = item.second.get(CONFIG_CERTIFICATE, "");
Zhiyi Zhange537dd52020-10-01 18:02:24 -0700139 if (caCertStr == "") {
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700140 BOOST_THROW_EXCEPTION(std::runtime_error("Redirect-to item's ca-prefix or certificate cannot be empty."));
141 }
142 std::istringstream ss(caCertStr);
143 auto caCert = io::load<security::v2::Certificate>(ss);
144 if (!m_redirection) {
Zhiyi Zhange537dd52020-10-01 18:02:24 -0700145 m_redirection = std::vector<std::shared_ptr<security::v2::Certificate>>();
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700146 }
Zhiyi Zhange537dd52020-10-01 18:02:24 -0700147 m_redirection->push_back(caCert);
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700148 }
149 }
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700150}
151
152void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700153RequesterCaCache::load(const std::string& fileName)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700154{
155 JsonSection configJson;
156 try {
157 boost::property_tree::read_json(fileName, configJson);
158 }
159 catch (const std::exception& error) {
160 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to parse configuration file " + fileName + ", " + error.what()));
161 }
162 if (configJson.begin() == configJson.end()) {
163 BOOST_THROW_EXCEPTION(std::runtime_error("No JSON configuration found in file: " + fileName));
164 }
165 load(configJson);
166}
167
168void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700169RequesterCaCache::load(const JsonSection& configSection)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700170{
171 m_caItems.clear();
172 auto caList = configSection.get_child("ca-list");
173 for (auto item : caList) {
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700174 CaProfile caItem;
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700175 caItem.parse(item.second);
176 if (caItem.m_cert == nullptr) {
177 BOOST_THROW_EXCEPTION(std::runtime_error("No CA certificate is loaded from JSON configuration."));
178 }
179 m_caItems.push_back(std::move(caItem));
180 }
181}
182
183void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700184RequesterCaCache::save(const std::string& fileName) const
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700185{
186 JsonSection configJson;
187 for (const auto& caItem : m_caItems) {
188 configJson.push_back(std::make_pair("", caItem.toJson()));
189 }
190 std::stringstream ss;
191 boost::property_tree::write_json(ss, configJson);
192 std::ofstream configFile;
193 configFile.open(fileName);
194 configFile << ss.str();
195 configFile.close();
196}
197
198void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700199RequesterCaCache::removeCaProfile(const Name& caName)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700200{
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700201 m_caItems.remove_if([&](const CaProfile& item) { return item.m_caPrefix == caName; });
202}
203
204void
205RequesterCaCache::addCaProfile(const CaProfile& profile)
206{
207 for (auto& item : m_caItems) {
208 if (item.m_caPrefix == profile.m_caPrefix) {
209 item = profile;
210 return;
211 }
212 }
213 m_caItems.push_back(profile);
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700214}
215
216} // namespace ndncert
217} // namespace ndn