blob: a41aa563ace348d314b53191813b82395e761d38 [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#include <iostream>
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070022#include <ndn-cxx/security/verification-helpers.hpp>
23#include <ndn-cxx/util/io.hpp>
24
25namespace ndn {
26namespace ndncert {
27
Zhiyi Zhang46049832020-09-28 17:08:12 -070028_LOG_INIT(ndncert.challenge.credential);
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070029NDNCERT_REGISTER_CHALLENGE(ChallengeCredential, "Credential");
30
Zhiyi Zhang46049832020-09-28 17:08:12 -070031const std::string ChallengeCredential::PARAMETER_KEY_CREDENTIAL_CERT = "issued-cert";
32const std::string ChallengeCredential::PARAMETER_KEY_PROOF_OF_PRIVATE_KEY = "proof-of-private-key";
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070033
34ChallengeCredential::ChallengeCredential(const std::string& configPath)
Zhiyi Zhang22998612020-09-25 14:43:23 -070035 : ChallengeModule("Credential")
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070036{
Davide Pesaventob48bbda2020-07-27 19:41:37 -040037 if (configPath.empty()) {
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070038 m_configFile = std::string(SYSCONFDIR) + "/ndncert/challenge-credential.conf";
39 }
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080040 else {
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070041 m_configFile = configPath;
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080042 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070043}
44
45void
46ChallengeCredential::parseConfigFile()
47{
48 JsonSection config;
49 try {
50 boost::property_tree::read_json(m_configFile, config);
51 }
52 catch (const boost::property_tree::info_parser_error& error) {
Zhiyi Zhang46049832020-09-28 17:08:12 -070053 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to parse configuration file " + m_configFile +
54 " " + error.message() + " line " + std::to_string(error.line())));
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070055 }
56
57 if (config.begin() == config.end()) {
Zhiyi Zhang46049832020-09-28 17:08:12 -070058 BOOST_THROW_EXCEPTION(std::runtime_error("Error processing configuration file: " + m_configFile + " no data"));
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070059 }
60
61 m_trustAnchors.clear();
62 auto anchorList = config.get_child("anchor-list");
63 auto it = anchorList.begin();
64 for (; it != anchorList.end(); it++) {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080065 std::istringstream ss(it->second.get("certificate", ""));
66 auto cert = io::load<security::v2::Certificate>(ss);
67 if (cert == nullptr) {
68 _LOG_ERROR("Cannot load the certificate from config file");
69 continue;
70 }
71 m_trustAnchors.push_back(*cert);
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070072 }
73}
74
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070075// For CA
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070076std::tuple<ErrorCode, std::string>
Suyong Won19fba4d2020-05-09 13:39:46 -070077ChallengeCredential::handleChallengeRequest(const Block& params, CertificateRequest& request)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -070078{
Suyong Won44d0cce2020-05-10 04:07:43 -070079 params.parse();
Zhiyi Zhang70fe2582017-05-19 15:01:03 -070080 if (m_trustAnchors.empty()) {
81 parseConfigFile();
82 }
Zhiyi Zhang22998612020-09-25 14:43:23 -070083 shared_ptr<security::v2::Certificate> selfSigned, credential;
84 auto& elements = params.elements();
85 for (size_t i = 0; i < elements.size(); i++) {
86 if (elements[i].type() == tlv_parameter_key) {
Zhiyi Zhang46049832020-09-28 17:08:12 -070087 if (readString(elements[i]) == PARAMETER_KEY_CREDENTIAL_CERT) {
Zhiyi Zhang22998612020-09-25 14:43:23 -070088 std::istringstream ss(readString(params.elements()[i + 1]));
89 credential = io::load<security::v2::Certificate>(ss);
90 if (credential == nullptr) {
Zhiyi Zhang46049832020-09-28 17:08:12 -070091 _LOG_ERROR("Cannot load challenge parameter: credential");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070092 return returnWithError(request, ErrorCode::INVALID_PARAMETER, "Cannot challenge credential: credential.");
Zhiyi Zhang22998612020-09-25 14:43:23 -070093 }
94 }
Zhiyi Zhang46049832020-09-28 17:08:12 -070095 else if (readString(elements[i]) == PARAMETER_KEY_PROOF_OF_PRIVATE_KEY) {
Zhiyi Zhang22998612020-09-25 14:43:23 -070096 std::istringstream ss(readString(params.elements()[i + 1]));
97 selfSigned = io::load<security::v2::Certificate>(ss);
98 if (selfSigned == nullptr) {
Zhiyi Zhang46049832020-09-28 17:08:12 -070099 _LOG_ERROR("Cannot load challenge parameter: proof of private key");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700100 return returnWithError(request, ErrorCode::INVALID_PARAMETER, "Cannot load challenge parameter: proof of private key.");
Zhiyi Zhang22998612020-09-25 14:43:23 -0700101 }
102 }
103 else {
104 continue;
105 }
106 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700107 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700108
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700109 // verify the credential and the self-signed cert
Zhiyi Zhang22998612020-09-25 14:43:23 -0700110 Name signingKeyName = credential->getSignature().getKeyLocator().getName();
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700111 for (auto anchor : m_trustAnchors) {
112 if (anchor.getKeyName() == signingKeyName) {
Zhiyi Zhang3fc7f062020-09-29 10:55:42 -0700113 if (security::verifySignature(*credential, anchor) &&
Zhiyi Zhang22998612020-09-25 14:43:23 -0700114 security::verifySignature(*selfSigned, *credential) &&
115 readString(selfSigned->getContent()) == request.m_requestId) {
Zhiyi Zhang46049832020-09-28 17:08:12 -0700116 return returnWithSuccess(request);
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700117 }
118 }
119 }
Zhiyi Zhang70fe2582017-05-19 15:01:03 -0700120
Zhiyi Zhang46049832020-09-28 17:08:12 -0700121 _LOG_TRACE("Cannot verify the proof of private key against credential");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700122 return returnWithError(request, ErrorCode::INVALID_PARAMETER, "Cannot verify the proof of private key against credential.");
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700123}
124
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700125// For Client
Zhiyi Zhang46049832020-09-28 17:08:12 -0700126std::vector<std::tuple<std::string, std::string>>
127ChallengeCredential::getRequestedParameterList(Status status, const std::string& challengeStatus)
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700128{
Zhiyi Zhang46049832020-09-28 17:08:12 -0700129 std::vector<std::tuple<std::string, std::string>> result;
130 if (status == Status::BEFORE_CHALLENGE) {
131 result.push_back(std::make_tuple(PARAMETER_KEY_CREDENTIAL_CERT, "Please provide the certificate issued by a trusted CA."));
132 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 -0700133 }
134 else {
Zhiyi Zhang46049832020-09-28 17:08:12 -0700135 BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected status or challenge status."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700136 }
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700137 return result;
138}
139
Suyong Won19fba4d2020-05-09 13:39:46 -0700140Block
Zhiyi Zhang46049832020-09-28 17:08:12 -0700141ChallengeCredential::genChallengeRequestTLV(Status status, const std::string& challengeStatus,
142 std::vector<std::tuple<std::string, std::string>>&& params)
Suyong Won19fba4d2020-05-09 13:39:46 -0700143{
144 Block request = makeEmptyBlock(tlv_encrypted_payload);
Zhiyi Zhang46049832020-09-28 17:08:12 -0700145 if (status == Status::BEFORE_CHALLENGE) {
146 if (params.size() != 2) {
147 BOOST_THROW_EXCEPTION(std::runtime_error("Wrong parameter provided."));
148 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700149 request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
Zhiyi Zhang46049832020-09-28 17:08:12 -0700150 for (const auto& item : params) {
151 if (std::get<0>(item) == PARAMETER_KEY_CREDENTIAL_CERT) {
152 request.push_back(makeStringBlock(tlv_parameter_key, PARAMETER_KEY_CREDENTIAL_CERT));
153 request.push_back(makeStringBlock(tlv_parameter_value, std::get<1>(item)));
154 }
155 else if (std::get<0>(item) == PARAMETER_KEY_PROOF_OF_PRIVATE_KEY) {
156 request.push_back(makeStringBlock(tlv_parameter_key, PARAMETER_KEY_PROOF_OF_PRIVATE_KEY));
157 request.push_back(makeStringBlock(tlv_parameter_value, std::get<1>(item)));
158 }
159 else {
160 BOOST_THROW_EXCEPTION(std::runtime_error("Wrong parameter provided."));
161 }
162 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700163 }
164 else {
Zhiyi Zhang46049832020-09-28 17:08:12 -0700165 BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected status or challenge status."));
Suyong Won19fba4d2020-05-09 13:39:46 -0700166 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700167 request.encode();
Suyong Won19fba4d2020-05-09 13:39:46 -0700168 return request;
169}
Zhiyi Zhang22998612020-09-25 14:43:23 -0700170} // namespace ndncert
171} // namespace ndn