blob: f5d7434b848dc1fd2950f15d96c1c064bcee0882 [file] [log] [blame]
Zhiyi Zhang0a89b722017-04-28 17:56:01 -07001/**
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -07002 * Copyright (c) 2017-2019, 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{
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070041 if (configPath == "") {
42 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
81ChallengeCredential::handleChallengeRequest(const JsonSection& 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
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080087 std::istringstream ss1(params.get(JSON_CREDENTIAL_CERT, ""));
88 auto cert = io::load<security::v2::Certificate>(ss1);
89 if (cert == nullptr) {
90 _LOG_ERROR("Cannot load credential parameter: cert");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070091 request.m_status = STATUS_FAILURE;
92 request.m_challengeStatus = FAILURE_INVALID_FORMAT_CREDENTIAL;
93 updateRequestOnChallengeEnd(request);
94 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070095 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070096 ss1.str("");
97 ss1.clear();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070098 // load self-signed data
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080099 std::istringstream ss2(params.get(JSON_CREDENTIAL_SELF, ""));
100 auto self = io::load<Data>(ss2);
101 if (self == nullptr) {
102 _LOG_TRACE("Cannot load credential parameter: self-signed cert");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700103 request.m_status = STATUS_FAILURE;
104 request.m_challengeStatus = FAILURE_INVALID_FORMAT_SELF_SIGNED;
105 updateRequestOnChallengeEnd(request);
106 return;
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700107 }
108 ss2.str("");
109 ss2.clear();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700110
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700111 // verify the credential and the self-signed cert
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800112 Name signingKeyName = cert->getSignature().getKeyLocator().getName();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700113 for (auto anchor : m_trustAnchors) {
114 if (anchor.getKeyName() == signingKeyName) {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800115 if (security::verifySignature(*cert, anchor) && security::verifySignature(*self, *cert)
116 && readString(self->getContent()) == request.m_requestId) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700117 request.m_status = STATUS_PENDING;
118 request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
119 updateRequestOnChallengeEnd(request);
120 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700121 }
122 }
123 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700124
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700125 _LOG_TRACE("Cannot verify the credential + self-signed Data + data content");
126 request.m_status = STATUS_FAILURE;
127 request.m_challengeStatus = FAILURE_INVALID_CREDENTIAL;
128 updateRequestOnChallengeEnd(request);
129 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700130}
131
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700132// For Client
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700133JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700134ChallengeCredential::getRequirementForChallenge(int status, const std::string& challengeStatus)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700135{
136 JsonSection result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700137 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
138 result.put(JSON_CREDENTIAL_CERT, "Please_copy_anchor_signed_cert_here");
139 result.put(JSON_CREDENTIAL_SELF, "Please_copy_key_signed_request_id_data_here");
140 }
141 else {
142 _LOG_ERROR("Client's status and challenge status are wrong");
143 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700144 return result;
145}
146
147JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700148ChallengeCredential::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700149{
150 JsonSection result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700151 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800152 result.put(JSON_CREDENTIAL_CERT, params.get(JSON_CREDENTIAL_CERT, ""));
153 result.put(JSON_CREDENTIAL_SELF, params.get(JSON_CREDENTIAL_SELF, ""));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700154 }
155 else {
156 _LOG_ERROR("Client's status and challenge status are wrong");
157 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700158 return result;
159}
160
161} // namespace ndncert
162} // namespace ndn