signature-info.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2020 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later version.
10  *
11  * ndn-cxx library 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 Lesser General Public License for more details.
14  *
15  * You should have received copies of the GNU General Public License and GNU Lesser
16  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20  */
21 
26 
27 #include <boost/range/adaptor/reversed.hpp>
28 
29 namespace ndn {
30 
31 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<SignatureInfo>));
32 BOOST_CONCEPT_ASSERT((WireEncodable<SignatureInfo>));
33 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<SignatureInfo>));
34 BOOST_CONCEPT_ASSERT((WireDecodable<SignatureInfo>));
35 static_assert(std::is_base_of<tlv::Error, SignatureInfo::Error>::value,
36  "SignatureInfo::Error must inherit from tlv::Error");
37 
39 
40 SignatureInfo::SignatureInfo(tlv::SignatureTypeValue type, optional<KeyLocator> keyLocator)
41  : m_type(type)
42  , m_keyLocator(std::move(keyLocator))
43 {
44 }
45 
47 {
48  wireDecode(block, type);
49 }
50 
51 template<encoding::Tag TAG>
52 size_t
54 {
55  if (m_type == -1) {
56  NDN_THROW(Error("Cannot encode invalid SignatureInfo"));
57  }
58 
59  // SignatureInfo = SIGNATURE-INFO-TYPE TLV-LENGTH
60  // SignatureType
61  // [KeyLocator]
62  // [ValidityPeriod]
63  // *OtherSubelements
64 
65  // InterestSignatureInfo = INTEREST-SIGNATURE-INFO-TYPE TLV-LENGTH
66  // SignatureType
67  // [KeyLocator]
68  // [SignatureNonce]
69  // [SignatureTime]
70  // [SignatureSeqNum]
71  // *OtherSubelements
72 
73  size_t totalLength = 0;
74 
75  // m_otherTlvs contains (if set) SignatureNonce, SignatureTime, SignatureSeqNum, ValidityPeriod,
76  // and AdditionalDescription, as well as any custom elements added by the user
77  for (const auto& block : m_otherTlvs | boost::adaptors::reversed) {
78  totalLength += encoder.prependBlock(block);
79  }
80 
81  if (m_keyLocator) {
82  totalLength += m_keyLocator->wireEncode(encoder);
83  }
84 
85  totalLength += prependNonNegativeIntegerBlock(encoder, tlv::SignatureType,
86  static_cast<uint64_t>(m_type));
87 
88  totalLength += encoder.prependVarNumber(totalLength);
89  totalLength += encoder.prependVarNumber(to_underlying(type));
90 
91  return totalLength;
92 }
93 
94 template size_t
95 SignatureInfo::wireEncode<encoding::EncoderTag>(encoding::EncodingBuffer&, SignatureInfo::Type) const;
96 
97 template size_t
98 SignatureInfo::wireEncode<encoding::EstimatorTag>(encoding::EncodingEstimator&, SignatureInfo::Type) const;
99 
100 const Block&
102 {
103  if (m_wire.hasWire())
104  return m_wire;
105 
106  EncodingEstimator estimator;
107  size_t estimatedSize = wireEncode(estimator, type);
108 
109  EncodingBuffer buffer(estimatedSize, 0);
110  wireEncode(buffer, type);
111 
112  m_wire = buffer.block();
113  return m_wire;
114 }
115 
116 void
118 {
119  m_type = -1;
120  m_keyLocator = nullopt;
121  m_otherTlvs.clear();
122 
123  m_wire = wire;
124  m_wire.parse();
125 
126  if (m_wire.type() != to_underlying(type)) {
127  NDN_THROW(Error("SignatureInfo", m_wire.type()));
128  }
129 
130  size_t lastCriticalElement = 0;
131  for (const auto& element : m_wire.elements()) {
132  switch (element.type()) {
133  case tlv::SignatureType: {
134  if (lastCriticalElement > 0) {
135  NDN_THROW(Error("SignatureType element is repeated or out-of-order"));
136  }
137  m_type = readNonNegativeIntegerAs<tlv::SignatureTypeValue>(element);
138  lastCriticalElement = 1;
139  break;
140  }
141  case tlv::KeyLocator: {
142  if (lastCriticalElement > 1) {
143  NDN_THROW(Error("KeyLocator element is repeated or out-of-order"));
144  }
145  m_keyLocator.emplace(element);
146  lastCriticalElement = 2;
147  break;
148  }
149  case tlv::SignatureNonce: {
150  // Must handle SignatureNonce specifically because we must check that its length is >0
151  if (element.value_size() < 1) {
152  NDN_THROW(Error("SignatureNonce element cannot be empty"));
153  }
154  m_otherTlvs.push_back(element);
155  break;
156  }
157  case tlv::ValidityPeriod:
158  // ValidityPeriod is treated differently than other "extension" TLVs for historical reasons:
159  // It is intended to be non-critical, but its TLV-TYPE is in the critical range. Therefore,
160  // we must handle it specifically.
161  m_otherTlvs.push_back(element);
162  break;
163  default: {
164  // If the TLV-TYPE is unrecognized and critical, abort decoding
165  if (tlv::isCriticalType(element.type())) {
166  NDN_THROW(Error("Unrecognized element of critical type " + to_string(element.type())));
167  }
168  // Otherwise, store in m_otherTlvs
169  m_otherTlvs.push_back(element);
170  }
171  }
172  }
173 
174  if (m_type == -1) {
175  NDN_THROW(Error("Missing SignatureType in SignatureInfo"));
176  }
177 }
178 
181 {
182  if (type != m_type) {
183  m_type = type;
184  m_wire.reset();
185  }
186  return *this;
187 }
188 
189 const KeyLocator&
191 {
192  if (!hasKeyLocator()) {
193  NDN_THROW(Error("KeyLocator does not exist in SignatureInfo"));
194  }
195  return *m_keyLocator;
196 }
197 
199 SignatureInfo::setKeyLocator(optional<KeyLocator> keyLocator)
200 {
201  if (keyLocator != m_keyLocator) {
202  m_keyLocator = std::move(keyLocator);
203  m_wire.reset();
204  }
205  return *this;
206 }
207 
208 void
210 {
211  setKeyLocator(nullopt);
212 }
213 
216 {
217  auto it = findOtherTlv(tlv::ValidityPeriod);
218  if (it == m_otherTlvs.end()) {
219  NDN_THROW(Error("ValidityPeriod does not exist in SignatureInfo"));
220  }
221  return security::ValidityPeriod(*it);
222 }
223 
225 SignatureInfo::setValidityPeriod(optional<security::ValidityPeriod> validityPeriod)
226 {
227  if (!validityPeriod) {
229  }
230  else {
231  addCustomTlv(validityPeriod->wireEncode());
232  }
233  return *this;
234 }
235 
236 void
238 {
239  setValidityPeriod(nullopt);
240 }
241 
242 optional<std::vector<uint8_t>>
244 {
245  auto it = findOtherTlv(tlv::SignatureNonce);
246  if (it == m_otherTlvs.end()) {
247  return nullopt;
248  }
249  return std::vector<uint8_t>(it->value_begin(), it->value_end());
250 }
251 
253 SignatureInfo::setNonce(optional<std::vector<uint8_t>> nonce)
254 {
255  if (!nonce) {
257  }
258  else {
259  addCustomTlv(makeBinaryBlock(tlv::SignatureNonce, nonce->data(), nonce->size()));
260  }
261  return *this;
262 }
263 
264 optional<time::system_clock::time_point>
266 {
267  auto it = findOtherTlv(tlv::SignatureTime);
268  if (it == m_otherTlvs.end()) {
269  return nullopt;
270  }
271  return time::fromUnixTimestamp(time::milliseconds(readNonNegativeInteger(*it)));
272 }
273 
275 SignatureInfo::setTime(optional<time::system_clock::time_point> time)
276 {
277  if (!time) {
279  }
280  else {
282  }
283  return *this;
284 }
285 
286 optional<uint64_t>
288 {
289  auto it = findOtherTlv(tlv::SignatureSeqNum);
290  if (it == m_otherTlvs.end()) {
291  return nullopt;
292  }
293  return readNonNegativeInteger(*it);
294 }
295 
297 SignatureInfo::setSeqNum(optional<uint64_t> seqNum)
298 {
299  if (!seqNum) {
301  }
302  else {
304  }
305  return *this;
306 }
307 
308 optional<Block>
309 SignatureInfo::getCustomTlv(uint32_t type) const
310 {
311  auto it = findOtherTlv(type);
312  if (it == m_otherTlvs.end()) {
313  return nullopt;
314  }
315  return *it;
316 }
317 
318 void
320 {
321  auto existingIt = std::find_if(m_otherTlvs.begin(), m_otherTlvs.end(), [&block] (const Block& b) {
322  return b.type() == block.type();
323  });
324  if (existingIt == m_otherTlvs.end()) {
325  m_otherTlvs.push_back(std::move(block));
326  m_wire.reset();
327  }
328  else if (*existingIt != block) {
329  *existingIt = std::move(block);
330  m_wire.reset();
331  }
332 }
333 
334 void
336 {
337  auto it = std::remove_if(m_otherTlvs.begin(), m_otherTlvs.end(), [type] (const Block& block) {
338  return block.type() == type;
339  });
340 
341  if (it != m_otherTlvs.end()) {
342  m_otherTlvs.erase(it, m_otherTlvs.end());
343  m_wire.reset();
344  }
345 }
346 
347 const Block&
349 {
350  auto it = findOtherTlv(type);
351  if (it == m_otherTlvs.end()) {
352  NDN_THROW(Error("TLV-TYPE " + to_string(type) + " sub-element does not exist in SignatureInfo"));
353  }
354  return *it;
355 }
356 
357 void
359 {
360  addCustomTlv(block);
361 }
362 
363 std::vector<Block>::const_iterator
364 SignatureInfo::findOtherTlv(uint32_t type) const
365 {
366  return std::find_if(m_otherTlvs.begin(), m_otherTlvs.end(), [type] (const Block& block) {
367  return block.type() == type;
368  });
369 }
370 
371 bool
372 operator==(const SignatureInfo& lhs, const SignatureInfo& rhs)
373 {
374  return lhs.m_type == rhs.m_type &&
375  lhs.m_keyLocator == rhs.m_keyLocator &&
376  lhs.m_otherTlvs == rhs.m_otherTlvs;
377 }
378 
379 std::ostream&
380 operator<<(std::ostream& os, const SignatureInfo& info)
381 {
382  if (info.getSignatureType() == -1) {
383  return os << "Invalid SignatureInfo";
384  }
385 
386  os << static_cast<tlv::SignatureTypeValue>(info.getSignatureType());
387  if (info.hasKeyLocator()) {
388  os << " " << info.getKeyLocator();
389  }
390  if (!info.m_otherTlvs.empty()) {
391  os << " { ";
392  for (const auto& block : info.m_otherTlvs) {
393  switch (block.type()) {
394  case tlv::SignatureNonce: {
395  os << "Nonce=";
396  auto nonce = *info.getNonce();
397  printHex(os, nonce.data(), nonce.size(), false);
398  os << " ";
399  break;
400  }
401  case tlv::SignatureTime:
402  os << "Time=" << time::toUnixTimestamp(*info.getTime()).count() << " ";
403  break;
405  os << "SeqNum=" << *info.getSeqNum() << " ";
406  break;
407  case tlv::ValidityPeriod:
408  os << "ValidityPeriod=" << info.getValidityPeriod() << " ";
409  break;
410  default:
411  os << block.type() << " ";
412  break;
413  }
414  }
415  os << "}";
416  }
417 
418  return os;
419 }
420 
421 } // namespace ndn
SignatureInfo & setSeqNum(optional< uint64_t > seqNum)
Append or replace SignatureSeqNum.
friend std::ostream & operator<<(std::ostream &os, const SignatureInfo &info)
Definition: data.cpp:26
const KeyLocator & getKeyLocator() const
Get KeyLocator.
system_clock::TimePoint fromUnixTimestamp(milliseconds duration)
Convert UNIX timestamp to system_clock::TimePoint.
Definition: time.cpp:119
Represents a SignatureInfo or InterestSignatureInfo TLV element.
EncodingImpl specialization for actual TLV encoding.
size_t prependNonNegativeIntegerBlock(EncodingImpl< TAG > &encoder, uint32_t type, uint64_t value)
Prepend a TLV element containing a non-negative integer.
std::string to_string(const T &val)
Definition: backports.hpp:101
constexpr bool isCriticalType(uint32_t type)
Determine whether a TLV-TYPE is "critical" for evolvability purpose.
Definition: tlv.hpp:177
optional< uint64_t > getSeqNum() const
Get SignatureSeqNum.
const Block & getTypeSpecificTlv(uint32_t type) const
Get SignatureType-specific sub-element.
SignatureInfo & setValidityPeriod(optional< security::ValidityPeriod > validityPeriod)
Append or replace ValidityPeriod.
STL namespace.
int32_t getSignatureType() const noexcept
Get SignatureType.
void parse() const
Parse TLV-VALUE into sub-elements.
Definition: block.cpp:325
Represents a TLV element of the NDN packet format.
Definition: block.hpp:42
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition: block.hpp:217
Block makeNonNegativeIntegerBlock(uint32_t type, uint64_t value)
Create a TLV block containing a non-negative integer.
uint64_t readNonNegativeInteger(const Block &block)
Read a non-negative integer from a TLV element.
optional< Block > getCustomTlv(uint32_t type) const
Get first custom TLV element with the specified TLV-TYPE.
void unsetValidityPeriod()
Remove ValidityPeriod.
optional< time::system_clock::time_point > getTime() const
Get SignatureTime.
EncodingImpl specialization for TLV size estimation.
const element_container & elements() const
Get container of sub-elements.
Definition: block.hpp:378
#define NDN_THROW(e)
Definition: exception.hpp:61
void appendTypeSpecificTlv(const Block &block)
Append SignatureType-specific sub-element.
friend bool operator==(const SignatureInfo &lhs, const SignatureInfo &rhs)
Abstraction of validity period.
bool hasKeyLocator() const noexcept
Check if KeyLocator is present.
optional< std::vector< uint8_t > > getNonce() const
Get SignatureNonce.
void reset() noexcept
Reset the Block to a default-constructed state.
Definition: block.cpp:250
Block makeBinaryBlock(uint32_t type, const uint8_t *value, size_t length)
Create a TLV block copying TLV-VALUE from raw buffer.
SignatureInfo & setTime(optional< time::system_clock::time_point > time=time::system_clock::now())
Append or replace SignatureTime.
void unsetKeyLocator()
Remove KeyLocator.
SignatureTypeValue
SignatureType values.
Definition: tlv.hpp:131
SignatureInfo & setSignatureType(tlv::SignatureTypeValue type)
Set SignatureType.
size_t wireEncode(EncodingImpl< TAG > &encoder, Type type=Type::Data) const
Fast encoding or block size estimation.
void removeCustomTlv(uint32_t type)
Remove all arbitrary TLV elements with the specified TLV-TYPE from this SignatureInfo.
milliseconds toUnixTimestamp(const system_clock::TimePoint &point)
Convert system_clock::TimePoint to UNIX timestamp.
Definition: time.cpp:113
SignatureInfo & setKeyLocator(optional< KeyLocator > keyLocator)
Set KeyLocator.
void printHex(std::ostream &os, uint64_t num, bool wantUpperCase)
Output the hex representation of num to the output stream os.
void addCustomTlv(Block block)
Append an arbitrary TLV element to this SignatureInfo.
constexpr std::underlying_type_t< T > to_underlying(T val) noexcept
Definition: backports.hpp:140
void wireDecode(const Block &wire, Type type=Type::Data)
Decode from wire format.
EncodingImpl< EncoderTag > EncodingBuffer
SignatureInfo & setNonce(optional< std::vector< uint8_t >> nonce)
Append or replace SignatureNonce.
uint32_t type() const
Return the TLV-TYPE of the Block.
Definition: block.hpp:261
EncodingImpl< EstimatorTag > EncodingEstimator
security::ValidityPeriod getValidityPeriod() const
Get ValidityPeriod.