blob: 4853eede9254aa1faf96a9f8059167fccc970c52 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
* ndncert is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received copies of the GNU General Public License along with
* ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndncert authors and contributors.
*/
#include "challenge-pin.hpp"
#include <ndn-cxx/util/random.hpp>
namespace ndn {
namespace ndncert {
_LOG_INIT(ndncert.challenge.pin);
NDNCERT_REGISTER_CHALLENGE(ChallengePin, "pin");
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";
ChallengePin::ChallengePin(const size_t& maxAttemptTimes, const time::seconds& secretLifetime)
: ChallengeModule("pin")
, m_secretLifetime(secretLifetime)
, m_maxAttemptTimes(maxAttemptTimes)
{
}
// For CA
std::tuple<ErrorCode, std::string>
ChallengePin::handleChallengeRequest(const Block& params, RequestState& request)
{
params.parse();
auto currentTime = time::system_clock::now();
if (request.m_status == Status::BEFORE_CHALLENGE) {
_LOG_TRACE("Challenge Interest arrives. Init the challenge");
// for the first time, init the challenge
std::string secretCode = generateSecretCode();
JsonSection secretJson;
secretJson.add(PARAMETER_KEY_CODE, secretCode);
_LOG_TRACE("Secret for request " << request.m_requestId << " : " << secretCode);
return returnWithNewChallengeStatus(request, NEED_CODE, std::move(secretJson), m_maxAttemptTimes, m_secretLifetime);
}
if (request.m_challengeState) {
if (request.m_challengeState->m_challengeStatus == NEED_CODE ||
request.m_challengeState->m_challengeStatus == WRONG_CODE) {
_LOG_TRACE("Challenge Interest arrives. Challenge Status: " << request.m_challengeState->m_challengeStatus);
// the incoming interest should bring the pin code
std::string givenCode = readString(params.get(tlv_parameter_value));
auto secret = request.m_challengeState->m_secrets;
if (currentTime - request.m_challengeState->m_timestamp >= m_secretLifetime) {
return returnWithError(request, ErrorCode::OUT_OF_TIME, "Secret expired.");
}
if (givenCode == secret.get<std::string>(PARAMETER_KEY_CODE)) {
_LOG_TRACE("Correct PIN code. Challenge succeeded.");
return returnWithSuccess(request);
}
// check rest attempt times
if (request.m_challengeState->m_remainingTries > 1) {
auto remainTime = m_secretLifetime - (currentTime - request.m_challengeState->m_timestamp);
_LOG_TRACE("Wrong PIN code provided. Remaining Tries - 1.");
return returnWithNewChallengeStatus(request, WRONG_CODE, std::move(secret),
request.m_challengeState->m_remainingTries - 1,
time::duration_cast<time::seconds>(remainTime));
}
else {
// run out times
_LOG_TRACE("Wrong PIN code provided. Ran out tires. Challenge failed.");
return returnWithError(request, ErrorCode::OUT_OF_TRIES, "Ran out tires.");
}
}
}
return returnWithError(request, ErrorCode::INVALID_PARAMETER, "Unexpected status or challenge status");
}
// For Client
std::vector<std::tuple<std::string, std::string>>
ChallengePin::getRequestedParameterList(Status status, const std::string& challengeStatus)
{
std::vector<std::tuple<std::string, std::string>> result;
if (status == Status::BEFORE_CHALLENGE) {
// do nothing
}
else if (status == Status::CHALLENGE && challengeStatus == NEED_CODE) {
result.push_back(std::make_tuple(PARAMETER_KEY_CODE, "Please input your PIN code"));
}
else if (status == Status::CHALLENGE && challengeStatus == WRONG_CODE) {
result.push_back(std::make_tuple(PARAMETER_KEY_CODE, "Incorrect PIN code, please try again"));
}
else {
BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected status or challenge status."));
}
return result;
}
Block
ChallengePin::genChallengeRequestTLV(Status status, const std::string& challengeStatus, std::vector<std::tuple<std::string, std::string>>&& params)
{
Block request = makeEmptyBlock(tlv_encrypted_payload);
if (status == Status::BEFORE_CHALLENGE) {
request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
}
else if (status == Status::CHALLENGE && (challengeStatus == NEED_CODE || challengeStatus == WRONG_CODE)) {
if (params.size() != 1 || std::get<0>(params[0]) != PARAMETER_KEY_CODE) {
BOOST_THROW_EXCEPTION(std::runtime_error("Wrong parameter provided."));
}
request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
request.push_back(makeStringBlock(tlv_parameter_key, PARAMETER_KEY_CODE));
request.push_back(makeStringBlock(tlv_parameter_value, std::get<1>(params[0])));
}
else {
BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected status or challenge status."));
}
request.encode();
return request;
}
} // namespace ndncert
} // namespace ndn