Change the logic in credential challenge: credential cert can under different prefix

Change-Id: Ieab9d5e111c84da8ad7896b9fac8f28887da9f2d
diff --git a/src/challenge-module/challenge-credential.cpp b/src/challenge-module/challenge-credential.cpp
index 0e5a053..2a35395 100644
--- a/src/challenge-module/challenge-credential.cpp
+++ b/src/challenge-module/challenge-credential.cpp
@@ -32,13 +32,17 @@
 const std::string ChallengeCredential::FAILURE_INVALID_FORMAT = "failure-invalid-format";
 const std::string ChallengeCredential::FAILURE_INVALID_CREDENTIAL = "failure-invalid-credential";
 
-const std::string ChallengeCredential::JSON_CREDENTIAL = "signed-cert";
+const std::string ChallengeCredential::JSON_CREDENTIAL_CERT = "issued-cert";
+const std::string ChallengeCredential::JSON_CREDENTIAL_SELF = "self-signed";
 
 ChallengeCredential::ChallengeCredential(const std::string& configPath)
-  : ChallengeModule("CREDENTIAL")
-  , m_configFile(configPath)
+  : ChallengeModule("Credential")
 {
-  parseConfigFile();
+  if (configPath == "") {
+    m_configFile = std::string(SYSCONFDIR) + "/ndncert/challenge-credential.conf";
+  }
+  else
+    m_configFile = configPath;
 }
 
 void
@@ -70,37 +74,52 @@
 JsonSection
 ChallengeCredential::processSelectInterest(const Interest& interest, CertificateRequest& request)
 {
+  if (m_trustAnchors.empty()) {
+    parseConfigFile();
+  }
+
   // interest format: /caName/CA/_SELECT/{"request-id":"id"}/CREDENTIAL/{"credential":"..."}/<signature>
   request.setChallengeType(CHALLENGE_TYPE);
-  JsonSection credentialJson = getJsonFromNameComponent(interest.getName(),
-                                                        request.getCaName().size() + 4);
-  std::istringstream ss(credentialJson.get<std::string>(JSON_CREDENTIAL));
+  JsonSection credentialJson = getJsonFromNameComponent(interest.getName(), request.getCaName().size() + 4);
 
-  security::v2::Certificate credential;
+  // load credential parameters
+  std::istringstream ss1(credentialJson.get<std::string>(JSON_CREDENTIAL_CERT));
+  security::v2::Certificate cert;
   try {
-    credential = *(io::load<security::v2::Certificate>(ss));
+    cert = *(io::load<security::v2::Certificate>(ss1));
   }
   catch (const std::exception& e) {
-    _LOG_TRACE("Cannot load credential parameter" << e.what());
+    _LOG_TRACE("Cannot load credential parameter: cert" << e.what());
     request.setStatus(FAILURE_INVALID_FORMAT);
     return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE_INVALID_FORMAT);
   }
+  ss1.str("");
+  ss1.clear();
 
-  if (credential.getContent() != request.getCert().getContent()
-      || credential.getKeyName() != request.getCert().getKeyName()) {
-    request.setStatus(FAILURE_INVALID_CREDENTIAL);
-    return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE_INVALID_CREDENTIAL);
+  std::istringstream ss2(credentialJson.get<std::string>(JSON_CREDENTIAL_SELF));
+  security::v2::Certificate self;
+  try {
+    self = *(io::load<security::v2::Certificate>(ss2));
   }
-  Name signingKeyName = credential.getSignature().getKeyLocator().getName();
+  catch (const std::exception& e) {
+    _LOG_TRACE("Cannot load credential parameter: self-signed cert" << e.what());
+    request.setStatus(FAILURE_INVALID_FORMAT);
+    return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE_INVALID_FORMAT);
+  }
+  ss2.str("");
+  ss2.clear();
 
+  // verify two parameters
+  Name signingKeyName = cert.getSignature().getKeyLocator().getName();
   for (auto anchor : m_trustAnchors) {
     if (anchor.getKeyName() == signingKeyName) {
-      if (security::verifySignature(credential, anchor)) {
+      if (security::verifySignature(cert, anchor) && security::verifySignature(self, cert)) {
         request.setStatus(SUCCESS);
         return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, SUCCESS);
       }
     }
   }
+
   request.setStatus(FAILURE_INVALID_CREDENTIAL);
   return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE_INVALID_CREDENTIAL);
 }
@@ -116,7 +135,8 @@
 ChallengeCredential::getSelectRequirements()
 {
   std::list<std::string> result;
-  result.push_back("Please input the bytes of a same key certificate signed by trust anchor");
+  result.push_back("Please input the bytes of a certificate issued by the trusted CA");
+  result.push_back("Please input the bytes of a self-signed certificate for the corresponding key");
   return result;
 }
 
@@ -134,8 +154,9 @@
 {
   JsonSection result;
   BOOST_ASSERT(status == WAIT_SELECTION);
-  BOOST_ASSERT(paramList.size() == 1);
-  result.put(JSON_CREDENTIAL, paramList.front());
+  BOOST_ASSERT(paramList.size() == 2);
+  result.put(JSON_CREDENTIAL_CERT, paramList.front());
+  result.put(JSON_CREDENTIAL_SELF, paramList.back());
   return result;
 }
 
