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-2023 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 
25 
26 #include <algorithm>
27 #include <boost/range/adaptor/reversed.hpp>
28 
29 namespace ndn {
30 
32 
33 SignatureInfo::SignatureInfo(tlv::SignatureTypeValue type, std::optional<KeyLocator> keyLocator)
34  : m_type(type)
35  , m_keyLocator(std::move(keyLocator))
36 {
37 }
38 
40 {
41  wireDecode(block, type);
42 }
43 
44 template<encoding::Tag TAG>
45 size_t
47 {
48  if (m_type == -1) {
49  NDN_THROW(Error("Cannot encode invalid SignatureInfo"));
50  }
51 
52  // SignatureInfo = SIGNATURE-INFO-TYPE TLV-LENGTH
53  // SignatureType
54  // [KeyLocator]
55  // [ValidityPeriod]
56  // *OtherSubelements
57 
58  // InterestSignatureInfo = INTEREST-SIGNATURE-INFO-TYPE TLV-LENGTH
59  // SignatureType
60  // [KeyLocator]
61  // [SignatureNonce]
62  // [SignatureTime]
63  // [SignatureSeqNum]
64  // *OtherSubelements
65 
66  size_t totalLength = 0;
67 
68  // m_otherTlvs contains (if set) SignatureNonce, SignatureTime, SignatureSeqNum, ValidityPeriod,
69  // and AdditionalDescription, as well as any custom elements added by the user
70  for (const auto& block : m_otherTlvs | boost::adaptors::reversed) {
71  totalLength += prependBlock(encoder, block);
72  }
73 
74  if (m_keyLocator) {
75  totalLength += m_keyLocator->wireEncode(encoder);
76  }
77 
78  totalLength += prependNonNegativeIntegerBlock(encoder, tlv::SignatureType,
79  static_cast<uint64_t>(m_type));
80 
81  totalLength += encoder.prependVarNumber(totalLength);
82  totalLength += encoder.prependVarNumber(to_underlying(type));
83 
84  return totalLength;
85 }
86 
87 template size_t
88 SignatureInfo::wireEncode<encoding::EncoderTag>(EncodingBuffer&, SignatureInfo::Type) const;
89 
90 template size_t
91 SignatureInfo::wireEncode<encoding::EstimatorTag>(EncodingEstimator&, SignatureInfo::Type) const;
92 
93 const Block&
95 {
96  if (m_wire.hasWire())
97  return m_wire;
98 
99  EncodingEstimator estimator;
100  size_t estimatedSize = wireEncode(estimator, type);
101 
102  EncodingBuffer buffer(estimatedSize, 0);
103  wireEncode(buffer, type);
104 
105  m_wire = buffer.block();
106  return m_wire;
107 }
108 
109 void
111 {
112  m_type = -1;
113  m_keyLocator = std::nullopt;
114  m_otherTlvs.clear();
115 
116  m_wire = wire;
117  m_wire.parse();
118 
119  if (m_wire.type() != to_underlying(type)) {
120  NDN_THROW(Error("SignatureInfo", m_wire.type()));
121  }
122 
123  size_t lastCriticalElement = 0;
124  for (const auto& element : m_wire.elements()) {
125  switch (element.type()) {
126  case tlv::SignatureType: {
127  if (lastCriticalElement > 0) {
128  NDN_THROW(Error("SignatureType element is repeated or out-of-order"));
129  }
130  m_type = readNonNegativeIntegerAs<tlv::SignatureTypeValue>(element);
131  lastCriticalElement = 1;
132  break;
133  }
134  case tlv::KeyLocator: {
135  if (lastCriticalElement > 1) {
136  NDN_THROW(Error("KeyLocator element is repeated or out-of-order"));
137  }
138  m_keyLocator.emplace(element);
139  lastCriticalElement = 2;
140  break;
141  }
142  case tlv::SignatureNonce: {
143  // Must handle SignatureNonce specifically because we must check that its length is >0
144  if (element.value_size() < 1) {
145  NDN_THROW(Error("SignatureNonce element cannot be empty"));
146  }
147  m_otherTlvs.push_back(element);
148  break;
149  }
150  case tlv::ValidityPeriod:
151  // ValidityPeriod is treated differently than other "extension" TLVs for historical reasons:
152  // It is intended to be non-critical, but its TLV-TYPE is in the critical range. Therefore,
153  // we must handle it specifically.
154  m_otherTlvs.push_back(element);
155  break;
156  default: {
157  // If the TLV-TYPE is unrecognized and critical, abort decoding
158  if (tlv::isCriticalType(element.type())) {
159  NDN_THROW(Error("Unrecognized element of critical type " + to_string(element.type())));
160  }
161  // Otherwise, store in m_otherTlvs
162  m_otherTlvs.push_back(element);
163  }
164  }
165  }
166 
167  if (m_type == -1) {
168  NDN_THROW(Error("Missing SignatureType in SignatureInfo"));
169  }
170 }
171 
174 {
175  if (type != m_type) {
176  m_type = type;
177  m_wire.reset();
178  }
179  return *this;
180 }
181 
182 const KeyLocator&
184 {
185  if (!hasKeyLocator()) {
186  NDN_THROW(Error("KeyLocator does not exist in SignatureInfo"));
187  }
188  return *m_keyLocator;
189 }
190 
192 SignatureInfo::setKeyLocator(std::optional<KeyLocator> keyLocator)
193 {
194  if (keyLocator != m_keyLocator) {
195  m_keyLocator = std::move(keyLocator);
196  m_wire.reset();
197  }
198  return *this;
199 }
200 
203 {
204  auto it = findOtherTlv(tlv::ValidityPeriod);
205  if (it == m_otherTlvs.end()) {
206  NDN_THROW(Error("ValidityPeriod does not exist in SignatureInfo"));
207  }
208  return security::ValidityPeriod(*it);
209 }
210 
212 SignatureInfo::setValidityPeriod(std::optional<security::ValidityPeriod> validityPeriod)
213 {
214  if (!validityPeriod) {
216  }
217  else {
218  addCustomTlv(validityPeriod->wireEncode());
219  }
220  return *this;
221 }
222 
223 std::optional<std::vector<uint8_t>>
225 {
226  auto it = findOtherTlv(tlv::SignatureNonce);
227  if (it == m_otherTlvs.end()) {
228  return std::nullopt;
229  }
230  return std::vector<uint8_t>(it->value_begin(), it->value_end());
231 }
232 
234 SignatureInfo::setNonce(std::optional<span<const uint8_t>> nonce)
235 {
236  if (!nonce) {
238  }
239  else {
241  }
242  return *this;
243 }
244 
245 std::optional<time::system_clock::time_point>
247 {
248  auto it = findOtherTlv(tlv::SignatureTime);
249  if (it == m_otherTlvs.end()) {
250  return std::nullopt;
251  }
253 }
254 
256 SignatureInfo::setTime(std::optional<time::system_clock::time_point> time)
257 {
258  if (!time) {
260  }
261  else {
263  static_cast<uint64_t>(time::toUnixTimestamp(*time).count())));
264  }
265  return *this;
266 }
267 
268 std::optional<uint64_t>
270 {
271  auto it = findOtherTlv(tlv::SignatureSeqNum);
272  if (it == m_otherTlvs.end()) {
273  return std::nullopt;
274  }
275  return readNonNegativeInteger(*it);
276 }
277 
279 SignatureInfo::setSeqNum(std::optional<uint64_t> seqNum)
280 {
281  if (!seqNum) {
283  }
284  else {
286  }
287  return *this;
288 }
289 
290 std::optional<Block>
291 SignatureInfo::getCustomTlv(uint32_t type) const
292 {
293  auto it = findOtherTlv(type);
294  if (it == m_otherTlvs.end()) {
295  return std::nullopt;
296  }
297  return *it;
298 }
299 
300 void
302 {
303  auto existingIt = std::find_if(m_otherTlvs.begin(), m_otherTlvs.end(), [&block] (const Block& b) {
304  return b.type() == block.type();
305  });
306  if (existingIt == m_otherTlvs.end()) {
307  m_otherTlvs.push_back(std::move(block));
308  m_wire.reset();
309  }
310  else if (*existingIt != block) {
311  *existingIt = std::move(block);
312  m_wire.reset();
313  }
314 }
315 
316 void
318 {
319  auto it = std::remove_if(m_otherTlvs.begin(), m_otherTlvs.end(), [type] (const Block& block) {
320  return block.type() == type;
321  });
322 
323  if (it != m_otherTlvs.end()) {
324  m_otherTlvs.erase(it, m_otherTlvs.end());
325  m_wire.reset();
326  }
327 }
328 
329 std::vector<Block>::const_iterator
330 SignatureInfo::findOtherTlv(uint32_t type) const
331 {
332  return std::find_if(m_otherTlvs.begin(), m_otherTlvs.end(), [type] (const Block& block) {
333  return block.type() == type;
334  });
335 }
336 
337 bool
338 operator==(const SignatureInfo& lhs, const SignatureInfo& rhs)
339 {
340  return lhs.m_type == rhs.m_type &&
341  lhs.m_keyLocator == rhs.m_keyLocator &&
342  lhs.m_otherTlvs == rhs.m_otherTlvs;
343 }
344 
345 std::ostream&
346 operator<<(std::ostream& os, const SignatureInfo& info)
347 {
348  if (info.getSignatureType() == -1) {
349  return os << "Invalid SignatureInfo";
350  }
351 
352  os << static_cast<tlv::SignatureTypeValue>(info.getSignatureType());
353  if (info.hasKeyLocator()) {
354  os << " " << info.getKeyLocator();
355  }
356  if (!info.m_otherTlvs.empty()) {
357  os << " { ";
358  for (const auto& block : info.m_otherTlvs) {
359  switch (block.type()) {
360  case tlv::SignatureNonce: {
361  os << "Nonce=";
362  auto nonce = *info.getNonce();
363  printHex(os, nonce, false);
364  os << " ";
365  break;
366  }
367  case tlv::SignatureTime:
368  os << "Time=" << time::toUnixTimestamp(*info.getTime()).count() << " ";
369  break;
371  os << "SeqNum=" << *info.getSeqNum() << " ";
372  break;
373  case tlv::ValidityPeriod:
374  os << "ValidityPeriod=" << info.getValidityPeriod() << " ";
375  break;
376  default:
377  os << block.type() << " ";
378  break;
379  }
380  }
381  os << "}";
382  }
383 
384  return os;
385 }
386 
387 } // 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:424
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition: block.hpp:205
uint32_t type() const noexcept
Return the TLV-TYPE of the Block.
Definition: block.hpp:275
void reset() noexcept
Reset the Block to a default-constructed state.
Definition: block.cpp:293
void parse() const
Parse TLV-VALUE into sub-elements.
Definition: block.cpp:326
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 & setSeqNum(std::optional< uint64_t > seqNum)
Append or replace SignatureSeqNum.
std::optional< uint64_t > getSeqNum() const
Get SignatureSeqNum.
std::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.
int32_t getSignatureType() const noexcept
Get the SignatureType.
SignatureInfo & setTime(std::optional< time::system_clock::time_point > time=time::system_clock::now())
Append or replace SignatureTime.
SignatureInfo & setValidityPeriod(std::optional< security::ValidityPeriod > validityPeriod)
Append, replace, or remove the ValidityPeriod element.
bool hasKeyLocator() const noexcept
Check if KeyLocator is present.
void removeCustomTlv(uint32_t type)
Remove all arbitrary TLV elements with the specified TLV-TYPE from this SignatureInfo.
void wireDecode(const Block &wire, Type type=Type::Data)
Decode from wire format.
std::optional< Block > getCustomTlv(uint32_t type) const
Get first custom TLV element with the specified TLV-TYPE.
std::optional< time::system_clock::time_point > getTime() const
Get SignatureTime.
SignatureInfo & setNonce(std::optional< span< const uint8_t >> nonce)
Append or replace SignatureNonce.
SignatureInfo & setKeyLocator(std::optional< KeyLocator > keyLocator)
Set or unset the KeyLocator element.
const KeyLocator & getKeyLocator() const
Get the KeyLocator element.
Represents a ValidityPeriod TLV element.
#define NDN_THROW(e)
Definition: exception.hpp:56
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:30
constexpr system_clock::time_point fromUnixTimestamp(system_clock::duration d)
Convert UNIX timestamp to system_clock::time_point.
Definition: time.hpp:274
constexpr Duration toUnixTimestamp(const system_clock::time_point &tp)
Convert system_clock::time_point to UNIX timestamp.
Definition: time.hpp:265
::boost::chrono::milliseconds milliseconds
Definition: time.hpp:52
@ 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:367
std::ostream & operator<<(std::ostream &os, const Data &data)
Definition: data.cpp:377
constexpr std::underlying_type_t< T > to_underlying(T val) noexcept
Definition: backports.hpp:44
SignatureInfo info