blob: f38c778ad4c5727e6d403dd12daed8a5c2c2bc30 [file] [log] [blame]
Zhiyi Zhang65ba9322017-01-19 14:15:03 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento0dc02012021-11-23 22:55:03 -05002/*
Davide Pesavento9510c912024-02-25 17:50:05 -05003 * Copyright (c) 2017-2024, Regents of the University of California.
Zhiyi Zhang65ba9322017-01-19 14:15:03 -08004 *
5 * This file is part of ndncert, a certificate management system based on NDN.
6 *
7 * ndncert is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License along with
16 * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ndncert authors and contributors.
19 */
20
21#include "challenge-pin.hpp"
Davide Pesavento0dc02012021-11-23 22:55:03 -050022
Davide Pesavento9510c912024-02-25 17:50:05 -050023#include <ndn-cxx/util/logger.hpp>
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080024#include <ndn-cxx/util/random.hpp>
25
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080026namespace ndncert {
27
Zhiyi Zhangd61b4a82020-10-10 15:18:43 -070028NDN_LOG_INIT(ndncert.challenge.pin);
Zhiyi Zhang36706832019-07-04 21:33:03 -070029NDNCERT_REGISTER_CHALLENGE(ChallengePin, "pin");
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080030
31const std::string ChallengePin::NEED_CODE = "need-code";
32const std::string ChallengePin::WRONG_CODE = "wrong-code";
Zhiyi Zhangead9f002020-10-03 15:42:52 -070033const std::string ChallengePin::PARAMETER_KEY_CODE = "code";
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080034
35ChallengePin::ChallengePin(const size_t& maxAttemptTimes, const time::seconds& secretLifetime)
Davide Pesavento0dc02012021-11-23 22:55:03 -050036 : ChallengeModule("pin", maxAttemptTimes, secretLifetime)
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080037{
38}
39
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070040// For CA
Zhiyi Zhangaafc55e2020-09-28 17:54:48 -070041std::tuple<ErrorCode, std::string>
Zhiyi Zhang32d4b4e2020-10-28 22:10:49 -070042ChallengePin::handleChallengeRequest(const Block& params, ca::RequestState& request)
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080043{
Suyong Won44d0cce2020-05-10 04:07:43 -070044 params.parse();
Zhiyi Zhang8da54d62019-11-21 00:03:05 -080045 auto currentTime = time::system_clock::now();
Davide Pesavento6866b902024-12-22 23:11:26 -050046
tylerliu7b9185c2020-11-24 12:15:18 -080047 if (request.status == Status::BEFORE_CHALLENGE) {
Davide Pesavento6866b902024-12-22 23:11:26 -050048 NDN_LOG_TRACE("Begin challenge");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070049 // for the first time, init the challenge
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070050 std::string secretCode = generateSecretCode();
51 JsonSection secretJson;
Zhiyi Zhang46049832020-09-28 17:08:12 -070052 secretJson.add(PARAMETER_KEY_CODE, secretCode);
Davide Pesavento6866b902024-12-22 23:11:26 -050053 NDN_LOG_TRACE("Secret for request " << ndn::toHex(request.requestId) << " is " << secretCode);
Davide Pesavento0dc02012021-11-23 22:55:03 -050054 return returnWithNewChallengeStatus(request, NEED_CODE, std::move(secretJson), m_maxAttemptTimes,
55 m_secretLifetime);
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080056 }
Davide Pesavento6866b902024-12-22 23:11:26 -050057
tylerliu7b9185c2020-11-24 12:15:18 -080058 if (request.challengeState) {
59 if (request.challengeState->challengeStatus == NEED_CODE ||
60 request.challengeState->challengeStatus == WRONG_CODE) {
Davide Pesavento6866b902024-12-22 23:11:26 -050061 NDN_LOG_TRACE("Challenge status: " << request.challengeState->challengeStatus);
Zhiyi Zhanga749f442020-09-29 17:19:51 -070062 // the incoming interest should bring the pin code
tylerliu50d679e2020-10-14 14:08:39 -070063 std::string givenCode = readString(params.get(tlv::ParameterValue));
tylerliu7b9185c2020-11-24 12:15:18 -080064 auto secret = request.challengeState->secrets;
65 if (currentTime - request.challengeState->timestamp >= m_secretLifetime) {
Davide Pesavento6866b902024-12-22 23:11:26 -050066 NDN_LOG_TRACE("Secret expired");
Zhiyi Zhanga749f442020-09-29 17:19:51 -070067 return returnWithError(request, ErrorCode::OUT_OF_TIME, "Secret expired.");
68 }
69 if (givenCode == secret.get<std::string>(PARAMETER_KEY_CODE)) {
Davide Pesavento6866b902024-12-22 23:11:26 -050070 NDN_LOG_TRACE("PIN is correct, challenge succeeded");
Zhiyi Zhanga749f442020-09-29 17:19:51 -070071 return returnWithSuccess(request);
72 }
73 // check rest attempt times
tylerliu7b9185c2020-11-24 12:15:18 -080074 if (request.challengeState->remainingTries > 1) {
75 auto remainTime = m_secretLifetime - (currentTime - request.challengeState->timestamp);
Davide Pesavento6866b902024-12-22 23:11:26 -050076 NDN_LOG_TRACE("Wrong PIN, remaining tries = " << request.challengeState->remainingTries - 1);
Zhiyi Zhanga749f442020-09-29 17:19:51 -070077 return returnWithNewChallengeStatus(request, WRONG_CODE, std::move(secret),
tylerliu7b9185c2020-11-24 12:15:18 -080078 request.challengeState->remainingTries - 1,
Zhiyi Zhanga749f442020-09-29 17:19:51 -070079 time::duration_cast<time::seconds>(remainTime));
80 }
81 else {
Davide Pesavento6866b902024-12-22 23:11:26 -050082 NDN_LOG_TRACE("Wrong PIN, no tries remaining");
83 return returnWithError(request, ErrorCode::OUT_OF_TRIES, "Ran out of tries.");
Zhiyi Zhanga749f442020-09-29 17:19:51 -070084 }
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080085 }
86 }
Davide Pesavento6866b902024-12-22 23:11:26 -050087
88 return returnWithError(request, ErrorCode::INVALID_PARAMETER, "Unexpected challenge status.");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070089}
90
91// For Client
tylerliu40226332020-11-11 15:37:16 -080092std::multimap<std::string, std::string>
Zhiyi Zhang46049832020-09-28 17:08:12 -070093ChallengePin::getRequestedParameterList(Status status, const std::string& challengeStatus)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070094{
tylerliu40226332020-11-11 15:37:16 -080095 std::multimap<std::string, std::string> result;
Zhiyi Zhang46049832020-09-28 17:08:12 -070096 if (status == Status::BEFORE_CHALLENGE) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070097 // do nothing
98 }
Zhiyi Zhang48f23782020-09-28 12:11:24 -070099 else if (status == Status::CHALLENGE && challengeStatus == NEED_CODE) {
tylerliu40226332020-11-11 15:37:16 -0800100 result.emplace(PARAMETER_KEY_CODE, "Please input your PIN code");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700101 }
Zhiyi Zhang48f23782020-09-28 12:11:24 -0700102 else if (status == Status::CHALLENGE && challengeStatus == WRONG_CODE) {
tylerliu40226332020-11-11 15:37:16 -0800103 result.emplace(PARAMETER_KEY_CODE, "Incorrect PIN code, please try again");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700104 }
105 else {
Davide Pesavento6866b902024-12-22 23:11:26 -0500106 NDN_THROW(std::runtime_error("Unexpected challenge status"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700107 }
Zhiyi Zhangf72c0542017-03-16 14:45:30 -0700108 return result;
109}
110
Suyong Won19fba4d2020-05-09 13:39:46 -0700111Block
tylerliu6563f932020-10-30 11:13:38 -0700112ChallengePin::genChallengeRequestTLV(Status status, const std::string& challengeStatus,
tylerliuf2e6bb52020-12-13 13:23:05 -0800113 const std::multimap<std::string, std::string>& params)
Suyong Won19fba4d2020-05-09 13:39:46 -0700114{
tylerliu1f480be2020-11-10 13:02:53 -0800115 Block request(tlv::EncryptedPayload);
Zhiyi Zhang46049832020-09-28 17:08:12 -0700116 if (status == Status::BEFORE_CHALLENGE) {
Davide Pesavento0dc02012021-11-23 22:55:03 -0500117 request.push_back(ndn::makeStringBlock(tlv::SelectedChallenge, CHALLENGE_TYPE));
Suyong Won19fba4d2020-05-09 13:39:46 -0700118 }
Zhiyi Zhang46049832020-09-28 17:08:12 -0700119 else if (status == Status::CHALLENGE && (challengeStatus == NEED_CODE || challengeStatus == WRONG_CODE)) {
tylerliu40226332020-11-11 15:37:16 -0800120 if (params.size() != 1 || params.find(PARAMETER_KEY_CODE) == params.end()) {
Davide Pesavento6866b902024-12-22 23:11:26 -0500121 NDN_THROW(std::runtime_error("Wrong parameter provided"));
Zhiyi Zhang46049832020-09-28 17:08:12 -0700122 }
Davide Pesavento0dc02012021-11-23 22:55:03 -0500123 request.push_back(ndn::makeStringBlock(tlv::SelectedChallenge, CHALLENGE_TYPE));
124 request.push_back(ndn::makeStringBlock(tlv::ParameterKey, PARAMETER_KEY_CODE));
125 request.push_back(ndn::makeStringBlock(tlv::ParameterValue, params.find(PARAMETER_KEY_CODE)->second));
Suyong Won19fba4d2020-05-09 13:39:46 -0700126 }
127 else {
Davide Pesavento6866b902024-12-22 23:11:26 -0500128 NDN_THROW(std::runtime_error("Unexpected challenge status"));
Suyong Won19fba4d2020-05-09 13:39:46 -0700129 }
Suyong Won44d0cce2020-05-10 04:07:43 -0700130 request.encode();
Suyong Won19fba4d2020-05-09 13:39:46 -0700131 return request;
132}
Davide Pesavento0dc02012021-11-23 22:55:03 -0500133
Zhiyi Zhange4891b72020-10-10 15:11:57 -0700134} // namespace ndncert