diff --git a/src/challenge-module/challenge-credential.hpp b/src/challenge-module/challenge-credential.hpp
index 07f4b88..a617f18 100644
--- a/src/challenge-module/challenge-credential.hpp
+++ b/src/challenge-module/challenge-credential.hpp
@@ -32,6 +32,10 @@
  * could proof his/her possession of an existing certificate from other certificate, th
  * requester could finish the challenge.
  *
+ * The requester needs to provide the proof of the possession of a certificate issued by
+ * a trust anchor. The challenge require the requester to pass the BASE64 certificate and
+ * a BASE64 self-signed certificate whose key is the same as the key in certificate.
+ *
  * The main process of this challenge module is:
  *   1. Requester provides a certificate signed by that trusted certificate as credential.
  *   2. The challenge module will verify the signature of the credential.
@@ -42,7 +46,7 @@
 class ChallengeCredential : public ChallengeModule
 {
 public:
-  ChallengeCredential(const std::string& configPath = "challenge-credential.conf");
+  ChallengeCredential(const std::string& configPath = "");
 
 PUBLIC_WITH_TESTS_ELSE_PROTECTED:
   JsonSection
@@ -72,7 +76,8 @@
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   static const std::string FAILURE_INVALID_CREDENTIAL;
   static const std::string FAILURE_INVALID_FORMAT;
-  static const std::string JSON_CREDENTIAL;
+  static const std::string JSON_CREDENTIAL_CERT;
+  static const std::string JSON_CREDENTIAL_SELF;
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   std::list<security::v2::Certificate> m_trustAnchors;
diff --git a/tests/unit-tests/challenge-credential.t.cpp b/tests/unit-tests/challenge-credential.t.cpp
index 8a0cfe5..772c57f 100644
--- a/tests/unit-tests/challenge-credential.t.cpp
+++ b/tests/unit-tests/challenge-credential.t.cpp
@@ -32,8 +32,9 @@
 BOOST_AUTO_TEST_CASE(LoadConfig)
 {
   ChallengeCredential challenge("./tests/unit-tests/challenge-credential.conf.test");
-  BOOST_CHECK_EQUAL(challenge.CHALLENGE_TYPE, "CREDENTIAL");
+  BOOST_CHECK_EQUAL(challenge.CHALLENGE_TYPE, "Credential");
 
+  challenge.parseConfigFile();
   BOOST_CHECK_EQUAL(challenge.m_trustAnchors.size(), 1);
   auto cert = challenge.m_trustAnchors.front();
   BOOST_CHECK_EQUAL(cert.getName(),
@@ -44,23 +45,29 @@
 {
   // create trust anchor
   ChallengeCredential challenge("./tests/unit-tests/challenge-credential.conf.test");
-  auto identity0 = addIdentity(Name("/trust"));
-  auto key0 = identity0.getDefaultKey();
-  auto trustAnchor = key0.getDefaultCertificate();
+  auto identity = addIdentity(Name("/trust"));
+  auto key = identity.getDefaultKey();
+  auto trustAnchor = key.getDefaultCertificate();
+  challenge.parseConfigFile();
   challenge.m_trustAnchors.front() = trustAnchor;
 
   // create certificate request
-  auto identity = addIdentity(Name("/example"));
-  auto key = identity.getDefaultKey();
-  auto cert = key.getDefaultCertificate();
-  CertificateRequest request(Name("/example"), "123", cert);
+  auto identityA = addIdentity(Name("/example"));
+  auto keyA = identityA.getDefaultKey();
+  auto certA = key.getDefaultCertificate();
+  CertificateRequest request(Name("/example"), "123", certA);
+
+  // create requester's existing cert
+  auto identityB = addIdentity(Name("/trust/cert"));
+  auto keyB = identityB.getDefaultKey();
+  auto certB = key.getDefaultCertificate();
 
   // using trust anchor to sign cert request to get credential
-  Name credentialName = cert.getKeyName();
+  Name credentialName = certB.getKeyName();
   credentialName.append("Credential").appendVersion();
-  security::v2::Certificate credential = cert;
+  security::v2::Certificate credential = certB;
   credential.setName(credentialName);
-  credential.setContent(cert.getContent());
+  credential.setContent(certB.getContent());
   m_keyChain.sign(credential, signingByCertificate(trustAnchor));
 
   // generate SELECT interest
@@ -71,15 +78,20 @@
   ss.str("");
   ss.clear();
 
-  io::save<security::v2::Certificate>(credential, ss);
   std::list<std::string> paramList;
-  std::string jsonString = ss.str();
-  paramList.push_back(jsonString);
-  JsonSection credentialJson = challenge.genSelectParamsJson(ChallengeModule::WAIT_SELECTION, paramList);
-  BOOST_CHECK_EQUAL(credentialJson.get<std::string>(ChallengeCredential::JSON_CREDENTIAL), jsonString);
+  io::save<security::v2::Certificate>(credential, ss);
+  std::string paramString = ss.str();
+  paramList.push_back(paramString);
   ss.str("");
   ss.clear();
 
+  io::save<security::v2::Certificate>(certB, ss);
+  paramString = ss.str();
+  paramList.push_back(paramString);
+  ss.str("");
+  ss.clear();
+  JsonSection credentialJson = challenge.genSelectParamsJson(ChallengeModule::WAIT_SELECTION, paramList);
+
   boost::property_tree::write_json(ss, credentialJson);
   Block jsonContent = makeStringBlock(ndn::tlv::NameComponent, ss.str());