update challenge modules aginst spec

Change-Id: Ibcfe851a77df1854f417d60cd48a66f8213aedc6
diff --git a/src/challenge-module.cpp b/src/challenge-module.cpp
index 7e97830..f6c96c8 100644
--- a/src/challenge-module.cpp
+++ b/src/challenge-module.cpp
@@ -24,13 +24,15 @@
 namespace ndn {
 namespace ndncert {
 
-ChallengeModule::ChallengeModule(const std::string& uniqueType)
-  : CHALLENGE_TYPE(uniqueType)
+ChallengeModule::ChallengeModule(const std::string& challengeType,
+                                 size_t maxAttemptTimes,
+                                 time::seconds secretLifetime)
+  : CHALLENGE_TYPE(challengeType)
+  , m_maxAttemptTimes(maxAttemptTimes)
+  , m_secretLifetime(secretLifetime)
 {
 }
 
-ChallengeModule::~ChallengeModule() = default;
-
 bool
 ChallengeModule::isChallengeSupported(const std::string& challengeType)
 {
diff --git a/src/challenge-module.hpp b/src/challenge-module.hpp
index 1219399..1f31bd2 100644
--- a/src/challenge-module.hpp
+++ b/src/challenge-module.hpp
@@ -28,9 +28,10 @@
 
 class ChallengeModule : noncopyable {
 public:
-  explicit ChallengeModule(const std::string& uniqueType);
+  explicit
+  ChallengeModule(const std::string& challengeType, size_t maxAttemptTimes, time::seconds secretLifetime);
 
-  virtual ~ChallengeModule();
+  virtual ~ChallengeModule() = default;
 
   template <class ChallengeType>
   static void
@@ -77,6 +78,8 @@
 
 public:
   const std::string CHALLENGE_TYPE;
+  const size_t m_maxAttemptTimes;
+  const time::seconds m_secretLifetime;
 
 private:
   typedef function<unique_ptr<ChallengeModule>()> ChallengeCreateFunc;
diff --git a/src/challenge-modules/challenge-credential.cpp b/src/challenge-modules/challenge-credential.cpp
index 7102434..cf429b5 100644
--- a/src/challenge-modules/challenge-credential.cpp
+++ b/src/challenge-modules/challenge-credential.cpp
@@ -20,6 +20,8 @@
 #include "challenge-credential.hpp"
 #include <iostream>
 #include <ndn-cxx/security/verification-helpers.hpp>
+#include <ndn-cxx/security/signing-helpers.hpp>
+#include <ndn-cxx/security/transform/public-key.hpp>
 #include <ndn-cxx/util/io.hpp>
 
 namespace ndn {
@@ -32,7 +34,7 @@
 const std::string ChallengeCredential::PARAMETER_KEY_PROOF_OF_PRIVATE_KEY = "proof-of-private-key";
 
 ChallengeCredential::ChallengeCredential(const std::string& configPath)
-    : ChallengeModule("Credential")
+    : ChallengeModule("Credential", 1, time::seconds(1))
 {
   if (configPath.empty()) {
     m_configFile = std::string(SYSCONFDIR) + "/ndncert/challenge-credential.conf";
@@ -80,12 +82,14 @@
   if (m_trustAnchors.empty()) {
     parseConfigFile();
   }
-  shared_ptr<security::v2::Certificate> selfSigned, credential;
-  auto& elements = params.elements();
+  shared_ptr<security::v2::Certificate> credential;
+  const uint8_t* signature;
+  size_t signatureLen;
+  const auto& elements = params.elements();
   for (size_t i = 0; i < elements.size(); i++) {
     if (elements[i].type() == tlv_parameter_key) {
       if (readString(elements[i]) == PARAMETER_KEY_CREDENTIAL_CERT) {
-        std::istringstream ss(readString(params.elements()[i + 1]));
+        std::istringstream ss(readString(elements[i + 1]));
         credential = io::load<security::v2::Certificate>(ss);
         if (credential == nullptr) {
           _LOG_ERROR("Cannot load challenge parameter: credential");
@@ -93,26 +97,21 @@
         }
       }
       else if (readString(elements[i]) == PARAMETER_KEY_PROOF_OF_PRIVATE_KEY) {
-        std::istringstream ss(readString(params.elements()[i + 1]));
-        selfSigned = io::load<security::v2::Certificate>(ss);
-        if (selfSigned == nullptr) {
-          _LOG_ERROR("Cannot load challenge parameter: proof of private key");
-          return returnWithError(request, ErrorCode::INVALID_PARAMETER, "Cannot load challenge parameter: proof of private key.");
-        }
-      }
-      else {
-        continue;
+        signature = elements[i + 1].value();
+        signatureLen = elements[i + 1].value_size();
       }
     }
   }
 
   // verify the credential and the self-signed cert
   Name signingKeyName = credential->getSignature().getKeyLocator().getName();
+  security::transform::PublicKey key;
+  const auto& pubKeyBuffer = credential->getPublicKey();
+  key.loadPkcs8(pubKeyBuffer.data(), pubKeyBuffer.size());
   for (auto anchor : m_trustAnchors) {
     if (anchor.getKeyName() == signingKeyName) {
       if (security::verifySignature(*credential, anchor) &&
-          security::verifySignature(*selfSigned, *credential) &&
-          readString(selfSigned->getContent()) == request.m_requestId) {
+          security::verifySignature((uint8_t*)request.m_requestId.c_str(), request.m_requestId.size(), signature, signatureLen, key)) {
         return returnWithSuccess(request);
       }
     }
@@ -130,11 +129,9 @@
   if (status == Status::BEFORE_CHALLENGE) {
     result.push_back(std::make_tuple(PARAMETER_KEY_CREDENTIAL_CERT, "Please provide the certificate issued by a trusted CA."));
     result.push_back(std::make_tuple(PARAMETER_KEY_PROOF_OF_PRIVATE_KEY, "Please sign a Data packet with request ID as the content."));
+    return result;
   }
-  else {
-    BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected status or challenge status."));
-  }
-  return result;
+  BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected status or challenge status."));
 }
 
 Block
@@ -150,11 +147,16 @@
     for (const auto& item : params) {
       if (std::get<0>(item) == PARAMETER_KEY_CREDENTIAL_CERT) {
         request.push_back(makeStringBlock(tlv_parameter_key, PARAMETER_KEY_CREDENTIAL_CERT));
-        request.push_back(makeStringBlock(tlv_parameter_value, std::get<1>(item)));
+        Block valueBlock = makeEmptyBlock(tlv_parameter_value);
+        auto& certTlvStr = std::get<1>(item);
+        valueBlock.push_back(Block((uint8_t*)certTlvStr.c_str(), certTlvStr.size()));
+        request.push_back(valueBlock);
       }
       else if (std::get<0>(item) == PARAMETER_KEY_PROOF_OF_PRIVATE_KEY) {
         request.push_back(makeStringBlock(tlv_parameter_key, PARAMETER_KEY_PROOF_OF_PRIVATE_KEY));
-        request.push_back(makeStringBlock(tlv_parameter_value, std::get<1>(item)));
+        auto& sigTlvStr = std::get<1>(item);
+        Block valueBlock = makeBinaryBlock(tlv_parameter_value, (uint8_t*)sigTlvStr.c_str(), sigTlvStr.size());
+        request.push_back(valueBlock);
       }
       else {
         BOOST_THROW_EXCEPTION(std::runtime_error("Wrong parameter provided."));
@@ -167,5 +169,26 @@
   request.encode();
   return request;
 }
+
+void
+ChallengeCredential::fulfillParameters(std::vector<std::tuple<std::string, std::string>>& params,
+                                       KeyChain& keyChain, const Name& issuedCertName, const std::string& requestId)
+{
+  auto& pib = keyChain.getPib();
+  auto id = pib.getIdentity(security::v2::extractIdentityFromCertName(issuedCertName));
+  auto issuedCert = id.getKey(security::v2::extractKeyNameFromCertName(issuedCertName)).getCertificate(issuedCertName);
+  auto issuedCertTlv = issuedCert.wireEncode();
+  auto signatureTlv = keyChain.sign((uint8_t*)requestId.c_str(), requestId.length(), security::signingByCertificate(issuedCertName));
+  for (auto& item : params) {
+    if (std::get<0>(item) == PARAMETER_KEY_CREDENTIAL_CERT) {
+      std::get<1>(item) = std::string((char*)issuedCertTlv.wire(), issuedCertTlv.size());
+    }
+    else if (std::get<0>(item) == PARAMETER_KEY_PROOF_OF_PRIVATE_KEY) {
+      std::get<1>(item) = std::string((char*)signatureTlv.value(), signatureTlv.value_size());
+    }
+  }
+  return;
+}
+
 }  // namespace ndncert
 }  // namespace ndn
diff --git a/src/challenge-modules/challenge-credential.hpp b/src/challenge-modules/challenge-credential.hpp
index e356289..07b0158 100644
--- a/src/challenge-modules/challenge-credential.hpp
+++ b/src/challenge-modules/challenge-credential.hpp
@@ -63,15 +63,19 @@
   genChallengeRequestTLV(Status status, const std::string& challengeStatus,
                          std::vector<std::tuple<std::string, std::string>>&& params) override;
 
+  static void
+  fulfillParameters(std::vector<std::tuple<std::string, std::string>>& params,
+                    KeyChain& keyChain, const Name& issuedCertName, const std::string& requestId);
+
+  // challenge parameters
+  static const std::string PARAMETER_KEY_CREDENTIAL_CERT;
+  static const std::string PARAMETER_KEY_PROOF_OF_PRIVATE_KEY;
+
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   void
   parseConfigFile();
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-  // parameters
-  static const std::string PARAMETER_KEY_CREDENTIAL_CERT;
-  static const std::string PARAMETER_KEY_PROOF_OF_PRIVATE_KEY;
-
   std::list<security::v2::Certificate> m_trustAnchors;
   std::string m_configFile;
 };
diff --git a/src/challenge-modules/challenge-email.cpp b/src/challenge-modules/challenge-email.cpp
index c12ba88..d98972f 100644
--- a/src/challenge-modules/challenge-email.cpp
+++ b/src/challenge-modules/challenge-email.cpp
@@ -29,16 +29,15 @@
 
 const std::string ChallengeEmail::NEED_CODE = "need-code";
 const std::string ChallengeEmail::WRONG_CODE = "wrong-code";
+const std::string ChallengeEmail::INVALID_EMAIL = "invalid-email";
 const std::string ChallengeEmail::PARAMETER_KEY_EMAIL = "email";
 const std::string ChallengeEmail::PARAMETER_KEY_CODE = "code";
 
 ChallengeEmail::ChallengeEmail(const std::string& scriptPath,
                                const size_t& maxAttemptTimes,
                                const time::seconds secretLifetime)
-    : ChallengeModule("email")
+    : ChallengeModule("email", maxAttemptTimes, secretLifetime)
     , m_sendEmailScript(scriptPath)
-    , m_maxAttemptTimes(maxAttemptTimes)
-    , m_secretLifetime(secretLifetime)
 {
 }
 
@@ -52,7 +51,7 @@
     // for the first time, init the challenge
     std::string emailAddress = readString(params.get(tlv_parameter_value));
     if (!isValidEmailAddress(emailAddress)) {
-      return returnWithError(request, ErrorCode::INVALID_PARAMETER, "Invalid email address format.");
+      return returnWithNewChallengeStatus(request, INVALID_EMAIL, JsonSection(), m_maxAttemptTimes - 1, m_secretLifetime);
     }
     auto lastComponentRequested = readString(request.m_cert.getIdentity().get(-1));
     if (lastComponentRequested != emailAddress) {
diff --git a/src/challenge-modules/challenge-email.hpp b/src/challenge-modules/challenge-email.hpp
index f853e95..bfae052 100644
--- a/src/challenge-modules/challenge-email.hpp
+++ b/src/challenge-modules/challenge-email.hpp
@@ -53,7 +53,7 @@
 public:
   ChallengeEmail(const std::string& scriptPath = "ndncert-send-email-challenge",
                  const size_t& maxAttemptTimes = 3,
-                 const time::seconds secretLifetime = time::minutes(20));
+                 const time::seconds secretLifetime = time::seconds(300));
 
   // For CA
   std::tuple<ErrorCode, std::string>
@@ -67,6 +67,14 @@
   genChallengeRequestTLV(Status status, const std::string& challengeStatus,
                          std::vector<std::tuple<std::string, std::string>>&& params) override;
 
+  // challenge status
+  static const std::string NEED_CODE;
+  static const std::string WRONG_CODE;
+  static const std::string INVALID_EMAIL;
+  // challenge parameters
+  static const std::string PARAMETER_KEY_EMAIL;
+  static const std::string PARAMETER_KEY_CODE;
+
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   static bool
   isValidEmailAddress(const std::string& emailAddress);
@@ -75,18 +83,8 @@
   sendEmail(const std::string& emailAddress, const std::string& secret,
             const RequestState& request) const;
 
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-  // challenge status
-  static const std::string NEED_CODE;
-  static const std::string WRONG_CODE;
-  // parameters
-  static const std::string PARAMETER_KEY_EMAIL;
-  static const std::string PARAMETER_KEY_CODE;
-
 private:
   std::string m_sendEmailScript;
-  int m_maxAttemptTimes;
-  time::seconds m_secretLifetime;
 };
 
 } // namespace ndncert
diff --git a/src/challenge-modules/challenge-pin.cpp b/src/challenge-modules/challenge-pin.cpp
index fd5b5a5..ecc17db 100644
--- a/src/challenge-modules/challenge-pin.cpp
+++ b/src/challenge-modules/challenge-pin.cpp
@@ -29,12 +29,10 @@
 
 const std::string ChallengePin::NEED_CODE = "need-code";
 const std::string ChallengePin::WRONG_CODE = "wrong-code";
-const std::string ChallengePin::PARAMETER_KEY_CODE = "pin-code";
+const std::string ChallengePin::PARAMETER_KEY_CODE = "code";
 
 ChallengePin::ChallengePin(const size_t& maxAttemptTimes, const time::seconds& secretLifetime)
-    : ChallengeModule("pin")
-    , m_secretLifetime(secretLifetime)
-    , m_maxAttemptTimes(maxAttemptTimes)
+    : ChallengeModule("pin", maxAttemptTimes, secretLifetime)
 {
 }
 
diff --git a/src/challenge-modules/challenge-pin.hpp b/src/challenge-modules/challenge-pin.hpp
index 0b73cb2..7b58a27 100644
--- a/src/challenge-modules/challenge-pin.hpp
+++ b/src/challenge-modules/challenge-pin.hpp
@@ -62,17 +62,11 @@
   genChallengeRequestTLV(Status status, const std::string& challengeStatus,
                          std::vector<std::tuple<std::string, std::string>>&& params) override;
 
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   // challenge status
   static const std::string NEED_CODE;
   static const std::string WRONG_CODE;
   // parameters
   static const std::string PARAMETER_KEY_CODE;
-
-private:
-  time::seconds m_secretLifetime;
-  int m_maxAttemptTimes;
 };
 
 } // namespace ndncert
diff --git a/tests/unit-tests/challenge-email.t.cpp b/tests/unit-tests/challenge-email.t.cpp
index b29884e..27139c0 100644
--- a/tests/unit-tests/challenge-email.t.cpp
+++ b/tests/unit-tests/challenge-email.t.cpp
@@ -103,7 +103,9 @@
   ChallengeEmail challenge;
   challenge.handleChallengeRequest(paramTLV, request);
 
-  BOOST_CHECK(request.m_status == Status::FAILURE);
+  BOOST_CHECK_EQUAL(request.m_challengeType, "email");
+  BOOST_CHECK_EQUAL(request.m_challengeState->m_challengeStatus, ChallengeEmail::INVALID_EMAIL);
+  BOOST_CHECK_EQUAL(request.m_challengeState->m_remainingTries, 2);
 }
 
 BOOST_AUTO_TEST_CASE(OnChallengeRequestWithCode)