blob: 16724bcd9215bae58870cf0a839a87bd1f8b7cc6 [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{
Suyong Won44d0cce2020-05-10 04:07:43 -070083 params.parse();
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070084 if (m_trustAnchors.empty()) {
85 parseConfigFile();
86 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070087 // load credential parameter
Suyong Won19fba4d2020-05-09 13:39:46 -070088 // TODO: instead of string, should pass certificate byte value directly
89 std::istringstream ss1(readString(params.elements().at(1)));
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080090 auto cert = io::load<security::v2::Certificate>(ss1);
91 if (cert == nullptr) {
92 _LOG_ERROR("Cannot load credential parameter: cert");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070093 request.m_status = STATUS_FAILURE;
94 request.m_challengeStatus = FAILURE_INVALID_FORMAT_CREDENTIAL;
95 updateRequestOnChallengeEnd(request);
96 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070097 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070098 ss1.str("");
99 ss1.clear();
Suyong Won19fba4d2020-05-09 13:39:46 -0700100
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700101 // load self-signed data
Suyong Won19fba4d2020-05-09 13:39:46 -0700102 std::istringstream ss2(readString(params.elements().at(3)));
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800103 auto self = io::load<Data>(ss2);
104 if (self == nullptr) {
105 _LOG_TRACE("Cannot load credential parameter: self-signed cert");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700106 request.m_status = STATUS_FAILURE;
107 request.m_challengeStatus = FAILURE_INVALID_FORMAT_SELF_SIGNED;
108 updateRequestOnChallengeEnd(request);
109 return;
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700110 }
111 ss2.str("");
112 ss2.clear();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700113
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700114 // verify the credential and the self-signed cert
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400115 Name signingKeyName = cert->getSignatureInfo().getKeyLocator().getName();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700116 for (auto anchor : m_trustAnchors) {
117 if (anchor.getKeyName() == signingKeyName) {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800118 if (security::verifySignature(*cert, anchor) && security::verifySignature(*self, *cert)
119 && readString(self->getContent()) == request.m_requestId) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700120 request.m_status = STATUS_PENDING;
121 request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
122 updateRequestOnChallengeEnd(request);
123 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700124 }
125 }
126 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700127
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700128 _LOG_TRACE("Cannot verify the credential + self-signed Data + data content");
129 request.m_status = STATUS_FAILURE;
130 request.m_challengeStatus = FAILURE_INVALID_CREDENTIAL;
131 updateRequestOnChallengeEnd(request);
132 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700133}
134
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700135// For Client
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700136JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700137ChallengeCredential::getRequirementForChallenge(int status, const std::string& challengeStatus)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700138{
139 JsonSection result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700140 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
141 result.put(JSON_CREDENTIAL_CERT, "Please_copy_anchor_signed_cert_here");
142 result.put(JSON_CREDENTIAL_SELF, "Please_copy_key_signed_request_id_data_here");
143 }
144 else {
145 _LOG_ERROR("Client's status and challenge status are wrong");
146 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700147 return result;
148}
149
150JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700151ChallengeCredential::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700152{
153 JsonSection result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700154 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800155 result.put(JSON_CREDENTIAL_CERT, params.get(JSON_CREDENTIAL_CERT, ""));
156 result.put(JSON_CREDENTIAL_SELF, params.get(JSON_CREDENTIAL_SELF, ""));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700157 }
158 else {
159 _LOG_ERROR("Client's status and challenge status are wrong");
160 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700161 return result;
162}
163
Suyong Won19fba4d2020-05-09 13:39:46 -0700164Block
165ChallengeCredential::genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params)
166{
167 Block request = makeEmptyBlock(tlv_encrypted_payload);
168 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
169 request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
170 request.push_back(makeStringBlock(tlv_parameter_key, JSON_CREDENTIAL_CERT));
171 request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CREDENTIAL_CERT,"")));
172 request.push_back(makeStringBlock(tlv_parameter_key, JSON_CREDENTIAL_SELF));
173 request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CREDENTIAL_SELF,"")));
174 }
175 else {
176 _LOG_ERROR("Client's status and challenge status are wrong");
177 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700178 request.encode();
Suyong Won19fba4d2020-05-09 13:39:46 -0700179 return request;
180}
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700181} // namespace ndncert
182} // namespace ndn