Update the NDNCERT library to version NDNCERT v2

spec:[https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-new]

Change-Id: Ia480a8e70c4b38ca170dfe2fcf50d1265ab65f46
diff --git a/tools/ndncert-client.cpp b/tools/ndncert-client.cpp
index 3ad53aa..ea38694 100644
--- a/tools/ndncert-client.cpp
+++ b/tools/ndncert-client.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
  *
  * This file is part of ndncert, a certificate management system based on NDN.
  *
@@ -20,10 +20,8 @@
 
 #include "client-module.hpp"
 #include "challenge-module.hpp"
-
 #include <iostream>
 #include <string>
-
 #include <boost/program_options/options_description.hpp>
 #include <boost/program_options/variables_map.hpp>
 #include <boost/program_options/parsers.hpp>
@@ -32,208 +30,252 @@
 namespace ndn {
 namespace ndncert {
 
+static void startApplication();
+
 int nStep;
+Face face;
+security::v2::KeyChain keyChain;
+std::string challengeType;
+ClientModule client(keyChain);
 
-class ClientTool
+static std::list<std::string>
+captureParams(const JsonSection& requirement)
 {
-public:
-  ClientTool(ClientModule& clientModule)
-    : client(clientModule)
-  {
+  std::list<std::string> results;
+  for (auto& item : requirement) {
+    std::cerr << item.second.get<std::string>("") << std::endl;
+    std::cerr << "Please provide the argument: " << item.first << " : " << std::endl;
+    std::string tempParam;
+    getline(std::cin, tempParam);
+    results.push_back(tempParam);
   }
-
-  void
-  errorCb(const std::string& errorInfo)
-  {
-    std::cerr << "Error: " << errorInfo << std::endl;
+  std::cerr << "Got it. This is what you've provided:" << std::endl;
+  auto it1 = results.begin();
+  auto it2 = requirement.begin();
+  for (; it1 != results.end() && it2 != requirement.end(); it1++, it2++) {
+    std::cerr << it2->first << " : " << *it1 << std::endl;
   }
+  return results;
+}
 
-  void
-  downloadCb(const shared_ptr<RequestState>& state)
-  {
-    std::cerr << "Step " << nStep++
-              << "DONE! Certificate has already been installed to local keychain\n";
+static void
+onNackCb()
+{
+  std::cerr << "Got NACK\n";
+}
+
+static void
+timeoutCb()
+{
+  std::cerr << "Interest sent time out\n";
+}
+
+static void
+downloadCb(const Data& reply)
+{
+  client.onDownloadResponse(reply);
+  std::cerr << "Step " << nStep++
+            << ": DONE! Certificate has already been installed to local keychain\n";
+  return;
+}
+
+static void
+challengeCb(const Data& reply)
+{
+  client.onChallengeResponse(reply);
+  if (client.getApplicationStatus() == STATUS_SUCCESS) {
+    std::cerr << "DONE! Certificate has already been issued \n";
+    face.expressInterest(*client.generateDownloadInterest(), bind(&downloadCb, _2),
+                         bind(&onNackCb), bind(&timeoutCb));
     return;
   }
 
-  void
-  anchorCb(const Interest& request, const Data& reply,
-           const ClientCaItem& anchorItem, const Name& assignedName)
-  {
-    auto contentJson = ClientModule::getJsonFromData(reply);
-    auto caItem = ClientConfig::extractCaItem(contentJson);
-
-    if (!security::verifySignature(caItem.m_anchor, anchorItem.m_anchor)) {
-      std::cerr << "Fail to verify fetched anchor" << std::endl;
-      return;
-    }
-    client.getClientConf().m_caItems.push_back(caItem);
-
-    if (assignedName.toUri() != "/") {
-      client.sendNew(caItem, assignedName,
-                     bind(&ClientTool::newCb, this, _1),
-                     bind(&ClientTool::errorCb, this, _1));
-    }
-    else {
-      if (caItem.m_probe != "") {
-        std::cerr << "Step " << nStep++ << ": Probe Requirement-" << caItem.m_probe << std::endl;
-        std::string probeInfo;
-        getline(std::cin, probeInfo);
-        client.sendProbe(caItem, probeInfo,
-                         bind(&ClientTool::newCb, this, _1),
-                         bind(&ClientTool::errorCb, this, _1));
-      }
-      else {
-        std::cerr << "Step " << nStep++ << ": Please type in the identity name\n";
-        std::string nameComponent;
-        getline(std::cin, nameComponent);
-        Name identityName = caItem.m_caName.getPrefix(-1);
-        identityName.append(nameComponent);
-        client.sendNew(caItem, identityName,
-                       bind(&ClientTool::newCb, this, _1),
-                       bind(&ClientTool::errorCb, this, _1));
-      }
-    }
-  }
-
-  void
-  listCb(const std::list<Name>& caList, const Name& assignedName, const Name& schema,
-         const ClientCaItem& caItem)
-  {
-    if (assignedName.toUri() != "" && caList.size() == 1) {
-      // with recommendation
-
-      std::cerr << "Get recommended CA: " << caList.front()
-                << "Get recommended Identity: " << assignedName << std::endl;
-      client.requestCaTrustAnchor(caList.front(),
-                                  bind(&ClientTool::anchorCb, this, _1, _2, caItem, assignedName),
-                                  bind(&ClientTool::errorCb, this, _1));
-    }
-    else {
-      // without recommendation
-      int count = 0;
-      for (auto name : caList) {
-        std::cerr << "***************************************\n"
-                  << "Index: " << count++ << "\n"
-                  << "CA prefix:" << name << "\n"
-                  << "***************************************\n";
-      }
-      std::cerr << "Select an index to apply for a certificate\n";
-
-      std::string option;
-      getline(std::cin, option);
-      int caIndex = std::stoi(option);
-
-      std::vector<Name> caVector{std::begin(caList), std::end(caList)};
-      Name targetCaName = caVector[caIndex];
-
-      client.requestCaTrustAnchor(targetCaName,
-                                  bind(&ClientTool::anchorCb, this, _1, _2, caItem, Name("")),
-                                  bind(&ClientTool::errorCb, this, _1));
-    }
-  }
-
-  void
-  validateCb(const shared_ptr<RequestState>& state)
-  {
-    if (state->m_status == ChallengeModule::SUCCESS) {
-      std::cerr << "DONE! Certificate has already been issued \n";
-      client.requestDownload(state,
-                             bind(&ClientTool::downloadCb, this, _1),
-                             bind(&ClientTool::errorCb, this, _1));
-      return;
-    }
-
-    auto challenge = ChallengeModule::createChallengeModule(state->m_challengeType);
-    auto requirementList = challenge->getRequirementForValidate(state->m_status);
-
+  auto challenge = ChallengeModule::createChallengeModule(challengeType);
+  auto requirement = challenge->getRequirementForChallenge(client.getApplicationStatus(), client.getChallengeStatus());
+  if (requirement.size() > 0) {
     std::cerr << "Step " << nStep++ << ": Please satisfy following instruction(s)\n";
-    for (auto requirement : requirementList) {
-      std::cerr << "\t" << requirement << std::endl;
+    std::string redo = "";
+    std::list<std::string> capturedParams;
+    do {
+      capturedParams = captureParams(requirement);
+      std::cerr << "If anything is wrong, please type in OK; otherwise, type in REDO" << std::endl;
+      getline(std::cin, redo);
+    } while (redo == "REDO");
+    auto it1 = capturedParams.begin();
+    auto it2 = requirement.begin();
+    for (; it1 != capturedParams.end() && it2 != requirement.end(); it1++, it2++) {
+      it2->second.put("", *it1);
     }
-    std::list<std::string> paraList;
-    for (size_t i = 0; i < requirementList.size(); i++) {
-      std::string tempParam;
-      getline(std::cin, tempParam);
-      paraList.push_back(tempParam);
-    }
-    auto paramJson = challenge->genValidateParamsJson(state->m_status, paraList);
-    client.sendValidate(state, paramJson,
-                        bind(&ClientTool::validateCb, this, _1),
-                        bind(&ClientTool::errorCb, this, _1));
   }
+  face.expressInterest(*client.generateChallengeInterest(
+                        challenge->genChallengeRequestJson(
+                                   client.getApplicationStatus(),
+                                   client.getChallengeStatus(),
+                                   requirement)),
+                       bind(&challengeCb, _2),
+                       bind(&onNackCb),
+                       bind(&timeoutCb));
+}
 
-  void
-  selectCb(const shared_ptr<RequestState>& state)
-  {
-    auto challenge = ChallengeModule::createChallengeModule(state->m_challengeType);
-    auto requirementList = challenge->getRequirementForValidate(state->m_status);
-
-    std::cerr << "Step " << nStep++ << ": Please satisfy following instruction(s)" << std::endl;
-    for (auto item : requirementList) {
-      std::cerr << "\t" << item << std::endl;
-    }
-    std::list<std::string> paraList;
-    for (size_t i = 0; i < requirementList.size(); i++) {
-      std::string tempParam;
-      getline(std::cin, tempParam);
-      paraList.push_back(tempParam);
-    }
-
-    auto paramJson = challenge->genValidateParamsJson(state->m_status, paraList);
-    client.sendValidate(state, paramJson,
-                        bind(&ClientTool::validateCb, this, _1),
-                        bind(&ClientTool::errorCb, this, _1));
+static void
+newCb(const Data& reply)
+{
+  auto challengeList = client.onNewResponse(reply);
+  std::cerr << "Step " << nStep++ << ": Please type in the challenge ID from the following challenges\n";
+  for (auto item : challengeList) {
+    std::cerr << "\t" << item << std::endl;
   }
+  std::string choice;
+  getline(std::cin, choice);
 
-  void
-  newCb(const shared_ptr<RequestState>& state)
-  {
-    std::cerr << "Step " << nStep++ << ": Please select one challenge from following types\n";
-    for (auto item : state->m_challengeList) {
-      std::cerr << "\t" << item << std::endl;
-    }
-    std::string choice;
-    getline(std::cin, choice);
-
-    auto challenge = ChallengeModule::createChallengeModule(choice);
-    auto requirementList = challenge->getRequirementForSelect();
-    std::list<std::string> paraList;
-    if (requirementList.size() != 0) {
-      std::cerr << "Step " << nStep++ << ": Please satisfy following instruction(s)\n";
-      for (auto item : requirementList) {
-        std::cerr << "\t" << item << std::endl;
-      }
-      for (size_t i = 0; i < requirementList.size(); i++) {
-        std::string tempParam;
-        getline(std::cin, tempParam);
-        paraList.push_back(tempParam);
-      }
-    }
-    auto paramJson = challenge->genSelectParamsJson(state->m_status, paraList);
-    client.sendSelect(state, choice, paramJson,
-                      bind(&ClientTool::selectCb, this, _1),
-                      bind(&ClientTool::errorCb, this, _1));
+  auto challenge = ChallengeModule::createChallengeModule(choice);
+  if (challenge != nullptr) {
+    challengeType = choice;
   }
+  else {
+    std::cerr << "Cannot recognize the specified challenge. Exit";
+    return;
+  }
+  auto requirement = challenge->getRequirementForChallenge(client.getApplicationStatus(),
+                                                           client.getChallengeStatus());
+  if (requirement.size() > 0) {
+    std::cerr << "Step " << nStep++ << ": Please satisfy following instruction(s)\n";
+    std::string redo = "";
+    std::list<std::string> capturedParams;
+    do {
+      capturedParams = captureParams(requirement);
+      std::cerr << "If anything is wrong, please type in OK; otherwise, type in REDO" << std::endl;
+      getline(std::cin, redo);
+    } while (redo == "REDO");
+    auto it1 = capturedParams.begin();
+    auto it2 = requirement.begin();
+    for (; it1 != capturedParams.end() && it2 != requirement.end(); it1++, it2++) {
+      it2->second.put("", *it1);
+    }
+  }
+  face.expressInterest(*client.generateChallengeInterest(
+                               challenge->genChallengeRequestJson(
+                                          client.getApplicationStatus(),
+                                          client.getChallengeStatus(),
+                                          requirement)),
+                       bind(&challengeCb, _2),
+                       bind(&onNackCb),
+                       bind(&timeoutCb));
+}
 
-public:
-  ClientModule& client;
-};
+static void
+probeInfoCb(const Data& reply)
+{
+  auto contentJson = ClientModule::getJsonFromData(reply);
+  auto caItem = ClientConfig::extractCaItem(contentJson);
+
+  std::cerr << "Will install new trust anchor, please double check the identity info: \n"
+            << "This trust anchor packet is signed by " << reply.getSignature().getKeyLocator() << std::endl
+            << "The signing certificate is " << caItem.m_anchor << std::endl;
+  std::cerr << "Do you trust the information? Type in YES or NO" << std::endl;
+
+  std::string answer;
+  getline(std::cin, answer);
+  if (answer == "YES") {
+    client.onProbeInfoResponse(reply);
+    std::cerr << "You answered YES: new CA installed" << std::endl;
+    startApplication();
+  }
+  else {
+    std::cerr << "New CA not installed" << std::endl;
+    return;
+  }
+}
+
+static void
+probeCb(const Data& reply)
+{
+  std::cerr << "Step " << nStep++
+            << ": Please type in your expected validity period of your certificate."
+            << " Type in a number in unit of hour. The CA may change the validity"
+            << " period if your expected period is too long." << std::endl;
+  std::string periodStr;
+  getline(std::cin, periodStr);
+  int hours = std::stoi(periodStr);
+  face.expressInterest(*client.generateNewInterest(time::system_clock::now(),
+                                                   time::system_clock::now() + time::hours(hours)),
+                       bind(&newCb, _2),
+                       bind(&onNackCb),
+                       bind(&timeoutCb));
+}
+
+static void
+startApplication()
+{
+  nStep = 0;
+  auto caList = client.getClientConf().m_caItems;
+  int count = 0;
+  for (auto item : caList) {
+    std::cerr << "***************************************\n"
+              << "Index: " << count++ << "\n"
+              << "CA prefix:" << item.m_caName << "\n"
+              << "Introduction: " << item.m_caInfo << "\n"
+              << "***************************************\n";
+  }
+  std::vector<ClientCaItem> caVector{std::begin(caList), std::end(caList)};
+  std::cerr << "Step "
+            << nStep++ << ": Please type in the CA INDEX that you want to apply"
+            << " or type in NONE if your expected CA is not in the list\n";
+
+  std::string caIndexS;
+  getline(std::cin, caIndexS);
+  if (caIndexS == "NONE") {
+    std::cerr << "Step " << nStep << ": Please type in the CA Name\n";
+    face.expressInterest(*client.generateProbeInfoInterest(Name(caIndexS)),
+                         bind(&probeInfoCb, _2),
+                         bind(&onNackCb),
+                         bind(&timeoutCb));
+  }
+  else {
+    int caIndex = std::stoi(caIndexS);
+    BOOST_ASSERT(caIndex <= count);
+    auto targetCaItem = caVector[caIndex];
+
+    if (targetCaItem.m_probe != "") {
+      std::cerr << "Step " << nStep++ << ": Probe Requirement-" << targetCaItem.m_probe << std::endl;
+      std::string probeInfo;
+      getline(std::cin, probeInfo);
+      face.expressInterest(*client.generateProbeInterest(targetCaItem, probeInfo),
+                           bind(&probeCb, _2),
+                           bind(&onNackCb),
+                           bind(&timeoutCb));
+    }
+    else {
+      std::cerr << "Step " << nStep++ << ": Please type in the identity name you want to get (with CA prefix)\n";
+      std::string identityNameStr;
+      getline(std::cin, identityNameStr);
+      std::cerr << "Step "
+                << nStep++ << ": Please type in your expected validity period of your certificate."
+                << "Type in a number in unit of hour."
+                << " The CA may change the validity period if your expected period is too long.\n";
+      std::string periodStr;
+      getline(std::cin, periodStr);
+      int hours = std::stoi(periodStr);
+      face.expressInterest(*client.generateNewInterest(time::system_clock::now(),
+                                                       time::system_clock::now() + time::hours(hours),
+                                                       Name(identityNameStr)),
+                           bind(&newCb, _2),
+                           bind(&onNackCb),
+                           bind(&timeoutCb));
+    }
+  }
+}
+
 
 int
 main(int argc, char* argv[])
 {
   namespace po = boost::program_options;
   std::string configFilePath = std::string(SYSCONFDIR) + "/ndncert/client.conf";
-  bool isIntra = false;
-  po::options_description description("General Usage\n ndncert-client [-h] [-i] [-f]\n");
+  po::options_description description("General Usage\n ndncert-client [-h] [-f]\n");
   description.add_options()
-    ("help,h",
-     "produce help message")
-    ("intra-node,i",
-     "optional, if specified, switch on the intra-node mode")
-    ("config-file,f", po::value<std::string>(&configFilePath),
-     "config file name");
+    ("help,h", "produce help message")
+    ("config-file,f", po::value<std::string>(&configFilePath), "config file name");
   po::positional_options_description p;
 
   po::variables_map vm;
@@ -249,131 +291,8 @@
     std::cerr << description << std::endl;
     return 0;
   }
-  if (vm.count("intra-node") != 0) {
-    isIntra = true;
-  }
-
-  nStep = 0;
-  Face face;
-  security::v2::KeyChain keyChain;
-  ClientModule client(face, keyChain);
   client.getClientConf().load(configFilePath);
-  ClientTool tool(client);
-
-  if (isIntra) {
-    client.requestLocalhostList([&](const ClientConfig& config) {
-        auto caList = config.m_caItems;
-        int count = 0;
-        for (auto item : caList) {
-          std::cerr << "***************************************\n"
-                    << "Index: " << count++ << "\n"
-                    << "CA prefix:" << item.m_caName << "\n"
-                    << "Introduction: " << item.m_caInfo << "\n"
-                    << "***************************************\n";
-        }
-        std::vector<ClientCaItem> caVector{std::begin(caList), std::end(caList)};
-        std::cerr << "Step " << nStep++
-                  << ": Please type in the CA namespace index that you want to apply\n";
-        std::string caIndexS;
-        getline(std::cin, caIndexS);
-        int caIndex = std::stoi(caIndexS);
-
-        BOOST_ASSERT(caIndex <= count);
-
-        auto targetCaItem = caVector[caIndex];
-        if (targetCaItem.m_probe != "") {
-          std::cerr << "Step " << nStep++ << ": Probe Requirement-" << targetCaItem.m_probe << std::endl;
-          std::string probeInfo;
-          getline(std::cin, probeInfo);
-          client.sendProbe(targetCaItem, probeInfo,
-                           bind(&ClientTool::newCb, &tool, _1),
-                           bind(&ClientTool::errorCb, &tool, _1));
-        }
-        else {
-          std::cerr << "Step " << nStep++ << ": Please type in the identity name\n";
-          std::string nameComponent;
-          getline(std::cin, nameComponent);
-          Name identityName = targetCaItem.m_caName.getPrefix(-1);
-          identityName.append(nameComponent);
-          client.sendNew(targetCaItem, identityName,
-                         bind(&ClientTool::newCb, &tool, _1),
-                         bind(&ClientTool::errorCb, &tool, _1));
-        }
-      },
-      bind(&ClientTool::errorCb, &tool, _1));
-  }
-  else {
-    // Inter-node Application
-    bool listFirst = false;
-    auto caList = client.getClientConf().m_caItems;
-    int count = 0;
-    for (auto item : caList) {
-      std::cerr << "***************************************\n"
-                << "Index: " << count++ << "\n"
-                << "CA prefix:" << item.m_caName << "\n"
-                << "Introduction: " << item.m_caInfo << "\n"
-                << "***************************************\n";
-    }
-    std::vector<ClientCaItem> caVector{std::begin(caList), std::end(caList)};
-    std::cerr << "Step " << nStep++ << ": Please type in the CA namespace index that you want to apply\n";
-
-    std::string caIndexS;
-    getline(std::cin, caIndexS);
-    int caIndex = std::stoi(caIndexS);
-    BOOST_ASSERT(caIndex <= count);
-    auto targetCaItem = caVector[caIndex];
-
-    if (targetCaItem.m_isListEnabled) {
-      std::cerr << "This CA provides several sub-namepace CAs \n"
-                << "Do you want to (A) get a certificate from " << targetCaItem.m_caName << " directly? \n"
-                << "Or (B) get a certificate from one of its sub-namespace CAs? \n"
-                << "Please type in your choice (A or B) \n";
-      std::string listOption;
-      getline(std::cin, listOption);
-      if (listOption == "A" || listOption == "a") {
-        listFirst = false;
-      }
-      else if (listOption == "B" || listOption == "b") {
-        listFirst = true;
-        std::string additionalInfo = "";
-        if (targetCaItem.m_targetedList != "") {
-          std::cerr << "Step " << nStep++
-                    << ": Enter nothing if you want to see all available sub-namespace CAs"
-                    << " or follow the instruction to get a recommended CA\n"
-                    << "\t" << targetCaItem.m_targetedList << std::endl;
-          getline(std::cin, additionalInfo);
-        }
-        client.requestList(targetCaItem, additionalInfo,
-                           bind(&ClientTool::listCb, &tool, _1, _2, _3, targetCaItem),
-                           bind(&ClientTool::errorCb, &tool, _1));
-      }
-      else {
-        std::cerr << "Your input is not an option." << std::endl;
-        return 1;
-      }
-    }
-    if (!listFirst) {
-      if (targetCaItem.m_probe != "") {
-        std::cerr << "Step " << nStep++ << ": Probe Requirement-" << targetCaItem.m_probe << std::endl;
-        std::string probeInfo;
-        getline(std::cin, probeInfo);
-        client.sendProbe(targetCaItem, probeInfo,
-                         bind(&ClientTool::newCb, &tool, _1),
-                         bind(&ClientTool::errorCb, &tool, _1));
-      }
-      else {
-        std::cerr << "Step " << nStep++ << ": Please type in the identity name\n";
-        std::string nameComponent;
-        getline(std::cin, nameComponent);
-        Name identityName = targetCaItem.m_caName.getPrefix(-1);
-        identityName.append(nameComponent);
-        client.sendNew(targetCaItem, identityName,
-                       bind(&ClientTool::newCb, &tool, _1),
-                       bind(&ClientTool::errorCb, &tool, _1));
-      }
-    }
-  }
-
+  startApplication();
   face.processEvents();
   return 0;
 }