interest+data: forbid unrecognized TLV before Name

Change-Id: Id052b02be0aa3e36064c40872cee37f9c8dd3a78
diff --git a/src/data.cpp b/src/data.cpp
index 169d99c..f72673f 100644
--- a/src/data.cpp
+++ b/src/data.cpp
@@ -121,74 +121,73 @@
 void
 Data::wireDecode(const Block& wire)
 {
+  // Data ::= DATA-TLV TLV-LENGTH
+  //            Name
+  //            MetaInfo?
+  //            Content?
+  //            SignatureInfo
+  //            SignatureValue
+
   m_wire = wire;
   m_wire.parse();
-  bool hasName = false, hasSigInfo = false;
-  m_name.clear();
+
+  auto element = m_wire.elements_begin();
+  if (element == m_wire.elements_end() || element->type() != tlv::Name) {
+    BOOST_THROW_EXCEPTION(Error("Name element is missing or out of order"));
+  }
+  m_name.wireDecode(*element);
+  int lastElement = 1; // last recognized element index, in spec order
+
   m_metaInfo = MetaInfo();
   m_content = Block(tlv::Content);
   m_signature = Signature();
   m_fullName.clear();
 
-  int lastEle = 0; // last recognized element index, in spec order
-  for (const Block& ele : m_wire.elements()) {
-    switch (ele.type()) {
-      case tlv::Name: {
-        if (lastEle >= 1) {
-          BOOST_THROW_EXCEPTION(Error("Name element is out of order"));
-        }
-        hasName = true;
-        m_name.wireDecode(ele);
-        lastEle = 1;
-        break;
-      }
+  for (++element; element != m_wire.elements_end(); ++element) {
+    switch (element->type()) {
       case tlv::MetaInfo: {
-        if (lastEle >= 2) {
+        if (lastElement >= 2) {
           BOOST_THROW_EXCEPTION(Error("MetaInfo element is out of order"));
         }
-        m_metaInfo.wireDecode(ele);
-        lastEle = 2;
+        m_metaInfo.wireDecode(*element);
+        lastElement = 2;
         break;
       }
       case tlv::Content: {
-        if (lastEle >= 3) {
+        if (lastElement >= 3) {
           BOOST_THROW_EXCEPTION(Error("Content element is out of order"));
         }
-        m_content = ele;
-        lastEle = 3;
+        m_content = *element;
+        lastElement = 3;
         break;
       }
       case tlv::SignatureInfo: {
-        if (lastEle >= 4) {
+        if (lastElement >= 4) {
           BOOST_THROW_EXCEPTION(Error("SignatureInfo element is out of order"));
         }
-        hasSigInfo = true;
-        m_signature.setInfo(ele);
-        lastEle = 4;
+        m_signature.setInfo(*element);
+        lastElement = 4;
         break;
       }
       case tlv::SignatureValue: {
-        if (lastEle >= 5) {
+        if (lastElement >= 5) {
           BOOST_THROW_EXCEPTION(Error("SignatureValue element is out of order"));
         }
-        m_signature.setValue(ele);
-        lastEle = 5;
+        m_signature.setValue(*element);
+        lastElement = 5;
         break;
       }
       default: {
-        if (tlv::isCriticalType(ele.type())) {
+        if (tlv::isCriticalType(element->type())) {
           BOOST_THROW_EXCEPTION(Error("unrecognized element of critical type " +
-                                      to_string(ele.type())));
+                                      to_string(element->type())));
         }
         break;
       }
     }
   }
 
-  if (!hasName) {
-    BOOST_THROW_EXCEPTION(Error("Name element is missing"));
-  }
-  if (!hasSigInfo) {
+  if (!m_signature) {
     BOOST_THROW_EXCEPTION(Error("SignatureInfo element is missing"));
   }
 }
diff --git a/src/interest.cpp b/src/interest.cpp
index 50f5a13..0e845e3 100644
--- a/src/interest.cpp
+++ b/src/interest.cpp
@@ -305,33 +305,29 @@
   //                HopLimit?
   //                Parameters?
 
-  bool hasName = false;
+  auto element = m_wire.elements_begin();
+  if (element == m_wire.elements_end() || element->type() != tlv::Name) {
+    BOOST_THROW_EXCEPTION(Error("Name element is missing or out of order"));
+  }
+  m_name.wireDecode(*element);
+  if (m_name.empty()) {
+    BOOST_THROW_EXCEPTION(Error("Name has zero name components"));
+  }
+  int lastElement = 1; // last recognized element index, in spec order
+
   m_selectors = Selectors().setMaxSuffixComponents(1); // CanBePrefix=0
   m_nonce.reset();
   m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
   m_forwardingHint = DelegationList();
   m_parameters = Block();
 
-  int lastElement = 0; // last recognized element index, in spec order
-  for (const Block& element : m_wire.elements()) {
-    switch (element.type()) {
-      case tlv::Name: {
-        if (lastElement >= 1) {
-          BOOST_THROW_EXCEPTION(Error("Name element is out of order"));
-        }
-        hasName = true;
-        m_name.wireDecode(element);
-        if (m_name.empty()) {
-          BOOST_THROW_EXCEPTION(Error("Name has zero name components"));
-        }
-        lastElement = 1;
-        break;
-      }
+  for (++element; element != m_wire.elements_end(); ++element) {
+    switch (element->type()) {
       case tlv::CanBePrefix: {
         if (lastElement >= 2) {
           BOOST_THROW_EXCEPTION(Error("CanBePrefix element is out of order"));
         }
-        if (element.value_size() != 0) {
+        if (element->value_size() != 0) {
           BOOST_THROW_EXCEPTION(Error("CanBePrefix element has non-zero TLV-LENGTH"));
         }
         m_selectors.setMaxSuffixComponents(-1);
@@ -342,7 +338,7 @@
         if (lastElement >= 3) {
           BOOST_THROW_EXCEPTION(Error("MustBeFresh element is out of order"));
         }
-        if (element.value_size() != 0) {
+        if (element->value_size() != 0) {
           BOOST_THROW_EXCEPTION(Error("MustBeFresh element has non-zero TLV-LENGTH"));
         }
         m_selectors.setMustBeFresh(true);
@@ -353,7 +349,7 @@
         if (lastElement >= 4) {
           BOOST_THROW_EXCEPTION(Error("ForwardingHint element is out of order"));
         }
-        m_forwardingHint.wireDecode(element);
+        m_forwardingHint.wireDecode(*element);
         lastElement = 4;
         break;
       }
@@ -362,10 +358,10 @@
           BOOST_THROW_EXCEPTION(Error("Nonce element is out of order"));
         }
         uint32_t nonce = 0;
-        if (element.value_size() != sizeof(nonce)) {
+        if (element->value_size() != sizeof(nonce)) {
           BOOST_THROW_EXCEPTION(Error("Nonce element is malformed"));
         }
-        std::memcpy(&nonce, element.value(), sizeof(nonce));
+        std::memcpy(&nonce, element->value(), sizeof(nonce));
         m_nonce = nonce;
         lastElement = 5;
         break;
@@ -374,7 +370,7 @@
         if (lastElement >= 6) {
           BOOST_THROW_EXCEPTION(Error("InterestLifetime element is out of order"));
         }
-        m_interestLifetime = time::milliseconds(readNonNegativeInteger(element));
+        m_interestLifetime = time::milliseconds(readNonNegativeInteger(*element));
         lastElement = 6;
         break;
       }
@@ -382,7 +378,7 @@
         if (lastElement >= 7) {
           break; // HopLimit is non-critical, ignore out-of-order appearance
         }
-        if (element.value_size() != 1) {
+        if (element->value_size() != 1) {
           BOOST_THROW_EXCEPTION(Error("HopLimit element is malformed"));
         }
         // TLV-VALUE is ignored
@@ -393,23 +389,19 @@
         if (lastElement >= 8) {
           BOOST_THROW_EXCEPTION(Error("Parameters element is out of order"));
         }
-        m_parameters = element;
+        m_parameters = *element;
         lastElement = 8;
         break;
       }
       default: {
-        if (tlv::isCriticalType(element.type())) {
+        if (tlv::isCriticalType(element->type())) {
           BOOST_THROW_EXCEPTION(Error("unrecognized element of critical type " +
-                                      to_string(element.type())));
+                                      to_string(element->type())));
         }
         break;
       }
     }
   }
-
-  if (!hasName) {
-    BOOST_THROW_EXCEPTION(Error("Name element is missing"));
-  }
 }
 
 std::string
diff --git a/tests/unit-tests/data.t.cpp b/tests/unit-tests/data.t.cpp
index 521b7d9..0d91005 100644
--- a/tests/unit-tests/data.t.cpp
+++ b/tests/unit-tests/data.t.cpp
@@ -279,7 +279,7 @@
 
 BOOST_AUTO_TEST_CASE(Full)
 {
-  d.wireDecode("063C FC00 0703080144 FC00 1400 FC00 1500 FC00 16031B0100 FC00 "
+  d.wireDecode("063A 0703080144 FC00 1400 FC00 1500 FC00 16031B0100 FC00 "
                "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76 FC00"_block);
   BOOST_CHECK_EQUAL(d.getName(), "/D");
   BOOST_CHECK_EQUAL(d.getMetaInfo(), MetaInfo());
@@ -288,7 +288,7 @@
   BOOST_CHECK_EQUAL(d.getSignature().getValue().value_size(), 32);
 
   // encode without modification: retain original wire encoding
-  BOOST_CHECK_EQUAL(d.wireEncode().value_size(), 60);
+  BOOST_CHECK_EQUAL(d.wireEncode().value_size(), 58);
 
   // modify then re-encode as v0.2 format
   d.setName("/E");
@@ -332,6 +332,14 @@
   BOOST_CHECK_THROW(d.wireDecode("0605 0703080144"_block), tlv::Error);
 }
 
+BOOST_AUTO_TEST_CASE(UnrecognizedNonCriticalElementBeforeName)
+{
+  BOOST_CHECK_THROW(d.wireDecode(
+    "062F FC00 0703080144 16031B0100 "
+    "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76"_block),
+    tlv::Error);
+}
+
 BOOST_AUTO_TEST_CASE(UnrecognizedCriticalElement)
 {
   BOOST_CHECK_THROW(d.wireDecode(
diff --git a/tests/unit-tests/interest.t.cpp b/tests/unit-tests/interest.t.cpp
index 0f39c16..16e2ba2 100644
--- a/tests/unit-tests/interest.t.cpp
+++ b/tests/unit-tests/interest.t.cpp
@@ -236,7 +236,7 @@
 
 BOOST_AUTO_TEST_CASE(Full)
 {
-  i.wireDecode("0533 FC00 0703080149 FC00 2100 FC00 1200 "
+  i.wireDecode("0531 0703080149 FC00 2100 FC00 1200 "
                "FC00 1E0B(1F09 1E023E15 0703080148) FC00 0A044ACB1E4C "
                "FC00 0C0276A1 FC00 2201D6 FC00"_block);
   BOOST_CHECK_EQUAL(i.getName(), "/I");
@@ -249,7 +249,7 @@
   // HopLimit=214 is not stored
 
   // encode without modification: retain original wire encoding
-  BOOST_CHECK_EQUAL(i.wireEncode().value_size(), 51);
+  BOOST_CHECK_EQUAL(i.wireEncode().value_size(), 49);
 
   // modify then re-encode as v0.2 format
   i.setName("/J");
@@ -326,6 +326,11 @@
   BOOST_CHECK_THROW(i.wireDecode("050C 0703080149 0A05EFA420B262"_block), tlv::Error);
 }
 
+BOOST_AUTO_TEST_CASE(UnrecognizedNonCriticalElementBeforeName)
+{
+  BOOST_CHECK_THROW(i.wireDecode("0507 FC00 0703080149"_block), tlv::Error);
+}
+
 BOOST_AUTO_TEST_CASE(UnrecognizedCriticalElement)
 {
   BOOST_CHECK_THROW(i.wireDecode("0507 0703080149 FB00"_block), tlv::Error);