blob: 9f9515796678a07557bae799bc569d4fee435539 [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"
22#include "challenge-module.hpp"
23#include "logging.hpp"
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070024#include "crypto-support/enc-tlv.hpp"
Suyong Won19fba4d2020-05-09 13:39:46 -070025#include "protocol-detail/info.hpp"
26#include "protocol-detail/probe.hpp"
27#include "protocol-detail/new.hpp"
28#include "protocol-detail/challenge.hpp"
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080029#include <ndn-cxx/util/io.hpp>
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080030#include <ndn-cxx/security/verification-helpers.hpp>
31#include <ndn-cxx/security/signing-helpers.hpp>
Junxiao Shi7c068032017-05-28 13:40:47 +000032#include <ndn-cxx/util/random.hpp>
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -070033#include <ndn-cxx/metadata-object.hpp>
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080034
35namespace ndn {
36namespace ndncert {
37
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070038static const int IS_SUBNAME_MIN_OFFSET = 5;
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -070039static const time::seconds DEFAULT_DATA_FRESHNESS_PERIOD = 1_s;
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -070040static const time::seconds REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD = 120_s;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070041
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080042_LOG_INIT(ndncert.ca);
43
44CaModule::CaModule(Face& face, security::v2::KeyChain& keyChain,
45 const std::string& configPath, const std::string& storageType)
46 : m_face(face)
47 , m_keyChain(keyChain)
48{
Zhiyi Zhanga63b7372017-05-17 14:14:34 -070049 // load the config and create storage
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080050 m_config.load(configPath);
51 m_storage = CaStorage::createCaStorage(storageType);
52
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080053 registerPrefix();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080054}
55
56CaModule::~CaModule()
57{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070058 for (auto handle : m_interestFilterHandles) {
59 handle.cancel();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080060 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070061 for (auto handle : m_registeredPrefixHandles) {
62 handle.unregister();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080063 }
64}
65
66void
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080067CaModule::registerPrefix()
68{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070069 // register localhop discovery prefix
swa77020643ac2020-03-26 02:24:45 -070070 Name localhopInfoPrefix("/localhop/CA/INFO");
71 auto prefixId = m_face.setInterestFilter(InterestFilter(localhopInfoPrefix),
72 bind(&CaModule::onInfo, this, _2),
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080073 bind(&CaModule::onRegisterFailed, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070074 m_registeredPrefixHandles.push_back(prefixId);
swa77020643ac2020-03-26 02:24:45 -070075 _LOG_TRACE("Prefix " << localhopInfoPrefix << " got registered");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080076
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070077 // register prefixes
Suyong Won256c9062020-05-11 02:45:56 -070078 Name prefix = m_config.m_caPrefix;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070079 prefix.append("CA");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080080
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070081 prefixId = m_face.registerPrefix(prefix,
82 [&] (const Name& name) {
swa77020643ac2020-03-26 02:24:45 -070083 // 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);
87
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070088 // register PROBE prefix
swa77020643ac2020-03-26 02:24:45 -070089 filterId = m_face.setInterestFilter(Name(name).append("PROBE"),
90 bind(&CaModule::onProbe, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070091 m_interestFilterHandles.push_back(filterId);
92
93 // register NEW prefix
swa770de007bc2020-03-24 21:26:21 -070094 filterId = m_face.setInterestFilter(Name(name).append("NEW"),
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070095 bind(&CaModule::onNew, this, _2));
96 m_interestFilterHandles.push_back(filterId);
97
98 // register SELECT prefix
swa770de007bc2020-03-24 21:26:21 -070099 filterId = m_face.setInterestFilter(Name(name).append("CHALLENGE"),
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700100 bind(&CaModule::onChallenge, this, _2));
101 m_interestFilterHandles.push_back(filterId);
102
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700103 _LOG_TRACE("Prefix " << name << " got registered");
104 },
105 bind(&CaModule::onRegisterFailed, this, _2));
106 m_registeredPrefixHandles.push_back(prefixId);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800107}
108
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800109bool
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700110CaModule::setProbeHandler(const ProbeHandler& handler)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800111{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700112 m_config.m_probeHandler = handler;
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800113 return false;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800114}
115
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800116bool
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700117CaModule::setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800118{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700119 m_config.m_statusUpdateCallback = onUpdateCallback;
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800120 return false;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800121}
122
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700123shared_ptr<Data>
124CaModule::generateCaConfigMetaData()
swa77020643ac2020-03-26 02:24:45 -0700125{
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700126 // @TODO
127 // make metadata a class member variable m_infoMetadata
128 // check whether the m_infoMetadata has the latest versioned name, if not, then generate a new one
129 // otherwise, directly reply m_infoMetadata.makeData
130
131 auto infoPacket = generateCaConfigData();
132 MetadataObject metadata;
133 metadata.setVersionedName(infoPacket->getName().getPrefix(-1));
134 Name discoveryInterestName(infoPacket->getName().getPrefix(-2));
135 name::Component metadataComponent(32, reinterpret_cast<const uint8_t*>("metadata"), std::strlen("metadata"));
136 discoveryInterestName.append(metadataComponent);
137 auto metadataData = metadata.makeData(discoveryInterestName, m_keyChain, signingByIdentity(m_config.m_caPrefix));
138 return make_shared<Data>(metadataData);
139}
140
141shared_ptr<Data>
142CaModule::generateCaConfigData()
143{
144 // @TODO
145 // make CaInfo Data packet a class member variable m_infoData
146 // check whether the m_infoData is still valid, if not, then generate a new one
147 // otherwise, directly reply m_infoData
Suyong Won19fba4d2020-05-09 13:39:46 -0700148
149 const auto& pib = m_keyChain.getPib();
Suyong Won256c9062020-05-11 02:45:56 -0700150 const auto& identity = pib.getIdentity(m_config.m_caPrefix);
Suyong Won19fba4d2020-05-09 13:39:46 -0700151 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
152 Block contentTLV = INFO::encodeContentFromCAConfig(m_config, cert);
swa77020643ac2020-03-26 02:24:45 -0700153
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700154 Name infoPacketName(m_config.m_caPrefix);
155 infoPacketName.append("CA").append("INFO").appendVersion().appendSegment(0);
156 Data infoData(infoPacketName);
157 infoData.setContent(contentTLV);
158 infoData.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
159 m_keyChain.sign(infoData, signingByIdentity(m_config.m_caPrefix));
160 return make_shared<Data>(infoData);
161}
swa77020643ac2020-03-26 02:24:45 -0700162
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700163void
164CaModule::onInfo(const Interest& request)
165{
166 _LOG_TRACE("Received INFO request");
167
168 if (request.getName().get(-1).type() == 32) {
169 m_face.put(*generateCaConfigMetaData());
170 }
171 else {
172 m_face.put(*generateCaConfigData());
173 }
swa77020643ac2020-03-26 02:24:45 -0700174
175 _LOG_TRACE("Handle INFO: send out the INFO response");
176}
177
178void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700179CaModule::onProbe(const Interest& request)
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800180{
swa77020643ac2020-03-26 02:24:45 -0700181 // PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent]
182 _LOG_TRACE("Received PROBE request");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800183
swa77020643ac2020-03-26 02:24:45 -0700184 // process PROBE requests: find an available name
185 std::string availableId;
Suyong Won19fba4d2020-05-09 13:39:46 -0700186 const auto& parameterTLV = request.getApplicationParameters();
Suyong Won44d0cce2020-05-10 04:07:43 -0700187 parameterTLV.parse();
Suyong Won19fba4d2020-05-09 13:39:46 -0700188 if (!parameterTLV.hasValue()) {
189 _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
swa77020643ac2020-03-26 02:24:45 -0700190 return;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700191 }
swa77020643ac2020-03-26 02:24:45 -0700192 //std::string probeInfoStr = parameterJson.get(JSON_CLIENT_PROBE_INFO, "");
193 if (m_config.m_probeHandler) {
194 try {
Suyong Won19fba4d2020-05-09 13:39:46 -0700195 availableId = m_config.m_probeHandler(parameterTLV);
swa77020643ac2020-03-26 02:24:45 -0700196 }
197 catch (const std::exception& e) {
198 _LOG_TRACE("Cannot find PROBE input from PROBE parameters: " << e.what());
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700199 return;
200 }
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800201 }
swa77020643ac2020-03-26 02:24:45 -0700202 else {
203 // if there is no app-specified name lookup, use a random name id
204 availableId = std::to_string(random::generateSecureWord64());
205 }
Suyong Won256c9062020-05-11 02:45:56 -0700206 Name newIdentityName = m_config.m_caPrefix;
swa77020643ac2020-03-26 02:24:45 -0700207 newIdentityName.append(availableId);
208 _LOG_TRACE("Handle PROBE: generate an identity " << newIdentityName);
Suyong Won44d0cce2020-05-10 04:07:43 -0700209
Suyong Won19fba4d2020-05-09 13:39:46 -0700210 Block contentTLV = PROBE::encodeDataContent(newIdentityName.toUri(), m_config.m_probe, parameterTLV);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800211
212 Data result;
213 result.setName(request.getName());
Suyong Won19fba4d2020-05-09 13:39:46 -0700214 result.setContent(contentTLV);
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700215 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Suyong Won256c9062020-05-11 02:45:56 -0700216 m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800217 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700218 _LOG_TRACE("Handle PROBE: send out the PROBE response");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800219}
220
221void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700222CaModule::onNew(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800223{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700224 // NEW Naming Convention: /<CA-prefix>/CA/NEW/[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();
Suyong Won7968f7a2020-05-12 01:01:25 -0700227 parameterTLV.parse();
228
Suyong Won19fba4d2020-05-09 13:39:46 -0700229 if (!parameterTLV.hasValue()) {
230 _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700231 return;
232 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700233
234 std::string peerKeyBase64 = readString(parameterTLV.get(tlv_ecdh_pub));
235
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700236 if (peerKeyBase64 == "") {
Suyong Won19fba4d2020-05-09 13:39:46 -0700237 _LOG_ERROR("Empty ECDH PUB obtained from the Interest parameter.");
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700238 return;
239 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700240
241 // get server's ECDH pub key
242 auto myEcdhPubKeyBase64 = m_ecdh.getBase64PubKey();
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700243 try {
244 m_ecdh.deriveSecret(peerKeyBase64);
245 }
246 catch (const std::exception& e) {
247 _LOG_ERROR("Cannot derive a shared secret using the provided ECDH key: " << e.what());
248 return;
249 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700250 // generate salt for HKDF
251 auto saltInt = random::generateSecureWord64();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700252 // hkdf
253 hkdf(m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen,
Zhiyi Zhang36706832019-07-04 21:33:03 -0700254 (uint8_t*)&saltInt, sizeof(saltInt), m_aesKey, sizeof(m_aesKey));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700255
256 // parse certificate request
Suyong Won19fba4d2020-05-09 13:39:46 -0700257 Block cert_req = parameterTLV.get(tlv_cert_request);
Suyong Won7968f7a2020-05-12 01:01:25 -0700258 cert_req.parse();
259
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700260 shared_ptr<security::v2::Certificate> clientCert = nullptr;
Suyong Won7968f7a2020-05-12 01:01:25 -0700261
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800262 try {
Suyong Won7968f7a2020-05-12 01:01:25 -0700263 security::v2::Certificate cert = security::v2::Certificate(cert_req.get(tlv::Data));
264 clientCert = make_shared<security::v2::Certificate>(cert);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800265 }
266 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700267 _LOG_ERROR("Unrecognized certificate request: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800268 return;
269 }
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700270 // check the validity period
271 auto expectedPeriod = clientCert->getValidityPeriod().getPeriod();
272 auto currentTime = time::system_clock::now();
273 if (expectedPeriod.first < currentTime - REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD) {
274 _LOG_ERROR("Client requests a too old notBefore timepoint.");
275 return;
276 }
Suyong Won7968f7a2020-05-12 01:01:25 -0700277 if (expectedPeriod.second > currentTime + m_config.m_maxValidityPeriod ||
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700278 expectedPeriod.second <= expectedPeriod.first) {
279 _LOG_ERROR("Client requests an invalid validity period or a notAfter timepoint beyond the allowed time period.");
280 return;
281 }
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700282
Zhiyi Zhang5f749a22019-06-12 17:02:33 -0700283 // verify the self-signed certificate, the request, and the token
Suyong Won256c9062020-05-11 02:45:56 -0700284 if (!m_config.m_caPrefix.isPrefixOf(clientCert->getName()) // under ca prefix
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700285 || !security::v2::Certificate::isValidName(clientCert->getName()) // is valid cert name
Suyong Won256c9062020-05-11 02:45:56 -0700286 || clientCert->getName().size() != m_config.m_caPrefix.size() + IS_SUBNAME_MIN_OFFSET) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700287 _LOG_ERROR("Invalid self-signed certificate name " << clientCert->getName());
288 return;
289 }
290 if (!security::verifySignature(*clientCert, *clientCert)) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700291 _LOG_ERROR("Cert request with bad signature.");
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700292 return;
293 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700294 if (!security::verifySignature(request, *clientCert)) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700295 _LOG_ERROR("Interest with bad signature.");
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700296 return;
297 }
298
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700299 // create new request instance
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800300 std::string requestId = std::to_string(random::generateWord64());
Suyong Won256c9062020-05-11 02:45:56 -0700301 CertificateRequest certRequest(m_config.m_caPrefix, requestId, STATUS_BEFORE_CHALLENGE, *clientCert);
Suyong Won19fba4d2020-05-09 13:39:46 -0700302
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800303 try {
304 m_storage->addRequest(certRequest);
305 }
306 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700307 _LOG_ERROR("Cannot add new request instance into the storage: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800308 return;
309 }
310
311 Data result;
312 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700313 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Suyong Won19fba4d2020-05-09 13:39:46 -0700314 result.setContent(NEW::encodeDataContent(myEcdhPubKeyBase64,
315 std::to_string(saltInt),
316 certRequest,
317 m_config.m_supportedChallenges));
Suyong Won256c9062020-05-11 02:45:56 -0700318 m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800319 m_face.put(result);
Zhiyi Zhanga63b7372017-05-17 14:14:34 -0700320
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700321 if (m_config.m_statusUpdateCallback) {
322 m_config.m_statusUpdateCallback(certRequest);
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800323 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800324}
325
326void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700327CaModule::onChallenge(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800328{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700329 // get certificate request state
330 CertificateRequest certRequest = getCertificateRequest(request);
331 if (certRequest.m_requestId == "") {
332 // cannot get the request state
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700333 _LOG_ERROR("Cannot find certificate request state from CA's storage.");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800334 return;
335 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700336 // verify signature
337 if (!security::verifySignature(request, certRequest.m_cert)) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700338 _LOG_ERROR("Challenge Interest with bad signature.");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800339 return;
340 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700341 // decrypt the parameters
Suyong Won19fba4d2020-05-09 13:39:46 -0700342 Buffer paramTLVPayload;
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700343 try {
Suyong Won19fba4d2020-05-09 13:39:46 -0700344 paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), m_aesKey,
Zhiyi Zhangb8cb0472020-05-05 20:55:05 -0700345 (uint8_t*)"test", strlen("test"));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700346 }
347 catch (const std::exception& e) {
348 _LOG_ERROR("Cannot successfully decrypt the Interest parameters: " << e.what());
349 return;
350 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700351 if (paramTLVPayload.size() == 0) {
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700352 _LOG_ERROR("Got an empty buffer from content decryption.");
353 return;
354 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700355
Suyong Won44d0cce2020-05-10 04:07:43 -0700356 Block paramTLV = makeBinaryBlock(tlv_encrypted_payload, paramTLVPayload.data(), paramTLVPayload.size());
357 paramTLV.parse();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800358
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700359 // load the corresponding challenge module
Suyong Won19fba4d2020-05-09 13:39:46 -0700360 std::string challengeType = readString(paramTLV.get(tlv_selected_challenge));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800361 auto challenge = ChallengeModule::createChallengeModule(challengeType);
Suyong Won19fba4d2020-05-09 13:39:46 -0700362
Suyong Won44d0cce2020-05-10 04:07:43 -0700363 Block payload;
Suyong Won19fba4d2020-05-09 13:39:46 -0700364
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800365 if (challenge == nullptr) {
366 _LOG_TRACE("Unrecognized challenge type " << challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700367 certRequest.m_status = STATUS_FAILURE;
368 certRequest.m_challengeStatus = CHALLENGE_STATUS_UNKNOWN_CHALLENGE;
Suyong Won44d0cce2020-05-10 04:07:43 -0700369 payload = CHALLENGE::encodeDataPayload(certRequest);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800370 }
Zhiyi Zhanga9bda732017-05-20 22:58:55 -0700371 else {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700372 _LOG_TRACE("CHALLENGE module to be load: " << challengeType);
373 // let challenge module handle the request
Suyong Won19fba4d2020-05-09 13:39:46 -0700374 challenge->handleChallengeRequest(paramTLV, certRequest);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700375 if (certRequest.m_status == STATUS_FAILURE) {
376 // if challenge failed
377 m_storage->deleteRequest(certRequest.m_requestId);
Suyong Won44d0cce2020-05-10 04:07:43 -0700378 payload = CHALLENGE::encodeDataPayload(certRequest);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700379 _LOG_TRACE("Challenge failed");
Zhiyi Zhanga9bda732017-05-20 22:58:55 -0700380 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700381 else if (certRequest.m_status == STATUS_PENDING) {
382 // if challenge succeeded
383 auto issuedCert = issueCertificate(certRequest);
384 certRequest.m_cert = issuedCert;
385 certRequest.m_status = STATUS_SUCCESS;
386 try {
387 m_storage->addCertificate(certRequest.m_requestId, issuedCert);
388 m_storage->deleteRequest(certRequest.m_requestId);
389 _LOG_TRACE("New Certificate Issued " << issuedCert.getName());
390 }
391 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700392 _LOG_ERROR("Cannot add issued cert and remove the request: " << e.what());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700393 return;
394 }
395 if (m_config.m_statusUpdateCallback) {
396 m_config.m_statusUpdateCallback(certRequest);
397 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700398
Suyong Won44d0cce2020-05-10 04:07:43 -0700399 payload = CHALLENGE::encodeDataPayload(certRequest);
400 payload.parse();
401 payload.push_back(makeNestedBlock(tlv_issued_cert_name, issuedCert.getName()));
402 payload.encode();
Suyong Won19fba4d2020-05-09 13:39:46 -0700403
404 //contentJson.add(JSON_CA_CERT_ID, readString(issuedCert.getName().at(-1)));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700405 _LOG_TRACE("Challenge succeeded. Certificate has been issued");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800406 }
407 else {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700408 try {
409 m_storage->updateRequest(certRequest);
410 }
411 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700412 _LOG_TRACE("Cannot update request instance: " << e.what());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700413 return;
414 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700415 payload = CHALLENGE::encodeDataPayload(certRequest);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700416 _LOG_TRACE("No failure no success. Challenge moves on");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800417 }
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800418 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700419
420 Data result;
421 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700422 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700423
424 // encrypt the content
Suyong Won7968f7a2020-05-12 01:01:25 -0700425 auto contentBlock = encodeBlockWithAesGcm128(tlv::Content, m_aesKey, payload.value(),
426 payload.value_size(), (uint8_t*)"test", strlen("test"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700427 result.setContent(contentBlock);
Suyong Won256c9062020-05-11 02:45:56 -0700428 m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700429 m_face.put(result);
430
431 if (m_config.m_statusUpdateCallback) {
432 m_config.m_statusUpdateCallback(certRequest);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800433 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700434}
435
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800436security::v2::Certificate
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700437CaModule::issueCertificate(const CertificateRequest& certRequest)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800438{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700439 auto expectedPeriod =
440 certRequest.m_cert.getValidityPeriod().getPeriod();
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700441 security::ValidityPeriod period(expectedPeriod.first, expectedPeriod.second);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800442 security::v2::Certificate newCert;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700443
444 Name certName = certRequest.m_cert.getKeyName();
445 certName.append("NDNCERT").append(std::to_string(random::generateSecureWord64()));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800446 newCert.setName(certName);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700447 newCert.setContent(certRequest.m_cert.getContent());
448 _LOG_TRACE("cert request content " << certRequest.m_cert);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800449 SignatureInfo signatureInfo;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800450 signatureInfo.setValidityPeriod(period);
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700451 security::SigningInfo signingInfo(security::SigningInfo::SIGNER_TYPE_ID,
Suyong Won256c9062020-05-11 02:45:56 -0700452 m_config.m_caPrefix, signatureInfo);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800453
454 m_keyChain.sign(newCert, signingInfo);
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700455 _LOG_TRACE("new cert got signed" << newCert);
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800456 return newCert;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800457}
458
459CertificateRequest
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700460CaModule::getCertificateRequest(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800461{
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400462 std::string requestId;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800463 CertificateRequest certRequest;
464 try {
Suyong Won256c9062020-05-11 02:45:56 -0700465 requestId = readString(request.getName().at(m_config.m_caPrefix.size() + 2));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700466 }
467 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700468 _LOG_ERROR("Cannot read the request ID out from the request: " << e.what());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700469 }
470 try {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700471 _LOG_TRACE("Request Id to query the database " << requestId);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800472 certRequest = m_storage->getRequest(requestId);
473 }
474 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700475 _LOG_ERROR("Cannot get certificate request record from the storage: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800476 }
477 return certRequest;
478}
479
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700480<<<<<<< HEAD
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700481/**
482 * @brief Generate JSON file to response PROBE insterest
483 *
484 * PROBE response JSON format:
485 * {
Yufeng Zhang424d0362019-06-12 16:48:27 -0700486 * "name": "@p identifier"
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700487 * }
488 */
swa77020643ac2020-03-26 02:24:45 -0700489JsonSection
Yufeng Zhang424d0362019-06-12 16:48:27 -0700490CaModule::genProbeResponseJson(const Name& identifier, const std::string& m_probe, const JsonSection& parameterJson)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700491{
Zhiyi Zhang781a5602019-06-26 19:05:04 -0700492 std::vector<std::string> fields;
493 std::string delimiter = ":";
494 size_t last = 0;
495 size_t next = 0;
496 while ((next = m_probe.find(delimiter, last)) != std::string::npos) {
497 fields.push_back(m_probe.substr(last, next - last));
498 last = next + 1;
499 }
500 fields.push_back(m_probe.substr(last));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700501 JsonSection root;
Yufeng Zhang424d0362019-06-12 16:48:27 -0700502
503 for (size_t i = 0; i < fields.size(); ++i) {
Zhiyi Zhang781a5602019-06-26 19:05:04 -0700504 root.put(fields.at(i), parameterJson.get(fields.at(i), ""));
Yufeng Zhang424d0362019-06-12 16:48:27 -0700505 }
506
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700507 root.put(JSON_CA_NAME, identifier.toUri());
508 return root;
509}
510
511/**
512 * @brief Generate JSON file to response NEW interest
513 *
514 * Target JSON format:
515 * {
516 * "ecdh-pub": "@p echdPub",
517 * "salt": "@p salt"
518 * "request-id": "@p requestId",
519 * "status": "@p status",
520 * "challenges": [
521 * {
522 * "challenge-id": ""
523 * },
524 * {
525 * "challenge-id": ""
526 * },
527 * ...
528 * ]
529 * }
530 */
swa77020643ac2020-03-26 02:24:45 -0700531JsonSection
532CaModule::genInfoResponseJson()
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700533{
534 JsonSection root;
535 // ca-prefix
Suyong Won256c9062020-05-11 02:45:56 -0700536 Name caName = m_config.m_caPrefix;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700537 root.put("ca-prefix", caName.toUri());
538
539 // ca-info
540 const auto& pib = m_keyChain.getPib();
Suyong Won256c9062020-05-11 02:45:56 -0700541 const auto& identity = pib.getIdentity(m_config.m_caPrefix);
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700542 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400543 std::string caInfo;
544 if (m_config.m_caInfo.empty()) {
545 caInfo = "Issued by " + cert.getSignatureInfo().getKeyLocator().getName().toUri();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700546 }
547 else {
548 caInfo = m_config.m_caInfo;
549 }
550 root.put("ca-info", caInfo);
551
552 // probe
553 root.put("probe", m_config.m_probe);
554
555 // certificate
556 std::stringstream ss;
557 io::save(cert, ss);
558 root.put("certificate", ss.str());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700559 return root;
560}
561
swa77020643ac2020-03-26 02:24:45 -0700562JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700563CaModule::genNewResponseJson(const std::string& ecdhKey, const std::string& salt,
564 const CertificateRequest& request,
565 const std::list<std::string>& challenges)
566{
567 JsonSection root;
568 JsonSection challengesSection;
569 root.put(JSON_CA_ECDH, ecdhKey);
570 root.put(JSON_CA_SALT, salt);
Zhiyi Zhangff4bcb62019-09-08 12:57:42 -0700571 root.put(JSON_CA_REQUEST_ID, request.m_requestId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700572 root.put(JSON_CA_STATUS, std::to_string(request.m_status));
573
574 for (const auto& entry : challenges) {
575 JsonSection challenge;
576 challenge.put(JSON_CA_CHALLENGE_ID, entry);
577 challengesSection.push_back(std::make_pair("", challenge));
578 }
579 root.add_child(JSON_CA_CHALLENGES, challengesSection);
580 return root;
581}
582
swa77020643ac2020-03-26 02:24:45 -0700583JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700584CaModule::genChallengeResponseJson(const CertificateRequest& request)
585{
586 JsonSection root;
587 JsonSection challengesSection;
588 root.put(JSON_CA_STATUS, request.m_status);
589 root.put(JSON_CHALLENGE_STATUS, request.m_challengeStatus);
590 root.put(JSON_CHALLENGE_REMAINING_TRIES, std::to_string(request.m_remainingTries));
591 root.put(JSON_CHALLENGE_REMAINING_TIME, std::to_string(request.m_remainingTime));
592 return root;
593}
594
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700595=======
596>>>>>>> add two functions for CA Info Packet and Metadata Packet
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800597void
598CaModule::onRegisterFailed(const std::string& reason)
599{
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700600 _LOG_ERROR("Failed to register prefix in local hub's daemon, REASON: " << reason);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800601}
602
603Block
604CaModule::dataContentFromJson(const JsonSection& jsonSection)
605{
606 std::stringstream ss;
607 boost::property_tree::write_json(ss, jsonSection);
608 return makeStringBlock(ndn::tlv::Content, ss.str());
609}
610
611JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700612CaModule::jsonFromBlock(const Block& block)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800613{
614 std::string jsonString;
615 try {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700616 jsonString = encoding::readString(block);
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700617 std::istringstream ss(jsonString);
618 JsonSection json;
619 boost::property_tree::json_parser::read_json(ss, json);
620 return json;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800621 }
622 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700623 _LOG_ERROR("Cannot read JSON string from TLV Value: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800624 return JsonSection();
625 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800626}
627
628} // namespace ndncert
629} // namespace ndn