blob: 2089e2aa1ac22aad0edce0f0b29586462932e1ae [file] [log] [blame]
Yingdi Yu6ff31932015-03-23 13:30:07 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyevbe998ac2017-05-06 13:11:42 -07003 * Copyright (c) 2014-2017, Regents of the University of California
Yingdi Yu6ff31932015-03-23 13:30:07 -07004 *
Alexander Afanasyevbe998ac2017-05-06 13:11:42 -07005 * This file is part of NDN DeLorean, An Authentication System for Data Archives in
6 * Named Data Networking. See AUTHORS.md for complete list of NDN DeLorean authors
7 * and contributors.
Yingdi Yu6ff31932015-03-23 13:30:07 -07008 *
Alexander Afanasyevbe998ac2017-05-06 13:11:42 -07009 * NDN DeLorean is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
Yingdi Yu6ff31932015-03-23 13:30:07 -070013 *
Alexander Afanasyevbe998ac2017-05-06 13:11:42 -070014 * NDN DeLorean is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
16 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
Yingdi Yu6ff31932015-03-23 13:30:07 -070017 *
Alexander Afanasyevbe998ac2017-05-06 13:11:42 -070018 * You should have received a copy of the GNU General Public License along with NDN
19 * DeLorean, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Yingdi Yu6ff31932015-03-23 13:30:07 -070020 */
21
22#include "logger.hpp"
23#include "tlv.hpp"
24#include "conf/config-file.hpp"
25
26namespace nsl {
27
28const int Logger::N_DATA_FETCHING_RETRIAL = 2;
29
30Logger::Logger(ndn::Face& face, const std::string& configFile)
31 : m_face(face)
32 , m_merkleTree(m_db)
33 , m_validator(m_face)
34{
35 conf::ConfigFile conf(configFile);
36 conf.parse();
37
38 m_loggerName = conf.getLoggerName();
39
40 m_treePrefix = m_loggerName;
41 m_treePrefix.append("tree");
42 m_leafPrefix = m_loggerName;
43 m_leafPrefix.append("leaf");
44 m_logPrefix = m_loggerName;
45 m_logPrefix.append("log");
46
47 m_merkleTree.setLoggerName(m_treePrefix);
48 m_merkleTree.loadPendingSubTrees();
49
50 m_db.open(conf.getDbDir());
51
52 // initialize security environment: keychain
53 initializeKeys();
54
55 // load policy checker
56 m_policyChecker.loadPolicy(conf.getPolicy());
57
58 // load validator rules
59 m_validator.load(conf.getValidatorRule(), conf.getConfFileName());
60
61 // register subtree prefix
62 m_face.setInterestFilter(m_treePrefix,
63 bind(&Logger::onSubTreeInterest, this, _1, _2),
64 [] (const Name&) {},
65 [] (const Name&, const std::string&) {});
66
67 // register leaf prefix
68 m_face.setInterestFilter(m_leafPrefix,
69 bind(&Logger::onLeafInterest, this, _1, _2),
70 [] (const Name&) {},
71 [] (const Name&, const std::string&) {});
72
73 // register log prefix
74 m_face.setInterestFilter(m_logPrefix,
75 bind(&Logger::onLogRequestInterest, this, _1, _2),
76 [] (const Name&) {},
77 [] (const Name&, const std::string&) {});
78}
79
80NonNegativeInteger
81Logger::addSelfSignedCert(ndn::IdentityCertificate& cert, const Timestamp& timestamp)
82{
83 if (!ndn::Validator::verifySignature(cert, cert.getPublicKeyInfo()))
84 throw Error("Not self-signed cert");
85
86 NonNegativeInteger dataSeqNo = m_merkleTree.getNextLeafSeqNo();
87 Leaf leaf(cert.getFullName(), timestamp, dataSeqNo, dataSeqNo, m_leafPrefix);
88
89 if (m_merkleTree.addLeaf(dataSeqNo, leaf.getHash())) {
90 bool result = m_db.insertLeafData(leaf, cert);
91 BOOST_ASSERT(result);
92 m_db.getLeaf(dataSeqNo);
93 }
94 else
95 throw Error("Cannot add cert");
96
97 return dataSeqNo;
98}
99
100void
101Logger::initializeKeys()
102{
103 Name certName = m_keyChain.createIdentity(m_loggerName);
104
105 Name dskKeyName = m_keyChain.generateEcdsaKeyPair(m_loggerName);
106 std::vector<ndn::CertificateSubjectDescription> subjectDescription;
107 auto dskCert =
108 m_keyChain.prepareUnsignedIdentityCertificate(dskKeyName, m_loggerName,
109 time::system_clock::now(),
110 time::system_clock::now() + time::days(1),
111 subjectDescription);
112 m_keyChain.sign(*dskCert, certName);
113 m_keyChain.addCertificate(*dskCert);
114 m_dskCert = dskCert;
115}
116
117void
118Logger::onSubTreeInterest(const ndn::InterestFilter& interestFilter, const Interest& interest)
119{
120 Name interestName = interest.getName();
121
122 size_t levelOffset = m_treePrefix.size();
123 size_t seqNoOffset = m_treePrefix.size() + 1;
124
125 if (interestName.size() < seqNoOffset + 1)
126 return; // interest is too short to answer
127
128 NonNegativeInteger level;
129 NonNegativeInteger seqNo;
130
131 try {
132 seqNo = interestName.get(seqNoOffset).toNumber();
133 level = interestName.get(levelOffset).toNumber();
134 }
135 catch (tlv::Error&) {
136 return;
137 }
138
139 Node::Index peakIndex = SubTreeBinary::toSubTreePeakIndex(Node::Index(seqNo, level));
140 shared_ptr<Data> data;
141
142 data = m_merkleTree.getPendingSubTreeData(peakIndex.level);
143
144 if (data != nullptr && interestName.isPrefixOf(data->getName())) {
145 m_face.put(*data);
146 return;
147 }
148
149 data = m_db.getSubTreeData(peakIndex.level, peakIndex.seqNo);
150
151 if (data != nullptr && interestName.isPrefixOf(data->getName())) {
152 m_face.put(*data);
153 return;
154 }
155}
156
157void
158Logger::onLeafInterest(const ndn::InterestFilter& interestFilter, const Interest& interest)
159{
160 Name interestName = interest.getName();
161
162 size_t seqNoOffset = m_leafPrefix.size();
163 size_t hashOffset = m_leafPrefix.size() + 1;
164
165 if (interestName.size() < seqNoOffset + 1)
166 return; // interest is too short to answer
167
168 NonNegativeInteger seqNo;
169
170 try {
171 seqNo = interestName.get(seqNoOffset).toNumber();
172 }
173 catch (tlv::Error&) {
174 return;
175 }
176 auto result = m_db.getLeaf(seqNo);
177
178 if (result.first != nullptr) {
179 if (interestName.size() >= hashOffset + 1) {
180 ndn::ConstBufferPtr leafHash;
181 try {
182 leafHash = make_shared<ndn::Buffer>(interestName.get(hashOffset).value(),
183 interestName.get(hashOffset).value_size());
184 ndn::ConstBufferPtr hash = result.first->getHash();
185 if (*hash != *leafHash)
186 return;
187 }
188 catch (tlv::Error&) {
189 return;
190 }
191 }
192 result.first->setLoggerName(m_leafPrefix);
193 m_face.put(*result.first->encode());
194 }
195}
196
197void
198Logger::onLogRequestInterest(const ndn::InterestFilter& interestFilter, const Interest& interest)
199{
200 m_validator.validate(interest,
201 bind(&Logger::requestValidatedCallback, this, _1),
202 [] (const shared_ptr<const Interest>&, const std::string&) {});
203}
204
205void
206Logger::requestValidatedCallback(const shared_ptr<const Interest>& interest)
207{
208 BOOST_ASSERT(interest->getName().size() == (m_logPrefix.size() + 6));
209
210 Name request = interest->getName().getPrefix(-4); // TODO: remove sig-related components
211
212 size_t dataOffset = m_logPrefix.size();
213 size_t signerOffset = m_logPrefix.size() + 1;
214
215 if (request.size() < signerOffset + 1)
216 return; // request is too short to answer
217
218 Name dataName;
219 NonNegativeInteger signerSeqNo;
220 try {
221 dataName.wireDecode(request.get(dataOffset).blockFromValue());
222 signerSeqNo = request.get(signerOffset).toNumber();
223 }
224 catch (tlv::Error&) {
225 return;
226 }
227
228 auto result = m_db.getLeaf(signerSeqNo);
229 if (result.first == nullptr || result.second == nullptr)
230 return;
231
232 Interest dataInterest(dataName);
233 m_face.expressInterest(dataInterest,
234 bind(&Logger::dataReceivedCallback, this, _1, _2,
235 signerSeqNo, *interest),
236 bind(&Logger::dataTimeoutCallback, this, _1,
237 N_DATA_FETCHING_RETRIAL, signerSeqNo, *interest));
238}
239
240void
241Logger::dataReceivedCallback(const Interest& interest, Data& data,
242 const NonNegativeInteger& signerSeqNo,
243 const Interest& reqInterest)
244{
245 auto result = m_db.getLeaf(signerSeqNo);
246 BOOST_ASSERT(result.first != nullptr);
247 BOOST_ASSERT(result.second != nullptr);
248
249 Timestamp dataTimestamp = time::toUnixTimestamp(time::system_clock::now()).count() / 1000;
250
251 try {
252 ndn::IdentityCertificate cert(*result.second);
253
254 if (m_policyChecker.check(dataTimestamp, data, result.first->getTimestamp(), cert)) {
255 NonNegativeInteger dataSeqNo = m_merkleTree.getNextLeafSeqNo();
256 Leaf leaf(data.getFullName(), dataTimestamp, dataSeqNo, signerSeqNo, m_leafPrefix);
257
258 if (m_merkleTree.addLeaf(dataSeqNo, leaf.getHash())) {
259 if (data.getContentType() == ndn::tlv::ContentType_Key)
260 m_db.insertLeafData(leaf, data);
261 else
262 m_db.insertLeafData(leaf);
263
264 makeLogResponse(reqInterest, LoggerResponse(dataSeqNo));
265 }
266 else
267 makeLogResponse(reqInterest,
268 LoggerResponse(tlv::LogResponse_Error_Tree, "cannot add leaf"));
269 }
270 else
271 makeLogResponse(reqInterest,
272 LoggerResponse(tlv::LogResponse_Error_Policy, "cannot pass policy checking"));
273 }
274 catch (tlv::Error&) {
275 makeLogResponse(reqInterest,
276 LoggerResponse(tlv::LogResponse_Error_Signer, "signer is wrong"));
277 }
278}
279
280void
281Logger::dataTimeoutCallback(const Interest& interest, int nRetrials,
282 const NonNegativeInteger& signerSeqNo,
283 const Interest& reqInterest)
284{
285 if (nRetrials > 0) {
286 m_face.expressInterest(interest,
287 bind(&Logger::dataReceivedCallback, this, _1, _2,
288 signerSeqNo, reqInterest),
289 bind(&Logger::dataTimeoutCallback, this, _1,
290 nRetrials - 1, signerSeqNo, reqInterest));
291 }
292}
293
294void
295Logger::makeLogResponse(const Interest& reqInterest, const LoggerResponse& response)
296{
297 auto data = make_shared<Data>(reqInterest.getName());
298 data->setContent(response.wireEncode());
299
300 BOOST_ASSERT(m_dskCert != nullptr);
301 m_keyChain.sign(*data, m_dskCert->getName());
302 m_face.put(*data);
303}
304
305
306} // namespace nsl