blob: a4ca557b694e06f45f403ecf50be767ba6eec3a7 [file] [log] [blame]
Davide Pesaventob48bbda2020-07-27 19:41:37 -04001/*
2 * Copyright (c) 2017-2020, Regents of the University of California.
Zhiyi Zhang0a89b722017-04-28 17:56:01 -07003 *
4 * This file is part of ndncert, a certificate management system based on NDN.
5 *
6 * ndncert is free software: you can redistribute it and/or modify it under the terms
7 * of the GNU General Public License as published by the Free Software Foundation, either
8 * version 3 of the License, or (at your option) any later version.
9 *
10 * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
12 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 *
14 * You should have received copies of the GNU General Public License along with
15 * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * See AUTHORS.md for complete list of ndncert authors and contributors.
18 */
19
20#include "challenge-credential.hpp"
21#include "../logging.hpp"
22#include <ndn-cxx/security/verification-helpers.hpp>
23#include <ndn-cxx/util/io.hpp>
24
25namespace ndn {
26namespace ndncert {
27
28_LOG_INIT(ndncert.ChallengeCredential);
29
30NDNCERT_REGISTER_CHALLENGE(ChallengeCredential, "Credential");
31
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070032const std::string ChallengeCredential::FAILURE_INVALID_FORMAT_CREDENTIAL = "failure-cannot-parse-credential";
33const std::string ChallengeCredential::FAILURE_INVALID_FORMAT_SELF_SIGNED = "failure-cannot-parse-self-signed";
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070034const std::string ChallengeCredential::FAILURE_INVALID_CREDENTIAL = "failure-invalid-credential";
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070035const std::string ChallengeCredential::JSON_CREDENTIAL_CERT = "issued-cert";
36const std::string ChallengeCredential::JSON_CREDENTIAL_SELF = "self-signed";
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070037
38ChallengeCredential::ChallengeCredential(const std::string& configPath)
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070039 : ChallengeModule("Credential")
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070040{
Davide Pesaventob48bbda2020-07-27 19:41:37 -040041 if (configPath.empty()) {
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070042 m_configFile = std::string(SYSCONFDIR) + "/ndncert/challenge-credential.conf";
43 }
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080044 else {
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070045 m_configFile = configPath;
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080046 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070047}
48
49void
50ChallengeCredential::parseConfigFile()
51{
52 JsonSection config;
53 try {
54 boost::property_tree::read_json(m_configFile, config);
55 }
56 catch (const boost::property_tree::info_parser_error& error) {
57 BOOST_THROW_EXCEPTION(Error("Failed to parse configuration file " + m_configFile +
58 " " + error.message() + " line " + std::to_string(error.line())));
59 }
60
61 if (config.begin() == config.end()) {
62 BOOST_THROW_EXCEPTION(Error("Error processing configuration file: " + m_configFile + " no data"));
63 }
64
65 m_trustAnchors.clear();
66 auto anchorList = config.get_child("anchor-list");
67 auto it = anchorList.begin();
68 for (; it != anchorList.end(); it++) {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080069 std::istringstream ss(it->second.get("certificate", ""));
70 auto cert = io::load<security::v2::Certificate>(ss);
71 if (cert == nullptr) {
72 _LOG_ERROR("Cannot load the certificate from config file");
73 continue;
74 }
75 m_trustAnchors.push_back(*cert);
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070076 }
77}
78
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070079// For CA
80void
Suyong Won19fba4d2020-05-09 13:39:46 -070081ChallengeCredential::handleChallengeRequest(const Block& params, CertificateRequest& request)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070082{
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070083 if (m_trustAnchors.empty()) {
84 parseConfigFile();
85 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070086 // load credential parameter
Suyong Won19fba4d2020-05-09 13:39:46 -070087 // TODO: instead of string, should pass certificate byte value directly
88 std::istringstream ss1(readString(params.elements().at(1)));
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080089 auto cert = io::load<security::v2::Certificate>(ss1);
90 if (cert == nullptr) {
91 _LOG_ERROR("Cannot load credential parameter: cert");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070092 request.m_status = STATUS_FAILURE;
93 request.m_challengeStatus = FAILURE_INVALID_FORMAT_CREDENTIAL;
94 updateRequestOnChallengeEnd(request);
95 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070096 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070097 ss1.str("");
98 ss1.clear();
Suyong Won19fba4d2020-05-09 13:39:46 -070099
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700100 // load self-signed data
Suyong Won19fba4d2020-05-09 13:39:46 -0700101 std::istringstream ss2(readString(params.elements().at(3)));
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800102 auto self = io::load<Data>(ss2);
103 if (self == nullptr) {
104 _LOG_TRACE("Cannot load credential parameter: self-signed cert");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700105 request.m_status = STATUS_FAILURE;
106 request.m_challengeStatus = FAILURE_INVALID_FORMAT_SELF_SIGNED;
107 updateRequestOnChallengeEnd(request);
108 return;
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700109 }
110 ss2.str("");
111 ss2.clear();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700112
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700113 // verify the credential and the self-signed cert
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400114 Name signingKeyName = cert->getSignatureInfo().getKeyLocator().getName();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700115 for (auto anchor : m_trustAnchors) {
116 if (anchor.getKeyName() == signingKeyName) {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800117 if (security::verifySignature(*cert, anchor) && security::verifySignature(*self, *cert)
118 && readString(self->getContent()) == request.m_requestId) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700119 request.m_status = STATUS_PENDING;
120 request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
121 updateRequestOnChallengeEnd(request);
122 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700123 }
124 }
125 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700126
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700127 _LOG_TRACE("Cannot verify the credential + self-signed Data + data content");
128 request.m_status = STATUS_FAILURE;
129 request.m_challengeStatus = FAILURE_INVALID_CREDENTIAL;
130 updateRequestOnChallengeEnd(request);
131 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700132}
133
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700134// For Client
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700135JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700136ChallengeCredential::getRequirementForChallenge(int status, const std::string& challengeStatus)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700137{
138 JsonSection result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700139 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
140 result.put(JSON_CREDENTIAL_CERT, "Please_copy_anchor_signed_cert_here");
141 result.put(JSON_CREDENTIAL_SELF, "Please_copy_key_signed_request_id_data_here");
142 }
143 else {
144 _LOG_ERROR("Client's status and challenge status are wrong");
145 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700146 return result;
147}
148
149JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700150ChallengeCredential::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700151{
152 JsonSection result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700153 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800154 result.put(JSON_CREDENTIAL_CERT, params.get(JSON_CREDENTIAL_CERT, ""));
155 result.put(JSON_CREDENTIAL_SELF, params.get(JSON_CREDENTIAL_SELF, ""));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700156 }
157 else {
158 _LOG_ERROR("Client's status and challenge status are wrong");
159 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700160 return result;
161}
162
Suyong Won19fba4d2020-05-09 13:39:46 -0700163Block
164ChallengeCredential::genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params)
165{
166 Block request = makeEmptyBlock(tlv_encrypted_payload);
167 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
168 request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
169 request.push_back(makeStringBlock(tlv_parameter_key, JSON_CREDENTIAL_CERT));
170 request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CREDENTIAL_CERT,"")));
171 request.push_back(makeStringBlock(tlv_parameter_key, JSON_CREDENTIAL_SELF));
172 request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CREDENTIAL_SELF,"")));
173 }
174 else {
175 _LOG_ERROR("Client's status and challenge status are wrong");
176 }
177 request.parse();
178 return request;
179}
180
181
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700182} // namespace ndncert
183} // namespace ndn