blob: fe120ebef30543b71900f9e3990687351e09c0af [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
Zhiyi Zhang46049832020-09-28 17:08:12 -070031_LOG_INIT(ndncert.challenge.credential);
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070032NDNCERT_REGISTER_CHALLENGE(ChallengeCredential, "Credential");
33
Zhiyi Zhang46049832020-09-28 17:08:12 -070034const std::string ChallengeCredential::PARAMETER_KEY_CREDENTIAL_CERT = "issued-cert";
35const std::string ChallengeCredential::PARAMETER_KEY_PROOF_OF_PRIVATE_KEY = "proof-of-private-key";
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070036
37ChallengeCredential::ChallengeCredential(const std::string& configPath)
Zhiyi Zhang22998612020-09-25 14:43:23 -070038 : ChallengeModule("Credential")
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070039{
Davide Pesaventob48bbda2020-07-27 19:41:37 -040040 if (configPath.empty()) {
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070041 m_configFile = std::string(SYSCONFDIR) + "/ndncert/challenge-credential.conf";
42 }
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080043 else {
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070044 m_configFile = configPath;
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080045 }
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) {
Zhiyi Zhang46049832020-09-28 17:08:12 -070056 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to parse configuration file " + m_configFile +
57 " " + error.message() + " line " + std::to_string(error.line())));
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070058 }
59
60 if (config.begin() == config.end()) {
Zhiyi Zhang46049832020-09-28 17:08:12 -070061 BOOST_THROW_EXCEPTION(std::runtime_error("Error processing configuration file: " + m_configFile + " no data"));
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070062 }
63
64 m_trustAnchors.clear();
65 auto anchorList = config.get_child("anchor-list");
66 auto it = anchorList.begin();
67 for (; it != anchorList.end(); it++) {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080068 std::istringstream ss(it->second.get("certificate", ""));
69 auto cert = io::load<security::v2::Certificate>(ss);
70 if (cert == nullptr) {
71 _LOG_ERROR("Cannot load the certificate from config file");
72 continue;
73 }
74 m_trustAnchors.push_back(*cert);
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070075 }
76}
77
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070078// For CA
Zhiyi Zhang46049832020-09-28 17:08:12 -070079std::tuple<Error, std::string>
Suyong Won19fba4d2020-05-09 13:39:46 -070080ChallengeCredential::handleChallengeRequest(const Block& params, CertificateRequest& request)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070081{
Suyong Won44d0cce2020-05-10 04:07:43 -070082 params.parse();
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070083 if (m_trustAnchors.empty()) {
84 parseConfigFile();
85 }
Zhiyi Zhang22998612020-09-25 14:43:23 -070086 shared_ptr<security::v2::Certificate> selfSigned, credential;
87 auto& elements = params.elements();
88 for (size_t i = 0; i < elements.size(); i++) {
89 if (elements[i].type() == tlv_parameter_key) {
Zhiyi Zhang46049832020-09-28 17:08:12 -070090 if (readString(elements[i]) == PARAMETER_KEY_CREDENTIAL_CERT) {
Zhiyi Zhang22998612020-09-25 14:43:23 -070091 std::istringstream ss(readString(params.elements()[i + 1]));
92 credential = io::load<security::v2::Certificate>(ss);
93 if (credential == nullptr) {
Zhiyi Zhang46049832020-09-28 17:08:12 -070094 _LOG_ERROR("Cannot load challenge parameter: credential");
95 return returnWithError(request, Error::INVALID_PARAMETER, "Cannot challenge credential: credential.");
Zhiyi Zhang22998612020-09-25 14:43:23 -070096 }
97 }
Zhiyi Zhang46049832020-09-28 17:08:12 -070098 else if (readString(elements[i]) == PARAMETER_KEY_PROOF_OF_PRIVATE_KEY) {
Zhiyi Zhang22998612020-09-25 14:43:23 -070099 std::istringstream ss(readString(params.elements()[i + 1]));
100 selfSigned = io::load<security::v2::Certificate>(ss);
101 if (selfSigned == nullptr) {
Zhiyi Zhang46049832020-09-28 17:08:12 -0700102 _LOG_ERROR("Cannot load challenge parameter: proof of private key");
103 return returnWithError(request, Error::INVALID_PARAMETER, "Cannot load challenge parameter: proof of private key.");
Zhiyi Zhang22998612020-09-25 14:43:23 -0700104 }
105 }
106 else {
107 continue;
108 }
109 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700110 }
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 Zhang22998612020-09-25 14:43:23 -0700113 Name signingKeyName = credential->getSignature().getKeyLocator().getName();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700114 for (auto anchor : m_trustAnchors) {
115 if (anchor.getKeyName() == signingKeyName) {
Zhiyi Zhang22998612020-09-25 14:43:23 -0700116 if (security::verifySignature(*selfSigned, anchor) &&
117 security::verifySignature(*selfSigned, *credential) &&
118 readString(selfSigned->getContent()) == request.m_requestId) {
Zhiyi Zhang46049832020-09-28 17:08:12 -0700119 return returnWithSuccess(request);
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700120 }
121 }
122 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700123
Zhiyi Zhang46049832020-09-28 17:08:12 -0700124 _LOG_TRACE("Cannot verify the proof of private key against credential");
125 return returnWithError(request, Error::INVALID_PARAMETER, "Cannot verify the proof of private key against credential.");
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700126}
127
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700128// For Client
Zhiyi Zhang46049832020-09-28 17:08:12 -0700129std::vector<std::tuple<std::string, std::string>>
130ChallengeCredential::getRequestedParameterList(Status status, const std::string& challengeStatus)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700131{
Zhiyi Zhang46049832020-09-28 17:08:12 -0700132 std::vector<std::tuple<std::string, std::string>> result;
133 if (status == Status::BEFORE_CHALLENGE) {
134 result.push_back(std::make_tuple(PARAMETER_KEY_CREDENTIAL_CERT, "Please provide the certificate issued by a trusted CA."));
135 result.push_back(std::make_tuple(PARAMETER_KEY_PROOF_OF_PRIVATE_KEY, "Please sign a Data packet with request ID as the content."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700136 }
137 else {
Zhiyi Zhang46049832020-09-28 17:08:12 -0700138 BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected status or challenge status."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700139 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700140 return result;
141}
142
Suyong Won19fba4d2020-05-09 13:39:46 -0700143Block
Zhiyi Zhang46049832020-09-28 17:08:12 -0700144ChallengeCredential::genChallengeRequestTLV(Status status, const std::string& challengeStatus,
145 std::vector<std::tuple<std::string, std::string>>&& params)
Suyong Won19fba4d2020-05-09 13:39:46 -0700146{
147 Block request = makeEmptyBlock(tlv_encrypted_payload);
Zhiyi Zhang46049832020-09-28 17:08:12 -0700148 if (status == Status::BEFORE_CHALLENGE) {
149 if (params.size() != 2) {
150 BOOST_THROW_EXCEPTION(std::runtime_error("Wrong parameter provided."));
151 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700152 request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
Zhiyi Zhang46049832020-09-28 17:08:12 -0700153 for (const auto& item : params) {
154 if (std::get<0>(item) == PARAMETER_KEY_CREDENTIAL_CERT) {
155 request.push_back(makeStringBlock(tlv_parameter_key, PARAMETER_KEY_CREDENTIAL_CERT));
156 request.push_back(makeStringBlock(tlv_parameter_value, std::get<1>(item)));
157 }
158 else if (std::get<0>(item) == PARAMETER_KEY_PROOF_OF_PRIVATE_KEY) {
159 request.push_back(makeStringBlock(tlv_parameter_key, PARAMETER_KEY_PROOF_OF_PRIVATE_KEY));
160 request.push_back(makeStringBlock(tlv_parameter_value, std::get<1>(item)));
161 }
162 else {
163 BOOST_THROW_EXCEPTION(std::runtime_error("Wrong parameter provided."));
164 }
165 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700166 }
167 else {
Zhiyi Zhang46049832020-09-28 17:08:12 -0700168 BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected status or challenge status."));
Suyong Won19fba4d2020-05-09 13:39:46 -0700169 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700170 request.encode();
Suyong Won19fba4d2020-05-09 13:39:46 -0700171 return request;
172}
Zhiyi Zhang22998612020-09-25 14:43:23 -0700173} // namespace ndncert
174} // namespace ndn