name: Add support for ImplicitSha256DigestComponent
This support includes the following new API functions:
- name::Component::isImplicitSha256Digest()
- name::Component::fromImplicitSha256Digest(...)
- Name::appendImplicitSha256Digest(...)
- Updated toUri()/fromUri(...) to support "sha256digest=..." URI
representation of the ImplicitSha256Digest component
Change-Id: I756c4b94196cf031da98b5689bd60630533dfeb3
Refs: #1640, #2088
diff --git a/src/encoding/tlv.hpp b/src/encoding/tlv.hpp
index bb0f1c5..284ca26 100644
--- a/src/encoding/tlv.hpp
+++ b/src/encoding/tlv.hpp
@@ -61,6 +61,7 @@
Interest = 5,
Data = 6,
Name = 7,
+ ImplicitSha256DigestComponent = 1,
NameComponent = 8,
Selectors = 9,
Nonce = 10,
diff --git a/src/name-component.cpp b/src/name-component.cpp
index 893369f..8aad977 100644
--- a/src/name-component.cpp
+++ b/src/name-component.cpp
@@ -28,8 +28,12 @@
#include "encoding/block-helpers.hpp"
#include "encoding/encoding-buffer.hpp"
#include "util/string-helper.hpp"
+#include "security/cryptopp.hpp"
+#include "util/crypto.hpp"
#include "util/concepts.hpp"
+#include <boost/lexical_cast.hpp>
+
namespace ndn {
namespace name {
@@ -39,6 +43,13 @@
static_assert(std::is_base_of<tlv::Error, Component::Error>::value,
"name::Component::Error must inherit from tlv::Error");
+static const std::string&
+getSha256DigestUriPrefix()
+{
+ static const std::string prefix { "sha256digest=" };
+ return prefix;
+}
+
Component::Component()
: Block(tlv::NameComponent)
{
@@ -47,8 +58,9 @@
Component::Component(const Block& wire)
: Block(wire)
{
- if (type() != tlv::NameComponent)
- throw Error("Cannot construct name::Component from not a NameComponent TLV wire block");
+ if (type() != tlv::NameComponent && type() != tlv::ImplicitSha256DigestComponent)
+ throw Error("Cannot construct name::Component from not a NameComponent "
+ "or ImplicitSha256DigestComponent TLV wire block");
}
Component::Component(const ConstBufferPtr& buffer)
@@ -82,62 +94,93 @@
{
std::string trimmedString(escapedString + beginOffset, escapedString + endOffset);
trim(trimmedString);
- std::string value = unescape(trimmedString);
- if (value.find_first_not_of(".") == std::string::npos) {
- // Special case for component of only periods.
- if (value.size() <= 2)
- // Zero, one or two periods is illegal. Ignore this component.
- throw Error("Illegal URI (name component cannot be . or ..)");
- else
- // Remove 3 periods.
- return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
+ if (trimmedString.compare(0, getSha256DigestUriPrefix().size(),
+ getSha256DigestUriPrefix()) == 0) {
+ if (trimmedString.size() != getSha256DigestUriPrefix().size() + crypto::SHA256_DIGEST_SIZE * 2)
+ throw Error("Cannot convert to ImplicitSha256DigestComponent"
+ "(expected sha256 in hex encoding)");
+
+ try {
+ std::string value;
+ CryptoPP::StringSource(reinterpret_cast<const uint8_t*>(trimmedString.c_str()) +
+ getSha256DigestUriPrefix().size(),
+ trimmedString.size () - getSha256DigestUriPrefix().size(), true,
+ new CryptoPP::HexDecoder(new CryptoPP::StringSink(value)));
+
+ return fromImplicitSha256Digest(reinterpret_cast<const uint8_t*>(value.c_str()),
+ value.size());
+ }
+ catch (CryptoPP::Exception& e) {
+ throw Error("Cannot convert to a ImplicitSha256DigestComponent (invalid hex encoding)");
+ }
}
- else
- return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
+ else {
+ std::string value = unescape(trimmedString);
+
+ if (value.find_first_not_of(".") == std::string::npos) {
+ // Special case for component of only periods.
+ if (value.size() <= 2)
+ // Zero, one or two periods is illegal. Ignore this component.
+ throw Error("Illegal URI (name component cannot be . or ..)");
+ else
+ // Remove 3 periods.
+ return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
+ }
+ else
+ return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
+ }
}
void
Component::toUri(std::ostream& result) const
{
- const uint8_t* value = this->value();
- size_t valueSize = value_size();
+ if (type() == tlv::ImplicitSha256DigestComponent) {
+ result << getSha256DigestUriPrefix();
- bool gotNonDot = false;
- for (size_t i = 0; i < valueSize; ++i) {
- if (value[i] != 0x2e) {
- gotNonDot = true;
- break;
- }
- }
- if (!gotNonDot) {
- // Special case for component of zero or more periods. Add 3 periods.
- result << "...";
- for (size_t i = 0; i < valueSize; ++i)
- result << '.';
+ CryptoPP::StringSource(value(), value_size(), true,
+ new CryptoPP::HexEncoder(new CryptoPP::FileSink(result), false));
}
else {
- // In case we need to escape, set to upper case hex and save the previous flags.
- std::ios::fmtflags saveFlags = result.flags(std::ios::hex | std::ios::uppercase);
+ const uint8_t* value = this->value();
+ size_t valueSize = value_size();
+ bool gotNonDot = false;
for (size_t i = 0; i < valueSize; ++i) {
- uint8_t x = value[i];
- // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
- if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
- (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
- x == 0x2e || x == 0x5f)
- result << x;
- else {
- result << '%';
- if (x < 16)
- result << '0';
- result << static_cast<uint32_t>(x);
+ if (value[i] != 0x2e) {
+ gotNonDot = true;
+ break;
}
}
+ if (!gotNonDot) {
+ // Special case for component of zero or more periods. Add 3 periods.
+ result << "...";
+ for (size_t i = 0; i < valueSize; ++i)
+ result << '.';
+ }
+ else {
+ // In case we need to escape, set to upper case hex and save the previous flags.
+ std::ios::fmtflags saveFlags = result.flags(std::ios::hex | std::ios::uppercase);
- // Restore.
- result.flags(saveFlags);
+ for (size_t i = 0; i < valueSize; ++i) {
+ uint8_t x = value[i];
+ // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
+ if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
+ (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
+ x == 0x2e || x == 0x5f)
+ result << x;
+ else {
+ result << '%';
+ if (x < 16)
+ result << '0';
+ result << static_cast<uint32_t>(x);
+ }
+ }
+
+ // Restore.
+ result.flags(saveFlags);
+ }
}
}
@@ -149,6 +192,7 @@
return os.str();
}
+////////////////////////////////////////////////////////////////////////////////
bool
Component::isNumber() const
@@ -195,6 +239,7 @@
return isNumberWithMarker(SEQUENCE_NUMBER_MARKER);
}
+////////////////////////////////////////////////////////////////////////////////
uint64_t
Component::toNumber() const
@@ -247,11 +292,11 @@
return toNumberWithMarker(SEQUENCE_NUMBER_MARKER);
}
+////////////////////////////////////////////////////////////////////////////////
Component
Component::fromNumber(uint64_t number)
{
- /// \todo Change to tlv::NumberComponent
return nonNegativeIntegerBlock(tlv::NameComponent, number);
}
@@ -307,11 +352,52 @@
return fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo);
}
+////////////////////////////////////////////////////////////////////////////////
+
+bool
+Component::isGeneric() const
+{
+ return (type() == tlv::NameComponent);
+}
+
+bool
+Component::isImplicitSha256Digest() const
+{
+ return (type() == tlv::ImplicitSha256DigestComponent &&
+ value_size() == crypto::SHA256_DIGEST_SIZE);
+}
+
+Component
+Component::fromImplicitSha256Digest(const ConstBufferPtr& digest)
+{
+ if (digest->size() != crypto::SHA256_DIGEST_SIZE)
+ throw Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
+ boost::lexical_cast<std::string>(crypto::SHA256_DIGEST_SIZE) + " octets)");
+
+ return Block(tlv::ImplicitSha256DigestComponent, digest);
+}
+
+Component
+Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
+{
+ if (digestSize != crypto::SHA256_DIGEST_SIZE)
+ throw Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
+ boost::lexical_cast<std::string>(crypto::SHA256_DIGEST_SIZE) + " octets)");
+
+ return dataBlock(tlv::ImplicitSha256DigestComponent, digest, digestSize);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
int
Component::compare(const Component& other) const
{
// Imitate ndn_Exclude_compareComponents.
- if (value_size() < other.value_size())
+ if (type() < other.type())
+ return -1;
+ else if (type() > other.type())
+ return 1;
+ else if (value_size() < other.value_size())
return -1;
if (value_size() > other.value_size())
return 1;
@@ -346,7 +432,7 @@
}
totalLength += encoder.prependVarNumber(totalLength);
- totalLength += encoder.prependVarNumber(tlv::NameComponent);
+ totalLength += encoder.prependVarNumber(type());
return encoder.block();
}
@@ -360,7 +446,7 @@
if (value_size() > 0)
totalLength += block.prependByteArray(value(), value_size());
totalLength += block.prependVarNumber(value_size());
- totalLength += block.prependVarNumber(tlv::NameComponent);
+ totalLength += block.prependVarNumber(type());
return totalLength;
}
@@ -389,8 +475,9 @@
void
Component::wireDecode(const Block& wire)
{
- if (wire.type() != tlv::NameComponent)
- throw Error("name::Component::wireDecode called on not a NameComponent TLV wire block");
+ if (wire.type() != tlv::NameComponent || wire.type() != tlv::ImplicitSha256DigestComponent)
+ throw Error("name::Component::wireDecode called on not a NameComponent "
+ "or ImplicitSha256DigestComponent TLV wire block");
*this = wire;
}
diff --git a/src/name-component.hpp b/src/name-component.hpp
index b8023b1..e49275a 100644
--- a/src/name-component.hpp
+++ b/src/name-component.hpp
@@ -463,6 +463,34 @@
static Component
fromSequenceNumber(uint64_t seqNo);
+ ////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @brief Check if the component is GenericComponent
+ */
+ bool
+ isGeneric() const;
+
+ /**
+ * @brief Check if the component is ImplicitSha256DigestComponent
+ */
+ bool
+ isImplicitSha256Digest() const;
+
+ /**
+ * @brief Create ImplicitSha256DigestComponent component
+ */
+ static Component
+ fromImplicitSha256Digest(const ConstBufferPtr& digest);
+
+ /**
+ * @brief Create ImplicitSha256DigestComponent component
+ */
+ static Component
+ fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize);
+
+ ////////////////////////////////////////////////////////////////////////////////
+
bool
empty() const
{
diff --git a/src/name.cpp b/src/name.cpp
index 9090176..f9d91db 100644
--- a/src/name.cpp
+++ b/src/name.cpp
@@ -225,6 +225,19 @@
return *this;
}
+Name&
+Name::appendImplicitSha256Digest(const ConstBufferPtr& digest)
+{
+ m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest));
+ return *this;
+}
+
+Name&
+Name::appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
+{
+ m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest, digestSize));
+ return *this;
+}
Name
Name::getSubName(size_t iStartComponent, size_t nComponents) const
diff --git a/src/name.hpp b/src/name.hpp
index 1719e92..9743a96 100644
--- a/src/name.hpp
+++ b/src/name.hpp
@@ -334,6 +334,18 @@
appendSequenceNumber(uint64_t seqNo);
/**
+ * @brief Append ImplicitSha256Digest
+ */
+ Name&
+ appendImplicitSha256Digest(const ConstBufferPtr& digest);
+
+ /**
+ * @brief Append ImplicitSha256Digest
+ */
+ Name&
+ appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize);
+
+ /**
* @brief Get the successor of a name
*
* The successor of a name is defined as follows:
diff --git a/tests/unit-tests/test-name.cpp b/tests/unit-tests/test-name.cpp
index f10cf0a..01bd884 100644
--- a/tests/unit-tests/test-name.cpp
+++ b/tests/unit-tests/test-name.cpp
@@ -223,6 +223,8 @@
const Name& expected = it->template get<3>();
BOOST_TEST_MESSAGE("Check " << expected[0].toUri());
+ BOOST_CHECK_EQUAL(expected[0].isGeneric(), true);
+
name::Component actualComponent = it->template get<0>()(it->template get<4>());
BOOST_CHECK_EQUAL(actualComponent, expected[0]);
@@ -290,6 +292,58 @@
BOOST_CHECK_EQUAL(map[name3], 3);
}
+BOOST_AUTO_TEST_CASE(ImplictSha256Digest)
+{
+ Name n;
+
+ static const uint8_t DIGEST[] = { 0x28, 0xba, 0xd4, 0xb5, 0x27, 0x5b, 0xd3, 0x92,
+ 0xdb, 0xb6, 0x70, 0xc7, 0x5c, 0xf0, 0xb6, 0x6f,
+ 0x13, 0xf7, 0x94, 0x2b, 0x21, 0xe8, 0x0f, 0x55,
+ 0xc0, 0xe8, 0x6b, 0x37, 0x47, 0x53, 0xa5, 0x48 };
+
+ BOOST_REQUIRE_NO_THROW(n.appendImplicitSha256Digest(DIGEST, 32));
+ BOOST_REQUIRE_NO_THROW(n.appendImplicitSha256Digest(make_shared<Buffer>(DIGEST, 32)));
+ BOOST_CHECK_EQUAL(n.get(0), n.get(1));
+
+ BOOST_REQUIRE_THROW(n.appendImplicitSha256Digest(DIGEST, 34), name::Component::Error);
+ BOOST_REQUIRE_THROW(n.appendImplicitSha256Digest(DIGEST, 30), name::Component::Error);
+
+ n.append(DIGEST, 32);
+ BOOST_CHECK_LT(n.get(0), n.get(2));
+ BOOST_CHECK_EQUAL_COLLECTIONS(n.get(0).value_begin(), n.get(0).value_end(),
+ n.get(2).value_begin(), n.get(2).value_end());
+
+ n.append(DIGEST + 1, 32);
+ BOOST_CHECK_LT(n.get(0), n.get(3));
+
+ n.append(DIGEST + 2, 32);
+ BOOST_CHECK_LT(n.get(0), n.get(4));
+
+ BOOST_CHECK_EQUAL(n.get(0).toUri(), "sha256digest="
+ "28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548");
+
+ BOOST_CHECK_EQUAL(n.get(0).isImplicitSha256Digest(), true);
+ BOOST_CHECK_EQUAL(n.get(2).isImplicitSha256Digest(), false);
+
+ BOOST_CHECK_THROW(Name("/hello/sha256digest=hmm"), name::Component::Error);
+
+ Name n2;
+ // check canonical URI encoding (lower case)
+ BOOST_CHECK_NO_THROW(n2 = Name("/hello/sha256digest="
+ "28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548"));
+ BOOST_CHECK_EQUAL(n.get(0), n2.get(1));
+
+ // will accept hex value in upper case too
+ BOOST_CHECK_NO_THROW(n2 = Name("/hello/sha256digest="
+ "28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548"));
+ BOOST_CHECK_EQUAL(n.get(0), n2.get(1));
+
+ // this is not valid sha256digest component, will be treated as generic component
+ BOOST_CHECK_NO_THROW(n2 = Name("/hello/SHA256DIGEST="
+ "28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548"));
+ BOOST_CHECK_NE(n.get(0), n2.get(1));
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace ndn
diff --git a/tools/tlvdump.cpp b/tools/tlvdump.cpp
index 0273861..ab9fcd4 100644
--- a/tools/tlvdump.cpp
+++ b/tools/tlvdump.cpp
@@ -27,11 +27,11 @@
#include <iomanip>
#include <fstream>
-const uint32_t TLV_DICT_SIZE = 30;
+namespace ndn {
-const std::string TLV_DICT[TLV_DICT_SIZE] = {
+const std::vector<std::string> TLV_DICT = {
"RESERVED", // = 0
- "RESERVED", // = 1
+ "ImplicitSha256DigestComponent", // = 1
"RESERVED", // = 2
"RESERVED", // = 3
"RESERVED", // = 4
@@ -59,7 +59,7 @@
"FinalBlockId" // = 26
"SignatureType", // = 27,
"KeyLocator", // = 28,
- "KeyLocatorDigest", // = 29
+ "KeyDigest" // = 29
};
void
@@ -67,16 +67,16 @@
{
std::cout << type << " (";
- if (type < TLV_DICT_SIZE) {
+ if (type < TLV_DICT.size()) {
std::cout << TLV_DICT[type];
}
- else if (TLV_DICT_SIZE <= type && type < 128) {
+ else if (TLV_DICT.size() <= type && type < tlv::AppPrivateBlock1) {
std::cout << "RESERVED_1";
}
- else if (128 <= type && type < 253) {
+ else if (tlv::AppPrivateBlock1 <= type && type < 253) {
std::cout << "APP_TAG_1";
}
- else if (253 <= type && type < 32767) {
+ else if (253 <= type && type < tlv::AppPrivateBlock2) {
std::cout << "RESERVED_3";
}
else {
@@ -87,17 +87,17 @@
void
-BlockPrinter(const ndn::Block& block, const std::string& indent = "")
+BlockPrinter(const Block& block, const std::string& indent = "")
{
std::cout << indent;
printTypeInfo(block.type());
std::cout << " (size: " << block.value_size() << ")";
try {
- // if (block.type() != ndn::tlv::Content && block.type() != ndn::tlv::SignatureValue)
+ // if (block.type() != tlv::Content && block.type() != tlv::SignatureValue)
block.parse();
}
- catch (ndn::tlv::Error& e) {
+ catch (tlv::Error& e) {
// pass (e.g., leaf block reached)
// @todo: Figure how to deterministically figure out that value is not recursive TLV block
@@ -106,12 +106,12 @@
if (block.elements().empty())
{
std::cout << " [[";
- ndn::name::Component(block.value(), block.value_size()).toUri(std::cout);
+ name::Component(block.value(), block.value_size()).toUri(std::cout);
std::cout<< "]]";
}
std::cout << std::endl;
- for (ndn::Block::element_const_iterator i = block.elements_begin();
+ for (Block::element_const_iterator i = block.elements_begin();
i != block.elements_end();
++i)
{
@@ -120,10 +120,10 @@
}
void
-HexPrinter(const ndn::Block& block, const std::string& indent = "")
+HexPrinter(const Block& block, const std::string& indent = "")
{
std::cout << indent;
- for (ndn::Buffer::const_iterator i = block.begin (); i != block.value_begin(); ++i)
+ for (Buffer::const_iterator i = block.begin (); i != block.value_begin(); ++i)
{
std::cout << "0x";
std::cout << std::noshowbase << std::hex << std::setw(2) <<
@@ -135,7 +135,7 @@
if (block.elements_size() == 0 && block.value_size() > 0)
{
std::cout << indent << " ";
- for (ndn::Buffer::const_iterator i = block.value_begin (); i != block.value_end(); ++i)
+ for (Buffer::const_iterator i = block.value_begin (); i != block.value_end(); ++i)
{
std::cout << "0x";
std::cout << std::noshowbase << std::hex << std::setw(2) <<
@@ -146,7 +146,7 @@
}
else
{
- for (ndn::Block::element_const_iterator i = block.elements_begin();
+ for (Block::element_const_iterator i = block.elements_begin();
i != block.elements_end();
++i)
{
@@ -160,7 +160,7 @@
{
while (is.peek() != std::char_traits<char>::eof()) {
try {
- ndn::Block block = ndn::Block::fromStream(is);
+ Block block = Block::fromStream(is);
BlockPrinter(block, "");
// HexPrinter(block, "");
}
@@ -171,17 +171,19 @@
}
+} // namespace ndn
+
int main(int argc, const char *argv[])
{
if (argc == 1 ||
(argc == 2 && std::string(argv[1]) == "-"))
{
- parseBlocksFromStream(std::cin);
+ ndn::parseBlocksFromStream(std::cin);
}
else
{
std::ifstream file(argv[1]);
- parseBlocksFromStream(file);
+ ndn::parseBlocksFromStream(file);
}
return 0;