blob: 7439ef6aede8cbcf785ff196a0de29301896103b [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#include "challenge-module.hpp"
23#include "crypto-support/enc-tlv.hpp"
24#include "logging.hpp"
25#include "protocol-detail/challenge.hpp"
26#include "protocol-detail/error.hpp"
27#include "protocol-detail/info.hpp"
28#include "protocol-detail/new.hpp"
29#include "protocol-detail/probe.hpp"
30#include "protocol-detail/revoke.hpp"
Zhiyi Zhang01e91a32020-09-29 12:10:00 -070031#include <ndn-cxx/metadata-object.hpp>
32#include <ndn-cxx/security/signing-helpers.hpp>
33#include <ndn-cxx/security/verification-helpers.hpp>
34#include <ndn-cxx/util/io.hpp>
35#include <ndn-cxx/util/random.hpp>
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080036
37namespace ndn {
38namespace ndncert {
39
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -070040static const time::seconds DEFAULT_DATA_FRESHNESS_PERIOD = 1_s;
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -070041static const time::seconds REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD = 120_s;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070042
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080043_LOG_INIT(ndncert.ca);
44
45CaModule::CaModule(Face& face, security::v2::KeyChain& keyChain,
46 const std::string& configPath, const std::string& storageType)
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070047 : m_face(face)
48 , m_keyChain(keyChain)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080049{
Zhiyi Zhanga63b7372017-05-17 14:14:34 -070050 // load the config and create storage
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080051 m_config.load(configPath);
52 m_storage = CaStorage::createCaStorage(storageType);
53
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080054 registerPrefix();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080055}
56
57CaModule::~CaModule()
58{
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -070059 for (auto& handle : m_interestFilterHandles) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070060 handle.cancel();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080061 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -070062 for (auto& handle : m_registeredPrefixHandles) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070063 handle.unregister();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080064 }
65}
66
67void
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080068CaModule::registerPrefix()
69{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070070 // register localhop discovery prefix
swa77020643ac2020-03-26 02:24:45 -070071 Name localhopInfoPrefix("/localhop/CA/INFO");
72 auto prefixId = m_face.setInterestFilter(InterestFilter(localhopInfoPrefix),
73 bind(&CaModule::onInfo, this, _2),
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080074 bind(&CaModule::onRegisterFailed, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070075 m_registeredPrefixHandles.push_back(prefixId);
swa77020643ac2020-03-26 02:24:45 -070076 _LOG_TRACE("Prefix " << localhopInfoPrefix << " got registered");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080077
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070078 // register prefixes
Suyong Won256c9062020-05-11 02:45:56 -070079 Name prefix = m_config.m_caPrefix;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070080 prefix.append("CA");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080081
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070082 prefixId = m_face.registerPrefix(
83 prefix,
84 [&](const Name& name) {
85 // register INFO prefix
86 auto filterId = m_face.setInterestFilter(Name(name).append("INFO"),
87 bind(&CaModule::onInfo, this, _2));
88 m_interestFilterHandles.push_back(filterId);
swa77020643ac2020-03-26 02:24:45 -070089
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070090 // register PROBE prefix
91 filterId = m_face.setInterestFilter(Name(name).append("PROBE"),
92 bind(&CaModule::onProbe, this, _2));
93 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070094
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070095 // register NEW prefix
96 filterId = m_face.setInterestFilter(Name(name).append("NEW"),
Zhiyi Zhang01e91a32020-09-29 12:10:00 -070097 bind(&CaModule::onNewRenewRevoke, this, _2, RequestType::NEW));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070098 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070099
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700100 // register SELECT prefix
101 filterId = m_face.setInterestFilter(Name(name).append("CHALLENGE"),
102 bind(&CaModule::onChallenge, this, _2));
103 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700104
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700105 // register REVOKE prefix
106 filterId = m_face.setInterestFilter(Name(name).append("REVOKE"),
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700107 bind(&CaModule::onNewRenewRevoke, this, _2, RequestType::REVOKE));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700108 m_interestFilterHandles.push_back(filterId);
109 _LOG_TRACE("Prefix " << name << " got registered");
110 },
111 bind(&CaModule::onRegisterFailed, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700112 m_registeredPrefixHandles.push_back(prefixId);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800113}
114
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700115void
116CaModule::setNameAssignmentFunction(const NameAssignmentFunc& handler)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800117{
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700118 m_config.m_nameAssignmentFunc = handler;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800119}
120
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700121void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700122CaModule::setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800123{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700124 m_config.m_statusUpdateCallback = onUpdateCallback;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800125}
126
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700127shared_ptr<Data>
128CaModule::generateCaConfigMetaData()
swa77020643ac2020-03-26 02:24:45 -0700129{
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700130 // @TODO
131 // make metadata a class member variable m_infoMetadata
132 // check whether the m_infoMetadata has the latest versioned name, if not, then generate a new one
133 // otherwise, directly reply m_infoMetadata.makeData
134
135 auto infoPacket = generateCaConfigData();
136 MetadataObject metadata;
137 metadata.setVersionedName(infoPacket->getName().getPrefix(-1));
138 Name discoveryInterestName(infoPacket->getName().getPrefix(-2));
139 name::Component metadataComponent(32, reinterpret_cast<const uint8_t*>("metadata"), std::strlen("metadata"));
140 discoveryInterestName.append(metadataComponent);
141 auto metadataData = metadata.makeData(discoveryInterestName, m_keyChain, signingByIdentity(m_config.m_caPrefix));
142 return make_shared<Data>(metadataData);
143}
144
145shared_ptr<Data>
146CaModule::generateCaConfigData()
147{
148 // @TODO
149 // make CaInfo Data packet a class member variable m_infoData
150 // check whether the m_infoData is still valid, if not, then generate a new one
151 // otherwise, directly reply m_infoData
Suyong Won19fba4d2020-05-09 13:39:46 -0700152
153 const auto& pib = m_keyChain.getPib();
Suyong Won256c9062020-05-11 02:45:56 -0700154 const auto& identity = pib.getIdentity(m_config.m_caPrefix);
Suyong Won19fba4d2020-05-09 13:39:46 -0700155 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
Zhiyi Zhang61c43a62020-09-28 12:56:01 -0700156 Block contentTLV = INFO::encodeDataContent(m_config, cert);
swa77020643ac2020-03-26 02:24:45 -0700157
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700158 Name infoPacketName(m_config.m_caPrefix);
159 infoPacketName.append("CA").append("INFO").appendVersion().appendSegment(0);
160 Data infoData(infoPacketName);
161 infoData.setContent(contentTLV);
162 infoData.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
163 m_keyChain.sign(infoData, signingByIdentity(m_config.m_caPrefix));
164 return make_shared<Data>(infoData);
165}
swa77020643ac2020-03-26 02:24:45 -0700166
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700167void
168CaModule::onInfo(const Interest& request)
169{
170 _LOG_TRACE("Received INFO request");
171
172 if (request.getName().get(-1).type() == 32) {
173 m_face.put(*generateCaConfigMetaData());
174 }
175 else {
176 m_face.put(*generateCaConfigData());
177 }
swa77020643ac2020-03-26 02:24:45 -0700178
179 _LOG_TRACE("Handle INFO: send out the INFO response");
180}
181
182void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700183CaModule::onProbe(const Interest& request)
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800184{
swa77020643ac2020-03-26 02:24:45 -0700185 // PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent]
186 _LOG_TRACE("Received PROBE request");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800187
swa77020643ac2020-03-26 02:24:45 -0700188 // process PROBE requests: find an available name
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700189 std::string availableId = "";
Suyong Won19fba4d2020-05-09 13:39:46 -0700190 const auto& parameterTLV = request.getApplicationParameters();
Suyong Won44d0cce2020-05-10 04:07:43 -0700191 parameterTLV.parse();
Suyong Won19fba4d2020-05-09 13:39:46 -0700192 if (!parameterTLV.hasValue()) {
193 _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
swa77020643ac2020-03-26 02:24:45 -0700194 return;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700195 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700196
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700197 // if (m_config.m_nameAssignmentFunc) {
198 // try {
199 // availableId = m_config.m_nameAssignmentFunc(parameterTLV);
200 // }
201 // catch (const std::exception& e) {
202 // _LOG_TRACE("Cannot find PROBE input from PROBE parameters: " << e.what());
203 // return;
204 // }
205 // }
206 // else {
207 // // if there is no app-specified name lookup, use a random name id
208 // availableId = std::to_string(random::generateSecureWord64());
209 // }
210 // Name newIdentityName = m_config.m_caPrefix;
211 // newIdentityName.append(availableId);
212 // _LOG_TRACE("Handle PROBE: generate an identity " << newIdentityName);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800213
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700214 // Block contentTLV = PROBE::encodeDataContent(newIdentityName.toUri(), m_config.m_probe, parameterTLV);
215
216 // Data result;
217 // result.setName(request.getName());
218 // result.setContent(contentTLV);
219 // result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
220 // m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
221 // m_face.put(result);
222 // _LOG_TRACE("Handle PROBE: send out the PROBE response");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800223}
224
225void
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700226CaModule::onNewRenewRevoke(const Interest& request, RequestType requestType)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800227{
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700228 // NEW Naming Convention: /<CA-prefix>/CA/NEW/[SignedInterestParameters_Digest]
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700229 // REVOKE Naming Convention: /<CA-prefix>/CA/REVOKE/[SignedInterestParameters_Digest]
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700230 // get ECDH pub key and cert request
Suyong Won19fba4d2020-05-09 13:39:46 -0700231 const auto& parameterTLV = request.getApplicationParameters();
Suyong Won7968f7a2020-05-12 01:01:25 -0700232 parameterTLV.parse();
233
Suyong Won19fba4d2020-05-09 13:39:46 -0700234 if (!parameterTLV.hasValue()) {
235 _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700236 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
237 "Empty TLV obtained from the Interest parameter."));
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700238 return;
239 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700240
241 std::string peerKeyBase64 = readString(parameterTLV.get(tlv_ecdh_pub));
242
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700243 if (peerKeyBase64 == "") {
Suyong Won19fba4d2020-05-09 13:39:46 -0700244 _LOG_ERROR("Empty ECDH PUB obtained from the Interest parameter.");
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700245 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
246 "Empty ECDH PUB obtained from the Interest parameter."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700247 return;
248 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700249
250 // get server's ECDH pub key
251 auto myEcdhPubKeyBase64 = m_ecdh.getBase64PubKey();
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700252 try {
253 m_ecdh.deriveSecret(peerKeyBase64);
254 }
255 catch (const std::exception& e) {
256 _LOG_ERROR("Cannot derive a shared secret using the provided ECDH key: " << e.what());
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700257 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
258 "Cannot derive a shared secret using the provided ECDH key."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700259 return;
260 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700261 // generate salt for HKDF
262 auto saltInt = random::generateSecureWord64();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700263 // hkdf
264 hkdf(m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen,
Zhiyi Zhang36706832019-07-04 21:33:03 -0700265 (uint8_t*)&saltInt, sizeof(saltInt), m_aesKey, sizeof(m_aesKey));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700266
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700267 shared_ptr<security::v2::Certificate> clientCert = nullptr;
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700268 // parse certificate request
269 Block requestPayload = parameterTLV.get(tlv_cert_request);
270 requestPayload.parse();
271 try {
272 security::v2::Certificate cert = security::v2::Certificate(requestPayload.get(tlv::Data));
273 clientCert = make_shared<security::v2::Certificate>(cert);
274 }
275 catch (const std::exception& e) {
276 _LOG_ERROR("Unrecognized self-signed certificate: " << e.what());
277 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
278 "Unrecognized self-signed certificate."));
279 return;
280 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700281 if (requestType == RequestType::NEW) {
tylerliu4a00aad2020-09-26 02:03:17 -0700282 // check the validity period
283 auto expectedPeriod = clientCert->getValidityPeriod().getPeriod();
284 auto currentTime = time::system_clock::now();
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700285 if (expectedPeriod.first < currentTime - REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD ||
286 expectedPeriod.second > currentTime + m_config.m_maxValidityPeriod ||
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700287 expectedPeriod.second <= expectedPeriod.first) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700288 _LOG_ERROR("An invalid validity period is being requested.");
289 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_VALIDITY_PERIOD,
290 "An invalid validity period is being requested."));
tylerliu4a00aad2020-09-26 02:03:17 -0700291 return;
292 }
tylerliu4a00aad2020-09-26 02:03:17 -0700293 // verify the self-signed certificate, the request, and the token
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700294 if (!m_config.m_caPrefix.isPrefixOf(clientCert->getIdentity())
295 || !security::v2::Certificate::isValidName(clientCert->getName())
tylerliuc84c3ba2020-09-28 18:09:46 -0700296 || clientCert->getIdentity().size() <= m_config.m_caPrefix.size()
297 || clientCert->getIdentity().size() > m_config.m_caPrefix.size() + m_config.m_maxSuffixLength) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700298 _LOG_ERROR("An invalid certificate name is being requested " << clientCert->getName());
299 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::NAME_NOT_ALLOWED,
300 "An invalid certificate name is being requested."));
tylerliu4a00aad2020-09-26 02:03:17 -0700301 return;
302 }
303 if (!security::verifySignature(*clientCert, *clientCert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700304 _LOG_ERROR("Invalid signature in the self-signed certificate.");
305 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
306 "Invalid signature in the self-signed certificate."));
tylerliu4a00aad2020-09-26 02:03:17 -0700307 return;
308 }
309 if (!security::verifySignature(request, *clientCert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700310 _LOG_ERROR("Invalid signature in the Interest packet.");
311 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
312 "Invalid signature in the Interest packet."));
tylerliu4a00aad2020-09-26 02:03:17 -0700313 return;
314 }
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700315 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700316 else if (requestType == RequestType::REVOKE) {
tylerliu4a00aad2020-09-26 02:03:17 -0700317 // verify the certificate
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700318 if (!m_config.m_caPrefix.isPrefixOf(clientCert->getIdentity())
319 || !security::v2::Certificate::isValidName(clientCert->getName())
tylerliuc84c3ba2020-09-28 18:09:46 -0700320 || clientCert->getIdentity().size() <= m_config.m_caPrefix.size()
321 || clientCert->getIdentity().size() > m_config.m_caPrefix.size() + m_config.m_maxSuffixLength) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700322 _LOG_ERROR("An invalid certificate name is being requested " << clientCert->getName());
323 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::NAME_NOT_ALLOWED,
324 "An invalid certificate name is being requested."));
tylerliu4a00aad2020-09-26 02:03:17 -0700325 return;
326 }
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700327 const auto& cert = m_keyChain.getPib().getIdentity(m_config.m_caPrefix).getDefaultKey().getDefaultCertificate();
tylerliu4a00aad2020-09-26 02:03:17 -0700328 if (!security::verifySignature(*clientCert, cert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700329 _LOG_ERROR("Invalid signature in the certificate to revoke.");
330 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
331 "Invalid signature in the certificate to revoke."));
tylerliu4a00aad2020-09-26 02:03:17 -0700332 return;
333 }
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700334 }
335
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700336 // create new request instance
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800337 std::string requestId = std::to_string(random::generateWord64());
Zhiyi Zhang48f23782020-09-28 12:11:24 -0700338 CertificateRequest certRequest(m_config.m_caPrefix, requestId, requestType, Status::BEFORE_CHALLENGE, *clientCert);
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700339 m_storage->addRequest(certRequest);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800340 Data result;
341 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700342 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700343 if (requestType == RequestType::NEW) {
tylerliu4a00aad2020-09-26 02:03:17 -0700344 result.setContent(NEW::encodeDataContent(myEcdhPubKeyBase64,
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700345 std::to_string(saltInt),
346 certRequest,
347 m_config.m_supportedChallenges));
348 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700349 else if (requestType == RequestType::REVOKE) {
tylerliu4a00aad2020-09-26 02:03:17 -0700350 result.setContent(REVOKE::encodeDataContent(myEcdhPubKeyBase64,
351 std::to_string(saltInt),
352 certRequest,
353 m_config.m_supportedChallenges));
354 }
Suyong Won256c9062020-05-11 02:45:56 -0700355 m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800356 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700357 if (m_config.m_statusUpdateCallback) {
358 m_config.m_statusUpdateCallback(certRequest);
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800359 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800360}
361
362void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700363CaModule::onChallenge(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800364{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700365 // get certificate request state
366 CertificateRequest certRequest = getCertificateRequest(request);
367 if (certRequest.m_requestId == "") {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700368 _LOG_ERROR("No certificate request state can be found.");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700369 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700370 "No certificate request state can be found."));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800371 return;
372 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700373 // verify signature
374 if (!security::verifySignature(request, certRequest.m_cert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700375 _LOG_ERROR("Invalid Signature in the Interest packet.");
376 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
377 "Invalid Signature in the Interest packet."));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800378 return;
379 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700380 // decrypt the parameters
Suyong Won19fba4d2020-05-09 13:39:46 -0700381 Buffer paramTLVPayload;
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700382 try {
Suyong Won19fba4d2020-05-09 13:39:46 -0700383 paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), m_aesKey,
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700384 (uint8_t*)"test", strlen("test"));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700385 }
386 catch (const std::exception& e) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700387 _LOG_ERROR("Interest paramaters decryption failed: " << e.what());
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700388 m_storage->deleteRequest(certRequest.m_requestId);
389 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700390 "Interest paramaters decryption failed."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700391 return;
392 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700393 if (paramTLVPayload.size() == 0) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700394 _LOG_ERROR("No parameters are found after decryption.");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700395 m_storage->deleteRequest(certRequest.m_requestId);
396 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700397 "No parameters are found after decryption."));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700398 return;
399 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700400 Block paramTLV = makeBinaryBlock(tlv_encrypted_payload, paramTLVPayload.data(), paramTLVPayload.size());
401 paramTLV.parse();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800402
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700403 // load the corresponding challenge module
Suyong Won19fba4d2020-05-09 13:39:46 -0700404 std::string challengeType = readString(paramTLV.get(tlv_selected_challenge));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800405 auto challenge = ChallengeModule::createChallengeModule(challengeType);
406 if (challenge == nullptr) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700407 _LOG_TRACE("Unrecognized challenge type: " << challengeType);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700408 m_storage->deleteRequest(certRequest.m_requestId);
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700409 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER, "Unrecognized challenge type."));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700410 return;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800411 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700412
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700413 _LOG_TRACE("CHALLENGE module to be load: " << challengeType);
414 auto errorInfo = challenge->handleChallengeRequest(paramTLV, certRequest);
415 if (std::get<0>(errorInfo) != ErrorCode::NO_ERROR) {
416 m_storage->deleteRequest(certRequest.m_requestId);
417 m_face.put(generateErrorDataPacket(request.getName(), std::get<0>(errorInfo), std::get<1>(errorInfo)));
418 return;
419 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700420
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700421 Block payload;
422 if (certRequest.m_status == Status::PENDING) {
423 // if challenge succeeded
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700424 if (certRequest.m_requestType == RequestType::NEW) {
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700425 auto issuedCert = issueCertificate(certRequest);
426 certRequest.m_cert = issuedCert;
427 certRequest.m_status = Status::SUCCESS;
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700428 m_storage->addCertificate(certRequest.m_requestId, issuedCert);
429 m_storage->deleteRequest(certRequest.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700430
Suyong Won44d0cce2020-05-10 04:07:43 -0700431 payload = CHALLENGE::encodeDataPayload(certRequest);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700432 payload.parse();
433 payload.push_back(makeNestedBlock(tlv_issued_cert_name, issuedCert.getName()));
434 payload.encode();
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700435 _LOG_TRACE("Challenge succeeded. Certificate has been issued: " << issuedCert.getName());
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800436 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700437 else if (certRequest.m_requestType == RequestType::REVOKE) {
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700438 certRequest.m_status = Status::SUCCESS;
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700439 m_storage->deleteRequest(certRequest.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700440
441 payload = CHALLENGE::encodeDataPayload(certRequest);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700442 _LOG_TRACE("Challenge succeeded. Certificate has been revoked");
443 }
444 }
445 else {
446 m_storage->updateRequest(certRequest);
447 payload = CHALLENGE::encodeDataPayload(certRequest);
448 _LOG_TRACE("No failure no success. Challenge moves on");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800449 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700450
451 Data result;
452 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700453 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
Suyong Won7968f7a2020-05-12 01:01:25 -0700454 auto contentBlock = encodeBlockWithAesGcm128(tlv::Content, m_aesKey, payload.value(),
455 payload.value_size(), (uint8_t*)"test", strlen("test"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700456 result.setContent(contentBlock);
Suyong Won256c9062020-05-11 02:45:56 -0700457 m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700458 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700459 if (m_config.m_statusUpdateCallback) {
460 m_config.m_statusUpdateCallback(certRequest);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800461 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700462}
463
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800464security::v2::Certificate
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700465CaModule::issueCertificate(const CertificateRequest& certRequest)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800466{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700467 auto expectedPeriod =
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700468 certRequest.m_cert.getValidityPeriod().getPeriod();
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700469 security::ValidityPeriod period(expectedPeriod.first, expectedPeriod.second);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800470 security::v2::Certificate newCert;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700471
472 Name certName = certRequest.m_cert.getKeyName();
473 certName.append("NDNCERT").append(std::to_string(random::generateSecureWord64()));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800474 newCert.setName(certName);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700475 newCert.setContent(certRequest.m_cert.getContent());
476 _LOG_TRACE("cert request content " << certRequest.m_cert);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800477 SignatureInfo signatureInfo;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800478 signatureInfo.setValidityPeriod(period);
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700479 security::SigningInfo signingInfo(security::SigningInfo::SIGNER_TYPE_ID,
Suyong Won256c9062020-05-11 02:45:56 -0700480 m_config.m_caPrefix, signatureInfo);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800481
482 m_keyChain.sign(newCert, signingInfo);
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700483 _LOG_TRACE("new cert got signed" << newCert);
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800484 return newCert;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800485}
486
487CertificateRequest
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700488CaModule::getCertificateRequest(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800489{
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400490 std::string requestId;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800491 CertificateRequest certRequest;
492 try {
Suyong Won256c9062020-05-11 02:45:56 -0700493 requestId = readString(request.getName().at(m_config.m_caPrefix.size() + 2));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700494 }
495 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700496 _LOG_ERROR("Cannot read the request ID out from the request: " << e.what());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700497 }
498 try {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700499 _LOG_TRACE("Request Id to query the database " << requestId);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800500 certRequest = m_storage->getRequest(requestId);
501 }
502 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700503 _LOG_ERROR("Cannot get certificate request record from the storage: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800504 }
505 return certRequest;
506}
507
508void
509CaModule::onRegisterFailed(const std::string& reason)
510{
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700511 _LOG_ERROR("Failed to register prefix in local hub's daemon, REASON: " << reason);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800512}
513
514Block
515CaModule::dataContentFromJson(const JsonSection& jsonSection)
516{
517 std::stringstream ss;
518 boost::property_tree::write_json(ss, jsonSection);
519 return makeStringBlock(ndn::tlv::Content, ss.str());
520}
521
522JsonSection
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700523CaModule::jsonFromBlock(const Block& block)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800524{
525 std::string jsonString;
526 try {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700527 jsonString = encoding::readString(block);
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700528 std::istringstream ss(jsonString);
529 JsonSection json;
530 boost::property_tree::json_parser::read_json(ss, json);
531 return json;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800532 }
533 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700534 _LOG_ERROR("Cannot read JSON string from TLV Value: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800535 return JsonSection();
536 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800537}
538
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700539Data
540CaModule::generateErrorDataPacket(const Name& name, ErrorCode error, const std::string& errorInfo)
541{
542 Data result;
543 result.setName(name);
544 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
545 result.setContent(ErrorTLV::encodeDataContent(error, errorInfo));
546 m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
547 return result;
548}
549
550} // namespace ndncert
551} // namespace ndn