blob: 1386d1314b90603394f9b0b62088ac03e9f1e9c2 [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>
tylerliu8d9e7122020-10-06 18:57:06 -070025#include <name-assignments/assignment-funcs.hpp>
tylerliubcd83482020-10-07 14:45:28 -070026#include <name-assignments/assignment-or.hpp>
Zhiyi Zhang9829da92020-09-30 16:19:34 -070027
28namespace ndn {
29namespace ndncert {
30
31void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -070032CaProfile::parse(const JsonSection& configJson)
Zhiyi Zhang9829da92020-09-30 16:19:34 -070033{
34 // CA prefix
35 m_caPrefix = Name(configJson.get(CONFIG_CA_PREFIX, ""));
36 if (m_caPrefix.empty()) {
37 BOOST_THROW_EXCEPTION(std::runtime_error("Cannot parse ca-prefix from the config file"));
38 }
39 // CA info
40 m_caInfo = configJson.get(CONFIG_CA_INFO, "");
41 // CA max validity period
42 m_maxValidityPeriod = time::seconds(configJson.get(CONFIG_MAX_VALIDITY_PERIOD, 86400));
43 // CA max suffix length
44 m_maxSuffixLength = configJson.get_optional<size_t>(CONFIG_MAX_SUFFIX_LENGTH);
45 // probe parameter keys
46 m_probeParameterKeys.clear();
47 auto probeParametersJson = configJson.get_child_optional(CONFIG_PROBE_PARAMETERS);
48 if (probeParametersJson) {
49 for (const auto item : *probeParametersJson) {
50 auto probeParameter = item.second.get(CONFIG_PROBE_PARAMETER, "");
51 probeParameter = boost::algorithm::to_lower_copy(probeParameter);
52 if (probeParameter == "") {
53 BOOST_THROW_EXCEPTION(std::runtime_error("Probe parameter key cannot be empty."));
54 }
55 m_probeParameterKeys.push_back(probeParameter);
56 }
57 }
58 // supported challenges
59 m_supportedChallenges.clear();
60 auto challengeListJson = configJson.get_child_optional(CONFIG_SUPPORTED_CHALLENGES);
61 if (challengeListJson) {
62 for (const auto item : *challengeListJson) {
63 auto challengeType = item.second.get(CONFIG_CHALLENGE, "");
64 challengeType = boost::algorithm::to_lower_copy(challengeType);
65 if (challengeType == "") {
66 BOOST_THROW_EXCEPTION(std::runtime_error("Challenge type canont be empty."));
67 }
68 if (!ChallengeModule::isChallengeSupported(challengeType)) {
69 BOOST_THROW_EXCEPTION(std::runtime_error("Challenge " + challengeType + " is not supported."));
70 }
71 m_supportedChallenges.push_back(challengeType);
72 }
73 }
74 // anchor certificate
75 m_cert = nullptr;
Zhiyi Zhangfde50112020-10-01 16:36:33 -070076 auto certificateStr = configJson.get(CONFIG_CERTIFICATE, "");
Zhiyi Zhang9829da92020-09-30 16:19:34 -070077 if (certificateStr != "") {
78 std::istringstream ss(certificateStr);
79 m_cert = io::load<security::v2::Certificate>(ss);
80 }
81}
82
83JsonSection
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -070084CaProfile::toJson() const
Zhiyi Zhang9829da92020-09-30 16:19:34 -070085{
86 JsonSection caItem;
87 caItem.put(CONFIG_CA_PREFIX, m_caPrefix.toUri());
88 caItem.put(CONFIG_CA_INFO, m_caInfo);
89 caItem.put(CONFIG_MAX_VALIDITY_PERIOD, m_maxValidityPeriod.count());
90 caItem.put(CONFIG_MAX_SUFFIX_LENGTH, m_maxSuffixLength);
91 if (!m_probeParameterKeys.empty()) {
92 JsonSection probeParametersJson;
93 for (const auto& key : m_probeParameterKeys) {
94 JsonSection keyJson;
95 keyJson.put(CONFIG_PROBE_PARAMETER, key);
96 probeParametersJson.push_back(std::make_pair("", keyJson));
97 }
98 caItem.add_child("", probeParametersJson);
99 }
100 if (!m_supportedChallenges.empty()) {
101 JsonSection challengeListJson;
102 for (const auto& challenge : m_supportedChallenges) {
103 JsonSection challengeJson;
104 challengeJson.put(CONFIG_CHALLENGE, challenge);
105 challengeListJson.push_back(std::make_pair("", challengeJson));
106 }
107 caItem.add_child("", challengeListJson);
108 }
109 if (m_cert != nullptr) {
110 std::stringstream ss;
111 io::save(*m_cert, ss);
112 caItem.put("certificate", ss.str());
113 }
114 return caItem;
115}
116
117void
118CaConfig::load(const std::string& fileName)
119{
120 JsonSection configJson;
121 try {
122 boost::property_tree::read_json(fileName, configJson);
123 }
124 catch (const std::exception& error) {
125 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to parse configuration file " + fileName + ", " + error.what()));
126 }
127 if (configJson.begin() == configJson.end()) {
128 BOOST_THROW_EXCEPTION(std::runtime_error("No JSON configuration found in file: " + fileName));
129 }
130 m_caItem.parse(configJson);
131 if (m_caItem.m_supportedChallenges.size() == 0) {
132 BOOST_THROW_EXCEPTION(std::runtime_error("At least one challenge should be specified."));
133 }
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700134 // parse redirection section if appears
135 m_redirection = boost::none;
136 auto redirectionItems = configJson.get_child_optional(CONFIG_REDIRECTION);
137 if (redirectionItems) {
138 for (const auto item : *redirectionItems) {
139 auto caPrefixStr = item.second.get(CONFIG_CA_PREFIX, "");
140 auto caCertStr = item.second.get(CONFIG_CERTIFICATE, "");
Zhiyi Zhange537dd52020-10-01 18:02:24 -0700141 if (caCertStr == "") {
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700142 BOOST_THROW_EXCEPTION(std::runtime_error("Redirect-to item's ca-prefix or certificate cannot be empty."));
143 }
144 std::istringstream ss(caCertStr);
145 auto caCert = io::load<security::v2::Certificate>(ss);
146 if (!m_redirection) {
Zhiyi Zhange537dd52020-10-01 18:02:24 -0700147 m_redirection = std::vector<std::shared_ptr<security::v2::Certificate>>();
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700148 }
Zhiyi Zhange537dd52020-10-01 18:02:24 -0700149 m_redirection->push_back(caCert);
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700150 }
151 }
tylerliu8d9e7122020-10-06 18:57:06 -0700152 //parse name assignment if appears
153 m_nameAssignmentFunc = nullptr;
154 auto nameAssignmentItems = configJson.get_child_optional(CONFIG_NAME_ASSIGNMENT);
155 if (nameAssignmentItems) {
tylerliubcd83482020-10-07 14:45:28 -0700156 std::list<NameAssignmentFunc> funcs;
tylerliu8d9e7122020-10-06 18:57:06 -0700157 for (const auto item : *nameAssignmentItems) {
158 auto factory = NameAssignmentFuncFactory::createNameAssignmentFuncFactory(item.first);
159 if (!factory) {
160 BOOST_THROW_EXCEPTION(std::runtime_error("Invalid assignment factory type"));
161 }
162 try {
163 funcs.push_back(factory->getFunction(item.second.data()));
164 } catch (const std::exception& e) {
165 BOOST_THROW_EXCEPTION(std::runtime_error("Error on creating function"));
166 }
167 }
168 if (funcs.size() < 1) {
169 BOOST_THROW_EXCEPTION(std::runtime_error("Empty assignment body supplied"));
170 } else if (funcs.size() == 1) {
tylerliubcd83482020-10-07 14:45:28 -0700171 m_nameAssignmentFunc = *funcs.begin();
tylerliu8d9e7122020-10-06 18:57:06 -0700172 } else {
tylerliubcd83482020-10-07 14:45:28 -0700173 AssignmentOr orFunction;
174 m_nameAssignmentFunc = orFunction.getFunction(funcs);
tylerliu8d9e7122020-10-06 18:57:06 -0700175 }
176 }
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700177}
178
179void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700180RequesterCaCache::load(const std::string& fileName)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700181{
182 JsonSection configJson;
183 try {
184 boost::property_tree::read_json(fileName, configJson);
185 }
186 catch (const std::exception& error) {
187 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to parse configuration file " + fileName + ", " + error.what()));
188 }
189 if (configJson.begin() == configJson.end()) {
190 BOOST_THROW_EXCEPTION(std::runtime_error("No JSON configuration found in file: " + fileName));
191 }
192 load(configJson);
193}
194
195void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700196RequesterCaCache::load(const JsonSection& configSection)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700197{
198 m_caItems.clear();
199 auto caList = configSection.get_child("ca-list");
200 for (auto item : caList) {
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700201 CaProfile caItem;
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700202 caItem.parse(item.second);
203 if (caItem.m_cert == nullptr) {
204 BOOST_THROW_EXCEPTION(std::runtime_error("No CA certificate is loaded from JSON configuration."));
205 }
206 m_caItems.push_back(std::move(caItem));
207 }
208}
209
210void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700211RequesterCaCache::save(const std::string& fileName) const
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700212{
213 JsonSection configJson;
214 for (const auto& caItem : m_caItems) {
215 configJson.push_back(std::make_pair("", caItem.toJson()));
216 }
217 std::stringstream ss;
218 boost::property_tree::write_json(ss, configJson);
219 std::ofstream configFile;
220 configFile.open(fileName);
221 configFile << ss.str();
222 configFile.close();
223}
224
225void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700226RequesterCaCache::removeCaProfile(const Name& caName)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700227{
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700228 m_caItems.remove_if([&](const CaProfile& item) { return item.m_caPrefix == caName; });
229}
230
231void
232RequesterCaCache::addCaProfile(const CaProfile& profile)
233{
234 for (auto& item : m_caItems) {
235 if (item.m_caPrefix == profile.m_caPrefix) {
236 item = profile;
237 return;
238 }
239 }
240 m_caItems.push_back(profile);
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700241}
242
243} // namespace ndncert
244} // namespace ndn