blob: 4398de719bf4d8b957fb2a836e9565f5dbdbf498 [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 Zhangf5246c42017-01-26 09:39:20 -080033
34namespace ndn {
35namespace ndncert {
36
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070037static const int IS_SUBNAME_MIN_OFFSET = 5;
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)
45 : m_face(face)
46 , m_keyChain(keyChain)
47{
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 Zhangaf7c2902019-03-14 22:13:21 -070057 for (auto handle : m_interestFilterHandles) {
58 handle.cancel();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080059 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070060 for (auto handle : m_registeredPrefixHandles) {
61 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
77 Name prefix = m_config.m_caName;
78 prefix.append("CA");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080079
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070080 prefixId = m_face.registerPrefix(prefix,
81 [&] (const Name& name) {
swa77020643ac2020-03-26 02:24:45 -070082 // register INFO prefix
83 auto filterId = m_face.setInterestFilter(Name(name).append("INFO"),
84 bind(&CaModule::onInfo, this, _2));
85 m_interestFilterHandles.push_back(filterId);
86
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070087 // register PROBE prefix
swa77020643ac2020-03-26 02:24:45 -070088 filterId = m_face.setInterestFilter(Name(name).append("PROBE"),
89 bind(&CaModule::onProbe, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070090 m_interestFilterHandles.push_back(filterId);
91
92 // register NEW prefix
swa770de007bc2020-03-24 21:26:21 -070093 filterId = m_face.setInterestFilter(Name(name).append("NEW"),
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070094 bind(&CaModule::onNew, this, _2));
95 m_interestFilterHandles.push_back(filterId);
96
97 // register SELECT prefix
swa770de007bc2020-03-24 21:26:21 -070098 filterId = m_face.setInterestFilter(Name(name).append("CHALLENGE"),
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070099 bind(&CaModule::onChallenge, this, _2));
100 m_interestFilterHandles.push_back(filterId);
101
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700102 _LOG_TRACE("Prefix " << name << " got registered");
103 },
104 bind(&CaModule::onRegisterFailed, this, _2));
105 m_registeredPrefixHandles.push_back(prefixId);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800106}
107
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800108bool
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700109CaModule::setProbeHandler(const ProbeHandler& handler)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800110{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700111 m_config.m_probeHandler = handler;
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800112 return false;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800113}
114
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800115bool
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700116CaModule::setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800117{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700118 m_config.m_statusUpdateCallback = onUpdateCallback;
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800119 return false;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800120}
121
122void
swa77020643ac2020-03-26 02:24:45 -0700123CaModule::onInfo(const Interest& request)
124{
125 _LOG_TRACE("Received INFO request");
Suyong Won19fba4d2020-05-09 13:39:46 -0700126
127 const auto& pib = m_keyChain.getPib();
128 const auto& identity = pib.getIdentity(m_config.m_caName);
129 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
130 Block contentTLV = INFO::encodeContentFromCAConfig(m_config, cert);
swa77020643ac2020-03-26 02:24:45 -0700131 Data result;
132
133 result.setName(request.getName());
Suyong Won57462ca2020-05-05 22:20:09 -0700134 result.setContent(contentTLV);
swa77020643ac2020-03-26 02:24:45 -0700135 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
136
137 m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
138 m_face.put(result);
139
140 _LOG_TRACE("Handle INFO: send out the INFO response");
141}
142
143void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700144CaModule::onProbe(const Interest& request)
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800145{
swa77020643ac2020-03-26 02:24:45 -0700146 // PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent]
147 _LOG_TRACE("Received PROBE request");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800148
swa77020643ac2020-03-26 02:24:45 -0700149 // process PROBE requests: find an available name
150 std::string availableId;
Suyong Won19fba4d2020-05-09 13:39:46 -0700151 const auto& parameterTLV = request.getApplicationParameters();
Suyong Won44d0cce2020-05-10 04:07:43 -0700152 parameterTLV.parse();
Suyong Won19fba4d2020-05-09 13:39:46 -0700153 if (!parameterTLV.hasValue()) {
154 _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
swa77020643ac2020-03-26 02:24:45 -0700155 return;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700156 }
swa77020643ac2020-03-26 02:24:45 -0700157 //std::string probeInfoStr = parameterJson.get(JSON_CLIENT_PROBE_INFO, "");
158 if (m_config.m_probeHandler) {
159 try {
Suyong Won19fba4d2020-05-09 13:39:46 -0700160 availableId = m_config.m_probeHandler(parameterTLV);
swa77020643ac2020-03-26 02:24:45 -0700161 }
162 catch (const std::exception& e) {
163 _LOG_TRACE("Cannot find PROBE input from PROBE parameters: " << e.what());
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700164 return;
165 }
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800166 }
swa77020643ac2020-03-26 02:24:45 -0700167 else {
168 // if there is no app-specified name lookup, use a random name id
169 availableId = std::to_string(random::generateSecureWord64());
170 }
171 Name newIdentityName = m_config.m_caName;
172 newIdentityName.append(availableId);
173 _LOG_TRACE("Handle PROBE: generate an identity " << newIdentityName);
Suyong Won44d0cce2020-05-10 04:07:43 -0700174
Suyong Won19fba4d2020-05-09 13:39:46 -0700175 Block contentTLV = PROBE::encodeDataContent(newIdentityName.toUri(), m_config.m_probe, parameterTLV);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800176
177 Data result;
178 result.setName(request.getName());
Suyong Won19fba4d2020-05-09 13:39:46 -0700179 result.setContent(contentTLV);
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700180 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700181 m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800182 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700183 _LOG_TRACE("Handle PROBE: send out the PROBE response");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800184}
185
186void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700187CaModule::onNew(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800188{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700189 // NEW Naming Convention: /<CA-prefix>/CA/NEW/[SignedInterestParameters_Digest]
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700190 // get ECDH pub key and cert request
Suyong Won19fba4d2020-05-09 13:39:46 -0700191 const auto& parameterTLV = request.getApplicationParameters();
192 if (!parameterTLV.hasValue()) {
193 _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700194 return;
195 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700196
197 std::string peerKeyBase64 = readString(parameterTLV.get(tlv_ecdh_pub));
198
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700199 if (peerKeyBase64 == "") {
Suyong Won19fba4d2020-05-09 13:39:46 -0700200 _LOG_ERROR("Empty ECDH PUB obtained from the Interest parameter.");
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700201 return;
202 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700203
204 // get server's ECDH pub key
205 auto myEcdhPubKeyBase64 = m_ecdh.getBase64PubKey();
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700206 try {
207 m_ecdh.deriveSecret(peerKeyBase64);
208 }
209 catch (const std::exception& e) {
210 _LOG_ERROR("Cannot derive a shared secret using the provided ECDH key: " << e.what());
211 return;
212 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700213 // generate salt for HKDF
214 auto saltInt = random::generateSecureWord64();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700215 // hkdf
216 hkdf(m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen,
Zhiyi Zhang36706832019-07-04 21:33:03 -0700217 (uint8_t*)&saltInt, sizeof(saltInt), m_aesKey, sizeof(m_aesKey));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700218
219 // parse certificate request
Suyong Won19fba4d2020-05-09 13:39:46 -0700220 Block cert_req = parameterTLV.get(tlv_cert_request);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700221 shared_ptr<security::v2::Certificate> clientCert = nullptr;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800222 try {
Suyong Won19fba4d2020-05-09 13:39:46 -0700223 clientCert->wireDecode(cert_req);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800224 }
225 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700226 _LOG_ERROR("Unrecognized certificate request: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800227 return;
228 }
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700229 // check the validity period
230 auto expectedPeriod = clientCert->getValidityPeriod().getPeriod();
231 auto currentTime = time::system_clock::now();
232 if (expectedPeriod.first < currentTime - REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD) {
233 _LOG_ERROR("Client requests a too old notBefore timepoint.");
234 return;
235 }
236 if (expectedPeriod.second > currentTime + m_config.m_validityPeriod ||
237 expectedPeriod.second <= expectedPeriod.first) {
238 _LOG_ERROR("Client requests an invalid validity period or a notAfter timepoint beyond the allowed time period.");
239 return;
240 }
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700241
Zhiyi Zhang5f749a22019-06-12 17:02:33 -0700242 // verify the self-signed certificate, the request, and the token
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700243 if (!m_config.m_caName.isPrefixOf(clientCert->getName()) // under ca prefix
244 || !security::v2::Certificate::isValidName(clientCert->getName()) // is valid cert name
245 || clientCert->getName().size() != m_config.m_caName.size() + IS_SUBNAME_MIN_OFFSET) {
246 _LOG_ERROR("Invalid self-signed certificate name " << clientCert->getName());
247 return;
248 }
249 if (!security::verifySignature(*clientCert, *clientCert)) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700250 _LOG_ERROR("Cert request with bad signature.");
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700251 return;
252 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700253 if (!security::verifySignature(request, *clientCert)) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700254 _LOG_ERROR("Interest with bad signature.");
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700255 return;
256 }
257
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700258 // create new request instance
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800259 std::string requestId = std::to_string(random::generateWord64());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700260 CertificateRequest certRequest(m_config.m_caName, requestId, STATUS_BEFORE_CHALLENGE, *clientCert);
Suyong Won19fba4d2020-05-09 13:39:46 -0700261
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800262 try {
263 m_storage->addRequest(certRequest);
264 }
265 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700266 _LOG_ERROR("Cannot add new request instance into the storage: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800267 return;
268 }
269
270 Data result;
271 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700272 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Suyong Won19fba4d2020-05-09 13:39:46 -0700273 result.setContent(NEW::encodeDataContent(myEcdhPubKeyBase64,
274 std::to_string(saltInt),
275 certRequest,
276 m_config.m_supportedChallenges));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700277 m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800278 m_face.put(result);
Zhiyi Zhanga63b7372017-05-17 14:14:34 -0700279
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700280 if (m_config.m_statusUpdateCallback) {
281 m_config.m_statusUpdateCallback(certRequest);
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800282 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800283}
284
285void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700286CaModule::onChallenge(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800287{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700288 // get certificate request state
289 CertificateRequest certRequest = getCertificateRequest(request);
290 if (certRequest.m_requestId == "") {
291 // cannot get the request state
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700292 _LOG_ERROR("Cannot find certificate request state from CA's storage.");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800293 return;
294 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700295 // verify signature
296 if (!security::verifySignature(request, certRequest.m_cert)) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700297 _LOG_ERROR("Challenge Interest with bad signature.");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800298 return;
299 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700300 // decrypt the parameters
Suyong Won19fba4d2020-05-09 13:39:46 -0700301 Buffer paramTLVPayload;
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700302 try {
Suyong Won19fba4d2020-05-09 13:39:46 -0700303 paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), m_aesKey,
Zhiyi Zhangb8cb0472020-05-05 20:55:05 -0700304 (uint8_t*)"test", strlen("test"));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700305 }
306 catch (const std::exception& e) {
307 _LOG_ERROR("Cannot successfully decrypt the Interest parameters: " << e.what());
308 return;
309 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700310 if (paramTLVPayload.size() == 0) {
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700311 _LOG_ERROR("Got an empty buffer from content decryption.");
312 return;
313 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700314
Suyong Won44d0cce2020-05-10 04:07:43 -0700315 Block paramTLV = makeBinaryBlock(tlv_encrypted_payload, paramTLVPayload.data(), paramTLVPayload.size());
316 paramTLV.parse();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800317
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700318 // load the corresponding challenge module
Suyong Won19fba4d2020-05-09 13:39:46 -0700319 std::string challengeType = readString(paramTLV.get(tlv_selected_challenge));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800320 auto challenge = ChallengeModule::createChallengeModule(challengeType);
Suyong Won19fba4d2020-05-09 13:39:46 -0700321
Suyong Won44d0cce2020-05-10 04:07:43 -0700322 Block payload;
Suyong Won19fba4d2020-05-09 13:39:46 -0700323
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800324 if (challenge == nullptr) {
325 _LOG_TRACE("Unrecognized challenge type " << challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700326 certRequest.m_status = STATUS_FAILURE;
327 certRequest.m_challengeStatus = CHALLENGE_STATUS_UNKNOWN_CHALLENGE;
Suyong Won44d0cce2020-05-10 04:07:43 -0700328 payload = CHALLENGE::encodeDataPayload(certRequest);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800329 }
Zhiyi Zhanga9bda732017-05-20 22:58:55 -0700330 else {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700331 _LOG_TRACE("CHALLENGE module to be load: " << challengeType);
332 // let challenge module handle the request
Suyong Won19fba4d2020-05-09 13:39:46 -0700333 challenge->handleChallengeRequest(paramTLV, certRequest);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700334 if (certRequest.m_status == STATUS_FAILURE) {
335 // if challenge failed
336 m_storage->deleteRequest(certRequest.m_requestId);
Suyong Won44d0cce2020-05-10 04:07:43 -0700337 payload = CHALLENGE::encodeDataPayload(certRequest);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700338 _LOG_TRACE("Challenge failed");
Zhiyi Zhanga9bda732017-05-20 22:58:55 -0700339 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700340 else if (certRequest.m_status == STATUS_PENDING) {
341 // if challenge succeeded
342 auto issuedCert = issueCertificate(certRequest);
343 certRequest.m_cert = issuedCert;
344 certRequest.m_status = STATUS_SUCCESS;
345 try {
346 m_storage->addCertificate(certRequest.m_requestId, issuedCert);
347 m_storage->deleteRequest(certRequest.m_requestId);
348 _LOG_TRACE("New Certificate Issued " << issuedCert.getName());
349 }
350 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700351 _LOG_ERROR("Cannot add issued cert and remove the request: " << e.what());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700352 return;
353 }
354 if (m_config.m_statusUpdateCallback) {
355 m_config.m_statusUpdateCallback(certRequest);
356 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700357
Suyong Won44d0cce2020-05-10 04:07:43 -0700358 payload = CHALLENGE::encodeDataPayload(certRequest);
359 payload.parse();
360 payload.push_back(makeNestedBlock(tlv_issued_cert_name, issuedCert.getName()));
361 payload.encode();
Suyong Won19fba4d2020-05-09 13:39:46 -0700362
363 //contentJson.add(JSON_CA_CERT_ID, readString(issuedCert.getName().at(-1)));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700364 _LOG_TRACE("Challenge succeeded. Certificate has been issued");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800365 }
366 else {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700367 try {
368 m_storage->updateRequest(certRequest);
369 }
370 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700371 _LOG_TRACE("Cannot update request instance: " << e.what());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700372 return;
373 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700374 payload = CHALLENGE::encodeDataPayload(certRequest);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700375 _LOG_TRACE("No failure no success. Challenge moves on");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800376 }
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800377 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700378
379 Data result;
380 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700381 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700382
383 // encrypt the content
Suyong Won44d0cce2020-05-10 04:07:43 -0700384 auto payloadBuffer = payload.getBuffer();
385 auto contentBlock = encodeBlockWithAesGcm128(tlv::Content, m_aesKey, payloadBuffer->data(),
386 payloadBuffer->size(), (uint8_t*)"test", strlen("test"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700387 result.setContent(contentBlock);
388 m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
389 m_face.put(result);
390
391 if (m_config.m_statusUpdateCallback) {
392 m_config.m_statusUpdateCallback(certRequest);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800393 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700394}
395
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800396security::v2::Certificate
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700397CaModule::issueCertificate(const CertificateRequest& certRequest)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800398{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700399 auto expectedPeriod =
400 certRequest.m_cert.getValidityPeriod().getPeriod();
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700401 security::ValidityPeriod period(expectedPeriod.first, expectedPeriod.second);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800402 security::v2::Certificate newCert;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700403
404 Name certName = certRequest.m_cert.getKeyName();
405 certName.append("NDNCERT").append(std::to_string(random::generateSecureWord64()));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800406 newCert.setName(certName);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700407 newCert.setContent(certRequest.m_cert.getContent());
408 _LOG_TRACE("cert request content " << certRequest.m_cert);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800409 SignatureInfo signatureInfo;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800410 signatureInfo.setValidityPeriod(period);
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700411 security::SigningInfo signingInfo(security::SigningInfo::SIGNER_TYPE_ID,
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700412 m_config.m_caName, signatureInfo);
413 newCert.setFreshnessPeriod(m_config.m_freshnessPeriod);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800414
415 m_keyChain.sign(newCert, signingInfo);
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700416 _LOG_TRACE("new cert got signed" << newCert);
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800417 return newCert;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800418}
419
420CertificateRequest
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700421CaModule::getCertificateRequest(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800422{
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400423 std::string requestId;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800424 CertificateRequest certRequest;
425 try {
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700426 requestId = readString(request.getName().at(m_config.m_caName.size() + 2));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700427 }
428 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700429 _LOG_ERROR("Cannot read the request ID out from the request: " << e.what());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700430 }
431 try {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700432 _LOG_TRACE("Request Id to query the database " << requestId);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800433 certRequest = m_storage->getRequest(requestId);
434 }
435 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700436 _LOG_ERROR("Cannot get certificate request record from the storage: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800437 }
438 return certRequest;
439}
440
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700441/**
442 * @brief Generate JSON file to response PROBE insterest
443 *
444 * PROBE response JSON format:
445 * {
Yufeng Zhang424d0362019-06-12 16:48:27 -0700446 * "name": "@p identifier"
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700447 * }
448 */
swa77020643ac2020-03-26 02:24:45 -0700449JsonSection
Yufeng Zhang424d0362019-06-12 16:48:27 -0700450CaModule::genProbeResponseJson(const Name& identifier, const std::string& m_probe, const JsonSection& parameterJson)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700451{
Zhiyi Zhang781a5602019-06-26 19:05:04 -0700452 std::vector<std::string> fields;
453 std::string delimiter = ":";
454 size_t last = 0;
455 size_t next = 0;
456 while ((next = m_probe.find(delimiter, last)) != std::string::npos) {
457 fields.push_back(m_probe.substr(last, next - last));
458 last = next + 1;
459 }
460 fields.push_back(m_probe.substr(last));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700461 JsonSection root;
Yufeng Zhang424d0362019-06-12 16:48:27 -0700462
463 for (size_t i = 0; i < fields.size(); ++i) {
Zhiyi Zhang781a5602019-06-26 19:05:04 -0700464 root.put(fields.at(i), parameterJson.get(fields.at(i), ""));
Yufeng Zhang424d0362019-06-12 16:48:27 -0700465 }
466
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700467 root.put(JSON_CA_NAME, identifier.toUri());
468 return root;
469}
470
471/**
472 * @brief Generate JSON file to response NEW interest
473 *
474 * Target JSON format:
475 * {
476 * "ecdh-pub": "@p echdPub",
477 * "salt": "@p salt"
478 * "request-id": "@p requestId",
479 * "status": "@p status",
480 * "challenges": [
481 * {
482 * "challenge-id": ""
483 * },
484 * {
485 * "challenge-id": ""
486 * },
487 * ...
488 * ]
489 * }
490 */
swa77020643ac2020-03-26 02:24:45 -0700491JsonSection
492CaModule::genInfoResponseJson()
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700493{
494 JsonSection root;
495 // ca-prefix
496 Name caName = m_config.m_caName;
497 root.put("ca-prefix", caName.toUri());
498
499 // ca-info
500 const auto& pib = m_keyChain.getPib();
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700501 const auto& identity = pib.getIdentity(m_config.m_caName);
502 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400503 std::string caInfo;
504 if (m_config.m_caInfo.empty()) {
505 caInfo = "Issued by " + cert.getSignatureInfo().getKeyLocator().getName().toUri();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700506 }
507 else {
508 caInfo = m_config.m_caInfo;
509 }
510 root.put("ca-info", caInfo);
511
512 // probe
513 root.put("probe", m_config.m_probe);
514
515 // certificate
516 std::stringstream ss;
517 io::save(cert, ss);
518 root.put("certificate", ss.str());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700519 return root;
520}
521
swa77020643ac2020-03-26 02:24:45 -0700522JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700523CaModule::genNewResponseJson(const std::string& ecdhKey, const std::string& salt,
524 const CertificateRequest& request,
525 const std::list<std::string>& challenges)
526{
527 JsonSection root;
528 JsonSection challengesSection;
529 root.put(JSON_CA_ECDH, ecdhKey);
530 root.put(JSON_CA_SALT, salt);
Zhiyi Zhangff4bcb62019-09-08 12:57:42 -0700531 root.put(JSON_CA_REQUEST_ID, request.m_requestId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700532 root.put(JSON_CA_STATUS, std::to_string(request.m_status));
533
534 for (const auto& entry : challenges) {
535 JsonSection challenge;
536 challenge.put(JSON_CA_CHALLENGE_ID, entry);
537 challengesSection.push_back(std::make_pair("", challenge));
538 }
539 root.add_child(JSON_CA_CHALLENGES, challengesSection);
540 return root;
541}
542
swa77020643ac2020-03-26 02:24:45 -0700543JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700544CaModule::genChallengeResponseJson(const CertificateRequest& request)
545{
546 JsonSection root;
547 JsonSection challengesSection;
548 root.put(JSON_CA_STATUS, request.m_status);
549 root.put(JSON_CHALLENGE_STATUS, request.m_challengeStatus);
550 root.put(JSON_CHALLENGE_REMAINING_TRIES, std::to_string(request.m_remainingTries));
551 root.put(JSON_CHALLENGE_REMAINING_TIME, std::to_string(request.m_remainingTime));
552 return root;
553}
554
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800555void
556CaModule::onRegisterFailed(const std::string& reason)
557{
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700558 _LOG_ERROR("Failed to register prefix in local hub's daemon, REASON: " << reason);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800559}
560
561Block
562CaModule::dataContentFromJson(const JsonSection& jsonSection)
563{
564 std::stringstream ss;
565 boost::property_tree::write_json(ss, jsonSection);
566 return makeStringBlock(ndn::tlv::Content, ss.str());
567}
568
569JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700570CaModule::jsonFromBlock(const Block& block)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800571{
572 std::string jsonString;
573 try {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700574 jsonString = encoding::readString(block);
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700575 std::istringstream ss(jsonString);
576 JsonSection json;
577 boost::property_tree::json_parser::read_json(ss, json);
578 return json;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800579 }
580 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700581 _LOG_ERROR("Cannot read JSON string from TLV Value: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800582 return JsonSection();
583 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800584}
585
586} // namespace ndncert
587} // namespace ndn