tools/ndns-daemon: fix bug that validator cannot fetch certificate

refs #2206

Change-Id: I10c69d95e6a5fd020038211ce419763fd62afcb3
diff --git a/tests/unit/daemon/name-server.cpp b/tests/unit/daemon/name-server.cpp
index 578533d..f721a5e 100644
--- a/tests/unit/daemon/name-server.cpp
+++ b/tests/unit/daemon/name-server.cpp
@@ -41,7 +41,7 @@
 public:
   NameServerFixture()
     : face(ndn::util::makeDummyClientFace({ false, true }))
-    , zone(m_net.getName())
+    , zone(m_root.getName())
     , validator(*face)
     , server(zone, m_certName, *face, m_session, m_keyChain, validator)
   {
@@ -69,7 +69,7 @@
 BOOST_AUTO_TEST_CASE(NdnsQuery)
 {
   Query q(hint, zone, ndns::label::NDNS_ITERATIVE_QUERY);
-  q.setRrLabel(Name("ndnsim"));
+  q.setRrLabel(Name("net"));
   q.setRrType(ndns::label::NS_RR_TYPE);
 
   bool hasDataBack = false;
@@ -125,7 +125,7 @@
     BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RAW);
   };
 
-  q.setRrLabel("dsk-3");
+  q.setRrLabel("dsk-1");
 
   face->receive(q.toInterest());
   run();
@@ -138,7 +138,7 @@
   Response re;
   re.setZone(zone);
   re.setQueryType(label::NDNS_ITERATIVE_QUERY);
-  re.setRrLabel(Name("ndnsim"));
+  re.setRrLabel(Name("net"));
   re.setRrType(label::NS_RR_TYPE);
   re.setNdnsType(NDNS_RESP);
 
@@ -191,7 +191,7 @@
   Response re;
   re.setZone(zone);
   re.setQueryType(label::NDNS_ITERATIVE_QUERY);
-  re.setRrLabel(Name("ndnsim-XYZ")); // insert new records
+  re.setRrLabel(Name("net-XYZ")); // insert new records
   re.setRrType(label::NS_RR_TYPE);
   re.setNdnsType(NDNS_RESP);
 
@@ -239,6 +239,188 @@
   BOOST_CHECK_EQUAL(hasDataBack, true);
 }
 
