blob: 08131c19340f2950366d59d8c2881bed8697cdc5 [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"
Zhiyi Zhang22998612020-09-25 14:43:23 -070021
22#include <iostream>
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070023#include <ndn-cxx/security/verification-helpers.hpp>
24#include <ndn-cxx/util/io.hpp>
25
Zhiyi Zhang22998612020-09-25 14:43:23 -070026#include "../logging.hpp"
27
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070028namespace ndn {
29namespace ndncert {
30
31_LOG_INIT(ndncert.ChallengeCredential);
32
33NDNCERT_REGISTER_CHALLENGE(ChallengeCredential, "Credential");
34
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070035const std::string ChallengeCredential::FAILURE_INVALID_FORMAT_CREDENTIAL = "failure-cannot-parse-credential";
36const std::string ChallengeCredential::FAILURE_INVALID_FORMAT_SELF_SIGNED = "failure-cannot-parse-self-signed";
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070037const std::string ChallengeCredential::FAILURE_INVALID_CREDENTIAL = "failure-invalid-credential";
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070038const std::string ChallengeCredential::JSON_CREDENTIAL_CERT = "issued-cert";
tylerliu729212e2020-09-26 14:31:25 -070039const std::string ChallengeCredential::JSON_PROOF_OF_PRIVATE_KEY = "proof-of-private-key";
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070040
41ChallengeCredential::ChallengeCredential(const std::string& configPath)
Zhiyi Zhang22998612020-09-25 14:43:23 -070042 : ChallengeModule("Credential")
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070043{
Davide Pesaventob48bbda2020-07-27 19:41:37 -040044 if (configPath.empty()) {
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070045 m_configFile = std::string(SYSCONFDIR) + "/ndncert/challenge-credential.conf";
46 }
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080047 else {
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070048 m_configFile = configPath;
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080049 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070050}
51
52void
53ChallengeCredential::parseConfigFile()
54{
55 JsonSection config;
56 try {
57 boost::property_tree::read_json(m_configFile, config);
58 }
59 catch (const boost::property_tree::info_parser_error& error) {
60 BOOST_THROW_EXCEPTION(Error("Failed to parse configuration file " + m_configFile +
61 " " + error.message() + " line " + std::to_string(error.line())));
62 }
63
64 if (config.begin() == config.end()) {
65 BOOST_THROW_EXCEPTION(Error("Error processing configuration file: " + m_configFile + " no data"));
66 }
67
68 m_trustAnchors.clear();
69 auto anchorList = config.get_child("anchor-list");
70 auto it = anchorList.begin();
71 for (; it != anchorList.end(); it++) {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080072 std::istringstream ss(it->second.get("certificate", ""));
73 auto cert = io::load<security::v2::Certificate>(ss);
74 if (cert == nullptr) {
75 _LOG_ERROR("Cannot load the certificate from config file");
76 continue;
77 }
78 m_trustAnchors.push_back(*cert);
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070079 }
80}
81
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070082// For CA
83void
Suyong Won19fba4d2020-05-09 13:39:46 -070084ChallengeCredential::handleChallengeRequest(const Block& params, CertificateRequest& request)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070085{
Suyong Won44d0cce2020-05-10 04:07:43 -070086 params.parse();
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070087 if (m_trustAnchors.empty()) {
88 parseConfigFile();
89 }
Zhiyi Zhang22998612020-09-25 14:43:23 -070090 shared_ptr<security::v2::Certificate> selfSigned, credential;
91 auto& elements = params.elements();
92 for (size_t i = 0; i < elements.size(); i++) {
93 if (elements[i].type() == tlv_parameter_key) {
94 if (readString(elements[i]) == JSON_CREDENTIAL_CERT) {
95 std::istringstream ss(readString(params.elements()[i + 1]));
96 credential = io::load<security::v2::Certificate>(ss);
97 if (credential == nullptr) {
98 _LOG_ERROR("Cannot load credential parameter: cert");
99 request.m_status = STATUS_FAILURE;
100 request.m_challengeStatus = FAILURE_INVALID_FORMAT_CREDENTIAL;
101 updateRequestOnChallengeEnd(request);
102 return;
103 }
104 }
tylerliu729212e2020-09-26 14:31:25 -0700105 else if (readString(elements[i]) == JSON_PROOF_OF_PRIVATE_KEY) {
Zhiyi Zhang22998612020-09-25 14:43:23 -0700106 std::istringstream ss(readString(params.elements()[i + 1]));
107 selfSigned = io::load<security::v2::Certificate>(ss);
108 if (selfSigned == nullptr) {
109 _LOG_ERROR("Cannot load credential parameter: cert");
110 request.m_status = STATUS_FAILURE;
111 request.m_challengeStatus = FAILURE_INVALID_FORMAT_SELF_SIGNED;
112 updateRequestOnChallengeEnd(request);
113 return;
114 }
115 }
116 else {
117 continue;
118 }
119 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700120 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700121
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700122 // verify the credential and the self-signed cert
Zhiyi Zhang22998612020-09-25 14:43:23 -0700123 Name signingKeyName = credential->getSignature().getKeyLocator().getName();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700124 for (auto anchor : m_trustAnchors) {
125 if (anchor.getKeyName() == signingKeyName) {
Zhiyi Zhang22998612020-09-25 14:43:23 -0700126 if (security::verifySignature(*selfSigned, anchor) &&
127 security::verifySignature(*selfSigned, *credential) &&
128 readString(selfSigned->getContent()) == request.m_requestId) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700129 request.m_status = STATUS_PENDING;
130 request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
131 updateRequestOnChallengeEnd(request);
132 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700133 }
134 }
135 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700136
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700137 _LOG_TRACE("Cannot verify the credential + self-signed Data + data content");
138 request.m_status = STATUS_FAILURE;
139 request.m_challengeStatus = FAILURE_INVALID_CREDENTIAL;
140 updateRequestOnChallengeEnd(request);
141 return;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700142}
143
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700144// For Client
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700145JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700146ChallengeCredential::getRequirementForChallenge(int status, const std::string& challengeStatus)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700147{
148 JsonSection result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700149 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
150 result.put(JSON_CREDENTIAL_CERT, "Please_copy_anchor_signed_cert_here");
tylerliu729212e2020-09-26 14:31:25 -0700151 result.put(JSON_PROOF_OF_PRIVATE_KEY, "Please_copy_key_signed_request_id_data_here");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700152 }
153 else {
154 _LOG_ERROR("Client's status and challenge status are wrong");
155 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700156 return result;
157}
158
159JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700160ChallengeCredential::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700161{
162 JsonSection result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700163 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800164 result.put(JSON_CREDENTIAL_CERT, params.get(JSON_CREDENTIAL_CERT, ""));
tylerliu729212e2020-09-26 14:31:25 -0700165 result.put(JSON_PROOF_OF_PRIVATE_KEY, params.get(JSON_PROOF_OF_PRIVATE_KEY, ""));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700166 }
167 else {
168 _LOG_ERROR("Client's status and challenge status are wrong");
169 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700170 return result;
171}
172
Suyong Won19fba4d2020-05-09 13:39:46 -0700173Block
174ChallengeCredential::genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params)
175{
176 Block request = makeEmptyBlock(tlv_encrypted_payload);
177 if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
178 request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
179 request.push_back(makeStringBlock(tlv_parameter_key, JSON_CREDENTIAL_CERT));
Zhiyi Zhang22998612020-09-25 14:43:23 -0700180 request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CREDENTIAL_CERT, "")));
tylerliu729212e2020-09-26 14:31:25 -0700181 request.push_back(makeStringBlock(tlv_parameter_key, JSON_PROOF_OF_PRIVATE_KEY));
182 request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_PROOF_OF_PRIVATE_KEY, "")));
Suyong Won19fba4d2020-05-09 13:39:46 -0700183 }
184 else {
185 _LOG_ERROR("Client's status and challenge status are wrong");
186 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700187 request.encode();
Suyong Won19fba4d2020-05-09 13:39:46 -0700188 return request;
189}
Zhiyi Zhang22998612020-09-25 14:43:23 -0700190} // namespace ndncert
191} // namespace ndn