blob: a6954a8db4bbadfee99a0dd11c8bbf9338ac90da [file] [log] [blame]
Zhiyi Zhangf5246c42017-01-26 09:39:20 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -08003 * Copyright (c) 2017-2018, 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 Zhang1c0bd372017-12-18 18:32:55 +080024#include <ndn-cxx/util/io.hpp>
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080025#include <ndn-cxx/security/verification-helpers.hpp>
26#include <ndn-cxx/security/signing-helpers.hpp>
Junxiao Shi7c068032017-05-28 13:40:47 +000027#include <ndn-cxx/util/random.hpp>
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080028
29namespace ndn {
30namespace ndncert {
31
32_LOG_INIT(ndncert.ca);
33
34CaModule::CaModule(Face& face, security::v2::KeyChain& keyChain,
35 const std::string& configPath, const std::string& storageType)
36 : m_face(face)
37 , m_keyChain(keyChain)
38{
Zhiyi Zhanga63b7372017-05-17 14:14:34 -070039 // load the config and create storage
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080040 m_config.load(configPath);
41 m_storage = CaStorage::createCaStorage(storageType);
42
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080043 registerPrefix();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080044}
45
46CaModule::~CaModule()
47{
48 for (auto prefixId : m_interestFilterIds) {
49 m_face.unsetInterestFilter(prefixId);
50 }
51 for (auto prefixId : m_registeredPrefixIds) {
52 m_face.unregisterPrefix(prefixId, nullptr, nullptr);
53 }
54}
55
56void
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080057CaModule::registerPrefix()
58{
59 // register localhost list prefix
60 Name localProbePrefix("/localhost/CA/_LIST");
61 auto prefixId = m_face.setInterestFilter(InterestFilter(localProbePrefix),
62 bind(&CaModule::handleLocalhostList, this, _2),
63 bind(&CaModule::onRegisterFailed, this, _2));
64 m_registeredPrefixIds.push_back(prefixId);
65 _LOG_TRACE("Prefix " << localProbePrefix << " got registered");
66
67 // register prefixes for each CA
68 for (const auto& item : m_config.m_caItems) {
69 Name prefix = item.m_caName;
70 prefix.append("CA");
71
72 prefixId = m_face.registerPrefix(prefix,
73 [&] (const Name& name) {
74 // NEW
75 auto filterId = m_face.setInterestFilter(Name(name).append("_NEW"),
76 bind(&CaModule::handleNew, this, _2, item));
77 m_interestFilterIds.push_back(filterId);
78 // SELECT
79 filterId = m_face.setInterestFilter(Name(name).append("_SELECT"),
80 bind(&CaModule::handleSelect, this, _2, item));
81 m_interestFilterIds.push_back(filterId);
82 // VALIDATE
83 filterId = m_face.setInterestFilter(Name(name).append("_VALIDATE"),
84 bind(&CaModule::handleValidate, this, _2, item));
85 m_interestFilterIds.push_back(filterId);
86 // STATUS
87 filterId = m_face.setInterestFilter(Name(name).append("_STATUS"),
88 bind(&CaModule::handleStatus, this, _2, item));
89 m_interestFilterIds.push_back(filterId);
90 // DOWNLOAD
91 filterId = m_face.setInterestFilter(Name(name).append("_DOWNLOAD"),
92 bind(&CaModule::handleDownload, this, _2, item));
93 m_interestFilterIds.push_back(filterId);
94 // PROBE
95 if (item.m_probe != "") {
96 filterId = m_face.setInterestFilter(Name(name).append("_PROBE"),
97 bind(&CaModule::handleProbe, this, _2, item));
98 m_interestFilterIds.push_back(filterId);
99 }
100 // LIST
101 if (item.m_relatedCaList.size() > 0) {
102 filterId = m_face.setInterestFilter(Name(name).append("_LIST"),
103 bind(&CaModule::handleList, this, _2, item));
104 m_interestFilterIds.push_back(filterId);
105 }
106 _LOG_TRACE("Prefix " << name << " got registered");
107 },
108 bind(&CaModule::onRegisterFailed, this, _2));
109 m_registeredPrefixIds.push_back(prefixId);
110 }
111}
112
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800113bool
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800114CaModule::setProbeHandler(const Name caName, const ProbeHandler& handler)
115{
116 for (auto& entry : m_config.m_caItems) {
117 if (entry.m_caName == caName) {
118 entry.m_probeHandler = handler;
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800119 return true;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800120 }
121 }
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800122 return false;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800123}
124
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800125bool
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800126CaModule::setRecommendCaHandler(const Name caName, const RecommendCaHandler& handler)
127{
128 for (auto& entry : m_config.m_caItems) {
129 if (entry.m_caName == caName) {
130 entry.m_recommendCaHandler = handler;
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800131 return true;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800132 }
133 }
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800134 return false;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800135}
136
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800137bool
138CaModule::setStatusUpdateCallback(const Name caName, const StatusUpdateCallback& onUpateCallback)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800139{
140 for (auto& entry : m_config.m_caItems) {
141 if (entry.m_caName == caName) {
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800142 entry.m_statusUpdateCallback = onUpateCallback;
143 return true;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800144 }
145 }
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800146 return false;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800147}
148
149void
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800150CaModule::handleLocalhostList(const Interest& request)
151{
152 _LOG_TRACE("Got Localhost LIST request");
153
154 JsonSection root;
155 JsonSection caListSection;
156
157 for (const auto& entry : m_config.m_caItems) {
158 JsonSection caItem;
159
160 const auto& pib = m_keyChain.getPib();
161 auto identity = pib.getIdentity(entry.m_caName);
162 auto cert = identity.getDefaultKey().getDefaultCertificate();
163
164 // ca-prefix
165 Name caName = entry.m_caName;
166 caName.append("CA");
167 caItem.put("ca-prefix", caName.toUri());
168
169 // ca-info
170 std::string caInfo;
171 if (entry.m_caInfo == "") {
172 caInfo = "Issued by " + cert.getSignature().getKeyLocator().getName().toUri();
173 }
174 else {
175 caInfo = entry.m_caInfo;
176 }
177 caItem.put("ca-info", caInfo);
178
179 // probe is always false for local client
180
181 // ca-target list
182 caItem.put("target-list", entry.m_targetedList);
183
184 // certificate
185 std::stringstream ss;
186 io::save(cert, ss);
187 caItem.put("certificate", ss.str());
188
189 caListSection.push_back(std::make_pair("", caItem));
190 }
191 root.add_child("ca-list", caListSection);
192
193 Data result;
194 Name dataName = request.getName();
195 dataName.appendTimestamp();
196 result.setName(dataName);
197 result.setContent(dataContentFromJson(root));
198 m_keyChain.sign(result, signingByIdentity(m_keyChain.getPib().getDefaultIdentity().getName()));
199 m_face.put(result);
200}
201
202void
203CaModule::handleList(const Interest& request, const CaItem& caItem)
204{
205 _LOG_TRACE("Got LIST request");
206
207 bool getRecommendation = false;
208 Name recommendedCaName;
209 std::string identityName;
210
211 // LIST naming convention: /CA-prefix/CA/_LIST/[optional info]
212 if (readString(request.getName().at(-1)) != "_LIST" && caItem.m_recommendCaHandler) {
213 const auto& additionInfo = readString(request.getName().at(-1));
214 try {
215 std::tie(recommendedCaName, identityName) = caItem.m_recommendCaHandler(additionInfo, caItem.m_relatedCaList);
216 getRecommendation = true;
217 }
218 catch (const std::exception& e) {
219 _LOG_TRACE("Cannot recommend CA for LIST request. Degrade to non-target list." << e.what());
220 }
221 }
222
223 JsonSection root;
224 JsonSection caListSection;
225 if (getRecommendation) {
226 // JSON format
227 // {
228 // "recommended-ca": "/ndn/edu/ucla"
229 // "recommended-identity": "something"
230 // "trust-schema": "schema Data packet name"
231 // }
232 root.put("recommended-ca", recommendedCaName.toUri());
233 root.put("recommended-identity", identityName);
234 }
235 else {
236 // JSON format
237 // {
238 // "ca-list": [
239 // {"ca-prefix": "/ndn/edu/ucla"},
240 // {"ca-prefix": "/ndn/edu/memphis"},
241 // ...
242 // ]
243 // "trust-schema": "schema Data packet name"
244 // }
245 for (const auto& entry : caItem.m_relatedCaList) {
246 JsonSection caItem;
247 caItem.put("ca-prefix", entry.toUri());
248 caListSection.push_back(std::make_pair("", caItem));
249 }
250 root.add_child("ca-list", caListSection);
251 }
252
253 // TODO: add trust schema
254 std::string schemaDataName = "TODO: add trust schema";
255 root.put("trust-schema", schemaDataName);
256
257 Data result;
258 Name dataName = request.getName();
259 dataName.appendTimestamp();
260 result.setName(dataName);
261 result.setContent(dataContentFromJson(root));
262 m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
263 m_face.put(result);
264}
265
266void
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800267CaModule::handleProbe(const Interest& request, const CaItem& caItem)
268{
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700269 // PROBE Naming Convention: /CA-prefix/CA/_PROBE/<Probe Information>
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800270 _LOG_TRACE("Handle PROBE request");
271
272 std::string identifier;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800273 if (caItem.m_probeHandler) {
274 try {
275 identifier = caItem.m_probeHandler(readString(request.getName().at(caItem.m_caName.size() + 2)));
276 }
277 catch (const std::exception& e) {
278 _LOG_TRACE("Cannot generate identifier for PROBE request " << e.what());
279 return;
280 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800281 }
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800282 else {
283 identifier = readString(request.getName().at(caItem.m_caName.size() + 2));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800284 }
285 Name identityName = caItem.m_caName;
286 identityName.append(identifier);
287
288 Data result;
289 result.setName(request.getName());
290 result.setContent(dataContentFromJson(genResponseProbeJson(identityName, "")));
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700291 m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800292 m_face.put(result);
293
294 _LOG_TRACE("Handle PROBE: generate identity " << identityName);
295}
296
297void
298CaModule::handleNew(const Interest& request, const CaItem& caItem)
299{
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700300 // NEW Naming Convention: /CA-prefix/CA/_NEW/<certificate-request>/[signature]
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800301 _LOG_TRACE("Handle NEW request");
302
303 security::v2::Certificate clientCert;
304 try {
305 clientCert.wireDecode(request.getName().at(caItem.m_caName.size() + 2).blockFromValue());
306 }
307 catch (const std::exception& e) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700308 _LOG_ERROR("Unrecognized certificate request " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800309 return;
310 }
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700311
312 if (!security::verifySignature(clientCert, clientCert)) {
313 _LOG_TRACE("Cert request with bad signature.");
314 return;
315 }
316 if (!security::verifySignature(request, clientCert)) {
317 _LOG_TRACE("Interest with bad signature.");
318 return;
319 }
320
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800321 std::string requestId = std::to_string(random::generateWord64());
322 CertificateRequest certRequest(caItem.m_caName, requestId, clientCert);
Zhiyi Zhanga63b7372017-05-17 14:14:34 -0700323 certRequest.setStatus(ChallengeModule::WAIT_SELECTION);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800324 try {
325 m_storage->addRequest(certRequest);
326 }
327 catch (const std::exception& e) {
328 _LOG_TRACE("Cannot add new request instance " << e.what());
329 return;
330 }
331
332 Data result;
333 result.setName(request.getName());
Zhiyi Zhanga63b7372017-05-17 14:14:34 -0700334 result.setContent(dataContentFromJson(genResponseNewJson(requestId, certRequest.getStatus(),
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800335 caItem.m_supportedChallenges)));
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700336 m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800337 m_face.put(result);
Zhiyi Zhanga63b7372017-05-17 14:14:34 -0700338
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800339 if (caItem.m_statusUpdateCallback) {
340 caItem.m_statusUpdateCallback(certRequest);
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800341 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800342}
343
344void
345CaModule::handleSelect(const Interest& request, const CaItem& caItem)
346{
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700347 // SELECT Naming Convention: /CA-prefix/CA/_SELECT/{Request-ID JSON}/<ChallengeID>/
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800348 // {Param JSON}/[Signature components]
349 _LOG_TRACE("Handle SELECT request");
350
351 CertificateRequest certRequest = getCertificateRequest(request, caItem.m_caName);
352 if (certRequest.getRequestId().empty()) {
353 return;
354 }
355
356 if (!security::verifySignature(request, certRequest.getCert())) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700357 _LOG_TRACE("Interest with bad signature.");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800358 return;
359 }
360
361 std::string challengeType;
362 try {
363 challengeType = readString(request.getName().at(caItem.m_caName.size() + 3));
364 }
365 catch (const std::exception& e) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700366 _LOG_ERROR(e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800367 return;
368 }
Zhiyi Zhange30eb352017-04-13 15:26:14 -0700369 _LOG_TRACE("SELECT request choosing challenge " << challengeType);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800370 auto challenge = ChallengeModule::createChallengeModule(challengeType);
371 if (challenge == nullptr) {
372 _LOG_TRACE("Unrecognized challenge type " << challengeType);
373 return;
374 }
375 JsonSection contentJson = challenge->handleChallengeRequest(request, certRequest);
Zhiyi Zhanga9bda732017-05-20 22:58:55 -0700376 if (certRequest.getStatus() == ChallengeModule::FAILURE) {
377 m_storage->deleteRequest(certRequest.getRequestId());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800378 }
Zhiyi Zhanga9bda732017-05-20 22:58:55 -0700379 else {
380 try {
381 m_storage->updateRequest(certRequest);
382 }
383 catch (const std::exception& e) {
384 _LOG_TRACE("Cannot update request instance " << e.what());
385 return;
386 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800387 }
388
389 Data result;
390 result.setName(request.getName());
391 result.setContent(dataContentFromJson(contentJson));
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700392 m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800393 m_face.put(result);
Zhiyi Zhanga63b7372017-05-17 14:14:34 -0700394
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800395 if (caItem.m_statusUpdateCallback) {
396 caItem.m_statusUpdateCallback(certRequest);
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800397 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800398}
399
400void
401CaModule::handleValidate(const Interest& request, const CaItem& caItem)
402{
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700403 // VALIDATE Naming Convention: /CA-prefix/CA/_VALIDATE/{Request-ID JSON}/<ChallengeID>/
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800404 // {Param JSON}/[Signature components]
405 _LOG_TRACE("Handle VALIDATE request");
406
407 CertificateRequest certRequest = getCertificateRequest(request, caItem.m_caName);
408 if (certRequest.getRequestId().empty()) {
409 return;
410 }
411
412 if (!security::verifySignature(request, certRequest.getCert())) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700413 _LOG_TRACE("Interest with bad signature.");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800414 return;
415 }
416
417 std::string challengeType = certRequest.getChallengeType();
418 auto challenge = ChallengeModule::createChallengeModule(challengeType);
419 if (challenge == nullptr) {
420 _LOG_TRACE("Unrecognized challenge type " << challengeType);
421 return;
422 }
423 JsonSection contentJson = challenge->handleChallengeRequest(request, certRequest);
Zhiyi Zhanga9bda732017-05-20 22:58:55 -0700424 if (certRequest.getStatus() == ChallengeModule::FAILURE) {
425 m_storage->deleteRequest(certRequest.getRequestId());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800426 }
Zhiyi Zhanga9bda732017-05-20 22:58:55 -0700427 else {
428 try {
429 m_storage->updateRequest(certRequest);
430 }
431 catch (const std::exception& e) {
432 _LOG_TRACE("Cannot update request instance " << e.what());
433 return;
434 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800435 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800436 Data result;
437 result.setName(request.getName());
438 result.setContent(dataContentFromJson(contentJson));
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700439 m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800440 m_face.put(result);
441
442 if (certRequest.getStatus() == ChallengeModule::SUCCESS) {
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800443 auto issuedCert = issueCertificate(certRequest, caItem);
444 if (caItem.m_statusUpdateCallback) {
445 certRequest.setCert(issuedCert);
446 caItem.m_statusUpdateCallback(certRequest);
447 }
448 try {
449 m_storage->addCertificate(certRequest.getRequestId(), issuedCert);
450 m_storage->deleteRequest(certRequest.getRequestId());
451 _LOG_TRACE("New Certificate Issued " << issuedCert.getName());
452 }
453 catch (const std::exception& e) {
454 _LOG_ERROR("Cannot add issued cert and remove the request " << e.what());
455 return;
456 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800457 }
458}
459
460void
461CaModule::handleStatus(const Interest& request, const CaItem& caItem)
462{
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700463 // STATUS Naming Convention: /CA-prefix/CA/_STATUS/{Request-ID JSON}/[Signature components]
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800464 _LOG_TRACE("Handle STATUS request");
465
466 CertificateRequest certRequest = getCertificateRequest(request, caItem.m_caName);
467 if (certRequest.getRequestId().empty()) {
468 return;
469 }
470
471 if (!security::verifySignature(request, certRequest.getCert())) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700472 _LOG_TRACE("Interest with bad signature.");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800473 return;
474 }
475
476 std::string challengeType = certRequest.getChallengeType();
477 auto challenge = ChallengeModule::createChallengeModule(challengeType);
478 if (challenge == nullptr) {
479 _LOG_TRACE("Unrecognized challenge type " << challengeType);
480 return;
481 }
482 JsonSection contentJson = challenge->handleChallengeRequest(request, certRequest);
483
484 Data result;
485 result.setName(request.getName());
486 result.setContent(dataContentFromJson(contentJson));
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700487 m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800488 m_face.put(result);
489}
490
491void
492CaModule::handleDownload(const Interest& request, const CaItem& caItem)
493{
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700494 // DOWNLOAD Naming Convention: /CA-prefix/CA/_DOWNLOAD/{Request-ID JSON}
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800495 _LOG_TRACE("Handle DOWNLOAD request");
496
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800497 Data result;
498 result.setName(request.getName());
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800499 if (readString(request.getName().at(-1)) == "ANCHOR") {
500 JsonSection contentJson;
501
502 const auto& pib = m_keyChain.getPib();
503 auto identity = pib.getIdentity(caItem.m_caName);
504 auto cert = identity.getDefaultKey().getDefaultCertificate();
505
506 // ca-prefix
507 Name caName = caItem.m_caName;
508 caName.append("CA");
509 contentJson.put("ca-prefix", caName.toUri());
510
511 // ca-info
512 std::string caInfo;
513 if (caItem.m_caInfo == "") {
514 caInfo = "Issued by " + cert.getSignature().getKeyLocator().getName().toUri();
515 }
516 else {
517 caInfo = caItem.m_caInfo;
518 }
519 contentJson.put("ca-info", caInfo);
520
521 // probe
522 contentJson.put("probe", caItem.m_probe);
523
524 // ca-target list
525 contentJson.put("target-list", caItem.m_targetedList);
526
527 // certificate
528 std::stringstream ss;
529 io::save(cert, ss);
530 contentJson.put("certificate", ss.str());
531
532 result.setContent(dataContentFromJson(contentJson));
533 }
534 else {
535 JsonSection requestIdJson = jsonFromNameComponent(request.getName(), caItem.m_caName.size() + 2);
536 std::string requestId = requestIdJson.get(JSON_REQUEST_ID, "");
537 security::v2::Certificate signedCert;
538 try {
539 signedCert = m_storage->getCertificate(requestId);
540 }
541 catch (const std::exception& e) {
542 _LOG_ERROR(e.what());
543 return;
544 }
545 result.setContent(signedCert.wireEncode());
546 }
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700547 m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800548 m_face.put(result);
549}
550
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800551security::v2::Certificate
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800552CaModule::issueCertificate(const CertificateRequest& certRequest, const CaItem& caItem)
553{
554 Name certName = certRequest.getCert().getKeyName();
555 certName.append("NDNCERT").appendVersion();
556 security::v2::Certificate newCert;
557 newCert.setName(certName);
558 newCert.setContent(certRequest.getCert().getContent());
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700559 _LOG_TRACE("cert request content " << certRequest.getCert());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800560 SignatureInfo signatureInfo;
561 security::ValidityPeriod period(time::system_clock::now(),
562 time::system_clock::now() + caItem.m_validityPeriod);
563 signatureInfo.setValidityPeriod(period);
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700564 security::SigningInfo signingInfo(security::SigningInfo::SIGNER_TYPE_ID,
565 caItem.m_caName, signatureInfo);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800566 newCert.setFreshnessPeriod(caItem.m_freshnessPeriod);
567
568 m_keyChain.sign(newCert, signingInfo);
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700569 _LOG_TRACE("new cert got signed" << newCert);
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800570 return newCert;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800571}
572
573CertificateRequest
574CaModule::getCertificateRequest(const Interest& request, const Name& caName)
575{
576 JsonSection requestIdJson = jsonFromNameComponent(request.getName(), caName.size() + 2);
577 std::string requestId = requestIdJson.get(JSON_REQUEST_ID, "");
578 CertificateRequest certRequest;
579 try {
580 certRequest = m_storage->getRequest(requestId);
581 }
582 catch (const std::exception& e) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700583 _LOG_ERROR(e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800584 }
585 return certRequest;
586}
587
588void
589CaModule::onRegisterFailed(const std::string& reason)
590{
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700591 _LOG_ERROR("Failed to register prefix in local hub's daemon, REASON: " << reason);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800592}
593
594Block
595CaModule::dataContentFromJson(const JsonSection& jsonSection)
596{
597 std::stringstream ss;
598 boost::property_tree::write_json(ss, jsonSection);
599 return makeStringBlock(ndn::tlv::Content, ss.str());
600}
601
602JsonSection
603CaModule::jsonFromNameComponent(const Name& name, int pos)
604{
605 std::string jsonString;
606 try {
607 jsonString = encoding::readString(name.at(pos));
608 }
609 catch (const std::exception& e) {
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700610 _LOG_ERROR(e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800611 return JsonSection();
612 }
613 std::istringstream ss(jsonString);
614 JsonSection json;
615 boost::property_tree::json_parser::read_json(ss, json);
616 return json;
617}
618
619} // namespace ndncert
620} // namespace ndn