blob: 2a9b5d7f9d0bc0e3ddadef45227419b99ab9711a [file] [log] [blame]
Zhiyi Zhangf5246c42017-01-26 09:39:20 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
swa770de007bc2020-03-24 21:26:21 -07002/**
Davide Pesaventob48bbda2020-07-27 19:41:37 -04003 * Copyright (c) 2017-2020, Regents of the University of California.
Zhiyi Zhangf5246c42017-01-26 09:39:20 -08004 *
5 * This file is part of ndncert, a certificate management system based on NDN.
6 *
7 * ndncert is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License along with
16 * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ndncert authors and contributors.
19 */
20
21#include "ca-module.hpp"
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070022
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -070023#include <ndn-cxx/metadata-object.hpp>
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070024#include <ndn-cxx/security/signing-helpers.hpp>
25#include <ndn-cxx/security/verification-helpers.hpp>
26#include <ndn-cxx/util/io.hpp>
27#include <ndn-cxx/util/random.hpp>
28
29#include "challenge-module.hpp"
30#include "crypto-support/enc-tlv.hpp"
31#include "logging.hpp"
32#include "protocol-detail/challenge.hpp"
33#include "protocol-detail/error.hpp"
34#include "protocol-detail/info.hpp"
35#include "protocol-detail/new.hpp"
36#include "protocol-detail/probe.hpp"
37#include "protocol-detail/revoke.hpp"
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080038
39namespace ndn {
40namespace ndncert {
41
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070042static const int IS_SUBNAME_MIN_OFFSET = 5;
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -070043static const time::seconds DEFAULT_DATA_FRESHNESS_PERIOD = 1_s;
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -070044static const time::seconds REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD = 120_s;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070045
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080046_LOG_INIT(ndncert.ca);
47
48CaModule::CaModule(Face& face, security::v2::KeyChain& keyChain,
49 const std::string& configPath, const std::string& storageType)
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070050 : m_face(face)
51 , m_keyChain(keyChain)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080052{
Zhiyi Zhanga63b7372017-05-17 14:14:34 -070053 // load the config and create storage
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080054 m_config.load(configPath);
55 m_storage = CaStorage::createCaStorage(storageType);
56
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080057 registerPrefix();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080058}
59
60CaModule::~CaModule()
61{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070062 for (auto handle : m_interestFilterHandles) {
63 handle.cancel();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080064 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070065 for (auto handle : m_registeredPrefixHandles) {
66 handle.unregister();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080067 }
68}
69
70void
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080071CaModule::registerPrefix()
72{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070073 // register localhop discovery prefix
swa77020643ac2020-03-26 02:24:45 -070074 Name localhopInfoPrefix("/localhop/CA/INFO");
75 auto prefixId = m_face.setInterestFilter(InterestFilter(localhopInfoPrefix),
76 bind(&CaModule::onInfo, this, _2),
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080077 bind(&CaModule::onRegisterFailed, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070078 m_registeredPrefixHandles.push_back(prefixId);
swa77020643ac2020-03-26 02:24:45 -070079 _LOG_TRACE("Prefix " << localhopInfoPrefix << " got registered");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080080
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070081 // register prefixes
Suyong Won256c9062020-05-11 02:45:56 -070082 Name prefix = m_config.m_caPrefix;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070083 prefix.append("CA");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080084
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070085 prefixId = m_face.registerPrefix(
86 prefix,
87 [&](const Name& name) {
88 // register INFO prefix
89 auto filterId = m_face.setInterestFilter(Name(name).append("INFO"),
90 bind(&CaModule::onInfo, this, _2));
91 m_interestFilterHandles.push_back(filterId);
swa77020643ac2020-03-26 02:24:45 -070092
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070093 // register PROBE prefix
94 filterId = m_face.setInterestFilter(Name(name).append("PROBE"),
95 bind(&CaModule::onProbe, this, _2));
96 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070097
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070098 // register NEW prefix
99 filterId = m_face.setInterestFilter(Name(name).append("NEW"),
100 bind(&CaModule::onNew, this, _2));
101 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700102
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700103 // register SELECT prefix
104 filterId = m_face.setInterestFilter(Name(name).append("CHALLENGE"),
105 bind(&CaModule::onChallenge, this, _2));
106 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700107
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700108 // register REVOKE prefix
109 filterId = m_face.setInterestFilter(Name(name).append("REVOKE"),
110 bind(&CaModule::onRevoke, this, _2));
111 m_interestFilterHandles.push_back(filterId);
112 _LOG_TRACE("Prefix " << name << " got registered");
113 },
114 bind(&CaModule::onRegisterFailed, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700115 m_registeredPrefixHandles.push_back(prefixId);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800116}
117
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700118void
119CaModule::setNameAssignmentFunction(const NameAssignmentFunc& handler)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800120{
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700121 m_config.m_nameAssignmentFunc = handler;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800122}
123
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800124bool
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700125CaModule::setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800126{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700127 m_config.m_statusUpdateCallback = onUpdateCallback;
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800128 return false;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800129}
130
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700131shared_ptr<Data>
132CaModule::generateCaConfigMetaData()
swa77020643ac2020-03-26 02:24:45 -0700133{
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700134 // @TODO
135 // make metadata a class member variable m_infoMetadata
136 // check whether the m_infoMetadata has the latest versioned name, if not, then generate a new one
137 // otherwise, directly reply m_infoMetadata.makeData
138
139 auto infoPacket = generateCaConfigData();
140 MetadataObject metadata;
141 metadata.setVersionedName(infoPacket->getName().getPrefix(-1));
142 Name discoveryInterestName(infoPacket->getName().getPrefix(-2));
143 name::Component metadataComponent(32, reinterpret_cast<const uint8_t*>("metadata"), std::strlen("metadata"));
144 discoveryInterestName.append(metadataComponent);
145 auto metadataData = metadata.makeData(discoveryInterestName, m_keyChain, signingByIdentity(m_config.m_caPrefix));
146 return make_shared<Data>(metadataData);
147}
148
149shared_ptr<Data>
150CaModule::generateCaConfigData()
151{
152 // @TODO
153 // make CaInfo Data packet a class member variable m_infoData
154 // check whether the m_infoData is still valid, if not, then generate a new one
155 // otherwise, directly reply m_infoData
Suyong Won19fba4d2020-05-09 13:39:46 -0700156
157 const auto& pib = m_keyChain.getPib();
Suyong Won256c9062020-05-11 02:45:56 -0700158 const auto& identity = pib.getIdentity(m_config.m_caPrefix);
Suyong Won19fba4d2020-05-09 13:39:46 -0700159 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
Zhiyi Zhang61c43a62020-09-28 12:56:01 -0700160 Block contentTLV = INFO::encodeDataContent(m_config, cert);
swa77020643ac2020-03-26 02:24:45 -0700161
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700162 Name infoPacketName(m_config.m_caPrefix);
163 infoPacketName.append("CA").append("INFO").appendVersion().appendSegment(0);
164 Data infoData(infoPacketName);
165 infoData.setContent(contentTLV);
166 infoData.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
167 m_keyChain.sign(infoData, signingByIdentity(m_config.m_caPrefix));
168 return make_shared<Data>(infoData);
169}
swa77020643ac2020-03-26 02:24:45 -0700170
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700171void
172CaModule::onInfo(const Interest& request)
173{
174 _LOG_TRACE("Received INFO request");
175
176 if (request.getName().get(-1).type() == 32) {
177 m_face.put(*generateCaConfigMetaData());
178 }
179 else {
180 m_face.put(*generateCaConfigData());
181 }
swa77020643ac2020-03-26 02:24:45 -0700182
183 _LOG_TRACE("Handle INFO: send out the INFO response");
184}
185
186void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700187CaModule::onProbe(const Interest& request)
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800188{
swa77020643ac2020-03-26 02:24:45 -0700189 // PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent]
190 _LOG_TRACE("Received PROBE request");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800191
swa77020643ac2020-03-26 02:24:45 -0700192 // process PROBE requests: find an available name
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700193 std::string availableId = "";
Suyong Won19fba4d2020-05-09 13:39:46 -0700194 const auto& parameterTLV = request.getApplicationParameters();
Suyong Won44d0cce2020-05-10 04:07:43 -0700195 parameterTLV.parse();
Suyong Won19fba4d2020-05-09 13:39:46 -0700196 if (!parameterTLV.hasValue()) {
197 _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
swa77020643ac2020-03-26 02:24:45 -0700198 return;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700199 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700200
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700201 // if (m_config.m_nameAssignmentFunc) {
202 // try {
203 // availableId = m_config.m_nameAssignmentFunc(parameterTLV);
204 // }
205 // catch (const std::exception& e) {
206 // _LOG_TRACE("Cannot find PROBE input from PROBE parameters: " << e.what());
207 // return;
208 // }
209 // }
210 // else {
211 // // if there is no app-specified name lookup, use a random name id
212 // availableId = std::to_string(random::generateSecureWord64());
213 // }
214 // Name newIdentityName = m_config.m_caPrefix;
215 // newIdentityName.append(availableId);
216 // _LOG_TRACE("Handle PROBE: generate an identity " << newIdentityName);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800217
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700218 // Block contentTLV = PROBE::encodeDataContent(newIdentityName.toUri(), m_config.m_probe, parameterTLV);
219
220 // Data result;
221 // result.setName(request.getName());
222 // result.setContent(contentTLV);
223 // result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
224 // m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
225 // m_face.put(result);
226 // _LOG_TRACE("Handle PROBE: send out the PROBE response");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800227}
228
229void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700230CaModule::onNew(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800231{
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700232 // NEW Naming Convention: /<CA-prefix>/CA/NEW/[SignedInterestParameters_Digest]
233 onRequestInit(request, REQUEST_TYPE_NEW);
tylerliu4a00aad2020-09-26 02:03:17 -0700234}
235
236void
237CaModule::onRevoke(const Interest& request)
238{
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700239 // REVOKE Naming Convention: /<CA-prefix>/CA/REVOKE/[SignedInterestParameters_Digest]
240 onRequestInit(request, REQUEST_TYPE_REVOKE);
tylerliu4a00aad2020-09-26 02:03:17 -0700241}
242
243void
244CaModule::onRequestInit(const Interest& request, int requestType)
245{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700246 // get ECDH pub key and cert request
Suyong Won19fba4d2020-05-09 13:39:46 -0700247 const auto& parameterTLV = request.getApplicationParameters();
Suyong Won7968f7a2020-05-12 01:01:25 -0700248 parameterTLV.parse();
249
Suyong Won19fba4d2020-05-09 13:39:46 -0700250 if (!parameterTLV.hasValue()) {
251 _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700252 return;
253 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700254
255 std::string peerKeyBase64 = readString(parameterTLV.get(tlv_ecdh_pub));
256
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700257 if (peerKeyBase64 == "") {
Suyong Won19fba4d2020-05-09 13:39:46 -0700258 _LOG_ERROR("Empty ECDH PUB obtained from the Interest parameter.");
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700259 return;
260 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700261
262 // get server's ECDH pub key
263 auto myEcdhPubKeyBase64 = m_ecdh.getBase64PubKey();
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700264 try {
265 m_ecdh.deriveSecret(peerKeyBase64);
266 }
267 catch (const std::exception& e) {
268 _LOG_ERROR("Cannot derive a shared secret using the provided ECDH key: " << e.what());
269 return;
270 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700271 // generate salt for HKDF
272 auto saltInt = random::generateSecureWord64();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700273 // hkdf
274 hkdf(m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen,
Zhiyi Zhang36706832019-07-04 21:33:03 -0700275 (uint8_t*)&saltInt, sizeof(saltInt), m_aesKey, sizeof(m_aesKey));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700276
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700277 shared_ptr<security::v2::Certificate> clientCert = nullptr;
Suyong Won7968f7a2020-05-12 01:01:25 -0700278
tylerliu4a00aad2020-09-26 02:03:17 -0700279 if (requestType == REQUEST_TYPE_NEW) {
280 // parse certificate request
281 Block cert_req = parameterTLV.get(tlv_cert_request);
282 cert_req.parse();
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700283
tylerliu4a00aad2020-09-26 02:03:17 -0700284 try {
285 security::v2::Certificate cert = security::v2::Certificate(cert_req.get(tlv::Data));
286 clientCert = make_shared<security::v2::Certificate>(cert);
287 }
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700288 catch (const std::exception& e) {
tylerliu4a00aad2020-09-26 02:03:17 -0700289 _LOG_ERROR("Unrecognized certificate request: " << e.what());
290 return;
291 }
292 // check the validity period
293 auto expectedPeriod = clientCert->getValidityPeriod().getPeriod();
294 auto currentTime = time::system_clock::now();
295 if (expectedPeriod.first < currentTime - REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD) {
296 _LOG_ERROR("Client requests a too old notBefore timepoint.");
297 return;
298 }
299 if (expectedPeriod.second > currentTime + m_config.m_maxValidityPeriod ||
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700300 expectedPeriod.second <= expectedPeriod.first) {
tylerliu4a00aad2020-09-26 02:03:17 -0700301 _LOG_ERROR("Client requests an invalid validity period or a notAfter timepoint beyond the allowed time period.");
302 return;
303 }
304
305 // verify the self-signed certificate, the request, and the token
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700306<<<<<<< HEAD
tylerliu4a00aad2020-09-26 02:03:17 -0700307 if (!m_config.m_caPrefix.isPrefixOf(clientCert->getName()) // under ca prefix
308 || !security::v2::Certificate::isValidName(clientCert->getName()) // is valid cert name
tylerliu0b6d0db2020-09-28 17:52:02 -0700309 || clientCert->getName().size() < m_config.m_caPrefix.size() + IS_SUBNAME_MIN_OFFSET
310 || clientCert->getName().size() >
311 m_config.m_caPrefix.size() + IS_SUBNAME_MIN_OFFSET - 1 + m_config.m_maxSuffixLength) {
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700312=======
313 if (!m_config.m_caPrefix.isPrefixOf(clientCert->getName()) // under ca prefix
314 || !security::v2::Certificate::isValidName(clientCert->getName()) // is valid cert name
315 || clientCert->getName().size() < m_config.m_caPrefix.size() + IS_SUBNAME_MIN_OFFSET) {
316>>>>>>> apply Error Data packet in challenge status
tylerliu4a00aad2020-09-26 02:03:17 -0700317 _LOG_ERROR("Invalid self-signed certificate name " << clientCert->getName());
318 return;
319 }
320 if (!security::verifySignature(*clientCert, *clientCert)) {
321 _LOG_ERROR("Cert request with bad signature.");
322 return;
323 }
324 if (!security::verifySignature(request, *clientCert)) {
325 _LOG_ERROR("Interest with bad signature.");
326 return;
327 }
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700328 }
329 else if (requestType == REQUEST_TYPE_REVOKE) {
tylerliu4a00aad2020-09-26 02:03:17 -0700330 // parse certificate request
331 Block cert_revoke = parameterTLV.get(tlv_cert_to_revoke);
332 cert_revoke.parse();
333
334 try {
335 security::v2::Certificate cert = security::v2::Certificate(cert_revoke.get(tlv::Data));
336 clientCert = make_shared<security::v2::Certificate>(cert);
337 }
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700338 catch (const std::exception& e) {
tylerliu4a00aad2020-09-26 02:03:17 -0700339 _LOG_ERROR("Unrecognized certificate: " << e.what());
340 return;
341 }
342
343 // verify the certificate
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700344<<<<<<< HEAD
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700345 if (!m_config.m_caPrefix.isPrefixOf(clientCert->getName()) // under ca prefix
tylerliu4a00aad2020-09-26 02:03:17 -0700346 || !security::v2::Certificate::isValidName(clientCert->getName()) // is valid cert name
tylerliu0b6d0db2020-09-28 17:52:02 -0700347 || clientCert->getName().size() < m_config.m_caPrefix.size() + IS_SUBNAME_MIN_OFFSET
348 || clientCert->getName().size() >
349 m_config.m_caPrefix.size() + IS_SUBNAME_MIN_OFFSET - 1 + m_config.m_maxSuffixLength) {
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700350=======
351 if (!m_config.m_caPrefix.isPrefixOf(clientCert->getName()) // under ca prefix
352 || !security::v2::Certificate::isValidName(clientCert->getName()) // is valid cert name
353 || clientCert->getName().size() < m_config.m_caPrefix.size() + IS_SUBNAME_MIN_OFFSET) {
354>>>>>>> apply Error Data packet in challenge status
tylerliu4a00aad2020-09-26 02:03:17 -0700355 _LOG_ERROR("Invalid certificate name " << clientCert->getName());
356 return;
357 }
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700358 const auto& cert = m_keyChain.getPib().getIdentity(m_config.m_caPrefix).getDefaultKey().getDefaultCertificate();
tylerliu4a00aad2020-09-26 02:03:17 -0700359 if (!security::verifySignature(*clientCert, cert)) {
360 _LOG_ERROR("Cert request with bad signature.");
361 return;
362 }
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700363 }
364
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700365 // create new request instance
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800366 std::string requestId = std::to_string(random::generateWord64());
Zhiyi Zhang48f23782020-09-28 12:11:24 -0700367 CertificateRequest certRequest(m_config.m_caPrefix, requestId, requestType, Status::BEFORE_CHALLENGE, *clientCert);
Suyong Won19fba4d2020-05-09 13:39:46 -0700368
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800369 try {
370 m_storage->addRequest(certRequest);
371 }
372 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700373 _LOG_ERROR("Cannot add new request instance into the storage: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800374 return;
375 }
376
377 Data result;
378 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700379 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
tylerliu4a00aad2020-09-26 02:03:17 -0700380 if (requestType == REQUEST_TYPE_NEW) {
381 result.setContent(NEW::encodeDataContent(myEcdhPubKeyBase64,
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700382 std::to_string(saltInt),
383 certRequest,
384 m_config.m_supportedChallenges));
385 }
386 else if (requestType == REQUEST_TYPE_REVOKE) {
tylerliu4a00aad2020-09-26 02:03:17 -0700387 result.setContent(REVOKE::encodeDataContent(myEcdhPubKeyBase64,
388 std::to_string(saltInt),
389 certRequest,
390 m_config.m_supportedChallenges));
391 }
Suyong Won256c9062020-05-11 02:45:56 -0700392 m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800393 m_face.put(result);
Zhiyi Zhanga63b7372017-05-17 14:14:34 -0700394
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700395 if (m_config.m_statusUpdateCallback) {
396 m_config.m_statusUpdateCallback(certRequest);
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800397 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800398}
399
400void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700401CaModule::onChallenge(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800402{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700403 // get certificate request state
404 CertificateRequest certRequest = getCertificateRequest(request);
405 if (certRequest.m_requestId == "") {
406 // cannot get the request state
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700407 _LOG_ERROR("Cannot find certificate request state from CA's storage.");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700408 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
409 "Cannot find certificate request state from CA's storage."));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800410 return;
411 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700412 // verify signature
413 if (!security::verifySignature(request, certRequest.m_cert)) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700414 _LOG_ERROR("Challenge Interest with bad signature.");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700415 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE, "Bad signature."));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800416 return;
417 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700418 // decrypt the parameters
Suyong Won19fba4d2020-05-09 13:39:46 -0700419 Buffer paramTLVPayload;
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700420 try {
Suyong Won19fba4d2020-05-09 13:39:46 -0700421 paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), m_aesKey,
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700422 (uint8_t*)"test", strlen("test"));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700423 }
424 catch (const std::exception& e) {
425 _LOG_ERROR("Cannot successfully decrypt the Interest parameters: " << e.what());
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700426 m_storage->deleteRequest(certRequest.m_requestId);
427 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
428 "Cannot successfully decrypt the Interest parameters."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700429 return;
430 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700431 if (paramTLVPayload.size() == 0) {
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700432 _LOG_ERROR("Got an empty buffer from content decryption.");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700433 m_storage->deleteRequest(certRequest.m_requestId);
434 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
435 "Empty buffer from content decryption."));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700436 return;
437 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700438 Block paramTLV = makeBinaryBlock(tlv_encrypted_payload, paramTLVPayload.data(), paramTLVPayload.size());
439 paramTLV.parse();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800440
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700441 // load the corresponding challenge module
Suyong Won19fba4d2020-05-09 13:39:46 -0700442 std::string challengeType = readString(paramTLV.get(tlv_selected_challenge));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800443 auto challenge = ChallengeModule::createChallengeModule(challengeType);
444 if (challenge == nullptr) {
445 _LOG_TRACE("Unrecognized challenge type " << challengeType);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700446 m_storage->deleteRequest(certRequest.m_requestId);
447 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER, "Unrecognized challenge type"));
448 return;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800449 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700450
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700451 _LOG_TRACE("CHALLENGE module to be load: " << challengeType);
452 auto errorInfo = challenge->handleChallengeRequest(paramTLV, certRequest);
453 if (std::get<0>(errorInfo) != ErrorCode::NO_ERROR) {
454 m_storage->deleteRequest(certRequest.m_requestId);
455 m_face.put(generateErrorDataPacket(request.getName(), std::get<0>(errorInfo), std::get<1>(errorInfo)));
456 return;
457 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700458
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700459 Block payload;
460 if (certRequest.m_status == Status::PENDING) {
461 // if challenge succeeded
462 if (certRequest.m_requestType == REQUEST_TYPE_NEW) {
463 auto issuedCert = issueCertificate(certRequest);
464 certRequest.m_cert = issuedCert;
465 certRequest.m_status = Status::SUCCESS;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700466 try {
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700467 m_storage->addCertificate(certRequest.m_requestId, issuedCert);
468 m_storage->deleteRequest(certRequest.m_requestId);
469 _LOG_TRACE("New Certificate Issued " << issuedCert.getName());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700470 }
471 catch (const std::exception& e) {
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700472 _LOG_ERROR("Cannot add issued cert and remove the request: " << e.what());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700473 return;
474 }
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700475
Suyong Won44d0cce2020-05-10 04:07:43 -0700476 payload = CHALLENGE::encodeDataPayload(certRequest);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700477 payload.parse();
478 payload.push_back(makeNestedBlock(tlv_issued_cert_name, issuedCert.getName()));
479 payload.encode();
480
481 //contentJson.add(JSON_CA_CERT_ID, readString(issuedCert.getName().at(-1)));
482 _LOG_TRACE("Challenge succeeded. Certificate has been issued");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800483 }
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700484 else if (certRequest.m_requestType == REQUEST_TYPE_REVOKE) {
485 certRequest.m_status = Status::SUCCESS;
486 try {
487 m_storage->deleteRequest(certRequest.m_requestId);
488 _LOG_TRACE("Certificate Revoked");
489 }
490 catch (const std::exception& e) {
491 _LOG_ERROR("Cannot add issued cert and remove the request: " << e.what());
492 return;
493 }
494
495 payload = CHALLENGE::encodeDataPayload(certRequest);
496 payload.parse();
497 _LOG_TRACE("Challenge succeeded. Certificate has been revoked");
498 }
499 }
500 else {
501 m_storage->updateRequest(certRequest);
502 payload = CHALLENGE::encodeDataPayload(certRequest);
503 _LOG_TRACE("No failure no success. Challenge moves on");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800504 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700505
506 Data result;
507 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700508 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700509
510 // encrypt the content
Suyong Won7968f7a2020-05-12 01:01:25 -0700511 auto contentBlock = encodeBlockWithAesGcm128(tlv::Content, m_aesKey, payload.value(),
512 payload.value_size(), (uint8_t*)"test", strlen("test"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700513 result.setContent(contentBlock);
Suyong Won256c9062020-05-11 02:45:56 -0700514 m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700515 m_face.put(result);
516
517 if (m_config.m_statusUpdateCallback) {
518 m_config.m_statusUpdateCallback(certRequest);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800519 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700520}
521
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800522security::v2::Certificate
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700523CaModule::issueCertificate(const CertificateRequest& certRequest)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800524{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700525 auto expectedPeriod =
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700526 certRequest.m_cert.getValidityPeriod().getPeriod();
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700527 security::ValidityPeriod period(expectedPeriod.first, expectedPeriod.second);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800528 security::v2::Certificate newCert;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700529
530 Name certName = certRequest.m_cert.getKeyName();
531 certName.append("NDNCERT").append(std::to_string(random::generateSecureWord64()));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800532 newCert.setName(certName);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700533 newCert.setContent(certRequest.m_cert.getContent());
534 _LOG_TRACE("cert request content " << certRequest.m_cert);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800535 SignatureInfo signatureInfo;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800536 signatureInfo.setValidityPeriod(period);
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700537 security::SigningInfo signingInfo(security::SigningInfo::SIGNER_TYPE_ID,
Suyong Won256c9062020-05-11 02:45:56 -0700538 m_config.m_caPrefix, signatureInfo);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800539
540 m_keyChain.sign(newCert, signingInfo);
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700541 _LOG_TRACE("new cert got signed" << newCert);
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800542 return newCert;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800543}
544
545CertificateRequest
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700546CaModule::getCertificateRequest(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800547{
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400548 std::string requestId;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800549 CertificateRequest certRequest;
550 try {
Suyong Won256c9062020-05-11 02:45:56 -0700551 requestId = readString(request.getName().at(m_config.m_caPrefix.size() + 2));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700552 }
553 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700554 _LOG_ERROR("Cannot read the request ID out from the request: " << e.what());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700555 }
556 try {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700557 _LOG_TRACE("Request Id to query the database " << requestId);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800558 certRequest = m_storage->getRequest(requestId);
559 }
560 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700561 _LOG_ERROR("Cannot get certificate request record from the storage: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800562 }
563 return certRequest;
564}
565
566void
567CaModule::onRegisterFailed(const std::string& reason)
568{
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700569 _LOG_ERROR("Failed to register prefix in local hub's daemon, REASON: " << reason);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800570}
571
572Block
573CaModule::dataContentFromJson(const JsonSection& jsonSection)
574{
575 std::stringstream ss;
576 boost::property_tree::write_json(ss, jsonSection);
577 return makeStringBlock(ndn::tlv::Content, ss.str());
578}
579
580JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700581CaModule::jsonFromBlock(const Block& block)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800582{
583 std::string jsonString;
584 try {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700585 jsonString = encoding::readString(block);
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700586 std::istringstream ss(jsonString);
587 JsonSection json;
588 boost::property_tree::json_parser::read_json(ss, json);
589 return json;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800590 }
591 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700592 _LOG_ERROR("Cannot read JSON string from TLV Value: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800593 return JsonSection();
594 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800595}
596
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700597Data
598CaModule::generateErrorDataPacket(const Name& name, ErrorCode error, const std::string& errorInfo)
599{
600 Data result;
601 result.setName(name);
602 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
603 result.setContent(ErrorTLV::encodeDataContent(error, errorInfo));
604 m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
605 return result;
606}
607
608} // namespace ndncert
609} // namespace ndn