blob: 9af6f28385bd27ff70901b6e8bbe19034397c81c [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 Zhangc2c4ed22020-10-14 17:16:28 -070025#include "name-assignment/assignment-func.hpp"
Zhiyi Zhang9829da92020-09-30 16:19:34 -070026
27namespace ndn {
28namespace ndncert {
29
Zhiyi Zhang59812232020-10-12 13:11:35 -070030// Parse CA Configuration file
31const std::string CONFIG_CA_PREFIX = "ca-prefix";
32const std::string CONFIG_CA_INFO = "ca-info";
33const std::string CONFIG_MAX_VALIDITY_PERIOD = "max-validity-period";
34const std::string CONFIG_MAX_SUFFIX_LENGTH = "max-suffix-length";
35const std::string CONFIG_PROBE_PARAMETERS = "probe-parameters";
36const std::string CONFIG_PROBE_PARAMETER = "probe-parameter-key";
37const std::string CONFIG_SUPPORTED_CHALLENGES = "supported-challenges";
38const std::string CONFIG_CHALLENGE = "challenge";
39const std::string CONFIG_CERTIFICATE = "certificate";
40const std::string CONFIG_REDIRECTION = "redirect-to";
41const std::string CONFIG_NAME_ASSIGNMENT = "name-assignment";
42
Zhiyi Zhang9829da92020-09-30 16:19:34 -070043void
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -070044CaProfile::parse(const JsonSection& configJson)
Zhiyi Zhang9829da92020-09-30 16:19:34 -070045{
46 // CA prefix
47 m_caPrefix = Name(configJson.get(CONFIG_CA_PREFIX, ""));
48 if (m_caPrefix.empty()) {
tylerliu41c11532020-10-10 16:14:45 -070049 NDN_THROW(std::runtime_error("Cannot parse ca-prefix from the config file"));
Zhiyi Zhang9829da92020-09-30 16:19:34 -070050 }
51 // CA info
52 m_caInfo = configJson.get(CONFIG_CA_INFO, "");
53 // CA max validity period
54 m_maxValidityPeriod = time::seconds(configJson.get(CONFIG_MAX_VALIDITY_PERIOD, 86400));
55 // CA max suffix length
Zhiyi Zhang997669a2020-10-28 21:15:40 -070056 m_maxSuffixLength = nullopt;
57 auto maxSuffixLength = configJson.get_optional<size_t>(CONFIG_MAX_SUFFIX_LENGTH);
58 if (maxSuffixLength.has_value()) {
59 m_maxSuffixLength = *maxSuffixLength;
60 }
Zhiyi Zhang9829da92020-09-30 16:19:34 -070061 // probe parameter keys
62 m_probeParameterKeys.clear();
63 auto probeParametersJson = configJson.get_child_optional(CONFIG_PROBE_PARAMETERS);
64 if (probeParametersJson) {
tylerliua2d048b2020-10-09 16:10:16 -070065 for (const auto& item : *probeParametersJson) {
Zhiyi Zhang9829da92020-09-30 16:19:34 -070066 auto probeParameter = item.second.get(CONFIG_PROBE_PARAMETER, "");
67 probeParameter = boost::algorithm::to_lower_copy(probeParameter);
68 if (probeParameter == "") {
tylerliu41c11532020-10-10 16:14:45 -070069 NDN_THROW(std::runtime_error("Probe parameter key cannot be empty."));
Zhiyi Zhang9829da92020-09-30 16:19:34 -070070 }
71 m_probeParameterKeys.push_back(probeParameter);
72 }
73 }
74 // supported challenges
75 m_supportedChallenges.clear();
76 auto challengeListJson = configJson.get_child_optional(CONFIG_SUPPORTED_CHALLENGES);
77 if (challengeListJson) {
tylerliua2d048b2020-10-09 16:10:16 -070078 for (const auto& item : *challengeListJson) {
Zhiyi Zhang9829da92020-09-30 16:19:34 -070079 auto challengeType = item.second.get(CONFIG_CHALLENGE, "");
80 challengeType = boost::algorithm::to_lower_copy(challengeType);
81 if (challengeType == "") {
tylerliu41c11532020-10-10 16:14:45 -070082 NDN_THROW(std::runtime_error("Challenge type canont be empty."));
Zhiyi Zhang9829da92020-09-30 16:19:34 -070083 }
84 if (!ChallengeModule::isChallengeSupported(challengeType)) {
tylerliu41c11532020-10-10 16:14:45 -070085 NDN_THROW(std::runtime_error("Challenge " + challengeType + " is not supported."));
Zhiyi Zhang9829da92020-09-30 16:19:34 -070086 }
87 m_supportedChallenges.push_back(challengeType);
88 }
89 }
90 // anchor certificate
91 m_cert = nullptr;
Zhiyi Zhangfde50112020-10-01 16:36:33 -070092 auto certificateStr = configJson.get(CONFIG_CERTIFICATE, "");
Zhiyi Zhang9829da92020-09-30 16:19:34 -070093 if (certificateStr != "") {
94 std::istringstream ss(certificateStr);
tylerliua7bea662020-10-08 18:51:02 -070095 m_cert = io::load<security::Certificate>(ss);
Zhiyi Zhang9829da92020-09-30 16:19:34 -070096 }
97}
98
99JsonSection
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700100CaProfile::toJson() const
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700101{
102 JsonSection caItem;
103 caItem.put(CONFIG_CA_PREFIX, m_caPrefix.toUri());
104 caItem.put(CONFIG_CA_INFO, m_caInfo);
105 caItem.put(CONFIG_MAX_VALIDITY_PERIOD, m_maxValidityPeriod.count());
Zhiyi Zhang997669a2020-10-28 21:15:40 -0700106 if (m_maxSuffixLength) {
107 caItem.put(CONFIG_MAX_SUFFIX_LENGTH, *m_maxSuffixLength);
108 }
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700109 if (!m_probeParameterKeys.empty()) {
110 JsonSection probeParametersJson;
111 for (const auto& key : m_probeParameterKeys) {
112 JsonSection keyJson;
113 keyJson.put(CONFIG_PROBE_PARAMETER, key);
114 probeParametersJson.push_back(std::make_pair("", keyJson));
115 }
116 caItem.add_child("", probeParametersJson);
117 }
118 if (!m_supportedChallenges.empty()) {
119 JsonSection challengeListJson;
120 for (const auto& challenge : m_supportedChallenges) {
121 JsonSection challengeJson;
122 challengeJson.put(CONFIG_CHALLENGE, challenge);
123 challengeListJson.push_back(std::make_pair("", challengeJson));
124 }
125 caItem.add_child("", challengeListJson);
126 }
127 if (m_cert != nullptr) {
128 std::stringstream ss;
129 io::save(*m_cert, ss);
130 caItem.put("certificate", ss.str());
131 }
132 return caItem;
133}
134
Zhiyi Zhang32d4b4e2020-10-28 22:10:49 -0700135namespace ca {
136
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700137void
138CaConfig::load(const std::string& fileName)
139{
140 JsonSection configJson;
141 try {
142 boost::property_tree::read_json(fileName, configJson);
143 }
144 catch (const std::exception& error) {
tylerliu41c11532020-10-10 16:14:45 -0700145 NDN_THROW(std::runtime_error("Failed to parse configuration file " + fileName + ", " + error.what()));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700146 }
147 if (configJson.begin() == configJson.end()) {
tylerliu41c11532020-10-10 16:14:45 -0700148 NDN_THROW(std::runtime_error("No JSON configuration found in file: " + fileName));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700149 }
150 m_caItem.parse(configJson);
151 if (m_caItem.m_supportedChallenges.size() == 0) {
tylerliu41c11532020-10-10 16:14:45 -0700152 NDN_THROW(std::runtime_error("At least one challenge should be specified."));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700153 }
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700154 // parse redirection section if appears
Zhiyi Zhang997669a2020-10-28 21:15:40 -0700155 m_redirection = nullopt;
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700156 auto redirectionItems = configJson.get_child_optional(CONFIG_REDIRECTION);
157 if (redirectionItems) {
tylerliua2d048b2020-10-09 16:10:16 -0700158 for (const auto& item : *redirectionItems) {
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700159 auto caPrefixStr = item.second.get(CONFIG_CA_PREFIX, "");
160 auto caCertStr = item.second.get(CONFIG_CERTIFICATE, "");
Zhiyi Zhange537dd52020-10-01 18:02:24 -0700161 if (caCertStr == "") {
tylerliu41c11532020-10-10 16:14:45 -0700162 NDN_THROW(std::runtime_error("Redirect-to item's ca-prefix or certificate cannot be empty."));
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700163 }
164 std::istringstream ss(caCertStr);
tylerliua7bea662020-10-08 18:51:02 -0700165 auto caCert = io::load<security::Certificate>(ss);
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700166 if (!m_redirection) {
tylerliua7bea662020-10-08 18:51:02 -0700167 m_redirection = std::vector<std::shared_ptr<security::Certificate>>();
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700168 }
Zhiyi Zhange537dd52020-10-01 18:02:24 -0700169 m_redirection->push_back(caCert);
Zhiyi Zhangfde50112020-10-01 16:36:33 -0700170 }
171 }
tylerliu8d9e7122020-10-06 18:57:06 -0700172 //parse name assignment if appears
Zhiyi Zhang74c61142020-10-07 21:00:49 -0700173 m_nameAssignmentFuncs.clear();
tylerliu8d9e7122020-10-06 18:57:06 -0700174 auto nameAssignmentItems = configJson.get_child_optional(CONFIG_NAME_ASSIGNMENT);
175 if (nameAssignmentItems) {
tylerliua2d048b2020-10-09 16:10:16 -0700176 for (const auto& item : *nameAssignmentItems) {
Zhiyi Zhang74c61142020-10-07 21:00:49 -0700177 auto func = NameAssignmentFunc::createNameAssignmentFunc(item.first, item.second.data());
Zhiyi Zhang17064022020-10-07 18:34:44 -0700178 if (func == nullptr) {
tylerliu41c11532020-10-10 16:14:45 -0700179 NDN_THROW(std::runtime_error("Error on creating name assignment function"));
Zhiyi Zhang8683ec92020-10-07 18:18:35 -0700180 }
Zhiyi Zhang74c61142020-10-07 21:00:49 -0700181 m_nameAssignmentFuncs.push_back(std::move(func));
tylerliu8d9e7122020-10-06 18:57:06 -0700182 }
183 }
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700184}
185
Zhiyi Zhang32d4b4e2020-10-28 22:10:49 -0700186} // namespace ca
187
Zhiyi Zhang3002e6b2020-10-29 18:54:07 -0700188namespace requester {
189
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700190void
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700191ProfileStorage::load(const std::string& fileName)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700192{
193 JsonSection configJson;
194 try {
195 boost::property_tree::read_json(fileName, configJson);
196 }
197 catch (const std::exception& error) {
tylerliu41c11532020-10-10 16:14:45 -0700198 NDN_THROW(std::runtime_error("Failed to parse configuration file " + fileName + ", " + error.what()));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700199 }
200 if (configJson.begin() == configJson.end()) {
tylerliu41c11532020-10-10 16:14:45 -0700201 NDN_THROW(std::runtime_error("No JSON configuration found in file: " + fileName));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700202 }
203 load(configJson);
204}
205
206void
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700207ProfileStorage::load(const JsonSection& configSection)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700208{
209 m_caItems.clear();
210 auto caList = configSection.get_child("ca-list");
211 for (auto item : caList) {
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700212 CaProfile caItem;
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700213 caItem.parse(item.second);
214 if (caItem.m_cert == nullptr) {
tylerliu41c11532020-10-10 16:14:45 -0700215 NDN_THROW(std::runtime_error("No CA certificate is loaded from JSON configuration."));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700216 }
217 m_caItems.push_back(std::move(caItem));
218 }
219}
220
221void
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700222ProfileStorage::save(const std::string& fileName) const
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700223{
224 JsonSection configJson;
225 for (const auto& caItem : m_caItems) {
226 configJson.push_back(std::make_pair("", caItem.toJson()));
227 }
228 std::stringstream ss;
229 boost::property_tree::write_json(ss, configJson);
230 std::ofstream configFile;
231 configFile.open(fileName);
232 configFile << ss.str();
233 configFile.close();
234}
235
236void
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700237ProfileStorage::removeCaProfile(const Name& caName)
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700238{
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700239 m_caItems.remove_if([&](const CaProfile& item) { return item.m_caPrefix == caName; });
240}
241
242void
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700243ProfileStorage::addCaProfile(const CaProfile& profile)
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -0700244{
245 for (auto& item : m_caItems) {
246 if (item.m_caPrefix == profile.m_caPrefix) {
247 item = profile;
248 return;
249 }
250 }
251 m_caItems.push_back(profile);
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700252}
253
Zhiyi Zhang3002e6b2020-10-29 18:54:07 -0700254} // namespace requester
Zhiyi Zhange4891b72020-10-10 15:11:57 -0700255} // namespace ndncert
256} // namespace ndn