blob: e862d3760bc28e5232c3e4e8626799e19f8eae0d [file] [log] [blame]
peizhen guocf4df2d2014-08-12 13:22:32 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014, Regents of the University of California
4 *
5 * This file is part of NSL (NDN Signature Logger).
6 * See AUTHORS.md for complete list of NSL authors and contributors.
7 *
8 * NSL is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * NSL, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
Yingdi Yu0c3e5912015-03-17 14:22:38 -070019 * See AUTHORS.md for complete list of nsl authors and contributors.
peizhen guocf4df2d2014-08-12 13:22:32 -070020 */
Yingdi Yu0c3e5912015-03-17 14:22:38 -070021
peizhen guocf4df2d2014-08-12 13:22:32 -070022#include "leaf.hpp"
Yingdi Yu0c3e5912015-03-17 14:22:38 -070023#include "tlv.hpp"
24#include <ndn-cxx/security/digest-sha256.hpp>
25#include <ndn-cxx/encoding/block-helpers.hpp>
26#include <ndn-cxx/util/crypto.hpp>
peizhen guocf4df2d2014-08-12 13:22:32 -070027
Yingdi Yu0c3e5912015-03-17 14:22:38 -070028namespace nsl {
peizhen guocf4df2d2014-08-12 13:22:32 -070029
Yingdi Yu0c3e5912015-03-17 14:22:38 -070030const Name Leaf::EMPTY_NAME;
31const size_t Leaf::N_LOGGER_LEAF_SUFFIX = 4;
32const ssize_t Leaf::OFFSET_LEAF_SEQNO = -2;
33const ssize_t Leaf::OFFSET_LEAF_HASH = -1;
34
35Leaf::Leaf()
peizhen guocf4df2d2014-08-12 13:22:32 -070036{
peizhen guocf4df2d2014-08-12 13:22:32 -070037}
38
Yingdi Yu0c3e5912015-03-17 14:22:38 -070039Leaf::Leaf(const Name& dataName,
40 const Timestamp& timestamp,
41 const NonNegativeInteger& dataSeqNo,
42 const NonNegativeInteger& signerSeqNo,
43 const Name& loggerName)
44 : m_dataName(dataName)
45 , m_timestamp(timestamp)
46 , m_dataSeqNo(dataSeqNo)
47 , m_signerSeqNo(signerSeqNo)
48 , m_loggerName(loggerName)
49{
50 if (m_dataSeqNo < m_signerSeqNo)
51 throw Error("Leaf: signer seqNo should be less than the data seqNo");
52}
peizhen guocf4df2d2014-08-12 13:22:32 -070053
54void
Yingdi Yu0c3e5912015-03-17 14:22:38 -070055Leaf::setDataSeqNo(const NonNegativeInteger& dataSeqNo)
peizhen guocf4df2d2014-08-12 13:22:32 -070056{
Yingdi Yu0c3e5912015-03-17 14:22:38 -070057 if (dataSeqNo < m_signerSeqNo)
58 throw Error("Leaf: signer seqNo should be less than the data seqNo");
59
60 m_wire.reset();
61 m_dataSeqNo = dataSeqNo;
62}
63
64void
65Leaf::setDataName(const Name& dataName)
66{
67 m_wire.reset();
68 m_dataName = dataName;
69}
70
71void
72Leaf::setTimestamp(const Timestamp& timestamp)
73{
74 m_wire.reset();
75 m_timestamp = timestamp;
76}
77
78void
79Leaf::setSignerSeqNo(const NonNegativeInteger& signerSeqNo)
80{
81 if (m_dataSeqNo < signerSeqNo)
82 throw Error("Leaf: signer seqNo should be less than the data seqNo");
83
84 m_wire.reset();
85 m_signerSeqNo = signerSeqNo;
86}
87
88void
89Leaf::setLoggerName(const Name& loggerName)
90{
91 m_loggerName = loggerName;
92}
93
94ndn::ConstBufferPtr
95Leaf::getHash() const
96{
97 wireEncode();
98 return ndn::crypto::sha256(m_wire.wire(), m_wire.size());
99}
100
101shared_ptr<Data>
102Leaf::encode() const
103{
104 auto data = make_shared<Data>();
105
106 ndn::ConstBufferPtr hash = getHash();
107
108 // Name
109 Name dataName = m_loggerName;
110 dataName.appendNumber(m_dataSeqNo).append(hash->buf(), hash->size());
111 data->setName(dataName);
112
113 // Content
114 data->setContent(wireEncode());
115
116 // Signature
117 ndn::DigestSha256 sig;
118 data->setSignature(sig);
119
120 Block sigValue(tlv::SignatureValue,
121 ndn::crypto::sha256(data->wireEncode().value(),
122 data->wireEncode().value_size() -
123 data->getSignature().getValue().size()));
124 data->setSignatureValue(sigValue);
125
126 data->wireEncode();
127
128 return data;
129}
130
131void
132Leaf::decode(const Data& data)
133{
134 const Name& dataName = data.getName();
135
136 if (!m_loggerName.isPrefixOf(dataName))
137 throw Error("decode: leaf data name does not match logger name");
138
139 if (m_loggerName.size() + N_LOGGER_LEAF_SUFFIX != dataName.size())
140 throw Error("decode: leaf data name does not follow the naming convention");
141
142 ndn::ConstBufferPtr leafHash;
143 NonNegativeInteger dataSeqNo;
144 try {
145 leafHash = make_shared<ndn::Buffer>(dataName.get(OFFSET_LEAF_HASH).value(),
146 dataName.get(OFFSET_LEAF_HASH).value_size());
147
148 dataSeqNo = dataName.get(OFFSET_LEAF_SEQNO).toNumber();
149 }
150 catch (tlv::Error&) {
151 throw Error("decode: logger name encoding error");
152 }
153
154 wireDecode(data.getContent().blockFromValue());
155
156 if (*leafHash != *getHash())
157 throw Error("decode: inconsistent hash");
158
159 if (m_dataSeqNo != dataSeqNo)
160 throw Error("decode: seqNo does not match");
161}
162
163template<ndn::encoding::Tag TAG>
164size_t
165Leaf::wireEncode(ndn::EncodingImpl<TAG>& block) const
166{
167 size_t totalLength = 0;
168
169 totalLength += ndn::prependNonNegativeIntegerBlock(block, tlv::SignerSeqNo, m_signerSeqNo);
170 totalLength += ndn::prependNonNegativeIntegerBlock(block, tlv::DataSeqNo, m_dataSeqNo);
171 totalLength += ndn::prependNonNegativeIntegerBlock(block, tlv::Timestamp, m_timestamp);
172 totalLength += m_dataName.wireEncode(block);
173
174 totalLength += block.prependVarNumber(totalLength);
175 totalLength += block.prependVarNumber(tlv::LoggerLeaf);
176
177 return totalLength;
178}
179
180template size_t
181Leaf::wireEncode<ndn::encoding::EncoderTag>(ndn::EncodingImpl<ndn::encoding::EncoderTag>&) const;
182
183template size_t
184Leaf::wireEncode<ndn::encoding::EstimatorTag>(ndn::EncodingImpl<ndn::encoding::EstimatorTag>&) const;
185
186
187const Block&
188Leaf::wireEncode() const
189{
190 if (m_wire.hasWire())
191 return m_wire;
192
193 ndn::EncodingEstimator estimator;
194 size_t estimatedSize = wireEncode(estimator);
195
196 ndn::EncodingBuffer buffer(estimatedSize, 0);
197 wireEncode(buffer);
198
199 m_wire = buffer.block();
200 return m_wire;
201}
202
203void
204Leaf::wireDecode(const Block& wire)
205{
206 if (!wire.hasWire()) {
207 throw Error("The supplied block does not contain wire format");
208 }
209
210 m_wire = wire;
211 m_wire.parse();
212
213 if (m_wire.type() != tlv::LoggerLeaf)
214 throw tlv::Error("Unexpected TLV type when decoding logger leaf");
215
216 Block::element_const_iterator it = m_wire.elements_begin();
217
218 // the first block must be dataName
219 if (it != m_wire.elements_end() && it->type() == tlv::Name) {
220 m_dataName.wireDecode(*it);
221 it++;
222 }
223 else
224 throw Error("The first sub-TLV is not Name");
225
226 // the second block must be timestamp
227 if (it != m_wire.elements_end() && it->type() == tlv::Timestamp) {
228 m_timestamp = readNonNegativeInteger(*it);
229 it++;
230 }
231 else
232 throw Error("The second sub-TLV is not Timestamp");
233
234 // the third block must be DataSeqNo
235 if (it != m_wire.elements_end() && it->type() == tlv::DataSeqNo) {
236 m_dataSeqNo = readNonNegativeInteger(*it);
237 it++;
238 }
239 else
240 throw Error("The third sub-TLV is not DataSeqNo");
241
242 // the third block must be SignerSeqNo
243 if (it != m_wire.elements_end() && it->type() == tlv::SignerSeqNo) {
244 m_signerSeqNo = readNonNegativeInteger(*it);
245 it++;
246 }
247 else
248 throw Error("The fourth sub-TLV is not SignerSeqNo");
249
250 if (it != m_wire.elements_end())
251 throw Error("No more sub-TLV in LoggerLeaf");
peizhen guocf4df2d2014-08-12 13:22:32 -0700252}
253
254} // namespace nsl