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-2022 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 += prependBlock(encoder, 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>(EncodingBuffer&, SignatureInfo::Type) const;
96 
97 template size_t
98 SignatureInfo::wireEncode<encoding::EstimatorTag>(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 
210 {
211  auto it = findOtherTlv(tlv::ValidityPeriod);
212  if (it == m_otherTlvs.end()) {
213  NDN_THROW(Error("ValidityPeriod does not exist in SignatureInfo"));
214  }
215  return security::ValidityPeriod(*it);
216 }
217 
219 SignatureInfo::setValidityPeriod(optional<security::ValidityPeriod> validityPeriod)
220 {
221  if (!validityPeriod) {
223  }
224  else {
225  addCustomTlv(validityPeriod->wireEncode());
226  }
227  return *this;
228 }
229 
230 optional<std::vector<uint8_t>>
232 {
233  auto it = findOtherTlv(tlv::SignatureNonce);
234  if (it == m_otherTlvs.end()) {
235  return nullopt;
236  }
237  return std::vector<uint8_t>(it->value_begin(), it->value_end());
238 }
239 
241 SignatureInfo::setNonce(optional<span<const uint8_t>> nonce)
242 {
243  if (!nonce) {
245  }
246  else {
248  }
249  return *this;
250 }
251 
252 optional<time::system_clock::time_point>
254 {
255  auto it = findOtherTlv(tlv::SignatureTime);
256  if (it == m_otherTlvs.end()) {
257  return nullopt;
258  }
260 }
261 
263 SignatureInfo::setTime(optional<time::system_clock::time_point> time)
264 {
265  if (!time) {
267  }
268  else {
270  static_cast<uint64_t>(time::toUnixTimestamp(*time).count())));
271  }
272  return *this;
273 }
274 
275 optional<uint64_t>
277 {
278  auto it = findOtherTlv(tlv::SignatureSeqNum);
279  if (it == m_otherTlvs.end()) {
280  return nullopt;
281  }
282  return readNonNegativeInteger(*it);
283 }
284 
286 SignatureInfo::setSeqNum(optional<uint64_t> seqNum)
287 {
288  if (!seqNum) {
290  }
291  else {
293  }
294  return *this;
295 }
296 
297 optional<Block>
298 SignatureInfo::getCustomTlv(uint32_t type) const
299 {
300  auto it = findOtherTlv(type);
301  if (it == m_otherTlvs.end()) {
302  return nullopt;
303  }
304  return *it;
305 }
306 
307 void
309 {
310  auto existingIt = std::find_if(m_otherTlvs.begin(), m_otherTlvs.end(), [&block] (const Block& b) {
311  return b.type() == block.type();
312  });
313  if (existingIt == m_otherTlvs.end()) {
314  m_otherTlvs.push_back(std::move(block));
315  m_wire.reset();
316  }
317  else if (*existingIt != block) {
318  *existingIt = std::move(block);
319  m_wire.reset();
320  }
321 }
322 
323 void
325 {
326  auto it = std::remove_if(m_otherTlvs.begin(), m_otherTlvs.end(), [type] (const Block& block) {
327  return block.type() == type;
328  });
329 
330  if (it != m_otherTlvs.end()) {
331  m_otherTlvs.erase(it, m_otherTlvs.end());
332  m_wire.reset();
333  }
334 }
335 
336 std::vector<Block>::const_iterator
337 SignatureInfo::findOtherTlv(uint32_t type) const
338 {
339  return std::find_if(m_otherTlvs.begin(), m_otherTlvs.end(), [type] (const Block& block) {
340  return block.type() == type;
341  });
342 }
343 
344 bool
345 operator==(const SignatureInfo& lhs, const SignatureInfo& rhs)
346 {
347  return lhs.m_type == rhs.m_type &&
348  lhs.m_keyLocator == rhs.m_keyLocator &&
349  lhs.m_otherTlvs == rhs.m_otherTlvs;
350 }
351 
352 std::ostream&
353 operator<<(std::ostream& os, const SignatureInfo& info)
354 {
355  if (info.getSignatureType() == -1) {
356  return os << "Invalid SignatureInfo";
357  }
358 
359  os << static_cast<tlv::SignatureTypeValue>(info.getSignatureType());
360  if (info.hasKeyLocator()) {
361  os << " " << info.getKeyLocator();
362  }
363  if (!info.m_otherTlvs.empty()) {
364  os << " { ";
365  for (const auto& block : info.m_otherTlvs) {
366  switch (block.type()) {
367  case tlv::SignatureNonce: {
368  os << "Nonce=";
369  auto nonce = *info.getNonce();
370  printHex(os, nonce, false);
371  os << " ";
372  break;
373  }
374  case tlv::SignatureTime:
375  os << "Time=" << time::toUnixTimestamp(*info.getTime()).count() << " ";
376  break;
378  os << "SeqNum=" << *info.getSeqNum() << " ";
379  break;
380  case tlv::ValidityPeriod:
381  os << "ValidityPeriod=" << info.getValidityPeriod() << " ";
382  break;
383  default:
384  os << block.type() << " ";
385  break;
386  }
387  }
388  os << "}";
389  }
390 
391  return os;
392 }
393 
394 } // namespace ndn
Represents a TLV element of the NDN packet format.
Definition: block.hpp:45
const element_container & elements() const noexcept
Get container of sub-elements.
Definition: block.hpp:426
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition: block.hpp:221
uint32_t type() const noexcept
Return the TLV-TYPE of the Block.
Definition: block.hpp:277
void reset() noexcept
Reset the Block to a default-constructed state.
Definition: block.cpp:254
void parse() const
Parse TLV-VALUE into sub-elements.
Definition: block.cpp:324
Represents a SignatureInfo or InterestSignatureInfo TLV element.
size_t wireEncode(EncodingImpl< TAG > &encoder, Type type=Type::Data) const
Fast encoding or block size estimation.
SignatureInfo & setSignatureType(tlv::SignatureTypeValue type)
Set the SignatureType.
SignatureInfo & setValidityPeriod(optional< security::ValidityPeriod > validityPeriod)
Append, replace, or remove the ValidityPeriod element.
SignatureInfo & setNonce(optional< span< const uint8_t >> nonce)
Append or replace SignatureNonce.
optional< std::vector< uint8_t > > getNonce() const
Get SignatureNonce.
void addCustomTlv(Block block)
Append an arbitrary TLV element to this SignatureInfo.
security::ValidityPeriod getValidityPeriod() const
Get the ValidityPeriod element.
optional< uint64_t > getSeqNum() const
Get SignatureSeqNum.
int32_t getSignatureType() const noexcept
Get the SignatureType.
bool hasKeyLocator() const noexcept
Check if KeyLocator is present.
optional< Block > getCustomTlv(uint32_t type) const
Get first custom TLV element with the specified TLV-TYPE.
void removeCustomTlv(uint32_t type)
Remove all arbitrary TLV elements with the specified TLV-TYPE from this SignatureInfo.
optional< time::system_clock::time_point > getTime() const
Get SignatureTime.
void wireDecode(const Block &wire, Type type=Type::Data)
Decode from wire format.
SignatureInfo & setTime(optional< time::system_clock::time_point > time=time::system_clock::now())
Append or replace SignatureTime.
SignatureInfo & setSeqNum(optional< uint64_t > seqNum)
Append or replace SignatureSeqNum.
const KeyLocator & getKeyLocator() const
Get the KeyLocator element.
SignatureInfo & setKeyLocator(optional< KeyLocator > keyLocator)
Set or unset the KeyLocator element.
Represents a ValidityPeriod TLV element.
#define NDN_THROW(e)
Definition: exception.hpp:61
EncodingImpl< EstimatorTag > EncodingEstimator
uint64_t readNonNegativeInteger(const Block &block)
Read a non-negative integer from a TLV element.
size_t prependNonNegativeIntegerBlock(EncodingImpl< TAG > &encoder, uint32_t type, uint64_t value)
Prepend a TLV element containing a non-negative integer.
Block makeNonNegativeIntegerBlock(uint32_t type, uint64_t value)
Create a TLV block containing a non-negative integer.
Block makeBinaryBlock(uint32_t type, span< const uint8_t > value)
Create a TLV block copying the TLV-VALUE from a byte range.
EncodingImpl< EncoderTag > EncodingBuffer
size_t prependBlock(EncodingImpl< TAG > &encoder, const Block &block)
Prepend a TLV element.
std::string to_string(const errinfo_stacktrace &x)
Definition: exception.cpp:31
milliseconds toUnixTimestamp(const system_clock::time_point &point)
Convert system_clock::time_point to UNIX timestamp.
Definition: time.cpp:113
boost::chrono::milliseconds milliseconds
Definition: time.hpp:48
system_clock::time_point fromUnixTimestamp(milliseconds duration)
Convert UNIX timestamp to system_clock::time_point.
Definition: time.cpp:119
@ SignatureSeqNum
Definition: tlv.hpp:105
@ SignatureNonce
Definition: tlv.hpp:103
@ SignatureType
Definition: tlv.hpp:100
@ SignatureTime
Definition: tlv.hpp:104
@ KeyLocator
Definition: tlv.hpp:101
@ ValidityPeriod
Definition: tlv.hpp:107
constexpr bool isCriticalType(uint32_t type) noexcept
Determine whether a TLV-TYPE is "critical" for evolvability purpose.
Definition: tlv.hpp:162
SignatureTypeValue
SignatureType values.
Definition: tlv.hpp:127
Definition: data.cpp:25
void printHex(std::ostream &os, uint64_t num, bool wantUpperCase)
Output the hex representation of num to the output stream os.
bool operator==(const Data &lhs, const Data &rhs)
Definition: data.cpp:364
std::ostream & operator<<(std::ostream &os, const Data &data)
Definition: data.cpp:374
constexpr std::underlying_type_t< T > to_underlying(T val) noexcept
Definition: backports.hpp:125
SignatureInfo info