+BOOST_AUTO_TEST_CASE(UpdateValidatorCannotFetchCert)
+{
+  Name dskName = m_keyChain.generateRsaKeyPair(TEST_IDENTITY_NAME, false);
+  std::vector<CertificateSubjectDescription> desc;
+  time::system_clock::TimePoint notBefore = time::system_clock::now();
+  time::system_clock::TimePoint notAfter = notBefore + time::days(365);
+  shared_ptr<IdentityCertificate> dskCert =
+    m_keyChain.prepareUnsignedIdentityCertificate(dskName, m_certName,
+                                                  notBefore, notAfter, desc);
+
+  m_keyChain.sign(*dskCert, m_certName);
+  m_keyChain.addCertificateAsKeyDefault(*dskCert);
+  NDNS_LOG_TRACE("KeyChain: add cert: " << dskCert->getName() << ". KeyLocator: "
+                 << dskCert->getSignature().getKeyLocator().getName());
+
+  Rrset rrset(&m_root);
+  Name label = dskCert->getName().getPrefix(-2).getSubName(m_root.getName().size() + 1);
+  rrset.setLabel(label);
+  rrset.setType(label::CERT_RR_TYPE);
+  rrset.setVersion(dskCert->getName().get(-1));
+  rrset.setTtl(m_root.getTtl());
+  rrset.setData(dskCert->wireEncode());
+  m_session.insert(rrset);
+  NDNS_LOG_TRACE("DB: zone " << m_root << " add a ID-CERT RR with name="
+                 << dskCert->getName() << " rrLabel=" << label);
+
+  Response re;
+  re.setZone(zone);
+  re.setQueryType(label::NDNS_ITERATIVE_QUERY);
+  re.setRrLabel(Name("ndnsim-XYZ")); // insert new records
+  re.setRrType(label::NS_RR_TYPE);
+  re.setNdnsType(NDNS_RESP);
+
+  std::string str = "ns1.ndnsim.net";
+  re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
+  str = "ns2.ndnsim.net";
+  re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
+
+  shared_ptr<Data> data = re.toData();
+  m_keyChain.sign(*data, dskCert->getName());
+
+  Query q(Name(hint), Name(zone), ndns::label::NDNS_ITERATIVE_QUERY);
+  const Block& block = data->wireEncode();
+  Name name;
+  name.append(block);
+
+  q.setRrLabel(name);
+  q.setRrType(label::NDNS_UPDATE_LABEL);
+
+  bool hasDataBack = false;
+
+  // no data back, since the Update cannot pass verification
+  face->onData += [&] (const Data& data) {
+    hasDataBack = true;
+    BOOST_FAIL("UNEXPECTED");
+  };
+
+  face->receive(q.toInterest());
+  run();
+
+  BOOST_CHECK_EQUAL(hasDataBack, false);
+}
+
+class NameServerFixture2 : public DbTestData
+{
+public:
+  NameServerFixture2()
+    : face(ndn::util::makeDummyClientFace(io, { false, true }))
+    , validatorFace(ndn::util::makeDummyClientFace(io, { false, true }))
+    , zone(m_root.getName())
+    , validator(*validatorFace) // different face for validator
+    , server(zone, m_certName, *face, m_session, m_keyChain, validator)
+  {
+    // ensure prefix is registered
+    run();
+    validatorFace->onInterest += [&] (const Interest& interest) {
+      NDNS_LOG_TRACE("validatorFace get Interest: " << interest.getName());
+      face->receive(interest);
+    };
+  }
+
+  void
+  run()
+  {
+    io.poll();
+    io.reset();
+  }
+
+public:
+  boost::asio::io_service io;
+  shared_ptr<ndn::util::DummyClientFace> face;
+  shared_ptr<ndn::util::DummyClientFace> validatorFace;
+  Name hint;
+  const Name& zone;
+  Validator validator;
+  ndns::NameServer server;
+};
+
+BOOST_FIXTURE_TEST_CASE(UpdateValidatorFetchCert, NameServerFixture2)
+{
+  Name dskName = m_keyChain.generateRsaKeyPair(TEST_IDENTITY_NAME, false);
+  std::vector<CertificateSubjectDescription> desc;
+  time::system_clock::TimePoint notBefore = time::system_clock::now();
+  time::system_clock::TimePoint notAfter = notBefore + time::days(365);
+  shared_ptr<IdentityCertificate> dskCert =
+    m_keyChain.prepareUnsignedIdentityCertificate(dskName, m_certName,
+                                                  notBefore, notAfter, desc);
+
+  m_keyChain.sign(*dskCert, m_certName);
+  m_keyChain.addCertificateAsKeyDefault(*dskCert);
+  NDNS_LOG_TRACE("KeyChain: add cert: " << dskCert->getName() << ". KeyLocator: "
+                 << dskCert->getSignature().getKeyLocator().getName());
+
+  Rrset rrset(&m_root);
+  Name label = dskCert->getName().getPrefix(-2).getSubName(m_root.getName().size() + 1);
+  rrset.setLabel(label);
+  rrset.setType(label::CERT_RR_TYPE);
+  rrset.setVersion(dskCert->getName().get(-1));
+  rrset.setTtl(m_root.getTtl());
+  rrset.setData(dskCert->wireEncode());
+  m_session.insert(rrset);
+  NDNS_LOG_TRACE("DB: zone " << m_root << " add a ID-CERT RR with name="
+                 << dskCert->getName() << " rrLabel=" << label);
+
+  Response re;
+  re.setZone(zone);
+  re.setQueryType(label::NDNS_ITERATIVE_QUERY);
+  re.setRrLabel(Name("ndnsim-XYZ")); // insert new records
+  re.setRrType(label::NS_RR_TYPE);
+  re.setNdnsType(NDNS_RESP);
+
+  std::string str = "ns1.ndnsim.net";
+  re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
+  str = "ns2.ndnsim.net";
+  re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
+
+  shared_ptr<Data> data = re.toData();
+  m_keyChain.sign(*data, dskCert->getName());
+
+  Query q(Name(hint), Name(zone), ndns::label::NDNS_ITERATIVE_QUERY);
+  const Block& block = data->wireEncode();
+  Name name;
+  name.append(block);
+
+  q.setRrLabel(name);
+  q.setRrType(label::NDNS_UPDATE_LABEL);
+
+  bool hasDataBack = false;
+
+  shared_ptr<Regex> regex = make_shared<Regex>("(<>*)<KEY>(<>+)<ID-CERT><>");
+  face->onData += [&] (const Data& data) {
+    if (regex->match(data.getName())) {
+      validatorFace->receive(data); // It's data requested by validator
+    }
+    else {
+      // cert is requested by validator
+      hasDataBack = true;
+      NDNS_LOG_TRACE("get Data back");
+      BOOST_CHECK_EQUAL(data.getName().getPrefix(-1), q.toInterest().getName());
+      Response resp;
+
+      BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
+      std::cout << resp << std::endl;
+      BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RESP); // by default NDNS_RAW is enough
+      BOOST_CHECK_GT(resp.getRrs().size(), 0);
+      Block block = resp.getRrs()[0];
+      block.parse();
+      int ret = -1;
+      BOOST_CHECK_EQUAL(block.type(), ndns::tlv::RrData);
+      Block::element_const_iterator val = block.elements_begin();
+      BOOST_CHECK_EQUAL(val->type(), ndns::tlv::UpdateReturnCode); // the first must be return code
+      ret = readNonNegativeInteger(*val);
+      BOOST_CHECK_EQUAL(ret, 0);
+    }
+  };
+
+  face->receive(q.toInterest());
+  run();
+
+  BOOST_CHECK_EQUAL(hasDataBack, true);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace tests