blob: 7153731d3bdd19770f48286b9605d9c974e7c531 [file] [log] [blame]
Zhiyi Zhangf5246c42017-01-26 09:39:20 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
swa770de007bc2020-03-24 21:26:21 -07002/**
Davide Pesaventob48bbda2020-07-27 19:41:37 -04003 * Copyright (c) 2017-2020, Regents of the University of California.
Zhiyi Zhangf5246c42017-01-26 09:39:20 -08004 *
5 * This file is part of ndncert, a certificate management system based on NDN.
6 *
7 * ndncert is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License along with
16 * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ndncert authors and contributors.
19 */
20
21#include "ca-module.hpp"
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -070022#include "detail/crypto-helpers.hpp"
Zhiyi Zhangcd57da82020-10-08 20:35:40 -070023#include "identity-challenge/challenge-module.hpp"
Zhiyi Zhangc2c4ed22020-10-14 17:16:28 -070024#include "name-assignment/assignment-func.hpp"
Zhiyi Zhang062be6d2020-10-14 17:13:43 -070025#include "detail/challenge-encoder.hpp"
26#include "detail/error-encoder.hpp"
27#include "detail/info-encoder.hpp"
28#include "detail/new-renew-revoke-encoder.hpp"
29#include "detail/probe-encoder.hpp"
Zhiyi Zhang01e91a32020-09-29 12:10:00 -070030#include <ndn-cxx/metadata-object.hpp>
31#include <ndn-cxx/security/signing-helpers.hpp>
32#include <ndn-cxx/security/verification-helpers.hpp>
33#include <ndn-cxx/util/io.hpp>
34#include <ndn-cxx/util/random.hpp>
Zhiyi Zhang8683ec92020-10-07 18:18:35 -070035#include <ndn-cxx/util/string-helper.hpp>
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080036
37namespace ndn {
38namespace ndncert {
Zhiyi Zhang32d4b4e2020-10-28 22:10:49 -070039namespace ca {
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080040
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -070041static const time::seconds DEFAULT_DATA_FRESHNESS_PERIOD = 1_s;
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -070042static const time::seconds REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD = 120_s;
Zhiyi Zhang6d9eda62020-10-16 17:37:02 -070043static const int AES_128_KEY_LEN = 16;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070044
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -070045NDN_LOG_INIT(ndncert.ca);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080046
tylerliua7bea662020-10-08 18:51:02 -070047CaModule::CaModule(Face& face, security::KeyChain& keyChain,
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080048 const std::string& configPath, const std::string& storageType)
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070049 : m_face(face)
50 , m_keyChain(keyChain)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080051{
Zhiyi Zhanga63b7372017-05-17 14:14:34 -070052 // load the config and create storage
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080053 m_config.load(configPath);
Zhiyi Zhangd1d9f5a2020-10-05 18:04:23 -070054 m_storage = CaStorage::createCaStorage(storageType, m_config.m_caItem.m_caPrefix, "");
Zhiyi Zhanga2c39f72020-10-06 16:45:55 -070055 random::generateSecureBytes(m_requestIdGenKey, 32);
Zhiyi Zhang74c61142020-10-07 21:00:49 -070056 if (m_config.m_nameAssignmentFuncs.size() == 0) {
57 m_config.m_nameAssignmentFuncs.push_back(NameAssignmentFunc::createNameAssignmentFunc("random"));
Zhiyi Zhang8683ec92020-10-07 18:18:35 -070058 }
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080059 registerPrefix();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080060}
61
62CaModule::~CaModule()
63{
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -070064 for (auto& handle : m_interestFilterHandles) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070065 handle.cancel();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080066 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -070067 for (auto& handle : m_registeredPrefixHandles) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070068 handle.unregister();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080069 }
70}
71
72void
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080073CaModule::registerPrefix()
74{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070075 // register prefixes
Zhiyi Zhang9829da92020-09-30 16:19:34 -070076 Name prefix = m_config.m_caItem.m_caPrefix;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070077 prefix.append("CA");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080078
Zhiyi Zhangfbcab842020-10-07 15:17:13 -070079 auto prefixId = m_face.registerPrefix(
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070080 prefix,
81 [&](const Name& name) {
Zhiyi Zhang696cd042020-10-07 21:27:36 -070082 // register INFO RDR metadata prefix
83 name::Component metaDataComp(32, reinterpret_cast<const uint8_t*>("metadata"), std::strlen("metadata"));
84 auto filterId = m_face.setInterestFilter(Name(name).append("INFO").append(metaDataComp),
85 bind(&CaModule::onCaProfileDiscovery, this, _2));
86 m_interestFilterHandles.push_back(filterId);
87
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070088 // register PROBE prefix
Zhiyi Zhang696cd042020-10-07 21:27:36 -070089 filterId = m_face.setInterestFilter(Name(name).append("PROBE"),
Zhiyi Zhangcd57da82020-10-08 20:35:40 -070090 bind(&CaModule::onProbe, this, _2));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070091 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070092
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070093 // register NEW prefix
94 filterId = m_face.setInterestFilter(Name(name).append("NEW"),
Zhiyi Zhang01e91a32020-09-29 12:10:00 -070095 bind(&CaModule::onNewRenewRevoke, this, _2, RequestType::NEW));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070096 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070097
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070098 // register SELECT prefix
99 filterId = m_face.setInterestFilter(Name(name).append("CHALLENGE"),
100 bind(&CaModule::onChallenge, this, _2));
101 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700102
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700103 // register REVOKE prefix
104 filterId = m_face.setInterestFilter(Name(name).append("REVOKE"),
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700105 bind(&CaModule::onNewRenewRevoke, this, _2, RequestType::REVOKE));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700106 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700107 NDN_LOG_TRACE("Prefix " << name << " got registered");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700108 },
109 bind(&CaModule::onRegisterFailed, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700110 m_registeredPrefixHandles.push_back(prefixId);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800111}
112
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700113void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700114CaModule::setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800115{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700116 m_config.m_statusUpdateCallback = onUpdateCallback;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800117}
118
Zhiyi Zhang696cd042020-10-07 21:27:36 -0700119Data
120CaModule::getCaProfileData()
swa77020643ac2020-03-26 02:24:45 -0700121{
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700122 if (m_profileData == nullptr) {
123 const auto& pib = m_keyChain.getPib();
124 const auto& identity = pib.getIdentity(m_config.m_caItem.m_caPrefix);
125 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
Zhiyi Zhang8f1ade32020-10-14 16:42:57 -0700126 Block contentTLV = InfoEncoder::encodeDataContent(m_config.m_caItem, cert);
swa77020643ac2020-03-26 02:24:45 -0700127
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700128 Name infoPacketName(m_config.m_caItem.m_caPrefix);
129 infoPacketName.append("CA").append("INFO").appendVersion().appendSegment(0);
130 m_profileData = std::make_unique<Data>(infoPacketName);
131 m_profileData->setContent(contentTLV);
132 m_profileData->setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
133 m_keyChain.sign(*m_profileData, signingByIdentity(m_config.m_caItem.m_caPrefix));
134 }
Zhiyi Zhang696cd042020-10-07 21:27:36 -0700135 return *m_profileData;
136}
137
138void
139CaModule::onCaProfileDiscovery(const Interest& request)
140{
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700141 NDN_LOG_TRACE("Received CA Profile MetaData discovery Interest");
Zhiyi Zhang696cd042020-10-07 21:27:36 -0700142 if (m_profileData == nullptr) {
143 m_profileData = std::make_unique<Data>(getCaProfileData());
144 }
145 MetadataObject metadata;
146 metadata.setVersionedName(m_profileData->getName().getPrefix(-1));
147 Name discoveryInterestName(m_profileData->getName().getPrefix(-2));
148 name::Component metadataComponent(32, reinterpret_cast<const uint8_t*>("metadata"), std::strlen("metadata"));
149 discoveryInterestName.append(metadataComponent);
150 m_face.put(metadata.makeData(discoveryInterestName, m_keyChain, signingByIdentity(m_config.m_caItem.m_caPrefix)));
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700151}
swa77020643ac2020-03-26 02:24:45 -0700152
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700153void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700154CaModule::onProbe(const Interest& request)
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800155{
swa77020643ac2020-03-26 02:24:45 -0700156 // PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent]
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700157 NDN_LOG_TRACE("Received PROBE request");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800158
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700159 // process PROBE requests: collect probe parameters
Zhiyi Zhang8f1ade32020-10-14 16:42:57 -0700160 auto parameters = ProbeEncoder::decodeApplicationParameters(request.getApplicationParameters());
tylerliu8fc08072020-10-06 15:37:40 -0700161 std::vector<PartialName> availableComponents;
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700162 for (auto& item : m_config.m_nameAssignmentFuncs) {
163 auto names = item->assignName(parameters);
164 availableComponents.insert(availableComponents.end(), names.begin(), names.end());
165 }
Zhiyi Zhangcb8acf22020-10-07 19:35:16 -0700166 if (availableComponents.size() == 0) {
Zhiyi Zhang8683ec92020-10-07 18:18:35 -0700167 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhangcb8acf22020-10-07 19:35:16 -0700168 "Cannot generate available names from parameters provided."));
Zhiyi Zhang8683ec92020-10-07 18:18:35 -0700169 return;
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700170 }
171 std::vector<Name> availableNames;
172 for (const auto& component : availableComponents) {
173 Name newIdentityName = m_config.m_caItem.m_caPrefix;
174 newIdentityName.append(component);
175 availableNames.push_back(newIdentityName);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700176 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700177
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700178 Data result;
179 result.setName(request.getName());
Zhiyi Zhang8f1ade32020-10-14 16:42:57 -0700180 result.setContent(ProbeEncoder::encodeDataContent(availableNames, m_config.m_caItem.m_maxSuffixLength, m_config.m_redirection));
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700181 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
182 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
183 m_face.put(result);
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700184 NDN_LOG_TRACE("Handle PROBE: send out the PROBE response");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800185}
186
187void
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700188CaModule::onNewRenewRevoke(const Interest& request, RequestType requestType)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800189{
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700190 // NEW Naming Convention: /<CA-prefix>/CA/NEW/[SignedInterestParameters_Digest]
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700191 // REVOKE Naming Convention: /<CA-prefix>/CA/REVOKE/[SignedInterestParameters_Digest]
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700192 // get ECDH pub key and cert request
Suyong Won19fba4d2020-05-09 13:39:46 -0700193 const auto& parameterTLV = request.getApplicationParameters();
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700194 std::vector<uint8_t> ecdhPub;
tylerliua7bea662020-10-08 18:51:02 -0700195 shared_ptr<security::Certificate> clientCert;
tylerliu0790bdb2020-10-02 00:50:51 -0700196 try {
Zhiyi Zhang8f1ade32020-10-14 16:42:57 -0700197 NewRenewRevokeEncoder::decodeApplicationParameters(parameterTLV, requestType, ecdhPub, clientCert);
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700198 }
199 catch (const std::exception& e) {
tylerliu0790bdb2020-10-02 00:50:51 -0700200 if (!parameterTLV.hasValue()) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700201 NDN_LOG_ERROR("Empty TLV obtained from the Interest parameter.");
tylerliu0790bdb2020-10-02 00:50:51 -0700202 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
203 "Empty TLV obtained from the Interest parameter."));
204 return;
205 }
Suyong Won7968f7a2020-05-12 01:01:25 -0700206
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700207 NDN_LOG_ERROR("Unrecognized self-signed certificate: " << e.what());
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700208 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
tylerliu0790bdb2020-10-02 00:50:51 -0700209 "Unrecognized self-signed certificate."));
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700210 return;
211 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700212
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700213 if (ecdhPub.empty()) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700214 NDN_LOG_ERROR("Empty ECDH PUB obtained from the Interest parameter.");
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700215 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
216 "Empty ECDH PUB obtained from the Interest parameter."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700217 return;
218 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700219
220 // get server's ECDH pub key
tylerliu8e170d62020-09-30 01:31:53 -0700221 ECDHState ecdh;
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700222 auto myEcdhPubKeyBase64 = ecdh.getSelfPubKey();
223 std::vector<uint8_t> sharedSecret;
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700224 try {
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700225 sharedSecret = ecdh.deriveSecret(ecdhPub);
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700226 }
227 catch (const std::exception& e) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700228 NDN_LOG_ERROR("Cannot derive a shared secret using the provided ECDH key: " << e.what());
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700229 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
230 "Cannot derive a shared secret using the provided ECDH key."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700231 return;
232 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700233 // generate salt for HKDF
Zhiyi Zhangc9f9fac2020-10-18 19:51:51 -0700234 std::array<uint8_t, 32> salt;
235 random::generateSecureBytes(salt.data(), salt.size());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700236 // hkdf
tylerliu8e170d62020-09-30 01:31:53 -0700237 uint8_t aesKey[AES_128_KEY_LEN];
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700238 hkdf(sharedSecret.data(), sharedSecret.size(), salt.data(), salt.size(), aesKey, sizeof(aesKey));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700239
tylerliud9239f52020-09-30 17:25:16 -0700240 // verify identity name
241 if (!m_config.m_caItem.m_caPrefix.isPrefixOf(clientCert->getIdentity())
tylerliua7bea662020-10-08 18:51:02 -0700242 || !security::Certificate::isValidName(clientCert->getName())
tylerliud9239f52020-09-30 17:25:16 -0700243 || clientCert->getIdentity().size() <= m_config.m_caItem.m_caPrefix.size()) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700244 NDN_LOG_ERROR("An invalid certificate name is being requested " << clientCert->getName());
tylerliud9239f52020-09-30 17:25:16 -0700245 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::NAME_NOT_ALLOWED,
246 "An invalid certificate name is being requested."));
247 return;
248 }
249 if (m_config.m_caItem.m_maxSuffixLength) {
250 if (clientCert->getIdentity().size() > m_config.m_caItem.m_caPrefix.size() + *m_config.m_caItem.m_maxSuffixLength) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700251 NDN_LOG_ERROR("An invalid certificate name is being requested " << clientCert->getName());
tylerliud9239f52020-09-30 17:25:16 -0700252 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::NAME_NOT_ALLOWED,
253 "An invalid certificate name is being requested."));
254 return;
255 }
256 }
257
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700258 if (requestType == RequestType::NEW) {
tylerliu4a00aad2020-09-26 02:03:17 -0700259 // check the validity period
260 auto expectedPeriod = clientCert->getValidityPeriod().getPeriod();
261 auto currentTime = time::system_clock::now();
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700262 if (expectedPeriod.first < currentTime - REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD ||
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700263 expectedPeriod.second > currentTime + m_config.m_caItem.m_maxValidityPeriod ||
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700264 expectedPeriod.second <= expectedPeriod.first) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700265 NDN_LOG_ERROR("An invalid validity period is being requested.");
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700266 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_VALIDITY_PERIOD,
267 "An invalid validity period is being requested."));
tylerliu4a00aad2020-09-26 02:03:17 -0700268 return;
269 }
tylerliud9239f52020-09-30 17:25:16 -0700270
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700271 // verify signature
tylerliu4a00aad2020-09-26 02:03:17 -0700272 if (!security::verifySignature(*clientCert, *clientCert)) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700273 NDN_LOG_ERROR("Invalid signature in the self-signed certificate.");
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700274 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
275 "Invalid signature in the self-signed certificate."));
tylerliu4a00aad2020-09-26 02:03:17 -0700276 return;
277 }
278 if (!security::verifySignature(request, *clientCert)) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700279 NDN_LOG_ERROR("Invalid signature in the Interest packet.");
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700280 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
281 "Invalid signature in the Interest packet."));
tylerliu4a00aad2020-09-26 02:03:17 -0700282 return;
283 }
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700284 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700285 else if (requestType == RequestType::REVOKE) {
tylerliud9239f52020-09-30 17:25:16 -0700286 //verify cert is from this CA
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700287 const auto& cert = m_keyChain.getPib().getIdentity(m_config.m_caItem.m_caPrefix).getDefaultKey().getDefaultCertificate();
tylerliu4a00aad2020-09-26 02:03:17 -0700288 if (!security::verifySignature(*clientCert, cert)) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700289 NDN_LOG_ERROR("Invalid signature in the certificate to revoke.");
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700290 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
291 "Invalid signature in the certificate to revoke."));
tylerliu4a00aad2020-09-26 02:03:17 -0700292 return;
293 }
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700294 }
295
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700296 // create new request instance
Zhiyi Zhanga2c39f72020-10-06 16:45:55 -0700297 uint8_t requestIdData[32];
298 Block certNameTlv = clientCert->getName().wireEncode();
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700299 try {
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700300 hmacSha256(certNameTlv.wire(), certNameTlv.size(), m_requestIdGenKey, 32, requestIdData);
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700301 }
302 catch (const std::runtime_error& e) {
303 NDN_LOG_ERROR("Error computing the request ID: " << std::string(e.what()));
304 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
305 "Error computing the request ID."));
306 return;
307 }
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700308 RequestID id;
309 std::memcpy(id.data(), requestIdData, id.size());
Zhiyi Zhang32d4b4e2020-10-28 22:10:49 -0700310 RequestState requestState(m_config.m_caItem.m_caPrefix, id,
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700311 requestType, Status::BEFORE_CHALLENGE, *clientCert,
Zhiyi Zhang8f1ade32020-10-14 16:42:57 -0700312 makeBinaryBlock(ndn::tlv::ContentType_Key, aesKey, sizeof(aesKey)));
Zhiyi Zhang21d52b52020-10-05 18:29:15 -0700313 try {
314 m_storage->addRequest(requestState);
315 }
316 catch (const std::runtime_error& e) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700317 NDN_LOG_ERROR("Duplicate Request ID: The same request has been seen before.");
Zhiyi Zhanga2c39f72020-10-06 16:45:55 -0700318 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700319 "Duplicate Request ID: The same request has been seen before."));
Zhiyi Zhanga2c39f72020-10-06 16:45:55 -0700320 return;
Zhiyi Zhang21d52b52020-10-05 18:29:15 -0700321 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800322 Data result;
323 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700324 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Zhiyi Zhang8f1ade32020-10-14 16:42:57 -0700325 result.setContent(NewRenewRevokeEncoder::encodeDataContent(myEcdhPubKeyBase64,
Zhiyi Zhangc9f9fac2020-10-18 19:51:51 -0700326 salt,
Zhiyi Zhang121aae62020-10-26 13:44:33 -0700327 requestState.m_requestId, requestState.m_status,
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700328 m_config.m_caItem.m_supportedChallenges));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700329 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800330 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700331 if (m_config.m_statusUpdateCallback) {
tylerliu63900d52020-09-30 03:01:18 -0700332 m_config.m_statusUpdateCallback(requestState);
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800333 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800334}
335
336void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700337CaModule::onChallenge(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800338{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700339 // get certificate request state
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700340 auto requestState = getCertificateRequest(request);
Zhiyi Zhang84207c52020-10-28 21:45:44 -0700341 if (requestState == nullptr) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700342 NDN_LOG_ERROR("No certificate request state can be found.");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700343 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700344 "No certificate request state can be found."));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800345 return;
346 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700347 // verify signature
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700348 if (!security::verifySignature(request, requestState->m_cert)) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700349 NDN_LOG_ERROR("Invalid Signature in the Interest packet.");
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700350 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
351 "Invalid Signature in the Interest packet."));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800352 return;
353 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700354 // decrypt the parameters
Suyong Won19fba4d2020-05-09 13:39:46 -0700355 Buffer paramTLVPayload;
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700356 try {
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700357 paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(),
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700358 requestState->m_encryptionKey.value(),
359 requestState->m_requestId.data(),
360 requestState->m_requestId.size());
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700361 }
362 catch (const std::exception& e) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700363 NDN_LOG_ERROR("Interest paramaters decryption failed: " << e.what());
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700364 m_storage->deleteRequest(requestState->m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700365 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700366 "Interest paramaters decryption failed."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700367 return;
368 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700369 if (paramTLVPayload.size() == 0) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700370 NDN_LOG_ERROR("No parameters are found after decryption.");
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700371 m_storage->deleteRequest(requestState->m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700372 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700373 "No parameters are found after decryption."));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700374 return;
375 }
tylerliu50d679e2020-10-14 14:08:39 -0700376 Block paramTLV = makeBinaryBlock(tlv::EncryptedPayload, paramTLVPayload.data(), paramTLVPayload.size());
Suyong Won44d0cce2020-05-10 04:07:43 -0700377 paramTLV.parse();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800378
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700379 // load the corresponding challenge module
tylerliu50d679e2020-10-14 14:08:39 -0700380 std::string challengeType = readString(paramTLV.get(tlv::SelectedChallenge));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800381 auto challenge = ChallengeModule::createChallengeModule(challengeType);
382 if (challenge == nullptr) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700383 NDN_LOG_TRACE("Unrecognized challenge type: " << challengeType);
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700384 m_storage->deleteRequest(requestState->m_requestId);
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700385 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER, "Unrecognized challenge type."));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700386 return;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800387 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700388
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700389 NDN_LOG_TRACE("CHALLENGE module to be load: " << challengeType);
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700390 auto errorInfo = challenge->handleChallengeRequest(paramTLV, *requestState);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700391 if (std::get<0>(errorInfo) != ErrorCode::NO_ERROR) {
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700392 m_storage->deleteRequest(requestState->m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700393 m_face.put(generateErrorDataPacket(request.getName(), std::get<0>(errorInfo), std::get<1>(errorInfo)));
394 return;
395 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700396
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700397 Block payload;
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700398 if (requestState->m_status == Status::PENDING) {
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700399 // if challenge succeeded
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700400 if (requestState->m_requestType == RequestType::NEW) {
401 auto issuedCert = issueCertificate(*requestState);
402 requestState->m_cert = issuedCert;
403 requestState->m_status = Status::SUCCESS;
404 m_storage->deleteRequest(requestState->m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700405
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700406 payload = ChallengeEncoder::encodeDataContent(*requestState);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700407 payload.parse();
tylerliu50d679e2020-10-14 14:08:39 -0700408 payload.push_back(makeNestedBlock(tlv::IssuedCertName, issuedCert.getName()));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700409 payload.encode();
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700410 NDN_LOG_TRACE("Challenge succeeded. Certificate has been issued: " << issuedCert.getName());
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800411 }
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700412 else if (requestState->m_requestType == RequestType::REVOKE) {
413 requestState->m_status = Status::SUCCESS;
414 m_storage->deleteRequest(requestState->m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700415
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700416 payload = ChallengeEncoder::encodeDataContent(*requestState);
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700417 NDN_LOG_TRACE("Challenge succeeded. Certificate has been revoked");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700418 }
419 }
420 else {
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700421 m_storage->updateRequest(*requestState);
422 payload = ChallengeEncoder::encodeDataContent(*requestState);
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700423 NDN_LOG_TRACE("No failure no success. Challenge moves on");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800424 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700425
426 Data result;
427 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700428 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700429 auto contentBlock = encodeBlockWithAesGcm128(ndn::tlv::Content, requestState->m_encryptionKey.value(),
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700430 payload.value(), payload.value_size(),
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700431 requestState->m_requestId.data(),
432 requestState->m_requestId.size(),
433 requestState->m_aesBlockCounter);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700434 result.setContent(contentBlock);
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700435 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700436 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700437 if (m_config.m_statusUpdateCallback) {
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700438 m_config.m_statusUpdateCallback(*requestState);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800439 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700440}
441
tylerliua7bea662020-10-08 18:51:02 -0700442security::Certificate
Zhiyi Zhang32d4b4e2020-10-28 22:10:49 -0700443CaModule::issueCertificate(const RequestState& requestState)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800444{
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700445 auto expectedPeriod = requestState.m_cert.getValidityPeriod().getPeriod();
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700446 security::ValidityPeriod period(expectedPeriod.first, expectedPeriod.second);
tylerliua7bea662020-10-08 18:51:02 -0700447 security::Certificate newCert;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700448
tylerliu63900d52020-09-30 03:01:18 -0700449 Name certName = requestState.m_cert.getKeyName();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700450 certName.append("NDNCERT").append(std::to_string(random::generateSecureWord64()));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800451 newCert.setName(certName);
tylerliu63900d52020-09-30 03:01:18 -0700452 newCert.setContent(requestState.m_cert.getContent());
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700453 NDN_LOG_TRACE("cert request content " << requestState.m_cert);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800454 SignatureInfo signatureInfo;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800455 signatureInfo.setValidityPeriod(period);
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700456 security::SigningInfo signingInfo(security::SigningInfo::SIGNER_TYPE_ID,
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700457 m_config.m_caItem.m_caPrefix, signatureInfo);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800458
459 m_keyChain.sign(newCert, signingInfo);
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700460 NDN_LOG_TRACE("new cert got signed" << newCert);
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800461 return newCert;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800462}
463
Zhiyi Zhang32d4b4e2020-10-28 22:10:49 -0700464std::unique_ptr<RequestState>
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700465CaModule::getCertificateRequest(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800466{
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700467 RequestID requestId;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800468 try {
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700469 auto& component = request.getName().at(m_config.m_caItem.m_caPrefix.size() + 2);
470 std::memcpy(requestId.data(), component.value(), component.value_size());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700471 }
472 catch (const std::exception& e) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700473 NDN_LOG_ERROR("Cannot read the request ID out from the request: " << e.what());
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700474 return nullptr;
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700475 }
476 try {
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700477 NDN_LOG_TRACE("Request Id to query the database " << toHex(requestId.data(), requestId.size()));
Zhiyi Zhang32d4b4e2020-10-28 22:10:49 -0700478 return std::make_unique<RequestState>(m_storage->getRequest(requestId));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800479 }
480 catch (const std::exception& e) {
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700481 NDN_LOG_ERROR("Cannot get certificate request record from the storage: " << e.what());
Zhiyi Zhang8fdb36b2020-10-18 11:58:51 -0700482 return nullptr;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800483 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800484}
485
486void
487CaModule::onRegisterFailed(const std::string& reason)
488{
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -0700489 NDN_LOG_ERROR("Failed to register prefix in local hub's daemon, REASON: " << reason);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800490}
491
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700492Data
493CaModule::generateErrorDataPacket(const Name& name, ErrorCode error, const std::string& errorInfo)
494{
495 Data result;
496 result.setName(name);
497 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Zhiyi Zhang8f1ade32020-10-14 16:42:57 -0700498 result.setContent(ErrorEncoder::encodeDataContent(error, errorInfo));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700499 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700500 return result;
501}
502
Zhiyi Zhang32d4b4e2020-10-28 22:10:49 -0700503} // namespace ca
Zhiyi Zhange4891b72020-10-10 15:11:57 -0700504} // namespace ndncert
505} // namespace ndn