blob: 18db23707463cc8368282868e567fdfed4a1d231 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013-2020 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received copies of the GNU General Public License and GNU Lesser
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
* <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*/
#include "ndn-cxx/signature-info.hpp"
#include "ndn-cxx/encoding/block-helpers.hpp"
#include "ndn-cxx/util/concepts.hpp"
#include "ndn-cxx/util/string-helper.hpp"
#include <boost/range/adaptor/reversed.hpp>
namespace ndn {
BOOST_CONCEPT_ASSERT((boost::EqualityComparable<SignatureInfo>));
BOOST_CONCEPT_ASSERT((WireEncodable<SignatureInfo>));
BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<SignatureInfo>));
BOOST_CONCEPT_ASSERT((WireDecodable<SignatureInfo>));
static_assert(std::is_base_of<tlv::Error, SignatureInfo::Error>::value,
"SignatureInfo::Error must inherit from tlv::Error");
SignatureInfo::SignatureInfo() = default;
SignatureInfo::SignatureInfo(tlv::SignatureTypeValue type, optional<KeyLocator> keyLocator)
: m_type(type)
, m_keyLocator(std::move(keyLocator))
{
}
SignatureInfo::SignatureInfo(const Block& block, SignatureInfo::Type type)
{
wireDecode(block, type);
}
template<encoding::Tag TAG>
size_t
SignatureInfo::wireEncode(EncodingImpl<TAG>& encoder, SignatureInfo::Type type) const
{
if (m_type == -1) {
NDN_THROW(Error("Cannot encode invalid SignatureInfo"));
}
// SignatureInfo = SIGNATURE-INFO-TYPE TLV-LENGTH
// SignatureType
// [KeyLocator]
// [ValidityPeriod]
// *OtherSubelements
// InterestSignatureInfo = INTEREST-SIGNATURE-INFO-TYPE TLV-LENGTH
// SignatureType
// [KeyLocator]
// [SignatureNonce]
// [SignatureTime]
// [SignatureSeqNum]
// *OtherSubelements
size_t totalLength = 0;
// m_otherTlvs contains (if set) SignatureNonce, SignatureTime, SignatureSeqNum, ValidityPeriod,
// and AdditionalDescription, as well as any custom elements added by the user
for (const auto& block : m_otherTlvs | boost::adaptors::reversed) {
totalLength += encoder.prependBlock(block);
}
if (m_keyLocator) {
totalLength += m_keyLocator->wireEncode(encoder);
}
totalLength += prependNonNegativeIntegerBlock(encoder, tlv::SignatureType,
static_cast<uint64_t>(m_type));
totalLength += encoder.prependVarNumber(totalLength);
totalLength += encoder.prependVarNumber(to_underlying(type));
return totalLength;
}
template size_t
SignatureInfo::wireEncode<encoding::EncoderTag>(encoding::EncodingBuffer&, SignatureInfo::Type) const;
template size_t
SignatureInfo::wireEncode<encoding::EstimatorTag>(encoding::EncodingEstimator&, SignatureInfo::Type) const;
const Block&
SignatureInfo::wireEncode(SignatureInfo::Type type) const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator, type);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer, type);
m_wire = buffer.block();
return m_wire;
}
void
SignatureInfo::wireDecode(const Block& wire, SignatureInfo::Type type)
{
m_type = -1;
m_keyLocator = nullopt;
m_otherTlvs.clear();
m_wire = wire;
m_wire.parse();
if (m_wire.type() != to_underlying(type)) {
NDN_THROW(Error("SignatureInfo", m_wire.type()));
}
size_t lastCriticalElement = 0;
for (const auto& element : m_wire.elements()) {
switch (element.type()) {
case tlv::SignatureType: {
if (lastCriticalElement > 0) {
NDN_THROW(Error("SignatureType element is repeated or out-of-order"));
}
m_type = readNonNegativeIntegerAs<tlv::SignatureTypeValue>(element);
lastCriticalElement = 1;
break;
}
case tlv::KeyLocator: {
if (lastCriticalElement > 1) {
NDN_THROW(Error("KeyLocator element is repeated or out-of-order"));
}
m_keyLocator.emplace(element);
lastCriticalElement = 2;
break;
}
case tlv::SignatureNonce: {
// Must handle SignatureNonce specifically because we must check that its length is >0
if (element.value_size() < 1) {
NDN_THROW(Error("SignatureNonce element cannot be empty"));
}
m_otherTlvs.push_back(element);
break;
}
case tlv::ValidityPeriod:
// ValidityPeriod is treated differently than other "extension" TLVs for historical reasons:
// It is intended to be non-critical, but its TLV-TYPE is in the critical range. Therefore,
// we must handle it specifically.
m_otherTlvs.push_back(element);
break;
default: {
// If the TLV-TYPE is unrecognized and critical, abort decoding
if (tlv::isCriticalType(element.type())) {
NDN_THROW(Error("Unrecognized element of critical type " + to_string(element.type())));
}
// Otherwise, store in m_otherTlvs
m_otherTlvs.push_back(element);
}
}
}
if (m_type == -1) {
NDN_THROW(Error("Missing SignatureType in SignatureInfo"));
}
}
SignatureInfo&
SignatureInfo::setSignatureType(tlv::SignatureTypeValue type)
{
if (type != m_type) {
m_type = type;
m_wire.reset();
}
return *this;
}
const KeyLocator&
SignatureInfo::getKeyLocator() const
{
if (!hasKeyLocator()) {
NDN_THROW(Error("KeyLocator does not exist in SignatureInfo"));
}
return *m_keyLocator;
}
SignatureInfo&
SignatureInfo::setKeyLocator(optional<KeyLocator> keyLocator)
{
if (keyLocator != m_keyLocator) {
m_keyLocator = std::move(keyLocator);
m_wire.reset();
}
return *this;
}
security::ValidityPeriod
SignatureInfo::getValidityPeriod() const
{
auto it = findOtherTlv(tlv::ValidityPeriod);
if (it == m_otherTlvs.end()) {
NDN_THROW(Error("ValidityPeriod does not exist in SignatureInfo"));
}
return security::ValidityPeriod(*it);
}
SignatureInfo&
SignatureInfo::setValidityPeriod(optional<security::ValidityPeriod> validityPeriod)
{
if (!validityPeriod) {
removeCustomTlv(tlv::ValidityPeriod);
}
else {
addCustomTlv(validityPeriod->wireEncode());
}
return *this;
}
optional<std::vector<uint8_t>>
SignatureInfo::getNonce() const
{
auto it = findOtherTlv(tlv::SignatureNonce);
if (it == m_otherTlvs.end()) {
return nullopt;
}
return std::vector<uint8_t>(it->value_begin(), it->value_end());
}
SignatureInfo&
SignatureInfo::setNonce(optional<std::vector<uint8_t>> nonce)
{
if (!nonce) {
removeCustomTlv(tlv::SignatureNonce);
}
else {
addCustomTlv(makeBinaryBlock(tlv::SignatureNonce, nonce->data(), nonce->size()));
}
return *this;
}
optional<time::system_clock::time_point>
SignatureInfo::getTime() const
{
auto it = findOtherTlv(tlv::SignatureTime);
if (it == m_otherTlvs.end()) {
return nullopt;
}
return time::fromUnixTimestamp(time::milliseconds(readNonNegativeInteger(*it)));
}
SignatureInfo&
SignatureInfo::setTime(optional<time::system_clock::time_point> time)
{
if (!time) {
removeCustomTlv(tlv::SignatureTime);
}
else {
addCustomTlv(makeNonNegativeIntegerBlock(tlv::SignatureTime, time::toUnixTimestamp(*time).count()));
}
return *this;
}
optional<uint64_t>
SignatureInfo::getSeqNum() const
{
auto it = findOtherTlv(tlv::SignatureSeqNum);
if (it == m_otherTlvs.end()) {
return nullopt;
}
return readNonNegativeInteger(*it);
}
SignatureInfo&
SignatureInfo::setSeqNum(optional<uint64_t> seqNum)
{
if (!seqNum) {
removeCustomTlv(tlv::SignatureSeqNum);
}
else {
addCustomTlv(makeNonNegativeIntegerBlock(tlv::SignatureSeqNum, *seqNum));
}
return *this;
}
optional<Block>
SignatureInfo::getCustomTlv(uint32_t type) const
{
auto it = findOtherTlv(type);
if (it == m_otherTlvs.end()) {
return nullopt;
}
return *it;
}
void
SignatureInfo::addCustomTlv(Block block)
{
auto existingIt = std::find_if(m_otherTlvs.begin(), m_otherTlvs.end(), [&block] (const Block& b) {
return b.type() == block.type();
});
if (existingIt == m_otherTlvs.end()) {
m_otherTlvs.push_back(std::move(block));
m_wire.reset();
}
else if (*existingIt != block) {
*existingIt = std::move(block);
m_wire.reset();
}
}
void
SignatureInfo::removeCustomTlv(uint32_t type)
{
auto it = std::remove_if(m_otherTlvs.begin(), m_otherTlvs.end(), [type] (const Block& block) {
return block.type() == type;
});
if (it != m_otherTlvs.end()) {
m_otherTlvs.erase(it, m_otherTlvs.end());
m_wire.reset();
}
}
std::vector<Block>::const_iterator
SignatureInfo::findOtherTlv(uint32_t type) const
{
return std::find_if(m_otherTlvs.begin(), m_otherTlvs.end(), [type] (const Block& block) {
return block.type() == type;
});
}
bool
operator==(const SignatureInfo& lhs, const SignatureInfo& rhs)
{
return lhs.m_type == rhs.m_type &&
lhs.m_keyLocator == rhs.m_keyLocator &&
lhs.m_otherTlvs == rhs.m_otherTlvs;
}
std::ostream&
operator<<(std::ostream& os, const SignatureInfo& info)
{
if (info.getSignatureType() == -1) {
return os << "Invalid SignatureInfo";
}
os << static_cast<tlv::SignatureTypeValue>(info.getSignatureType());
if (info.hasKeyLocator()) {
os << " " << info.getKeyLocator();
}
if (!info.m_otherTlvs.empty()) {
os << " { ";
for (const auto& block : info.m_otherTlvs) {
switch (block.type()) {
case tlv::SignatureNonce: {
os << "Nonce=";
auto nonce = *info.getNonce();
printHex(os, nonce.data(), nonce.size(), false);
os << " ";
break;
}
case tlv::SignatureTime:
os << "Time=" << time::toUnixTimestamp(*info.getTime()).count() << " ";
break;
case tlv::SignatureSeqNum:
os << "SeqNum=" << *info.getSeqNum() << " ";
break;
case tlv::ValidityPeriod:
os << "ValidityPeriod=" << info.getValidityPeriod() << " ";
break;
default:
os << block.type() << " ";
break;
}
}
os << "}";
}
return os;
}
} // namespace ndn