blob: 983a44da429fa79525b7b7ec1fe345fc8f925e6c [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())) {
Alexander Afanasyevb1ba9c92017-05-06 13:16:18 -070090 m_db.insertLeafData(leaf, cert);
Yingdi Yu6ff31932015-03-23 13:30:07 -070091 m_db.getLeaf(dataSeqNo);
92 }
93 else
94 throw Error("Cannot add cert");
95
96 return dataSeqNo;
97}
98
99void
100Logger::initializeKeys()
101{
102 Name certName = m_keyChain.createIdentity(m_loggerName);
103
Alexander Afanasyevb1ba9c92017-05-06 13:16:18 -0700104 Name dskKeyName = m_keyChain.generateEcKeyPair(m_loggerName);
Yingdi Yu6ff31932015-03-23 13:30:07 -0700105 std::vector<ndn::CertificateSubjectDescription> subjectDescription;
106 auto dskCert =
107 m_keyChain.prepareUnsignedIdentityCertificate(dskKeyName, m_loggerName,
108 time::system_clock::now(),
109 time::system_clock::now() + time::days(1),
110 subjectDescription);
111 m_keyChain.sign(*dskCert, certName);
112 m_keyChain.addCertificate(*dskCert);
113 m_dskCert = dskCert;
114}
115
116void
117Logger::onSubTreeInterest(const ndn::InterestFilter& interestFilter, const Interest& interest)
118{
119 Name interestName = interest.getName();
120
121 size_t levelOffset = m_treePrefix.size();
122 size_t seqNoOffset = m_treePrefix.size() + 1;
123
124 if (interestName.size() < seqNoOffset + 1)
125 return; // interest is too short to answer
126
127 NonNegativeInteger level;
128 NonNegativeInteger seqNo;
129
130 try {
131 seqNo = interestName.get(seqNoOffset).toNumber();
132 level = interestName.get(levelOffset).toNumber();
133 }
134 catch (tlv::Error&) {
135 return;
136 }
137
138 Node::Index peakIndex = SubTreeBinary::toSubTreePeakIndex(Node::Index(seqNo, level));
139 shared_ptr<Data> data;
140
141 data = m_merkleTree.getPendingSubTreeData(peakIndex.level);
142
143 if (data != nullptr && interestName.isPrefixOf(data->getName())) {
144 m_face.put(*data);
145 return;
146 }
147
148 data = m_db.getSubTreeData(peakIndex.level, peakIndex.seqNo);
149
150 if (data != nullptr && interestName.isPrefixOf(data->getName())) {
151 m_face.put(*data);
152 return;
153 }
154}
155
156void
157Logger::onLeafInterest(const ndn::InterestFilter& interestFilter, const Interest& interest)
158{
159 Name interestName = interest.getName();
160
161 size_t seqNoOffset = m_leafPrefix.size();
162 size_t hashOffset = m_leafPrefix.size() + 1;
163
164 if (interestName.size() < seqNoOffset + 1)
165 return; // interest is too short to answer
166
167 NonNegativeInteger seqNo;
168
169 try {
170 seqNo = interestName.get(seqNoOffset).toNumber();
171 }
172 catch (tlv::Error&) {
173 return;
174 }
175 auto result = m_db.getLeaf(seqNo);
176
177 if (result.first != nullptr) {
178 if (interestName.size() >= hashOffset + 1) {
179 ndn::ConstBufferPtr leafHash;
180 try {
181 leafHash = make_shared<ndn::Buffer>(interestName.get(hashOffset).value(),
182 interestName.get(hashOffset).value_size());
183 ndn::ConstBufferPtr hash = result.first->getHash();
184 if (*hash != *leafHash)
185 return;
186 }
187 catch (tlv::Error&) {
188 return;
189 }
190 }
191 result.first->setLoggerName(m_leafPrefix);
192 m_face.put(*result.first->encode());
193 }
194}
195
196void
197Logger::onLogRequestInterest(const ndn::InterestFilter& interestFilter, const Interest& interest)
198{
199 m_validator.validate(interest,
200 bind(&Logger::requestValidatedCallback, this, _1),
201 [] (const shared_ptr<const Interest>&, const std::string&) {});
202}
203
204void
205Logger::requestValidatedCallback(const shared_ptr<const Interest>& interest)
206{
207 BOOST_ASSERT(interest->getName().size() == (m_logPrefix.size() + 6));
208
209 Name request = interest->getName().getPrefix(-4); // TODO: remove sig-related components
210
211 size_t dataOffset = m_logPrefix.size();
212 size_t signerOffset = m_logPrefix.size() + 1;
213
214 if (request.size() < signerOffset + 1)
215 return; // request is too short to answer
216
217 Name dataName;
218 NonNegativeInteger signerSeqNo;
219 try {
220 dataName.wireDecode(request.get(dataOffset).blockFromValue());
221 signerSeqNo = request.get(signerOffset).toNumber();
222 }
223 catch (tlv::Error&) {
224 return;
225 }
226
227 auto result = m_db.getLeaf(signerSeqNo);
228 if (result.first == nullptr || result.second == nullptr)
229 return;
230
231 Interest dataInterest(dataName);
232 m_face.expressInterest(dataInterest,
233 bind(&Logger::dataReceivedCallback, this, _1, _2,
234 signerSeqNo, *interest),
235 bind(&Logger::dataTimeoutCallback, this, _1,
236 N_DATA_FETCHING_RETRIAL, signerSeqNo, *interest));
237}
238
239void
240Logger::dataReceivedCallback(const Interest& interest, Data& data,
241 const NonNegativeInteger& signerSeqNo,
242 const Interest& reqInterest)
243{
244 auto result = m_db.getLeaf(signerSeqNo);
245 BOOST_ASSERT(result.first != nullptr);
246 BOOST_ASSERT(result.second != nullptr);
247
248 Timestamp dataTimestamp = time::toUnixTimestamp(time::system_clock::now()).count() / 1000;
249
250 try {
251 ndn::IdentityCertificate cert(*result.second);
252
253 if (m_policyChecker.check(dataTimestamp, data, result.first->getTimestamp(), cert)) {
254 NonNegativeInteger dataSeqNo = m_merkleTree.getNextLeafSeqNo();
255 Leaf leaf(data.getFullName(), dataTimestamp, dataSeqNo, signerSeqNo, m_leafPrefix);
256
257 if (m_merkleTree.addLeaf(dataSeqNo, leaf.getHash())) {
258 if (data.getContentType() == ndn::tlv::ContentType_Key)
259 m_db.insertLeafData(leaf, data);
260 else
261 m_db.insertLeafData(leaf);
262
263 makeLogResponse(reqInterest, LoggerResponse(dataSeqNo));
264 }
265 else
266 makeLogResponse(reqInterest,
267 LoggerResponse(tlv::LogResponse_Error_Tree, "cannot add leaf"));
268 }
269 else
270 makeLogResponse(reqInterest,
271 LoggerResponse(tlv::LogResponse_Error_Policy, "cannot pass policy checking"));
272 }
273 catch (tlv::Error&) {
274 makeLogResponse(reqInterest,
275 LoggerResponse(tlv::LogResponse_Error_Signer, "signer is wrong"));
276 }
277}
278
279void
280Logger::dataTimeoutCallback(const Interest& interest, int nRetrials,
281 const NonNegativeInteger& signerSeqNo,
282 const Interest& reqInterest)
283{
284 if (nRetrials > 0) {
285 m_face.expressInterest(interest,
286 bind(&Logger::dataReceivedCallback, this, _1, _2,
287 signerSeqNo, reqInterest),
288 bind(&Logger::dataTimeoutCallback, this, _1,
289 nRetrials - 1, signerSeqNo, reqInterest));
290 }
291}
292
293void
294Logger::makeLogResponse(const Interest& reqInterest, const LoggerResponse& response)
295{
296 auto data = make_shared<Data>(reqInterest.getName());
297 data->setContent(response.wireEncode());
298
299 BOOST_ASSERT(m_dskCert != nullptr);
300 m_keyChain.sign(*data, m_dskCert->getName());
301 m_face.put(*data);
302}
303
304
305} // namespace nsl