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/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;
}