blob: 839ccae8a50aa5d1601dc645e71851f2ecf847f2 [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 }
44 else
45 m_configFile = configPath;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070046}
47
48void
49ChallengeCredential::parseConfigFile()
50{
51 JsonSection config;
52 try {
53 boost::property_tree::read_json(m_configFile, config);
54 }
55 catch (const boost::property_tree::info_parser_error& error) {
56 BOOST_THROW_EXCEPTION(Error("Failed to parse configuration file " + m_configFile +
57 " " + error.message() + " line " + std::to_string(error.line())));
58 }
59
60 if (config.begin() == config.end()) {
61 BOOST_THROW_EXCEPTION(Error("Error processing configuration file: " + m_configFile + " no data"));
62 }
63
64 m_trustAnchors.clear();
65 auto anchorList = config.get_child("anchor-list");
66 auto it = anchorList.begin();
67 for (; it != anchorList.end(); it++) {
68 std::istringstream ss(it->second.get<std::string>("certificate"));
69 security::v2::Certificate cert = *(io::load<security::v2::Certificate>(ss));
70 m_trustAnchors.push_back(cert);
71 }
72}
73
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070074// For CA
75void
76ChallengeCredential::handleChallengeRequest(const JsonSection& params, CertificateRequest& request)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070077{
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070078 if (m_trustAnchors.empty()) {
79 parseConfigFile();
80 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070081 // load credential parameter
82 std::istringstream ss1(params.get<std::string>(JSON_CREDENTIAL_CERT));
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070083 security::v2::Certificate cert;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070084 try {
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070085 cert = *(io::load<security::v2::Certificate>(ss1));
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070086 }
87 catch (const std::exception& e) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070088 _LOG_ERROR("Cannot load credential parameter: cert" << e.what());
89 request.m_status = STATUS_FAILURE;
90 request.m_challengeStatus = FAILURE_INVALID_FORMAT_CREDENTIAL;
91 updateRequestOnChallengeEnd(request);
92 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070093 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070094 ss1.str("");
95 ss1.clear();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070096 // load self-signed data
97 std::istringstream ss2(params.get<std::string>(JSON_CREDENTIAL_SELF));
98 Data self;
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070099 try {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700100 self = *(io::load<Data>(ss2));
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700101 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700102 catch (const std::exception& e) {
103 _LOG_TRACE("Cannot load credential parameter: self-signed cert" << e.what());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700104 request.m_status = STATUS_FAILURE;
105 request.m_challengeStatus = FAILURE_INVALID_FORMAT_SELF_SIGNED;
106 updateRequestOnChallengeEnd(request);
107 return;
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700108 }
109 ss2.str("");
110 ss2.clear();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700111
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700112 // verify the credential and the self-signed cert
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700113 Name signingKeyName = cert.getSignature().getKeyLocator().getName();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700114 for (auto anchor : m_trustAnchors) {
115 if (anchor.getKeyName() == signingKeyName) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700116 if (security::verifySignature(cert, anchor) && security::verifySignature(self, cert)
117 && readString(self.getContent()) == request.m_requestId) {
118 request.m_status = STATUS_PENDING;
119 request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
120 updateRequestOnChallengeEnd(request);
121 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700122 }
123 }
124 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700125
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700126 _LOG_TRACE("Cannot verify the credential + self-signed Data + data content");
127 request.m_status = STATUS_FAILURE;
128 request.m_challengeStatus = FAILURE_INVALID_CREDENTIAL;
129 updateRequestOnChallengeEnd(request);
130 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700131}
132
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700133// For Client
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700134JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700135ChallengeCredential::getRequirementForChallenge(int status, const std::string& challengeStatus)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700136{
137 JsonSection result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700138 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
139 result.put(JSON_CREDENTIAL_CERT, "Please_copy_anchor_signed_cert_here");
140 result.put(JSON_CREDENTIAL_SELF, "Please_copy_key_signed_request_id_data_here");
141 }
142 else {
143 _LOG_ERROR("Client's status and challenge status are wrong");
144 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700145 return result;
146}
147
148JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700149ChallengeCredential::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700150{
151 JsonSection result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700152 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
153 result.put(JSON_CREDENTIAL_CERT, params.get<std::string>(JSON_CREDENTIAL_CERT, ""));
154 result.put(JSON_CREDENTIAL_SELF, params.get<std::string>(JSON_CREDENTIAL_SELF, ""));
155 }
156 else {
157 _LOG_ERROR("Client's status and challenge status are wrong");
158 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700159 return result;
160}
161
162} // namespace ndncert
163} // namespace ndn