blob: 05c6e77b0ddf89c8be4b3f6a3d74c6ba6323b696 [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"
Zhiyi Zhangdbd9d432020-10-07 15:56:27 -070022#include "identity-challenge/challenge-module.hpp"
Zhiyi Zhang9829da92020-09-30 16:19:34 -070023#include <ndn-cxx/util/io.hpp>
24#include <boost/filesystem.hpp>
Zhiyi Zhang8683ec92020-10-07 18:18:35 -070025#include "name-assignments/assignment-funcs.hpp"
Zhiyi Zhang9829da92020-09-30 16:19:34 -070026
27namespace ndn {
28namespace ndncert {
29
30void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -070031CaProfile::parse(const JsonSection& configJson)
Zhiyi Zhang9829da92020-09-30 16:19:34 -070032{
33 // CA prefix
34 m_caPrefix = Name(configJson.get(CONFIG_CA_PREFIX, ""));
35 if (m_caPrefix.empty()) {
36 BOOST_THROW_EXCEPTION(std::runtime_error("Cannot parse ca-prefix from the config file"));
37 }
38 // CA info
39 m_caInfo = configJson.get(CONFIG_CA_INFO, "");
40 // CA max validity period
41 m_maxValidityPeriod = time::seconds(configJson.get(CONFIG_MAX_VALIDITY_PERIOD, 86400));
42 // CA max suffix length
43 m_maxSuffixLength = configJson.get_optional<size_t>(CONFIG_MAX_SUFFIX_LENGTH);
44 // probe parameter keys
45 m_probeParameterKeys.clear();
46 auto probeParametersJson = configJson.get_child_optional(CONFIG_PROBE_PARAMETERS);
47 if (probeParametersJson) {
tylerliua2d048b2020-10-09 16:10:16 -070048 for (const auto& item : *probeParametersJson) {
Zhiyi Zhang9829da92020-09-30 16:19:34 -070049 auto probeParameter = item.second.get(CONFIG_PROBE_PARAMETER, "");
50 probeParameter = boost::algorithm::to_lower_copy(probeParameter);
51 if (probeParameter == "") {
52 BOOST_THROW_EXCEPTION(std::runtime_error("Probe parameter key cannot be empty."));
53 }
54 m_probeParameterKeys.push_back(probeParameter);
55 }
56 }
57 // supported challenges
58 m_supportedChallenges.clear();
59 auto challengeListJson = configJson.get_child_optional(CONFIG_SUPPORTED_CHALLENGES);
60 if (challengeListJson) {
tylerliua2d048b2020-10-09 16:10:16 -070061 for (const auto& item : *challengeListJson) {
Zhiyi Zhang9829da92020-09-30 16:19:34 -070062 auto challengeType = item.second.get(CONFIG_CHALLENGE, "");
63 challengeType = boost::algorithm::to_lower_copy(challengeType);
64 if (challengeType == "") {
65 BOOST_THROW_EXCEPTION(std::runtime_error("Challenge type canont be empty."));
66 }
67 if (!ChallengeModule::isChallengeSupported(challengeType)) {
68 BOOST_THROW_EXCEPTION(std::runtime_error("Challenge " + challengeType + " is not supported."));
69 }
70 m_supportedChallenges.push_back(challengeType);
71 }
72 }
73 // anchor certificate
74 m_cert = nullptr;
Zhiyi Zhangfde50112020-10-01 16:36:33 -070075 auto certificateStr = configJson.get(CONFIG_CERTIFICATE, "");
Zhiyi Zhang9829da92020-09-30 16:19:34 -070076 if (certificateStr != "") {
77 std::istringstream ss(certificateStr);
tylerliua7bea662020-10-08 18:51:02 -070078 m_cert = io::load<security::Certificate>(ss);
Zhiyi Zhang9829da92020-09-30 16:19:34 -070079 }
80}
81
82JsonSection
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -070083CaProfile::toJson() const
Zhiyi Zhang9829da92020-09-30 16:19:34 -070084{
85 JsonSection caItem;
86 caItem.put(CONFIG_CA_PREFIX, m_caPrefix.toUri());
87 caItem.put(CONFIG_CA_INFO, m_caInfo);
88 caItem.put(CONFIG_MAX_VALIDITY_PERIOD, m_maxValidityPeriod.count());
89 caItem.put(CONFIG_MAX_SUFFIX_LENGTH, m_maxSuffixLength);
90 if (!m_probeParameterKeys.empty()) {
91 JsonSection probeParametersJson;
92 for (const auto& key : m_probeParameterKeys) {
93 JsonSection keyJson;
94 keyJson.put(CONFIG_PROBE_PARAMETER, key);
95 probeParametersJson.push_back(std::make_pair("", keyJson));
96 }
97 caItem.add_child("", probeParametersJson);
98 }
99 if (!m_supportedChallenges.empty()) {
100 JsonSection challengeListJson;
101 for (const auto& challenge : m_supportedChallenges) {
102 JsonSection challengeJson;
103 challengeJson.put(CONFIG_CHALLENGE, challenge);
104 challengeListJson.push_back(std::make_pair("", challengeJson));
105 }
106 caItem.add_child("", challengeListJson);
107 }
108 if (m_cert != nullptr) {
109 std::stringstream ss;
110 io::save(*m_cert, ss);
111 caItem.put("certificate", ss.str());
112 }
113 return caItem;
114}
115
116void
117CaConfig::load(const std::string& fileName)
118{
119 JsonSection configJson;
120 try {
121 boost::property_tree::read_json(fileName, configJson);
122 }
123 catch (const std::exception& error) {
124 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to parse configuration file " + fileName + ", " + error.what()));
125 }
126 if (configJson.begin() == configJson.end()) {
127 BOOST_THROW_EXCEPTION(std::runtime_error("No JSON configuration found in file: " + fileName));
128 }
129 m_caItem.parse(configJson);
130 if (m_caItem.m_supportedChallenges.size() == 0) {
131 BOOST_THROW_EXCEPTION(std::runtime_error("At least one challenge should be specified."));
132 }
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700133 // parse redirection section if appears
134 m_redirection = boost::none;
135 auto redirectionItems = configJson.get_child_optional(CONFIG_REDIRECTION);
136 if (redirectionItems) {
tylerliua2d048b2020-10-09 16:10:16 -0700137 for (const auto& item : *redirectionItems) {
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700138 auto caPrefixStr = item.second.get(CONFIG_CA_PREFIX, "");
139 auto caCertStr = item.second.get(CONFIG_CERTIFICATE, "");
Zhiyi Zhange537dd52020-10-01 18:02:24 -0700140 if (caCertStr == "") {
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700141 BOOST_THROW_EXCEPTION(std::runtime_error("Redirect-to item's ca-prefix or certificate cannot be empty."));
142 }
143 std::istringstream ss(caCertStr);
tylerliua7bea662020-10-08 18:51:02 -0700144 auto caCert = io::load<security::Certificate>(ss);
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700145 if (!m_redirection) {
tylerliua7bea662020-10-08 18:51:02 -0700146 m_redirection = std::vector<std::shared_ptr<security::Certificate>>();
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700147 }
Zhiyi Zhange537dd52020-10-01 18:02:24 -0700148 m_redirection->push_back(caCert);
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700149 }
150 }
tylerliu8d9e7122020-10-06 18:57:06 -0700151 //parse name assignment if appears
Zhiyi Zhang74c61142020-10-07 21:00:49 -0700152 m_nameAssignmentFuncs.clear();
tylerliu8d9e7122020-10-06 18:57:06 -0700153 auto nameAssignmentItems = configJson.get_child_optional(CONFIG_NAME_ASSIGNMENT);
154 if (nameAssignmentItems) {
tylerliua2d048b2020-10-09 16:10:16 -0700155 for (const auto& item : *nameAssignmentItems) {
Zhiyi Zhang74c61142020-10-07 21:00:49 -0700156 auto func = NameAssignmentFunc::createNameAssignmentFunc(item.first, item.second.data());
Zhiyi Zhang17064022020-10-07 18:34:44 -0700157 if (func == nullptr) {
Zhiyi Zhang8683ec92020-10-07 18:18:35 -0700158 BOOST_THROW_EXCEPTION(std::runtime_error("Error on creating name assignment function"));
159 }
Zhiyi Zhang74c61142020-10-07 21:00:49 -0700160 m_nameAssignmentFuncs.push_back(std::move(func));
tylerliu8d9e7122020-10-06 18:57:06 -0700161 }
162 }
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700163}
164
165void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700166RequesterCaCache::load(const std::string& fileName)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700167{
168 JsonSection configJson;
169 try {
170 boost::property_tree::read_json(fileName, configJson);
171 }
172 catch (const std::exception& error) {
173 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to parse configuration file " + fileName + ", " + error.what()));
174 }
175 if (configJson.begin() == configJson.end()) {
176 BOOST_THROW_EXCEPTION(std::runtime_error("No JSON configuration found in file: " + fileName));
177 }
178 load(configJson);
179}
180
181void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700182RequesterCaCache::load(const JsonSection& configSection)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700183{
184 m_caItems.clear();
185 auto caList = configSection.get_child("ca-list");
186 for (auto item : caList) {
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700187 CaProfile caItem;
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700188 caItem.parse(item.second);
189 if (caItem.m_cert == nullptr) {
190 BOOST_THROW_EXCEPTION(std::runtime_error("No CA certificate is loaded from JSON configuration."));
191 }
192 m_caItems.push_back(std::move(caItem));
193 }
194}
195
196void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700197RequesterCaCache::save(const std::string& fileName) const
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700198{
199 JsonSection configJson;
200 for (const auto& caItem : m_caItems) {
201 configJson.push_back(std::make_pair("", caItem.toJson()));
202 }
203 std::stringstream ss;
204 boost::property_tree::write_json(ss, configJson);
205 std::ofstream configFile;
206 configFile.open(fileName);
207 configFile << ss.str();
208 configFile.close();
209}
210
211void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700212RequesterCaCache::removeCaProfile(const Name& caName)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700213{
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700214 m_caItems.remove_if([&](const CaProfile& item) { return item.m_caPrefix == caName; });
215}
216
217void
218RequesterCaCache::addCaProfile(const CaProfile& profile)
219{
220 for (auto& item : m_caItems) {
221 if (item.m_caPrefix == profile.m_caPrefix) {
222 item = profile;
223 return;
224 }
225 }
226 m_caItems.push_back(profile);
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700227}
228
229} // namespace ndncert
230} // namespace ndn