blob: 86e705f99b74c83ee46acb70aaea6b63f5dcf6c7 [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 "crypto-support/enc-tlv.hpp"
Zhiyi Zhangcd57da82020-10-08 20:35:40 -070023#include "identity-challenge/challenge-module.hpp"
24#include "name-assignments/assignment-funcs.hpp"
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070025#include "protocol-detail/challenge.hpp"
26#include "protocol-detail/error.hpp"
27#include "protocol-detail/info.hpp"
tylerliu4889a782020-09-30 22:47:49 -070028#include "protocol-detail/new-renew-revoke.hpp"
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070029#include "protocol-detail/probe.hpp"
Zhiyi Zhang01e91a32020-09-29 12:10:00 -070030#include <ndn-cxx/metadata-object.hpp>
31#include <ndn-cxx/security/signing-helpers.hpp>
32#include <ndn-cxx/security/verification-helpers.hpp>
33#include <ndn-cxx/util/io.hpp>
34#include <ndn-cxx/util/random.hpp>
Zhiyi Zhang8683ec92020-10-07 18:18:35 -070035#include <ndn-cxx/util/string-helper.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
tylerliua7bea662020-10-08 18:51:02 -070045CaModule::CaModule(Face& face, security::KeyChain& keyChain,
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080046 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);
Zhiyi Zhangd1d9f5a2020-10-05 18:04:23 -070052 m_storage = CaStorage::createCaStorage(storageType, m_config.m_caItem.m_caPrefix, "");
Zhiyi Zhanga2c39f72020-10-06 16:45:55 -070053 random::generateSecureBytes(m_requestIdGenKey, 32);
Zhiyi Zhang74c61142020-10-07 21:00:49 -070054 if (m_config.m_nameAssignmentFuncs.size() == 0) {
55 m_config.m_nameAssignmentFuncs.push_back(NameAssignmentFunc::createNameAssignmentFunc("random"));
Zhiyi Zhang8683ec92020-10-07 18:18:35 -070056 }
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080057 registerPrefix();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080058}
59
60CaModule::~CaModule()
61{
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -070062 for (auto& handle : m_interestFilterHandles) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070063 handle.cancel();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -080064 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -070065 for (auto& handle : m_registeredPrefixHandles) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070066 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 prefixes
Zhiyi Zhang9829da92020-09-30 16:19:34 -070074 Name prefix = m_config.m_caItem.m_caPrefix;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070075 prefix.append("CA");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080076
Zhiyi Zhangfbcab842020-10-07 15:17:13 -070077 auto prefixId = m_face.registerPrefix(
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070078 prefix,
79 [&](const Name& name) {
Zhiyi Zhang696cd042020-10-07 21:27:36 -070080 // register INFO RDR metadata prefix
81 name::Component metaDataComp(32, reinterpret_cast<const uint8_t*>("metadata"), std::strlen("metadata"));
82 auto filterId = m_face.setInterestFilter(Name(name).append("INFO").append(metaDataComp),
83 bind(&CaModule::onCaProfileDiscovery, this, _2));
84 m_interestFilterHandles.push_back(filterId);
85
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070086 // register PROBE prefix
Zhiyi Zhang696cd042020-10-07 21:27:36 -070087 filterId = m_face.setInterestFilter(Name(name).append("PROBE"),
Zhiyi Zhangcd57da82020-10-08 20:35:40 -070088 bind(&CaModule::onProbe, this, _2));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070089 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070090
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070091 // register NEW prefix
92 filterId = m_face.setInterestFilter(Name(name).append("NEW"),
Zhiyi Zhang01e91a32020-09-29 12:10:00 -070093 bind(&CaModule::onNewRenewRevoke, this, _2, RequestType::NEW));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070094 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070095
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070096 // register SELECT prefix
97 filterId = m_face.setInterestFilter(Name(name).append("CHALLENGE"),
98 bind(&CaModule::onChallenge, this, _2));
99 m_interestFilterHandles.push_back(filterId);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700100
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700101 // register REVOKE prefix
102 filterId = m_face.setInterestFilter(Name(name).append("REVOKE"),
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700103 bind(&CaModule::onNewRenewRevoke, this, _2, RequestType::REVOKE));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700104 m_interestFilterHandles.push_back(filterId);
105 _LOG_TRACE("Prefix " << name << " got registered");
106 },
107 bind(&CaModule::onRegisterFailed, this, _2));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700108 m_registeredPrefixHandles.push_back(prefixId);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800109}
110
Zhiyi Zhangf6c5d272020-09-28 10:17:32 -0700111void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700112CaModule::setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback)
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800113{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700114 m_config.m_statusUpdateCallback = onUpdateCallback;
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800115}
116
Zhiyi Zhang696cd042020-10-07 21:27:36 -0700117Data
118CaModule::getCaProfileData()
swa77020643ac2020-03-26 02:24:45 -0700119{
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700120 if (m_profileData == nullptr) {
121 const auto& pib = m_keyChain.getPib();
122 const auto& identity = pib.getIdentity(m_config.m_caItem.m_caPrefix);
123 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
124 Block contentTLV = INFO::encodeDataContent(m_config.m_caItem, cert);
swa77020643ac2020-03-26 02:24:45 -0700125
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700126 Name infoPacketName(m_config.m_caItem.m_caPrefix);
127 infoPacketName.append("CA").append("INFO").appendVersion().appendSegment(0);
128 m_profileData = std::make_unique<Data>(infoPacketName);
129 m_profileData->setContent(contentTLV);
130 m_profileData->setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
131 m_keyChain.sign(*m_profileData, signingByIdentity(m_config.m_caItem.m_caPrefix));
132 }
Zhiyi Zhang696cd042020-10-07 21:27:36 -0700133 return *m_profileData;
134}
135
136void
137CaModule::onCaProfileDiscovery(const Interest& request)
138{
139 _LOG_TRACE("Received CA Profile MetaData discovery Interest");
140 if (m_profileData == nullptr) {
141 m_profileData = std::make_unique<Data>(getCaProfileData());
142 }
143 MetadataObject metadata;
144 metadata.setVersionedName(m_profileData->getName().getPrefix(-1));
145 Name discoveryInterestName(m_profileData->getName().getPrefix(-2));
146 name::Component metadataComponent(32, reinterpret_cast<const uint8_t*>("metadata"), std::strlen("metadata"));
147 discoveryInterestName.append(metadataComponent);
148 m_face.put(metadata.makeData(discoveryInterestName, m_keyChain, signingByIdentity(m_config.m_caItem.m_caPrefix)));
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700149}
swa77020643ac2020-03-26 02:24:45 -0700150
Zhiyi Zhangfc1678a2020-05-12 16:52:14 -0700151void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700152CaModule::onProbe(const Interest& request)
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800153{
swa77020643ac2020-03-26 02:24:45 -0700154 // PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent]
155 _LOG_TRACE("Received PROBE request");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800156
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700157 // process PROBE requests: collect probe parameters
158 auto parameters = PROBE::decodeApplicationParameters(request.getApplicationParameters());
tylerliu8fc08072020-10-06 15:37:40 -0700159 std::vector<PartialName> availableComponents;
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700160 for (auto& item : m_config.m_nameAssignmentFuncs) {
161 auto names = item->assignName(parameters);
162 availableComponents.insert(availableComponents.end(), names.begin(), names.end());
163 }
Zhiyi Zhangcb8acf22020-10-07 19:35:16 -0700164 if (availableComponents.size() == 0) {
Zhiyi Zhang8683ec92020-10-07 18:18:35 -0700165 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhangcb8acf22020-10-07 19:35:16 -0700166 "Cannot generate available names from parameters provided."));
Zhiyi Zhang8683ec92020-10-07 18:18:35 -0700167 return;
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700168 }
169 std::vector<Name> availableNames;
170 for (const auto& component : availableComponents) {
171 Name newIdentityName = m_config.m_caItem.m_caPrefix;
172 newIdentityName.append(component);
173 availableNames.push_back(newIdentityName);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700174 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700175
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700176 Data result;
177 result.setName(request.getName());
Suyong Wone2afeb52020-10-04 03:05:39 +0900178 result.setContent(PROBE::encodeDataContent(availableNames, m_config.m_caItem.m_maxSuffixLength, m_config.m_redirection));
Zhiyi Zhang3e8ca252020-09-30 17:18:38 -0700179 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
180 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
181 m_face.put(result);
182 _LOG_TRACE("Handle PROBE: send out the PROBE response");
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800183}
184
185void
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700186CaModule::onNewRenewRevoke(const Interest& request, RequestType requestType)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800187{
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700188 // NEW Naming Convention: /<CA-prefix>/CA/NEW/[SignedInterestParameters_Digest]
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700189 // REVOKE Naming Convention: /<CA-prefix>/CA/REVOKE/[SignedInterestParameters_Digest]
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700190 // get ECDH pub key and cert request
Suyong Won19fba4d2020-05-09 13:39:46 -0700191 const auto& parameterTLV = request.getApplicationParameters();
tylerliu0790bdb2020-10-02 00:50:51 -0700192 std::string ecdhPub;
tylerliua7bea662020-10-08 18:51:02 -0700193 shared_ptr<security::Certificate> clientCert;
tylerliu0790bdb2020-10-02 00:50:51 -0700194 try {
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700195 NEW_RENEW_REVOKE::decodeApplicationParameters(parameterTLV, requestType, ecdhPub, clientCert);
196 }
197 catch (const std::exception& e) {
tylerliu0790bdb2020-10-02 00:50:51 -0700198 if (!parameterTLV.hasValue()) {
199 _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
200 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
201 "Empty TLV obtained from the Interest parameter."));
202 return;
203 }
Suyong Won7968f7a2020-05-12 01:01:25 -0700204
tylerliu0790bdb2020-10-02 00:50:51 -0700205 _LOG_ERROR("Unrecognized self-signed certificate: " << e.what());
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700206 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
tylerliu0790bdb2020-10-02 00:50:51 -0700207 "Unrecognized self-signed certificate."));
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700208 return;
209 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700210
tylerliu0790bdb2020-10-02 00:50:51 -0700211 if (ecdhPub == "") {
Suyong Won19fba4d2020-05-09 13:39:46 -0700212 _LOG_ERROR("Empty ECDH PUB obtained from the Interest parameter.");
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700213 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
214 "Empty ECDH PUB obtained from the Interest parameter."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700215 return;
216 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700217
218 // get server's ECDH pub key
tylerliu8e170d62020-09-30 01:31:53 -0700219 ECDHState ecdh;
220 auto myEcdhPubKeyBase64 = ecdh.getBase64PubKey();
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700221 try {
tylerliu0790bdb2020-10-02 00:50:51 -0700222 ecdh.deriveSecret(ecdhPub);
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700223 }
224 catch (const std::exception& e) {
225 _LOG_ERROR("Cannot derive a shared secret using the provided ECDH key: " << e.what());
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700226 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
227 "Cannot derive a shared secret using the provided ECDH key."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700228 return;
229 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700230 // generate salt for HKDF
231 auto saltInt = random::generateSecureWord64();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700232 // hkdf
tylerliu8e170d62020-09-30 01:31:53 -0700233 uint8_t aesKey[AES_128_KEY_LEN];
234 hkdf(ecdh.context->sharedSecret, ecdh.context->sharedSecretLen,
235 (uint8_t*)&saltInt, sizeof(saltInt), aesKey, sizeof(aesKey));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700236
tylerliud9239f52020-09-30 17:25:16 -0700237 // verify identity name
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700238<<<<<<< HEAD
tylerliud9239f52020-09-30 17:25:16 -0700239 if (!m_config.m_caItem.m_caPrefix.isPrefixOf(clientCert->getIdentity())
tylerliua7bea662020-10-08 18:51:02 -0700240 || !security::Certificate::isValidName(clientCert->getName())
tylerliud9239f52020-09-30 17:25:16 -0700241 || clientCert->getIdentity().size() <= m_config.m_caItem.m_caPrefix.size()) {
242 _LOG_ERROR("An invalid certificate name is being requested " << clientCert->getName());
243 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::NAME_NOT_ALLOWED,
244 "An invalid certificate name is being requested."));
245 return;
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700246=======
247 if (!m_config.m_caItem.m_caPrefix.isPrefixOf(clientCert->getIdentity()) || !security::v2::Certificate::isValidName(clientCert->getName()) || clientCert->getIdentity().size() <= m_config.m_caItem.m_caPrefix.size()) {
248 _LOG_ERROR("An invalid certificate name is being requested " << clientCert->getName());
249 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::NAME_NOT_ALLOWED,
250 "An invalid certificate name is being requested."));
251 return;
252>>>>>>> fix test errors
tylerliud9239f52020-09-30 17:25:16 -0700253 }
254 if (m_config.m_caItem.m_maxSuffixLength) {
255 if (clientCert->getIdentity().size() > m_config.m_caItem.m_caPrefix.size() + *m_config.m_caItem.m_maxSuffixLength) {
256 _LOG_ERROR("An invalid certificate name is being requested " << clientCert->getName());
257 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::NAME_NOT_ALLOWED,
258 "An invalid certificate name is being requested."));
259 return;
260 }
261 }
262
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700263 if (requestType == RequestType::NEW) {
tylerliu4a00aad2020-09-26 02:03:17 -0700264 // check the validity period
265 auto expectedPeriod = clientCert->getValidityPeriod().getPeriod();
266 auto currentTime = time::system_clock::now();
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700267 if (expectedPeriod.first < currentTime - REQUEST_VALIDITY_PERIOD_NOT_BEFORE_GRACE_PERIOD ||
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700268 expectedPeriod.second > currentTime + m_config.m_caItem.m_maxValidityPeriod ||
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700269 expectedPeriod.second <= expectedPeriod.first) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700270 _LOG_ERROR("An invalid validity period is being requested.");
271 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_VALIDITY_PERIOD,
272 "An invalid validity period is being requested."));
tylerliu4a00aad2020-09-26 02:03:17 -0700273 return;
274 }
tylerliud9239f52020-09-30 17:25:16 -0700275
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700276 // verify signature
tylerliu4a00aad2020-09-26 02:03:17 -0700277 if (!security::verifySignature(*clientCert, *clientCert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700278 _LOG_ERROR("Invalid signature in the self-signed certificate.");
279 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
280 "Invalid signature in the self-signed certificate."));
tylerliu4a00aad2020-09-26 02:03:17 -0700281 return;
282 }
283 if (!security::verifySignature(request, *clientCert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700284 _LOG_ERROR("Invalid signature in the Interest packet.");
285 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
286 "Invalid signature in the Interest packet."));
tylerliu4a00aad2020-09-26 02:03:17 -0700287 return;
288 }
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700289 }
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -0700290 else if (requestType == RequestType::REVOKE) {
tylerliud9239f52020-09-30 17:25:16 -0700291 //verify cert is from this CA
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700292 const auto& cert = m_keyChain.getPib().getIdentity(m_config.m_caItem.m_caPrefix).getDefaultKey().getDefaultCertificate();
tylerliu4a00aad2020-09-26 02:03:17 -0700293 if (!security::verifySignature(*clientCert, cert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700294 _LOG_ERROR("Invalid signature in the certificate to revoke.");
295 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
296 "Invalid signature in the certificate to revoke."));
tylerliu4a00aad2020-09-26 02:03:17 -0700297 return;
298 }
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700299 }
300
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700301 // create new request instance
Zhiyi Zhanga2c39f72020-10-06 16:45:55 -0700302 uint8_t requestIdData[32];
303 Block certNameTlv = clientCert->getName().wireEncode();
304 ndn_compute_hmac_sha256(certNameTlv.wire(), certNameTlv.size(), m_requestIdGenKey, 32, requestIdData);
Zhiyi Zhang8683ec92020-10-07 18:18:35 -0700305 CaState requestState(m_config.m_caItem.m_caPrefix, toHex(requestIdData, 32),
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700306 requestType, Status::BEFORE_CHALLENGE, *clientCert,
307 makeBinaryBlock(tlv::ContentType_Key, aesKey, sizeof(aesKey)));
Zhiyi Zhang21d52b52020-10-05 18:29:15 -0700308 try {
309 m_storage->addRequest(requestState);
310 }
311 catch (const std::runtime_error& e) {
Zhiyi Zhanga2c39f72020-10-06 16:45:55 -0700312 _LOG_ERROR("Duplicate Request ID: The same request has been seen before.");
313 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
314 "Duplicate Request ID: The same request has been seen before.."));
315 return;
Zhiyi Zhang21d52b52020-10-05 18:29:15 -0700316 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800317 Data result;
318 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700319 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
tylerliu4889a782020-09-30 22:47:49 -0700320 result.setContent(NEW_RENEW_REVOKE::encodeDataContent(myEcdhPubKeyBase64,
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700321 std::to_string(saltInt),
322 requestState,
323 m_config.m_caItem.m_supportedChallenges));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700324 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800325 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700326 if (m_config.m_statusUpdateCallback) {
tylerliu63900d52020-09-30 03:01:18 -0700327 m_config.m_statusUpdateCallback(requestState);
Zhiyi Zhang7420cf52017-12-18 18:59:21 +0800328 }
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800329}
330
331void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700332CaModule::onChallenge(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800333{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700334 // get certificate request state
tylerliu8704d032020-06-23 10:18:15 -0700335 CaState requestState = getCertificateRequest(request);
tylerliu63900d52020-09-30 03:01:18 -0700336 if (requestState.m_requestId == "") {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700337 _LOG_ERROR("No certificate request state can be found.");
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700338 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700339 "No certificate request state can be found."));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800340 return;
341 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700342 // verify signature
tylerliu63900d52020-09-30 03:01:18 -0700343 if (!security::verifySignature(request, requestState.m_cert)) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700344 _LOG_ERROR("Invalid Signature in the Interest packet.");
345 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::BAD_SIGNATURE,
346 "Invalid Signature in the Interest packet."));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800347 return;
348 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700349 // decrypt the parameters
Suyong Won19fba4d2020-05-09 13:39:46 -0700350 Buffer paramTLVPayload;
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700351 try {
tylerliu63900d52020-09-30 03:01:18 -0700352 paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), requestState.m_encryptionKey.value(),
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700353 (uint8_t*)"test", strlen("test"));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700354 }
355 catch (const std::exception& e) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700356 _LOG_ERROR("Interest paramaters decryption failed: " << e.what());
tylerliu63900d52020-09-30 03:01:18 -0700357 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700358 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700359 "Interest paramaters decryption failed."));
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700360 return;
361 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700362 if (paramTLVPayload.size() == 0) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700363 _LOG_ERROR("No parameters are found after decryption.");
tylerliu63900d52020-09-30 03:01:18 -0700364 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700365 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER,
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700366 "No parameters are found after decryption."));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700367 return;
368 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700369 Block paramTLV = makeBinaryBlock(tlv_encrypted_payload, paramTLVPayload.data(), paramTLVPayload.size());
370 paramTLV.parse();
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800371
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700372 // load the corresponding challenge module
Suyong Won19fba4d2020-05-09 13:39:46 -0700373 std::string challengeType = readString(paramTLV.get(tlv_selected_challenge));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800374 auto challenge = ChallengeModule::createChallengeModule(challengeType);
375 if (challenge == nullptr) {
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700376 _LOG_TRACE("Unrecognized challenge type: " << challengeType);
tylerliu63900d52020-09-30 03:01:18 -0700377 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700378 m_face.put(generateErrorDataPacket(request.getName(), ErrorCode::INVALID_PARAMETER, "Unrecognized challenge type."));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700379 return;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800380 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700381
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700382 _LOG_TRACE("CHALLENGE module to be load: " << challengeType);
tylerliu63900d52020-09-30 03:01:18 -0700383 auto errorInfo = challenge->handleChallengeRequest(paramTLV, requestState);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700384 if (std::get<0>(errorInfo) != ErrorCode::NO_ERROR) {
tylerliu63900d52020-09-30 03:01:18 -0700385 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700386 m_face.put(generateErrorDataPacket(request.getName(), std::get<0>(errorInfo), std::get<1>(errorInfo)));
387 return;
388 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700389
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700390 Block payload;
tylerliu63900d52020-09-30 03:01:18 -0700391 if (requestState.m_status == Status::PENDING) {
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700392 // if challenge succeeded
tylerliu63900d52020-09-30 03:01:18 -0700393 if (requestState.m_requestType == RequestType::NEW) {
394 auto issuedCert = issueCertificate(requestState);
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700395 requestState.m_cert = issuedCert;
396 requestState.m_status = Status::SUCCESS;
tylerliu63900d52020-09-30 03:01:18 -0700397 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700398
tylerliu63900d52020-09-30 03:01:18 -0700399 payload = CHALLENGE::encodeDataPayload(requestState);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700400 payload.parse();
401 payload.push_back(makeNestedBlock(tlv_issued_cert_name, issuedCert.getName()));
402 payload.encode();
Zhiyi Zhang01e91a32020-09-29 12:10:00 -0700403 _LOG_TRACE("Challenge succeeded. Certificate has been issued: " << issuedCert.getName());
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800404 }
tylerliu63900d52020-09-30 03:01:18 -0700405 else if (requestState.m_requestType == RequestType::REVOKE) {
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700406 requestState.m_status = Status::SUCCESS;
tylerliu63900d52020-09-30 03:01:18 -0700407 m_storage->deleteRequest(requestState.m_requestId);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700408
tylerliu63900d52020-09-30 03:01:18 -0700409 payload = CHALLENGE::encodeDataPayload(requestState);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700410 _LOG_TRACE("Challenge succeeded. Certificate has been revoked");
411 }
412 }
413 else {
tylerliu63900d52020-09-30 03:01:18 -0700414 m_storage->updateRequest(requestState);
415 payload = CHALLENGE::encodeDataPayload(requestState);
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700416 _LOG_TRACE("No failure no success. Challenge moves on");
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800417 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700418
419 Data result;
420 result.setName(request.getName());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700421 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
tylerliu63900d52020-09-30 03:01:18 -0700422 auto contentBlock = encodeBlockWithAesGcm128(tlv::Content, requestState.m_encryptionKey.value(), payload.value(),
Suyong Won7968f7a2020-05-12 01:01:25 -0700423 payload.value_size(), (uint8_t*)"test", strlen("test"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700424 result.setContent(contentBlock);
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700425 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700426 m_face.put(result);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700427 if (m_config.m_statusUpdateCallback) {
tylerliu63900d52020-09-30 03:01:18 -0700428 m_config.m_statusUpdateCallback(requestState);
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +0800429 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700430}
431
tylerliua7bea662020-10-08 18:51:02 -0700432security::Certificate
tylerliu8704d032020-06-23 10:18:15 -0700433CaModule::issueCertificate(const CaState& requestState)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800434{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700435 auto expectedPeriod =
tylerliu63900d52020-09-30 03:01:18 -0700436 requestState.m_cert.getValidityPeriod().getPeriod();
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700437 security::ValidityPeriod period(expectedPeriod.first, expectedPeriod.second);
tylerliua7bea662020-10-08 18:51:02 -0700438 security::Certificate newCert;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700439
tylerliu63900d52020-09-30 03:01:18 -0700440 Name certName = requestState.m_cert.getKeyName();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700441 certName.append("NDNCERT").append(std::to_string(random::generateSecureWord64()));
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800442 newCert.setName(certName);
tylerliu63900d52020-09-30 03:01:18 -0700443 newCert.setContent(requestState.m_cert.getContent());
444 _LOG_TRACE("cert request content " << requestState.m_cert);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800445 SignatureInfo signatureInfo;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800446 signatureInfo.setValidityPeriod(period);
Zhiyi Zhangad6cf932017-10-26 16:19:15 -0700447 security::SigningInfo signingInfo(security::SigningInfo::SIGNER_TYPE_ID,
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700448 m_config.m_caItem.m_caPrefix, signatureInfo);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800449
450 m_keyChain.sign(newCert, signingInfo);
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700451 _LOG_TRACE("new cert got signed" << newCert);
Zhiyi Zhang343cdfb2018-01-17 12:04:28 -0800452 return newCert;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800453}
454
tylerliu8704d032020-06-23 10:18:15 -0700455CaState
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700456CaModule::getCertificateRequest(const Interest& request)
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800457{
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400458 std::string requestId;
tylerliu8704d032020-06-23 10:18:15 -0700459 CaState requestState;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800460 try {
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700461 requestId = readString(request.getName().at(m_config.m_caItem.m_caPrefix.size() + 2));
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700462 }
463 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700464 _LOG_ERROR("Cannot read the request ID out from the request: " << e.what());
Zhiyi Zhang42e1cf32019-06-22 17:11:42 -0700465 }
466 try {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700467 _LOG_TRACE("Request Id to query the database " << requestId);
Zhiyi Zhangcd57da82020-10-08 20:35:40 -0700468 requestState = m_storage->getRequest(requestId);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800469 }
470 catch (const std::exception& e) {
Zhiyi Zhangbc2d4122019-09-10 12:10:54 -0700471 _LOG_ERROR("Cannot get certificate request record from the storage: " << e.what());
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800472 }
tylerliu63900d52020-09-30 03:01:18 -0700473 return requestState;
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800474}
475
476void
477CaModule::onRegisterFailed(const std::string& reason)
478{
Zhiyi Zhang693c1272017-05-20 22:58:55 -0700479 _LOG_ERROR("Failed to register prefix in local hub's daemon, REASON: " << reason);
Zhiyi Zhangf5246c42017-01-26 09:39:20 -0800480}
481
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700482Data
483CaModule::generateErrorDataPacket(const Name& name, ErrorCode error, const std::string& errorInfo)
484{
485 Data result;
486 result.setName(name);
487 result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
488 result.setContent(ErrorTLV::encodeDataContent(error, errorInfo));
Zhiyi Zhang9829da92020-09-30 16:19:34 -0700489 m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -0700490 return result;
491}
492
493} // namespace ndncert
494} // namespace ndn