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/src/challenge-module/challenge-credential.cpp b/src/challenge-module/challenge-credential.cpp
index 2a47e7a..839ccae 100644
--- a/src/challenge-module/challenge-credential.cpp
+++ b/src/challenge-module/challenge-credential.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017, 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.
*
@@ -29,9 +29,9 @@
NDNCERT_REGISTER_CHALLENGE(ChallengeCredential, "Credential");
-const std::string ChallengeCredential::FAILURE_INVALID_FORMAT = "failure-invalid-format";
+const std::string ChallengeCredential::FAILURE_INVALID_FORMAT_CREDENTIAL = "failure-cannot-parse-credential";
+const std::string ChallengeCredential::FAILURE_INVALID_FORMAT_SELF_SIGNED = "failure-cannot-parse-self-signed";
const std::string ChallengeCredential::FAILURE_INVALID_CREDENTIAL = "failure-invalid-credential";
-
const std::string ChallengeCredential::JSON_CREDENTIAL_CERT = "issued-cert";
const std::string ChallengeCredential::JSON_CREDENTIAL_SELF = "self-signed";
@@ -71,101 +71,91 @@
}
}
-JsonSection
-ChallengeCredential::processSelectInterest(const Interest& interest, CertificateRequest& request)
+// For CA
+void
+ChallengeCredential::handleChallengeRequest(const JsonSection& params, 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);
-
- // load credential parameters
- std::istringstream ss1(credentialJson.get<std::string>(JSON_CREDENTIAL_CERT));
+ // load credential parameter
+ std::istringstream ss1(params.get<std::string>(JSON_CREDENTIAL_CERT));
security::v2::Certificate cert;
try {
cert = *(io::load<security::v2::Certificate>(ss1));
}
catch (const std::exception& e) {
- _LOG_TRACE("Cannot load credential parameter: cert" << e.what());
- request.setStatus(FAILURE_INVALID_FORMAT);
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_INVALID_FORMAT);
+ _LOG_ERROR("Cannot load credential parameter: cert" << e.what());
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_FORMAT_CREDENTIAL;
+ updateRequestOnChallengeEnd(request);
+ return;
}
ss1.str("");
ss1.clear();
-
- std::istringstream ss2(credentialJson.get<std::string>(JSON_CREDENTIAL_SELF));
- security::v2::Certificate self;
+ // load self-signed data
+ std::istringstream ss2(params.get<std::string>(JSON_CREDENTIAL_SELF));
+ Data self;
try {
- self = *(io::load<security::v2::Certificate>(ss2));
+ self = *(io::load<Data>(ss2));
}
catch (const std::exception& e) {
_LOG_TRACE("Cannot load credential parameter: self-signed cert" << e.what());
- request.setStatus(FAILURE_INVALID_FORMAT);
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_INVALID_FORMAT);
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_FORMAT_SELF_SIGNED;
+ updateRequestOnChallengeEnd(request);
+ return;
}
ss2.str("");
ss2.clear();
- // verify two parameters
+ // verify the credential and the self-signed cert
Name signingKeyName = cert.getSignature().getKeyLocator().getName();
for (auto anchor : m_trustAnchors) {
if (anchor.getKeyName() == signingKeyName) {
- if (security::verifySignature(cert, anchor) && security::verifySignature(self, cert)) {
- request.setStatus(SUCCESS);
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, SUCCESS);
+ if (security::verifySignature(cert, anchor) && security::verifySignature(self, cert)
+ && readString(self.getContent()) == request.m_requestId) {
+ request.m_status = STATUS_PENDING;
+ request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
+ updateRequestOnChallengeEnd(request);
+ return;
}
}
}
- request.setStatus(FAILURE_INVALID_CREDENTIAL);
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE_INVALID_CREDENTIAL);
+ _LOG_TRACE("Cannot verify the credential + self-signed Data + data content");
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_CREDENTIAL;
+ updateRequestOnChallengeEnd(request);
+ return;
}
+// For Client
JsonSection
-ChallengeCredential::processValidateInterest(const Interest& interest, CertificateRequest& request)
-{
- // there is no validate request here, do nothing
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_INVALID_FORMAT);
-}
-
-std::list<std::string>
-ChallengeCredential::getSelectRequirements()
-{
- std::list<std::string> result;
- 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;
-}
-
-std::list<std::string>
-ChallengeCredential::getValidateRequirements(const std::string& status)
-{
- // there is no validate request here, do nothing
- std::list<std::string> result;
- return result;
-}
-
-JsonSection
-ChallengeCredential::doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
+ChallengeCredential::getRequirementForChallenge(int status, const std::string& challengeStatus)
{
JsonSection result;
- BOOST_ASSERT(status == WAIT_SELECTION);
- BOOST_ASSERT(paramList.size() == 2);
- result.put(JSON_CREDENTIAL_CERT, paramList.front());
- result.put(JSON_CREDENTIAL_SELF, paramList.back());
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ result.put(JSON_CREDENTIAL_CERT, "Please_copy_anchor_signed_cert_here");
+ result.put(JSON_CREDENTIAL_SELF, "Please_copy_key_signed_request_id_data_here");
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
return result;
}
JsonSection
-ChallengeCredential::doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
+ChallengeCredential::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
{
JsonSection result;
- BOOST_ASSERT(paramList.size() == 0);
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ result.put(JSON_CREDENTIAL_CERT, params.get<std::string>(JSON_CREDENTIAL_CERT, ""));
+ result.put(JSON_CREDENTIAL_SELF, params.get<std::string>(JSON_CREDENTIAL_SELF, ""));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
return result;
}
diff --git a/src/challenge-module/challenge-credential.hpp b/src/challenge-module/challenge-credential.hpp
index bcd8b5d..5d4a93c 100644
--- a/src/challenge-module/challenge-credential.hpp
+++ b/src/challenge-module/challenge-credential.hpp
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017, 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.
*
@@ -29,16 +29,17 @@
* @brief Provide Credential based challenge
*
* Credential here means the certificate issued by a trust anchor. Once the requester
- * could proof his/her possession of an existing certificate from other certificate, th
- * requester could finish the challenge.
+ * could proof his/her possession of an existing certificate from other certificate issuer,
+ * the 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.
+ * a BASE64 Data packet signed by the credential pub key and whose content is the request id.
*
* 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.
+ * 3. The content of the signed Data is the request id
*
* Failure info when application fails:
* FAILURE_INVALID_CREDENTIAL: When the cert issued from trust anchor or self-signed cert
@@ -50,26 +51,16 @@
public:
ChallengeCredential(const std::string& configPath = "");
-PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+ // For CA
+ void
+ handleChallengeRequest(const JsonSection& params, CertificateRequest& request) override;
+
+ // For Client
JsonSection
- processSelectInterest(const Interest& interest, CertificateRequest& request) override;
+ getRequirementForChallenge(int status, const std::string& challengeStatus) override;
JsonSection
- processValidateInterest(const Interest& interest, CertificateRequest& request) override;
-
- std::list<std::string>
- getSelectRequirements() override;
-
- std::list<std::string>
- getValidateRequirements(const std::string& status) override;
-
- JsonSection
- doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
-
- JsonSection
- doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
+ genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) override;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
@@ -77,8 +68,8 @@
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static const std::string FAILURE_INVALID_CREDENTIAL;
- static const std::string FAILURE_INVALID_FORMAT;
-
+ static const std::string FAILURE_INVALID_FORMAT_CREDENTIAL;
+ static const std::string FAILURE_INVALID_FORMAT_SELF_SIGNED;
static const std::string JSON_CREDENTIAL_CERT;
static const std::string JSON_CREDENTIAL_SELF;
diff --git a/src/challenge-module/challenge-email.cpp b/src/challenge-module/challenge-email.cpp
index b65d331..dbd3b2c 100644
--- a/src/challenge-module/challenge-email.cpp
+++ b/src/challenge-module/challenge-email.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.
*
@@ -31,15 +31,9 @@
const std::string ChallengeEmail::NEED_CODE = "need-code";
const std::string ChallengeEmail::WRONG_CODE = "wrong-code";
-
const std::string ChallengeEmail::FAILURE_INVALID_EMAIL = "failure-invalid-email";
-const std::string ChallengeEmail::FAILURE_TIMEOUT = "timeout";
-const std::string ChallengeEmail::FAILURE_MAXRETRY = "max-retry";
-
const std::string ChallengeEmail::JSON_EMAIL = "email";
-const std::string ChallengeEmail::JSON_CODE_TP = "code-timepoint";
const std::string ChallengeEmail::JSON_CODE = "code";
-const std::string ChallengeEmail::JSON_ATTEMPT_TIMES = "attempt-times";
ChallengeEmail::ChallengeEmail(const std::string& scriptPath,
const size_t& maxAttemptTimes,
@@ -51,131 +45,123 @@
{
}
-JsonSection
-ChallengeEmail::processSelectInterest(const Interest& interest, CertificateRequest& request)
+// For CA
+void
+ChallengeEmail::handleChallengeRequest(const JsonSection& params, CertificateRequest& request)
{
- // interest format: /caName/CA/_SELECT/{"request-id":"id"}/EMAIL/{"Email":"email"}/<signature>
- JsonSection emailJson = getJsonFromNameComponent(interest.getName(),
- request.getCaName().size() + 4);
- std::string emailAddress = emailJson.get<std::string>(JSON_EMAIL);
- if (!isValidEmailAddress(emailAddress)) {
- request.setStatus(FAILURE_INVALID_EMAIL);
- request.setChallengeType(CHALLENGE_TYPE);
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_INVALID_EMAIL);
+ if (request.m_challengeStatus == "") {
+ // for the first time, init the challenge
+ std::string emailAddress = params.get<std::string>(JSON_EMAIL);
+ if (!isValidEmailAddress(emailAddress)) {
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_EMAIL;
+ return;
+ }
+ request.m_status = STATUS_CHALLENGE;
+ request.m_challengeStatus = NEED_CODE;
+ request.m_challengeType = CHALLENGE_TYPE;
+ std::string emailCode = generateSecretCode();
+ JsonSection secretJson;
+ secretJson.add(JSON_CODE, emailCode);
+ request.m_challengeSecrets = secretJson;
+ request.m_challengeTp = time::toIsoString(time::system_clock::now());
+ request.m_remainingTime = m_secretLifetime.count();
+ request.m_remainingTries = m_maxAttemptTimes;
+ // send out the email
+ sendEmail(emailAddress, emailCode, request);
+ _LOG_TRACE("Secret for request " << request.m_requestId << " : " << emailCode);
+ return;
}
-
- std::string emailCode = generateSecretCode();
- sendEmail(emailAddress, emailCode, request.getCaName().toUri());
-
- request.setStatus(NEED_CODE);
- request.setChallengeType(CHALLENGE_TYPE);
- request.setChallengeSecrets(generateStoredSecrets(time::system_clock::now(),
- emailCode, m_maxAttemptTimes));
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, NEED_CODE);
-}
-
-JsonSection
-ChallengeEmail::processValidateInterest(const Interest& interest, CertificateRequest& request)
-{
- // interest format: /caName/CA/_VALIDATION/{"request-id":"id"}/EMAIL/{"code":"code"}/<signature>
- JsonSection infoJson = getJsonFromNameComponent(interest.getName(), request.getCaName().size() + 4);
- std::string givenCode = infoJson.get<std::string>(JSON_CODE);
-
- const auto parsedSecret = parseStoredSecrets(request.getChallengeSecrets());
- if (time::system_clock::now() - std::get<0>(parsedSecret) >= m_secretLifetime) {
- // secret expires
- request.setStatus(FAILURE_TIMEOUT);
- request.setChallengeSecrets(JsonSection());
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_TIMEOUT);
- }
- else if (givenCode == std::get<1>(parsedSecret)) {
- request.setStatus(SUCCESS);
- request.setChallengeSecrets(JsonSection());
- Name downloadName = genDownloadName(request.getCaName(), request.getRequestId());
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, SUCCESS, downloadName);
- }
- else {
- // check rest attempt times
- if (std::get<2>(parsedSecret) > 1) {
- int restAttemptTimes = std::get<2>(parsedSecret) - 1;
- request.setStatus(WRONG_CODE);
- request.setChallengeSecrets(generateStoredSecrets(std::get<0>(parsedSecret),
- std::get<1>(parsedSecret),
- restAttemptTimes));
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, WRONG_CODE);
+ else if (request.m_challengeStatus == NEED_CODE || request.m_challengeStatus == WRONG_CODE) {
+ _LOG_TRACE("Challenge Interest arrives. Challenge Status: " << request.m_challengeStatus);
+ // the incoming interest should bring the pin code
+ std::string givenCode = params.get<std::string>(JSON_CODE);
+ const auto realCode = request.m_challengeSecrets.get<std::string>(JSON_CODE);
+ if (time::system_clock::now() - time::fromIsoString(request.m_challengeTp) >= m_secretLifetime) {
+ // secret expires
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = CHALLENGE_STATUS_FAILURE_TIMEOUT;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("Secret expired. Challenge failed.");
+ return;
+ }
+ else if (givenCode == realCode) {
+ // the code is correct
+ request.m_status = STATUS_PENDING;
+ request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("Secret code matched. Challenge succeeded.");
+ return;
}
else {
- // run out times
- request.setStatus(FAILURE_MAXRETRY);
- request.setChallengeSecrets(JsonSection());
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_MAXRETRY);
+ // check rest attempt times
+ if (request.m_remainingTries > 1) {
+ request.m_challengeStatus = WRONG_CODE;
+ request.m_remainingTries = request.m_remainingTries - 1;
+ auto remainTime = m_secretLifetime - (time::system_clock::now() - time::fromIsoString(request.m_challengeTp));
+ request.m_remainingTime = remainTime.count();
+ _LOG_TRACE("Secret code didn't match. Remaining Tries - 1.");
+ return;
+ }
+ else {
+ // run out times
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = CHALLENGE_STATUS_FAILURE_MAXRETRY;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("Secret code didn't match. Ran out tires. Challenge failed.");
+ return;
+ }
}
}
-}
-
-std::list<std::string>
-ChallengeEmail::getSelectRequirements()
-{
- std::list<std::string> result;
- result.push_back("Please input your email address:");
- return result;
-}
-
-std::list<std::string>
-ChallengeEmail::getValidateRequirements(const std::string& status)
-{
- std::list<std::string> result;
- if (status == NEED_CODE) {
- result.push_back("Please input your verification code:");
+ else {
+ _LOG_ERROR("The challenge status is wrong");
+ request.m_status = STATUS_FAILURE;
+ return;
}
- else if (status == WRONG_CODE) {
- result.push_back("Incorrect PIN code, please try again and input your verification code:");
+}
+
+// For Client
+JsonSection
+ChallengeEmail::getRequirementForChallenge(int status, const std::string& challengeStatus)
+{
+ JsonSection result;
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ result.put(JSON_EMAIL, "Please_input_your_email_address");
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == NEED_CODE) {
+ result.put(JSON_CODE, "Please_input_your_verification_code");
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == WRONG_CODE) {
+ result.put(JSON_CODE, "Incorrect_code_please_try_again");
+ }
+ else {
+ _LOG_ERROR("CA's status and challenge status are wrong");
}
return result;
}
JsonSection
-ChallengeEmail::doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
+ChallengeEmail::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
{
JsonSection result;
- BOOST_ASSERT(status == WAIT_SELECTION);
- BOOST_ASSERT(paramList.size() == 1);
- result.put(JSON_EMAIL, paramList.front());
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ result.put(JSON_EMAIL, params.get<std::string>(JSON_EMAIL, ""));
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == NEED_CODE) {
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ result.put(JSON_CODE, params.get<std::string>(JSON_CODE, ""));
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == WRONG_CODE) {
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ result.put(JSON_CODE, params.get<std::string>(JSON_CODE, ""));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
return result;
}
-JsonSection
-ChallengeEmail::doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
-{
- JsonSection result;
- BOOST_ASSERT(paramList.size() == 1);
- result.put(JSON_CODE, paramList.front());
- return result;
-}
-
-std::tuple<time::system_clock::TimePoint, std::string, int>
-ChallengeEmail::parseStoredSecrets(const JsonSection& storedSecrets)
-{
- auto tp = time::fromIsoString(storedSecrets.get<std::string>(JSON_CODE_TP));
- std::string rightCode= storedSecrets.get<std::string>(JSON_CODE);
- int attemptTimes = std::stoi(storedSecrets.get<std::string>(JSON_ATTEMPT_TIMES));
-
- return std::make_tuple(tp, rightCode, attemptTimes);
-}
-
-JsonSection
-ChallengeEmail::generateStoredSecrets(const time::system_clock::TimePoint& tp,
- const std::string& secretCode, int attempTimes)
-{
- JsonSection json;
- json.put(JSON_CODE_TP, time::toIsoString(tp));
- json.put(JSON_CODE, secretCode);
- json.put(JSON_ATTEMPT_TIMES, std::to_string(attempTimes));
- return json;
-}
-
bool
ChallengeEmail::isValidEmailAddress(const std::string& emailAddress)
{
@@ -186,10 +172,10 @@
void
ChallengeEmail::sendEmail(const std::string& emailAddress, const std::string& secret,
- const std::string& caName) const
+ const CertificateRequest& request) const
{
std::string command = m_sendEmailScript;
- command += " \"" + emailAddress + "\" \"" + secret + "\" \"" + caName + "\"";
+ command += " \"" + emailAddress + "\" \"" + secret + "\" \"" + request.m_caName.toUri() + "\"";
int result = system(command.c_str());
if (result == -1) {
_LOG_TRACE("EmailSending Script " + m_sendEmailScript + " fails.");
diff --git a/src/challenge-module/challenge-email.hpp b/src/challenge-module/challenge-email.hpp
index a014d00..2f40f1f 100644
--- a/src/challenge-module/challenge-email.hpp
+++ b/src/challenge-module/challenge-email.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, 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.
*
@@ -56,26 +56,16 @@
const size_t& maxAttemptTimes = 3,
const time::seconds secretLifetime = time::minutes(20));
-PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+ // For CA
+ void
+ handleChallengeRequest(const JsonSection& params, CertificateRequest& request) override;
+
+ // For Client
JsonSection
- processSelectInterest(const Interest& interest, CertificateRequest& request) override;
+ getRequirementForChallenge(int status, const std::string& challengeStatus) override;
JsonSection
- processValidateInterest(const Interest& interest, CertificateRequest& request) override;
-
- std::list<std::string>
- getSelectRequirements() override;
-
- std::list<std::string>
- getValidateRequirements(const std::string& status) override;
-
- JsonSection
- doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
-
- JsonSection
- doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
+ genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) override;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static bool
@@ -83,28 +73,16 @@
void
sendEmail(const std::string& emailAddress, const std::string& secret,
- const std::string& caName) const;
+ const CertificateRequest& request) const;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
- static std::tuple<time::system_clock::TimePoint, std::string, int>
- parseStoredSecrets(const JsonSection& storedSecret);
-
- static JsonSection
- generateStoredSecrets(const time::system_clock::TimePoint& tp, const std::string& secretCode,
- int attempTimes);
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ // challenge status
static const std::string NEED_CODE;
static const std::string WRONG_CODE;
-
- static const std::string FAILURE_TIMEOUT;
static const std::string FAILURE_INVALID_EMAIL;
- static const std::string FAILURE_MAXRETRY;
-
+ // JSON attribute
static const std::string JSON_EMAIL;
- static const std::string JSON_CODE_TP;
static const std::string JSON_CODE;
- static const std::string JSON_ATTEMPT_TIMES;
private:
std::string m_sendEmailScript;
diff --git a/src/challenge-module/challenge-pin.cpp b/src/challenge-module/challenge-pin.cpp
index 2bb81ea..7de32f0 100644
--- a/src/challenge-module/challenge-pin.cpp
+++ b/src/challenge-module/challenge-pin.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, 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,7 +20,6 @@
#include "challenge-pin.hpp"
#include "logging.hpp"
-#include "json-helper.hpp"
#include <ndn-cxx/util/random.hpp>
namespace ndn {
@@ -32,13 +31,7 @@
const std::string ChallengePin::NEED_CODE = "need-code";
const std::string ChallengePin::WRONG_CODE = "wrong-code";
-
-const std::string ChallengePin::FAILURE_TIMEOUT = "failure-timeout";
-const std::string ChallengePin::FAILURE_MAXRETRY = "failure-max-retry";
-
-const std::string ChallengePin::JSON_CODE_TP = "code-timepoint";
-const std::string ChallengePin::JSON_PIN_CODE = "code";
-const std::string ChallengePin::JSON_ATTEMPT_TIMES = "attempt-times";
+const std::string ChallengePin::JSON_PIN_CODE = "pin-code";
ChallengePin::ChallengePin(const size_t& maxAttemptTimes, const time::seconds& secretLifetime)
: ChallengeModule("PIN")
@@ -47,119 +40,115 @@
{
}
-JsonSection
-ChallengePin::processSelectInterest(const Interest& interest, CertificateRequest& request)
+// For CA
+void
+ChallengePin::handleChallengeRequest(const JsonSection& params, CertificateRequest& request)
{
- // interest format: /caName/CA/_SELECT/{"request-id":"id"}/PIN/<signature>
- request.setStatus(NEED_CODE);
- request.setChallengeType(CHALLENGE_TYPE);
- std::string secretCode = generateSecretCode();
- request.setChallengeSecrets(generateStoredSecrets(time::system_clock::now(),
- secretCode,
- m_maxAttemptTimes));
- _LOG_TRACE("Secret for request " << request.getRequestId() << " : " << secretCode);
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, NEED_CODE);
-}
-
-JsonSection
-ChallengePin::processValidateInterest(const Interest& interest, CertificateRequest& request)
-{
- // interest format: /caName/CA/_VALIDATION/{"request-id":"id"}/PIN/{"code":"code"}/<signature>
- JsonSection infoJson = getJsonFromNameComponent(interest.getName(), request.getCaName().size() + 4);
- std::string givenCode = infoJson.get<std::string>(JSON_PIN_CODE);
-
- const auto parsedSecret = parseStoredSecrets(request.getChallengeSecrets());
- if (time::system_clock::now() - std::get<0>(parsedSecret) >= m_secretLifetime) {
- // secret expires
- request.setStatus(FAILURE_TIMEOUT);
- request.setChallengeSecrets(JsonSection());
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_TIMEOUT);
+ if (request.m_challengeStatus == "") {
+ _LOG_TRACE("Challenge Interest arrives. Init the challenge");
+ // for the first time, init the challenge
+ request.m_status = STATUS_CHALLENGE;
+ request.m_challengeStatus = NEED_CODE;
+ request.m_challengeType = CHALLENGE_TYPE;
+ std::string secretCode = generateSecretCode();
+ JsonSection secretJson;
+ secretJson.add(JSON_PIN_CODE, secretCode);
+ request.m_challengeSecrets = secretJson;
+ request.m_challengeTp = time::toIsoString(time::system_clock::now());
+ request.m_remainingTime = m_secretLifetime.count();
+ request.m_remainingTries = m_maxAttemptTimes;
+ _LOG_TRACE("Secret for request " << request.m_requestId << " : " << secretCode);
+ return;
}
- else if (givenCode == std::get<1>(parsedSecret)) {
- request.setStatus(SUCCESS);
- request.setChallengeSecrets(JsonSection());
- Name downloadName = genDownloadName(request.getCaName(), request.getRequestId());
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, SUCCESS, downloadName);
- }
- else {
- // check rest attempt times
- if (std::get<2>(parsedSecret) > 1) {
- int restAttemptTimes = std::get<2>(parsedSecret) - 1;
- request.setStatus(WRONG_CODE);
- request.setChallengeSecrets(generateStoredSecrets(std::get<0>(parsedSecret),
- std::get<1>(parsedSecret),
- restAttemptTimes));
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, WRONG_CODE);
+ else if (request.m_challengeStatus == NEED_CODE || request.m_challengeStatus == WRONG_CODE) {
+ _LOG_TRACE("Challenge Interest arrives. Challenge Status: " << request.m_challengeStatus);
+ // the incoming interest should bring the pin code
+ std::string givenCode = params.get<std::string>(JSON_PIN_CODE);
+ const auto realCode = request.m_challengeSecrets.get<std::string>(JSON_PIN_CODE);
+ if (time::system_clock::now() - time::fromIsoString(request.m_challengeTp) >= m_secretLifetime) {
+ // secret expires
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = CHALLENGE_STATUS_FAILURE_TIMEOUT;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("Secret expired. Challenge failed.");
+ return;
+ }
+ else if (givenCode == realCode) {
+ // the code is correct
+ request.m_status = STATUS_PENDING;
+ request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("PIN code matched. Challenge succeeded.");
+ return;
}
else {
- // run out times
- request.setStatus(FAILURE_MAXRETRY);
- request.setChallengeSecrets(JsonSection());
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_MAXRETRY);
+ // check rest attempt times
+ if (request.m_remainingTries > 1) {
+ request.m_challengeStatus = WRONG_CODE;
+ request.m_remainingTries = request.m_remainingTries - 1;
+ auto remainTime = m_secretLifetime - (time::system_clock::now() - time::fromIsoString(request.m_challengeTp));
+ request.m_remainingTime = remainTime.count();
+ _LOG_TRACE("PIN code didn't match. Remaining Tries - 1.");
+ return;
+ }
+ else {
+ // run out times
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = CHALLENGE_STATUS_FAILURE_MAXRETRY;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("PIN code didn't match. Ran out tires. Challenge failed.");
+ return;
+ }
}
}
-}
-
-std::list<std::string>
-ChallengePin::getSelectRequirements()
-{
- std::list<std::string> result;
- return result;
-}
-
-std::list<std::string>
-ChallengePin::getValidateRequirements(const std::string& status)
-{
- std::list<std::string> result;
- if (status == NEED_CODE) {
- result.push_back("Please input your verification code:");
+ else {
+ _LOG_ERROR("The challenge status is wrong");
+ request.m_status = STATUS_FAILURE;
+ return;
}
- else if (status == WRONG_CODE) {
- result.push_back("Incorrect PIN code, please try again and input your verification code:");
+}
+
+// For Client
+JsonSection
+ChallengePin::getRequirementForChallenge(int status, const std::string& challengeStatus)
+{
+ JsonSection result;
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ // do nothing
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == NEED_CODE) {
+ result.put(JSON_PIN_CODE, "Please_input_your_verification_code");
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == WRONG_CODE) {
+ result.put(JSON_PIN_CODE, "Incorrect_PIN_code_please_try_again");
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
}
return result;
}
JsonSection
-ChallengePin::doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
+ChallengePin::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
{
JsonSection result;
- BOOST_ASSERT(status == WAIT_SELECTION);
- BOOST_ASSERT(paramList.size() == 0);
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ // do nothing
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == NEED_CODE) {
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ result.put(JSON_PIN_CODE, params.get<std::string>(JSON_PIN_CODE, ""));
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == WRONG_CODE) {
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ result.put(JSON_PIN_CODE, params.get<std::string>(JSON_PIN_CODE, ""));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
return result;
}
-JsonSection
-ChallengePin::doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
-{
- JsonSection result;
- BOOST_ASSERT(paramList.size() == 1);
- result.put(JSON_PIN_CODE, paramList.front());
- return result;
-}
-
-std::tuple<time::system_clock::TimePoint, std::string, int>
-ChallengePin::parseStoredSecrets(const JsonSection& storedSecrets)
-{
- auto tp = time::fromIsoString(storedSecrets.get<std::string>(JSON_CODE_TP));
- std::string rightCode= storedSecrets.get<std::string>(JSON_PIN_CODE);
- int attemptTimes = std::stoi(storedSecrets.get<std::string>(JSON_ATTEMPT_TIMES));
-
- return std::make_tuple(tp, rightCode, attemptTimes);
-}
-
-JsonSection
-ChallengePin::generateStoredSecrets(const time::system_clock::TimePoint& tp,
- const std::string& secretCode, int attempTimes)
-{
- JsonSection json;
- json.put(JSON_CODE_TP, time::toIsoString(tp));
- json.put(JSON_PIN_CODE, secretCode);
- json.put(JSON_ATTEMPT_TIMES, std::to_string(attempTimes));
- return json;
-}
-
} // namespace ndncert
} // namespace ndn
diff --git a/src/challenge-module/challenge-pin.hpp b/src/challenge-module/challenge-pin.hpp
index 982ed4e..8eef944 100644
--- a/src/challenge-module/challenge-pin.hpp
+++ b/src/challenge-module/challenge-pin.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, 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.
*
@@ -51,45 +51,23 @@
ChallengePin(const size_t& maxAttemptTimes = 3,
const time::seconds& secretLifetime = time::seconds(3600));
-PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+ // For CA
+ void
+ handleChallengeRequest(const JsonSection& params, CertificateRequest& request) override;
+
+ // For Client
JsonSection
- processSelectInterest(const Interest& interest, CertificateRequest& request) override;
+ getRequirementForChallenge(int status, const std::string& challengeStatus) override;
JsonSection
- processValidateInterest(const Interest& interest, CertificateRequest& request) override;
-
- std::list<std::string>
- getSelectRequirements() override;
-
- std::list<std::string>
- getValidateRequirements(const std::string& status) override;
-
- JsonSection
- doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
-
- JsonSection
- doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
+ genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) override;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
- static std::tuple<time::system_clock::TimePoint, std::string, int>
- parseStoredSecrets(const JsonSection& storedSecret);
-
- static JsonSection
- generateStoredSecrets(const time::system_clock::TimePoint& tp, const std::string& secretCode,
- int attempTimes);
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ // challenge status
static const std::string NEED_CODE;
static const std::string WRONG_CODE;
-
- static const std::string FAILURE_TIMEOUT;
- static const std::string FAILURE_MAXRETRY;
-
- static const std::string JSON_CODE_TP;
+ // JSON attribute
static const std::string JSON_PIN_CODE;
- static const std::string JSON_ATTEMPT_TIMES;
private:
time::seconds m_secretLifetime;