blob: 324a85941f50aa858ed9aa782a3f3fb5995e41e7 [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 Zhangaafc55e2020-09-28 17:54:48 -070022#include "challenge-module.hpp"
23#include "crypto-support/enc-tlv.hpp"
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070024#include "protocol-detail/challenge.hpp"
25#include "protocol-detail/error.hpp"
26#include "protocol-detail/info.hpp"
tylerliu4889a782020-09-30 22:47:49 -070027#include "protocol-detail/new-renew-revoke.hpp"
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070028#include "protocol-detail/probe.hpp"
Zhiyi Zhang01e91a32020-09-29 12:10:00 -070029#include <ndn-cxx/metadata-object.hpp>
30#include <ndn-cxx/security/signing-helpers.hpp>
31#include <ndn-cxx/security/verification-helpers.hpp>
32#include <ndn-cxx/util/io.hpp>
33#include <ndn-cxx/util/random.hpp>
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080034
35namespace ndn {
36namespace ndncert {
37
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -070038static const time::seconds DEFAULT_DATA_FRESHNESS_PERIOD = 1_s;
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -070039static const time::seconds REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD = 120_s;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070040
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080041_LOG_INIT(ndncert.ca);
42
43CaModule::CaModule(Face& face, security::v2::KeyChain& keyChain,
44 const std::string& configPath, const std::string& storageType)
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070045 : m_face(face)
46 , m_keyChain(keyChain)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080047{
Zhiyi Zhanga63b7372017-05-17 14:14:34 -070048 // load the config and create storage
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080049 m_config.load(configPath);
50 m_storage = CaStorage::createCaStorage(storageType);
51
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080052 registerPrefix();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080053}
54
55CaModule::~CaModule()
56{
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -070057 for (auto& handle : m_interestFilterHandles) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070058 handle.cancel();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080059 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -070060 for (auto& handle : m_registeredPrefixHandles) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070061 handle.unregister();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080062 }
63}
64
65void
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080066CaModule::registerPrefix()
67{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070068 // register localhop discovery prefix
swa77020643ac2020-03-26 02:24:45 -070069 Name localhopInfoPrefix("/localhop/CA/INFO");
70 auto prefixId = m_face.setInterestFilter(InterestFilter(localhopInfoPrefix),
71 bind(&CaModule::onInfo, this, _2),
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080072 bind(&CaModule::onRegisterFailed, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070073 m_registeredPrefixHandles.push_back(prefixId);
swa77020643ac2020-03-26 02:24:45 -070074 _LOG_TRACE("Prefix " << localhopInfoPrefix << " got registered");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080075
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070076 // register prefixes
Zhiyi Zhang9829da92020-09-30 16:19:34 -070077 Name prefix = m_config.m_caItem.m_caPrefix;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070078 prefix.append("CA");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080079
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070080 prefixId = m_face.registerPrefix(
81 prefix,
82 [&](const Name& name) {
83 // register INFO prefix
84 auto filterId = m_face.setInterestFilter(Name(name).append("INFO"),
85 bind(&CaModule::onInfo, this, _2));
86 m_interestFilterHandles.push_back(filterId);
swa77020643ac2020-03-26 02:24:45 -070087
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070088 // register PROBE prefix
89 filterId = m_face.setInterestFilter(Name(name).append("PROBE"),
90 bind(&CaModule::onProbe, this, _2));
91 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);
107 _LOG_TRACE("Prefix " << name << " got registered");
108 },
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
114CaModule::setNameAssignmentFunction(const NameAssignmentFunc& handler)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800115{
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700116 m_config.m_nameAssignmentFunc = handler;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800117}
118
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700119void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700120CaModule::setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800121{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700122 m_config.m_statusUpdateCallback = onUpdateCallback;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800123}
124
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700125shared_ptr<Data>
126CaModule::generateCaConfigMetaData()
swa77020643ac2020-03-26 02:24:45 -0700127{
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700128 // @TODO
129 // make metadata a class member variable m_infoMetadata
130 // check whether the m_infoMetadata has the latest versioned name, if not, then generate a new one
131 // otherwise, directly reply m_infoMetadata.makeData
132
133 auto infoPacket = generateCaConfigData();
134 MetadataObject metadata;
135 metadata.setVersionedName(infoPacket->getName().getPrefix(-1));
136 Name discoveryInterestName(infoPacket->getName().getPrefix(-2));
137 name::Component metadataComponent(32, reinterpret_cast<const uint8_t*>("metadata"), std::strlen("metadata"));
138 discoveryInterestName.append(metadataComponent);
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700139 auto metadataData = metadata.makeData(discoveryInterestName, m_keyChain, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700140 return make_shared<Data>(metadataData);
141}
142
143shared_ptr<Data>
144CaModule::generateCaConfigData()
145{
146 // @TODO
147 // make CaInfo Data packet a class member variable m_infoData
148 // check whether the m_infoData is still valid, if not, then generate a new one
149 // otherwise, directly reply m_infoData
Suyong Won19fba4d2020-05-09 13:39:46 -0700150
151 const auto& pib = m_keyChain.getPib();
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700152 const auto& identity = pib.getIdentity(m_config.m_caItem.m_caPrefix);
Suyong Won19fba4d2020-05-09 13:39:46 -0700153 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700154 Block contentTLV = INFO::encodeDataContent(m_config.m_caItem, cert);
swa77020643ac2020-03-26 02:24:45 -0700155
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700156 Name infoPacketName(m_config.m_caItem.m_caPrefix);
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700157 infoPacketName.append("CA").append("INFO").appendVersion().appendSegment(0);
158 Data infoData(infoPacketName);
159 infoData.setContent(contentTLV);
160 infoData.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700161 m_keyChain.sign(infoData, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700162 return make_shared<Data>(infoData);
163}
swa77020643ac2020-03-26 02:24:45 -0700164
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700165void
166CaModule::onInfo(const Interest& request)
167{
168 _LOG_TRACE("Received INFO request");
169
170 if (request.getName().get(-1).type() == 32) {
171 m_face.put(*generateCaConfigMetaData());
172 }
173 else {
174 m_face.put(*generateCaConfigData());
175 }
swa77020643ac2020-03-26 02:24:45 -0700176
177 _LOG_TRACE("Handle INFO: send out the INFO response");
178}
179
180void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700181CaModule::onProbe(const Interest& request)
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800182{
swa77020643ac2020-03-26 02:24:45 -0700183 // PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent]
184 _LOG_TRACE("Received PROBE request");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800185
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700186 // process PROBE requests: collect probe parameters
187 auto parameters = PROBE::decodeApplicationParameters(request.getApplicationParameters());
188 std::vector<std::string> availableComponents;
189 if (m_config.m_nameAssignmentFunc) {
190 try {
191 availableComponents = m_config.m_nameAssignmentFunc(parameters);
192 }
193 catch (const std::exception& e) {
194 _LOG_TRACE("Cannot parse probe parameters: " << e.what());
195 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
196 "Cannot parse probe parameters: " + std::string(e.what())));
197 return;
198 }
199 }
200 else {
201 // if there is no app-specified name lookup, use a random name id
202 availableComponents.push_back(std::to_string(random::generateSecureWord64()));
203 }
204 std::vector<Name> availableNames;
205 for (const auto& component : availableComponents) {
206 Name newIdentityName = m_config.m_caItem.m_caPrefix;
207 newIdentityName.append(component);
208 availableNames.push_back(newIdentityName);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700209 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700210
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700211 Data result;
212 result.setName(request.getName());
Suyong Wone2afeb52020-10-04 03:05:39 +0900213 result.setContent(PROBE::encodeDataContent(availableNames, m_config.m_caItem.m_maxSuffixLength, m_config.m_redirection));
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700214 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
215 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
216 m_face.put(result);
217 _LOG_TRACE("Handle PROBE: send out the PROBE response");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800218}
219
220void
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700221CaModule::onNewRenewRevoke(const Interest& request, RequestType requestType)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800222{
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700223 // NEW Naming Convention: /<CA-prefix>/CA/NEW/[SignedInterestParameters_Digest]
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700224 // REVOKE Naming Convention: /<CA-prefix>/CA/REVOKE/[SignedInterestParameters_Digest]
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700225 // get ECDH pub key and cert request
Suyong Won19fba4d2020-05-09 13:39:46 -0700226 const auto& parameterTLV = request.getApplicationParameters();
tylerliu0790bdb2020-10-02 00:50:51 -0700227 std::string ecdhPub;
228 shared_ptr<security::v2::Certificate> clientCert;
229 try {
230 NEW_RENEW_REVOKE::decodeApplicationParameters(parameterTLV, requestType, ecdhPub, clientCert);
231 } catch (const std::exception& e) {
232 if (!parameterTLV.hasValue()) {
233 _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
234 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
235 "Empty TLV obtained from the Interest parameter."));
236 return;
237 }
Suyong Won7968f7a2020-05-12 01:01:25 -0700238
tylerliu0790bdb2020-10-02 00:50:51 -0700239 _LOG_ERROR("Unrecognized self-signed certificate: " << e.what());
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700240 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
tylerliu0790bdb2020-10-02 00:50:51 -0700241 "Unrecognized self-signed certificate."));
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700242 return;
243 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700244
tylerliu0790bdb2020-10-02 00:50:51 -0700245 if (ecdhPub == "") {
Suyong Won19fba4d2020-05-09 13:39:46 -0700246 _LOG_ERROR("Empty ECDH PUB obtained from the Interest parameter.");
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700247 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
248 "Empty ECDH PUB obtained from the Interest parameter."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700249 return;
250 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700251
252 // get server's ECDH pub key
tylerliu8e170d62020-09-30 01:31:53 -0700253 ECDHState ecdh;
254 auto myEcdhPubKeyBase64 = ecdh.getBase64PubKey();
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700255 try {
tylerliu0790bdb2020-10-02 00:50:51 -0700256 ecdh.deriveSecret(ecdhPub);
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700257 }
258 catch (const std::exception& e) {
259 _LOG_ERROR("Cannot derive a shared secret using the provided ECDH key: " << e.what());
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700260 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
261 "Cannot derive a shared secret using the provided ECDH key."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700262 return;
263 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700264 // generate salt for HKDF
265 auto saltInt = random::generateSecureWord64();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700266 // hkdf
tylerliu8e170d62020-09-30 01:31:53 -0700267 uint8_t aesKey[AES_128_KEY_LEN];
268 hkdf(ecdh.context->sharedSecret, ecdh.context->sharedSecretLen,
269 (uint8_t*)&saltInt, sizeof(saltInt), aesKey, sizeof(aesKey));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700270
tylerliud9239f52020-09-30 17:25:16 -0700271 // verify identity name
272 if (!m_config.m_caItem.m_caPrefix.isPrefixOf(clientCert->getIdentity())
273 || !security::v2::Certificate::isValidName(clientCert->getName())
274 || clientCert->getIdentity().size() <= m_config.m_caItem.m_caPrefix.size()) {
275 _LOG_ERROR("An invalid certificate name is being requested " << clientCert->getName());
276 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::NAME_NOT_ALLOWED,
277 "An invalid certificate name is being requested."));
278 return;
279 }
280 if (m_config.m_caItem.m_maxSuffixLength) {
281 if (clientCert->getIdentity().size() > m_config.m_caItem.m_caPrefix.size() + *m_config.m_caItem.m_maxSuffixLength) {
282 _LOG_ERROR("An invalid certificate name is being requested " << clientCert->getName());
283 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::NAME_NOT_ALLOWED,
284 "An invalid certificate name is being requested."));
285 return;
286 }
287 }
288
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700289 if (requestType == RequestType::NEW) {
tylerliu4a00aad2020-09-26 02:03:17 -0700290 // check the validity period
291 auto expectedPeriod = clientCert->getValidityPeriod().getPeriod();
292 auto currentTime = time::system_clock::now();
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700293 if (expectedPeriod.first < currentTime - REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD ||
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700294 expectedPeriod.second > currentTime + m_config.m_caItem.m_maxValidityPeriod ||
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700295 expectedPeriod.second <= expectedPeriod.first) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700296 _LOG_ERROR("An invalid validity period is being requested.");
297 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_VALIDITY_PERIOD,
298 "An invalid validity period is being requested."));
tylerliu4a00aad2020-09-26 02:03:17 -0700299 return;
300 }
tylerliud9239f52020-09-30 17:25:16 -0700301
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700302 // verify signature
tylerliu4a00aad2020-09-26 02:03:17 -0700303 if (!security::verifySignature(*clientCert, *clientCert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700304 _LOG_ERROR("Invalid signature in the self-signed certificate.");
305 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
306 "Invalid signature in the self-signed certificate."));
tylerliu4a00aad2020-09-26 02:03:17 -0700307 return;
308 }
309 if (!security::verifySignature(request, *clientCert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700310 _LOG_ERROR("Invalid signature in the Interest packet.");
311 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
312 "Invalid signature in the Interest packet."));
tylerliu4a00aad2020-09-26 02:03:17 -0700313 return;
314 }
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700315 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700316 else if (requestType == RequestType::REVOKE) {
tylerliud9239f52020-09-30 17:25:16 -0700317 //verify cert is from this CA
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700318 const auto& cert = m_keyChain.getPib().getIdentity(m_config.m_caItem.m_caPrefix).getDefaultKey().getDefaultCertificate();
tylerliu4a00aad2020-09-26 02:03:17 -0700319 if (!security::verifySignature(*clientCert, cert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700320 _LOG_ERROR("Invalid signature in the certificate to revoke.");
321 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
322 "Invalid signature in the certificate to revoke."));
tylerliu4a00aad2020-09-26 02:03:17 -0700323 return;
324 }
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700325 }
326
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700327 // create new request instance
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800328 std::string requestId = std::to_string(random::generateWord64());
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700329 RequestState requestState(m_config.m_caItem.m_caPrefix, requestId, requestType, Status::BEFORE_CHALLENGE, *clientCert,
tylerliu8e170d62020-09-30 01:31:53 -0700330 makeBinaryBlock(tlv::ContentType_Key, aesKey, sizeof(aesKey)));
tylerliu63900d52020-09-30 03:01:18 -0700331 m_storage->addRequest(requestState);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800332 Data result;
333 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700334 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
tylerliu4889a782020-09-30 22:47:49 -0700335 result.setContent(NEW_RENEW_REVOKE::encodeDataContent(myEcdhPubKeyBase64,
tylerliu4a00aad2020-09-26 02:03:17 -0700336 std::to_string(saltInt),
tylerliu63900d52020-09-30 03:01:18 -0700337 requestState,
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700338 m_config.m_caItem.m_supportedChallenges));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700339 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800340 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700341 if (m_config.m_statusUpdateCallback) {
tylerliu63900d52020-09-30 03:01:18 -0700342 m_config.m_statusUpdateCallback(requestState);
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800343 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800344}
345
346void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700347CaModule::onChallenge(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800348{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700349 // get certificate request state
tylerliu63900d52020-09-30 03:01:18 -0700350 RequestState requestState = getCertificateRequest(request);
351 if (requestState.m_requestId == "") {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700352 _LOG_ERROR("No certificate request state can be found.");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700353 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700354 "No certificate request state can be found."));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800355 return;
356 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700357 // verify signature
tylerliu63900d52020-09-30 03:01:18 -0700358 if (!security::verifySignature(request, requestState.m_cert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700359 _LOG_ERROR("Invalid Signature in the Interest packet.");
360 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
361 "Invalid Signature in the Interest packet."));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800362 return;
363 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700364 // decrypt the parameters
Suyong Won19fba4d2020-05-09 13:39:46 -0700365 Buffer paramTLVPayload;
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700366 try {
tylerliu63900d52020-09-30 03:01:18 -0700367 paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), requestState.m_encryptionKey.value(),
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700368 (uint8_t*)"test", strlen("test"));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700369 }
370 catch (const std::exception& e) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700371 _LOG_ERROR("Interest paramaters decryption failed: " << e.what());
tylerliu63900d52020-09-30 03:01:18 -0700372 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700373 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700374 "Interest paramaters decryption failed."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700375 return;
376 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700377 if (paramTLVPayload.size() == 0) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700378 _LOG_ERROR("No parameters are found after decryption.");
tylerliu63900d52020-09-30 03:01:18 -0700379 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700380 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700381 "No parameters are found after decryption."));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700382 return;
383 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700384 Block paramTLV = makeBinaryBlock(tlv_encrypted_payload, paramTLVPayload.data(), paramTLVPayload.size());
385 paramTLV.parse();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800386
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700387 // load the corresponding challenge module
Suyong Won19fba4d2020-05-09 13:39:46 -0700388 std::string challengeType = readString(paramTLV.get(tlv_selected_challenge));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800389 auto challenge = ChallengeModule::createChallengeModule(challengeType);
390 if (challenge == nullptr) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700391 _LOG_TRACE("Unrecognized challenge type: " << challengeType);
tylerliu63900d52020-09-30 03:01:18 -0700392 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700393 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER, "Unrecognized challenge type."));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700394 return;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800395 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700396
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700397 _LOG_TRACE("CHALLENGE module to be load: " << challengeType);
tylerliu63900d52020-09-30 03:01:18 -0700398 auto errorInfo = challenge->handleChallengeRequest(paramTLV, requestState);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700399 if (std::get<0>(errorInfo) != ErrorCode::NO_ERROR) {
tylerliu63900d52020-09-30 03:01:18 -0700400 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700401 m_face.put(generateErrorDataPacket(request.getName(), std::get<0>(errorInfo), std::get<1>(errorInfo)));
402 return;
403 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700404
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700405 Block payload;
tylerliu63900d52020-09-30 03:01:18 -0700406 if (requestState.m_status == Status::PENDING) {
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700407 // if challenge succeeded
tylerliu63900d52020-09-30 03:01:18 -0700408 if (requestState.m_requestType == RequestType::NEW) {
409 auto issuedCert = issueCertificate(requestState);
410 requestState.m_cert = issuedCert;
411 requestState.m_status = Status::SUCCESS;
412 m_storage->addCertificate(requestState.m_requestId, issuedCert);
413 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700414
tylerliu63900d52020-09-30 03:01:18 -0700415 payload = CHALLENGE::encodeDataPayload(requestState);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700416 payload.parse();
417 payload.push_back(makeNestedBlock(tlv_issued_cert_name, issuedCert.getName()));
418 payload.encode();
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700419 _LOG_TRACE("Challenge succeeded. Certificate has been issued: " << issuedCert.getName());
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800420 }
tylerliu63900d52020-09-30 03:01:18 -0700421 else if (requestState.m_requestType == RequestType::REVOKE) {
422 requestState.m_status = Status::SUCCESS;
423 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700424
tylerliu63900d52020-09-30 03:01:18 -0700425 payload = CHALLENGE::encodeDataPayload(requestState);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700426 _LOG_TRACE("Challenge succeeded. Certificate has been revoked");
427 }
428 }
429 else {
tylerliu63900d52020-09-30 03:01:18 -0700430 m_storage->updateRequest(requestState);
431 payload = CHALLENGE::encodeDataPayload(requestState);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700432 _LOG_TRACE("No failure no success. Challenge moves on");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800433 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700434
435 Data result;
436 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700437 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
tylerliu63900d52020-09-30 03:01:18 -0700438 auto contentBlock = encodeBlockWithAesGcm128(tlv::Content, requestState.m_encryptionKey.value(), payload.value(),
Suyong Won7968f7a2020-05-12 01:01:25 -0700439 payload.value_size(), (uint8_t*)"test", strlen("test"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700440 result.setContent(contentBlock);
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700441 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700442 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700443 if (m_config.m_statusUpdateCallback) {
tylerliu63900d52020-09-30 03:01:18 -0700444 m_config.m_statusUpdateCallback(requestState);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800445 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700446}
447
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800448security::v2::Certificate
tylerliu63900d52020-09-30 03:01:18 -0700449CaModule::issueCertificate(const RequestState& requestState)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800450{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700451 auto expectedPeriod =
tylerliu63900d52020-09-30 03:01:18 -0700452 requestState.m_cert.getValidityPeriod().getPeriod();
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700453 security::ValidityPeriod period(expectedPeriod.first, expectedPeriod.second);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800454 security::v2::Certificate newCert;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700455
tylerliu63900d52020-09-30 03:01:18 -0700456 Name certName = requestState.m_cert.getKeyName();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700457 certName.append("NDNCERT").append(std::to_string(random::generateSecureWord64()));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800458 newCert.setName(certName);
tylerliu63900d52020-09-30 03:01:18 -0700459 newCert.setContent(requestState.m_cert.getContent());
460 _LOG_TRACE("cert request content " << requestState.m_cert);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800461 SignatureInfo signatureInfo;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800462 signatureInfo.setValidityPeriod(period);
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700463 security::SigningInfo signingInfo(security::SigningInfo::SIGNER_TYPE_ID,
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700464 m_config.m_caItem.m_caPrefix, signatureInfo);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800465
466 m_keyChain.sign(newCert, signingInfo);
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700467 _LOG_TRACE("new cert got signed" << newCert);
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800468 return newCert;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800469}
470
Zhiyi Zhange232a742020-09-29 17:34:17 -0700471RequestState
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700472CaModule::getCertificateRequest(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800473{
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400474 std::string requestId;
tylerliu63900d52020-09-30 03:01:18 -0700475 RequestState requestState;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800476 try {
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700477 requestId = readString(request.getName().at(m_config.m_caItem.m_caPrefix.size() + 2));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700478 }
479 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700480 _LOG_ERROR("Cannot read the request ID out from the request: " << e.what());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700481 }
482 try {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700483 _LOG_TRACE("Request Id to query the database " << requestId);
tylerliu63900d52020-09-30 03:01:18 -0700484 requestState = m_storage->getRequest(requestId);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800485 }
486 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700487 _LOG_ERROR("Cannot get certificate request record from the storage: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800488 }
tylerliu63900d52020-09-30 03:01:18 -0700489 return requestState;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800490}
491
492void
493CaModule::onRegisterFailed(const std::string& reason)
494{
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700495 _LOG_ERROR("Failed to register prefix in local hub's daemon, REASON: " << reason);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800496}
497
498Block
499CaModule::dataContentFromJson(const JsonSection& jsonSection)
500{
501 std::stringstream ss;
502 boost::property_tree::write_json(ss, jsonSection);
503 return makeStringBlock(ndn::tlv::Content, ss.str());
504}
505
506JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700507CaModule::jsonFromBlock(const Block& block)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800508{
509 std::string jsonString;
510 try {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700511 jsonString = encoding::readString(block);
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700512 std::istringstream ss(jsonString);
513 JsonSection json;
514 boost::property_tree::json_parser::read_json(ss, json);
515 return json;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800516 }
517 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700518 _LOG_ERROR("Cannot read JSON string from TLV Value: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800519 return JsonSection();
520 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800521}
522
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700523Data
524CaModule::generateErrorDataPacket(const Name& name, ErrorCode error, const std::string& errorInfo)
525{
526 Data result;
527 result.setName(name);
528 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
529 result.setContent(ErrorTLV::encodeDataContent(error, errorInfo));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700530 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700531 return result;
532}
533
534} // namespace ndncert
535} // namespace ndn