blob: 7a575a9a73a89cb2d7ef06f411b864ff2111c6ea [file] [log] [blame]
Zhiyi Zhangf5246c42017-01-26 09:39:20 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -07003 * Copyright (c) 2017-2019, 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"
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080025#include <ndn-cxx/util/io.hpp>
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080026#include <ndn-cxx/security/verification-helpers.hpp>
27#include <ndn-cxx/security/signing-helpers.hpp>
Junxiao Shi7c068032017-05-28 13:40:47 +000028#include <ndn-cxx/util/random.hpp>
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080029
30namespace ndn {
31namespace ndncert {
32
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070033static const int IS_SUBNAME_MIN_OFFSET = 5;
34
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080035_LOG_INIT(ndncert.ca);
36
37CaModule::CaModule(Face& face, security::v2::KeyChain& keyChain,
38 const std::string& configPath, const std::string& storageType)
39 : m_face(face)
40 , m_keyChain(keyChain)
41{
Zhiyi Zhanga63b7372017-05-17 14:14:34 -070042 // load the config and create storage
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080043 m_config.load(configPath);
44 m_storage = CaStorage::createCaStorage(storageType);
45
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080046 registerPrefix();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080047}
48
49CaModule::~CaModule()
50{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070051 for (auto handle : m_interestFilterHandles) {
52 handle.cancel();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080053 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070054 for (auto handle : m_registeredPrefixHandles) {
55 handle.unregister();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080056 }
57}
58
59void
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080060CaModule::registerPrefix()
61{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070062 // register localhop discovery prefix
63 Name localhopProbePrefix("/localhop/CA/PROBE/INFO");
64 auto prefixId = m_face.setInterestFilter(InterestFilter(localhopProbePrefix),
65 bind(&CaModule::onProbe, this, _2),
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080066 bind(&CaModule::onRegisterFailed, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070067 m_registeredPrefixHandles.push_back(prefixId);
68 _LOG_TRACE("Prefix " << localhopProbePrefix << " got registered");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080069
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070070 // register prefixes
71 Name prefix = m_config.m_caName;
72 prefix.append("CA");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080073
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070074 prefixId = m_face.registerPrefix(prefix,
75 [&] (const Name& name) {
76 // register PROBE prefix
77 auto filterId = m_face.setInterestFilter(Name(name).append("_PROBE"),
78 bind(&CaModule::onProbe, this, _2));
79 m_interestFilterHandles.push_back(filterId);
80
81 // register NEW prefix
82 filterId = m_face.setInterestFilter(Name(name).append("_NEW"),
83 bind(&CaModule::onNew, this, _2));
84 m_interestFilterHandles.push_back(filterId);
85
86 // register SELECT prefix
87 filterId = m_face.setInterestFilter(Name(name).append("_CHALLENGE"),
88 bind(&CaModule::onChallenge, this, _2));
89 m_interestFilterHandles.push_back(filterId);
90
91 // register DOWNLOAD prefix
92 filterId = m_face.setInterestFilter(Name(name).append("_DOWNLOAD"),
93 bind(&CaModule::onDownload, this, _2));
94 m_interestFilterHandles.push_back(filterId);
95 _LOG_TRACE("Prefix " << name << " got registered");
96 },
97 bind(&CaModule::onRegisterFailed, this, _2));
98 m_registeredPrefixHandles.push_back(prefixId);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080099}
100
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800101bool
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700102CaModule::setProbeHandler(const ProbeHandler& handler)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800103{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700104 m_config.m_probeHandler = handler;
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800105 return false;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800106}
107
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800108bool
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700109CaModule::setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800110{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700111 m_config.m_statusUpdateCallback = onUpdateCallback;
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800112 return false;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800113}
114
115void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700116CaModule::onProbe(const Interest& request)
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800117{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700118 // PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent|INFO]
119 _LOG_TRACE("Receive PROBE request");
120 JsonSection contentJson;
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800121
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700122 // process PROBE INFO requests
123 if (readString(request.getName().at(-1)) == "INFO") {
124 contentJson = genProbeResponseJson();
125 }
126 else {
127 // if not a PROBE INFO, find an available name
128 std::string availableId = "";
129 const auto& parameterJson = jsonFromBlock(request.getApplicationParameters());
130 std::string probeInfoStr = parameterJson.get(JSON_CLIENT_PROBE_INFO, "");
131 if (m_config.m_probeHandler) {
132 try {
133 availableId = m_config.m_probeHandler(probeInfoStr);
134 }
135 catch (const std::exception& e) {
136 _LOG_TRACE("Cannot find PROBE input from PROBE parameters " << e.what());
137 return;
138 }
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800139 }
140 else {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700141 // if there is no app-specified name lookup, use a random name id
142 availableId = std::to_string(random::generateSecureWord64());
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800143 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700144 Name newIdentityName = m_config.m_caName;
145 _LOG_TRACE("Handle PROBE: generate an identity " << newIdentityName);
146 newIdentityName.append(availableId);
147 contentJson = genProbeResponseJson(newIdentityName.toUri());
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800148 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800149
150 Data result;
151 result.setName(request.getName());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700152 result.setContent(dataContentFromJson(contentJson));
153 m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800154 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700155 _LOG_TRACE("Handle PROBE: send out the PROBE response");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800156}
157
158void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700159CaModule::onNew(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800160{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700161 // NEW Naming Convention: /<CA-prefix>/CA/NEW/[SignedInterestParameters_Digest]
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800162
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700163 // get ECDH pub key and cert request
164 const auto& parameterJson = jsonFromBlock(request.getApplicationParameters());
165 std::string peerKeyBase64 = parameterJson.get(JSON_CLIENT_ECDH, "");
166
167 // get server's ECDH pub key
168 auto myEcdhPubKeyBase64 = m_ecdh.getBase64PubKey();
169 m_ecdh.deriveSecret(peerKeyBase64);
170 // generate salt for HKDF
171 auto saltInt = random::generateSecureWord64();
172 uint8_t salt[sizeof(saltInt)];
173 std::memcpy(salt, &saltInt, sizeof(saltInt));
174 // hkdf
175 hkdf(m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen,
176 salt, sizeof(saltInt), m_aesKey, 32);
177
178 // parse certificate request
179 std::string certRequestStr = parameterJson.get(JSON_CLIENT_CERT_REQ, "");
180 shared_ptr<security::v2::Certificate> clientCert = nullptr;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800181 try {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700182 std::stringstream ss(certRequestStr);
183 clientCert = io::load<security::v2::Certificate>(ss);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800184 }
185 catch (const std::exception& e) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700186 _LOG_ERROR("Unrecognized certificate request " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800187 return;
188 }
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700189
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700190 // verify the self-signed certificate and the request
191 if (!m_config.m_caName.isPrefixOf(clientCert->getName()) // under ca prefix
192 || !security::v2::Certificate::isValidName(clientCert->getName()) // is valid cert name
193 || clientCert->getName().size() != m_config.m_caName.size() + IS_SUBNAME_MIN_OFFSET) {
194 _LOG_ERROR("Invalid self-signed certificate name " << clientCert->getName());
195 return;
196 }
197 if (!security::verifySignature(*clientCert, *clientCert)) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700198 _LOG_TRACE("Cert request with bad signature.");
199 return;
200 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700201 if (!security::verifySignature(request, *clientCert)) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700202 _LOG_TRACE("Interest with bad signature.");
203 return;
204 }
205
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700206 // create new request instance
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800207 std::string requestId = std::to_string(random::generateWord64());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700208 CertificateRequest certRequest(m_config.m_caName, requestId, STATUS_BEFORE_CHALLENGE, *clientCert);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800209 try {
210 m_storage->addRequest(certRequest);
211 }
212 catch (const std::exception& e) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700213 _LOG_TRACE("Cannot add new request instance into the storage" << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800214 return;
215 }
216
217 Data result;
218 result.setName(request.getName());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700219 result.setContent(dataContentFromJson(genNewResponseJson(myEcdhPubKeyBase64,
220 std::to_string(saltInt),
221 certRequest,
222 m_config.m_supportedChallenges)));
223 m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800224 m_face.put(result);
Zhiyi Zhanga63b7372017-05-17 14:14:34 -0700225
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700226 if (m_config.m_statusUpdateCallback) {
227 m_config.m_statusUpdateCallback(certRequest);
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800228 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800229}
230
231void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700232CaModule::onChallenge(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800233{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700234 // get certificate request state
235 CertificateRequest certRequest = getCertificateRequest(request);
236 if (certRequest.m_requestId == "") {
237 // cannot get the request state
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800238 return;
239 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700240 // verify signature
241 if (!security::verifySignature(request, certRequest.m_cert)) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700242 _LOG_TRACE("Interest with bad signature.");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800243 return;
244 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700245 // decrypt the parameters
246 auto paramJsonPayload = parseEncBlock(m_ecdh.context->sharedSecret,
247 m_ecdh.context->sharedSecretLen,
248 request.getApplicationParameters());
249 std::string paramJsonStr((const char*)paramJsonPayload.data(), paramJsonPayload.size());
250 std::istringstream ss(paramJsonStr);
251 JsonSection paramJson;
252 boost::property_tree::json_parser::read_json(ss, paramJson);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800253
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700254 // load the corresponding challenge module
255 std::string challengeType = paramJson.get<std::string>(JSON_CLIENT_SELECTED_CHALLENGE);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800256 auto challenge = ChallengeModule::createChallengeModule(challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700257 JsonSection contentJson;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800258 if (challenge == nullptr) {
259 _LOG_TRACE("Unrecognized challenge type " << challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700260 certRequest.m_status = STATUS_FAILURE;
261 certRequest.m_challengeStatus = CHALLENGE_STATUS_UNKNOWN_CHALLENGE;
262 contentJson = genChallengeResponseJson(certRequest);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800263 }
Zhiyi Zhanga9bda732017-05-20 22:58:55 -0700264 else {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700265 _LOG_TRACE("CHALLENGE module to be load: " << challengeType);
266 // let challenge module handle the request
267 challenge->handleChallengeRequest(paramJson, certRequest);
268 if (certRequest.m_status == STATUS_FAILURE) {
269 // if challenge failed
270 m_storage->deleteRequest(certRequest.m_requestId);
271 contentJson = genChallengeResponseJson(certRequest);
272 _LOG_TRACE("Challenge failed");
Zhiyi Zhanga9bda732017-05-20 22:58:55 -0700273 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700274 else if (certRequest.m_status == STATUS_PENDING) {
275 // if challenge succeeded
276 auto issuedCert = issueCertificate(certRequest);
277 certRequest.m_cert = issuedCert;
278 certRequest.m_status = STATUS_SUCCESS;
279 try {
280 m_storage->addCertificate(certRequest.m_requestId, issuedCert);
281 m_storage->deleteRequest(certRequest.m_requestId);
282 _LOG_TRACE("New Certificate Issued " << issuedCert.getName());
283 }
284 catch (const std::exception& e) {
285 _LOG_ERROR("Cannot add issued cert and remove the request " << e.what());
286 return;
287 }
288 if (m_config.m_statusUpdateCallback) {
289 m_config.m_statusUpdateCallback(certRequest);
290 }
291 contentJson = genChallengeResponseJson(certRequest);
292 contentJson.add(JSON_CA_CERT_ID, readString(issuedCert.getName().at(-1)));
293 _LOG_TRACE("Challenge succeeded. Certificate has been issued");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800294 }
295 else {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700296 try {
297 m_storage->updateRequest(certRequest);
298 }
299 catch (const std::exception& e) {
300 _LOG_TRACE("Cannot update request instance " << e.what());
301 return;
302 }
303 contentJson = genChallengeResponseJson(certRequest);
304 _LOG_TRACE("No failure no success. Challenge moves on");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800305 }
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800306 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700307
308 Data result;
309 result.setName(request.getName());
310
311 // encrypt the content
312 std::stringstream ss2;
313 boost::property_tree::write_json(ss2, contentJson);
314 auto payload = ss2.str();
315 auto contentBlock = genEncBlock(tlv::Content, m_ecdh.context->sharedSecret,
316 m_ecdh.context->sharedSecretLen,
317 (const uint8_t*)payload.c_str(), payload.size());
318 result.setContent(contentBlock);
319 m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
320 m_face.put(result);
321
322 if (m_config.m_statusUpdateCallback) {
323 m_config.m_statusUpdateCallback(certRequest);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800324 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700325}
326
327void
328CaModule::onDownload(const Interest& request)
329{
330 auto requestId = readString(request.getName().at(-1));
331 security::v2::Certificate signedCert;
332 try {
333 signedCert = m_storage->getCertificate(requestId);
334 }
335 catch (const std::exception& e) {
336 _LOG_ERROR("Cannot read signed cert " << requestId << " from ca database " << e.what());
337 return;
338 }
339 Data result;
340 result.setName(request.getName());
341 result.setContent(signedCert.wireEncode());
342 m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800343 m_face.put(result);
344}
345
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800346security::v2::Certificate
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700347CaModule::issueCertificate(const CertificateRequest& certRequest)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800348{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700349 auto expectedPeriod =
350 certRequest.m_cert.getValidityPeriod().getPeriod();
351
352 time::system_clock::TimePoint startingTime, endingTime;
353 if (expectedPeriod.first > time::system_clock::now()
354 && expectedPeriod.first < time::system_clock::now()
355 + m_config.m_validityPeriod)
356 {
357 startingTime = expectedPeriod.first;
358 }
359 else {
360 startingTime = time::system_clock::now();
361 }
362 if (expectedPeriod.second < time::system_clock::now() + m_config.m_validityPeriod) {
363 endingTime = expectedPeriod.second;
364 }
365 else {
366 endingTime = time::system_clock::now() + m_config.m_validityPeriod;
367 }
368 security::ValidityPeriod period(startingTime, endingTime);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800369 security::v2::Certificate newCert;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700370
371 Name certName = certRequest.m_cert.getKeyName();
372 certName.append("NDNCERT").append(std::to_string(random::generateSecureWord64()));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800373 newCert.setName(certName);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700374 newCert.setContent(certRequest.m_cert.getContent());
375 _LOG_TRACE("cert request content " << certRequest.m_cert);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800376 SignatureInfo signatureInfo;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800377 signatureInfo.setValidityPeriod(period);
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700378 security::SigningInfo signingInfo(security::SigningInfo::SIGNER_TYPE_ID,
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700379 m_config.m_caName, signatureInfo);
380 newCert.setFreshnessPeriod(m_config.m_freshnessPeriod);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800381
382 m_keyChain.sign(newCert, signingInfo);
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700383 _LOG_TRACE("new cert got signed" << newCert);
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800384 return newCert;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800385}
386
387CertificateRequest
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700388CaModule::getCertificateRequest(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800389{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700390 std::string requestId = readString(request.getName().at(m_config.m_caName.size() + 2));
391 _LOG_TRACE("Requet Id to query the database " << requestId);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800392 CertificateRequest certRequest;
393 try {
394 certRequest = m_storage->getRequest(requestId);
395 }
396 catch (const std::exception& e) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700397 _LOG_ERROR(e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800398 }
399 return certRequest;
400}
401
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700402/**
403 * @brief Generate JSON file to response PROBE insterest
404 *
405 * PROBE response JSON format:
406 * {
407 * "name": "@p identifier",
408 * "ca-config": "@p caInformation"
409 * }
410 */
411const JsonSection
412CaModule::genProbeResponseJson(const Name& identifier)
413{
414 JsonSection root;
415 root.put(JSON_CA_NAME, identifier.toUri());
416 return root;
417}
418
419/**
420 * @brief Generate JSON file to response NEW interest
421 *
422 * Target JSON format:
423 * {
424 * "ecdh-pub": "@p echdPub",
425 * "salt": "@p salt"
426 * "request-id": "@p requestId",
427 * "status": "@p status",
428 * "challenges": [
429 * {
430 * "challenge-id": ""
431 * },
432 * {
433 * "challenge-id": ""
434 * },
435 * ...
436 * ]
437 * }
438 */
439const JsonSection
440CaModule::genProbeResponseJson()
441{
442 JsonSection root;
443 // ca-prefix
444 Name caName = m_config.m_caName;
445 root.put("ca-prefix", caName.toUri());
446
447 // ca-info
448 const auto& pib = m_keyChain.getPib();
449 auto identity = pib.getIdentity(m_config.m_caName);
450 auto cert = identity.getDefaultKey().getDefaultCertificate();
451 std::string caInfo = "";
452 if (m_config.m_caInfo == "") {
453 caInfo = "Issued by " + cert.getSignature().getKeyLocator().getName().toUri();
454 }
455 else {
456 caInfo = m_config.m_caInfo;
457 }
458 root.put("ca-info", caInfo);
459
460 // probe
461 root.put("probe", m_config.m_probe);
462
463 // certificate
464 std::stringstream ss;
465 io::save(cert, ss);
466 root.put("certificate", ss.str());
467
468 return root;
469}
470
471const JsonSection
472CaModule::genNewResponseJson(const std::string& ecdhKey, const std::string& salt,
473 const CertificateRequest& request,
474 const std::list<std::string>& challenges)
475{
476 JsonSection root;
477 JsonSection challengesSection;
478 root.put(JSON_CA_ECDH, ecdhKey);
479 root.put(JSON_CA_SALT, salt);
480 root.put(JSON_CA_EQUEST_ID, request.m_requestId);
481 root.put(JSON_CA_STATUS, std::to_string(request.m_status));
482
483 for (const auto& entry : challenges) {
484 JsonSection challenge;
485 challenge.put(JSON_CA_CHALLENGE_ID, entry);
486 challengesSection.push_back(std::make_pair("", challenge));
487 }
488 root.add_child(JSON_CA_CHALLENGES, challengesSection);
489 return root;
490}
491
492const JsonSection
493CaModule::genChallengeResponseJson(const CertificateRequest& request)
494{
495 JsonSection root;
496 JsonSection challengesSection;
497 root.put(JSON_CA_STATUS, request.m_status);
498 root.put(JSON_CHALLENGE_STATUS, request.m_challengeStatus);
499 root.put(JSON_CHALLENGE_REMAINING_TRIES, std::to_string(request.m_remainingTries));
500 root.put(JSON_CHALLENGE_REMAINING_TIME, std::to_string(request.m_remainingTime));
501 return root;
502}
503
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800504void
505CaModule::onRegisterFailed(const std::string& reason)
506{
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700507 _LOG_ERROR("Failed to register prefix in local hub's daemon, REASON: " << reason);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800508}
509
510Block
511CaModule::dataContentFromJson(const JsonSection& jsonSection)
512{
513 std::stringstream ss;
514 boost::property_tree::write_json(ss, jsonSection);
515 return makeStringBlock(ndn::tlv::Content, ss.str());
516}
517
518JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700519CaModule::jsonFromBlock(const Block& block)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800520{
521 std::string jsonString;
522 try {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700523 jsonString = encoding::readString(block);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800524 }
525 catch (const std::exception& e) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700526 _LOG_ERROR("Cannot read JSON string from TLV Value" << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800527 return JsonSection();
528 }
529 std::istringstream ss(jsonString);
530 JsonSection json;
531 boost::property_tree::json_parser::read_json(ss, json);
532 return json;
533}
534
535} // namespace ndncert
536} // namespace ndn