blob: 94ea3e739a3bc347e451574c11f07bdd2871ca08 [file] [log] [blame]
Zhiyi Zhang65ba9322017-01-19 14:15:03 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2017, Regents of the University of California.
4 *
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"
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080022#include "logging.hpp"
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080023#include "json-helper.hpp"
24#include <ndn-cxx/util/random.hpp>
25
26namespace ndn {
27namespace ndncert {
28
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080029_LOG_INIT(ndncert.challenge-pin);
30
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080031NDNCERT_REGISTER_CHALLENGE(ChallengePin, "PIN");
32
33const std::string ChallengePin::NEED_CODE = "need-code";
34const std::string ChallengePin::WRONG_CODE = "wrong-code";
35const std::string ChallengePin::FAILURE_TIMEOUT = "failure-timeout";
36const std::string ChallengePin::FAILURE_MAXRETRY = "failure-max-retry";
37
38const std::string ChallengePin::JSON_CODE_TP = "code-timepoint";
39const std::string ChallengePin::JSON_PIN_CODE = "code";
40const std::string ChallengePin::JSON_ATTEMPT_TIMES = "attempt-times";
41
42ChallengePin::ChallengePin(const size_t& maxAttemptTimes, const time::seconds& secretLifetime)
43 : ChallengeModule("PIN")
44 , m_secretLifetime(secretLifetime)
45 , m_maxAttemptTimes(maxAttemptTimes)
46{
47}
48
49JsonSection
50ChallengePin::processSelectInterest(const Interest& interest, CertificateRequest& request)
51{
Zhiyi Zhange30eb352017-04-13 15:26:14 -070052 // interest format: /caName/CA/_SELECT/{"request-id":"id"}/PIN/<signature>
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080053 request.setStatus(NEED_CODE);
54 request.setChallengeType(CHALLENGE_TYPE);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080055 std::string secretCode = generateSecretCode();
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080056 request.setChallengeSecrets(generateStoredSecrets(time::system_clock::now(),
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080057 secretCode,
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080058 m_maxAttemptTimes));
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080059 _LOG_TRACE("Secret for request " << request.getRequestId() << " : " << secretCode);
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080060 return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, NEED_CODE);
61}
62
63JsonSection
64ChallengePin::processValidateInterest(const Interest& interest, CertificateRequest& request)
65{
Zhiyi Zhange30eb352017-04-13 15:26:14 -070066 // interest format: /caName/CA/_VALIDATION/{"request-id":"id"}/PIN/{"code":"code"}/<signature>
67 JsonSection infoJson = getJsonFromNameComponent(interest.getName(), request.getCaName().size() + 4);
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080068 std::string givenCode = infoJson.get<std::string>(JSON_PIN_CODE);
69
70 const auto parsedSecret = parseStoredSecrets(request.getChallengeSecrets());
71 if (time::system_clock::now() - std::get<0>(parsedSecret) >= m_secretLifetime) {
72 // secret expires
73 request.setStatus(FAILURE_TIMEOUT);
74 request.setChallengeSecrets(JsonSection());
75 return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE_TIMEOUT);
76 }
77 else if (givenCode == std::get<1>(parsedSecret)) {
78 request.setStatus(SUCCESS);
79 request.setChallengeSecrets(JsonSection());
80 Name downloadName = genDownloadName(request.getCaName(), request.getRequestId());
81 return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, SUCCESS, downloadName);
82 }
83 else {
84 // check rest attempt times
85 if (std::get<2>(parsedSecret) > 1) {
86 int restAttemptTimes = std::get<2>(parsedSecret) - 1;
Zhiyi Zhang0df767e2017-02-21 16:05:36 -080087 request.setStatus(WRONG_CODE);
Zhiyi Zhang65ba9322017-01-19 14:15:03 -080088 request.setChallengeSecrets(generateStoredSecrets(std::get<0>(parsedSecret),
89 std::get<1>(parsedSecret),
90 restAttemptTimes));
91 return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, WRONG_CODE);
92 }
93 else {
94 // run out times
95 request.setStatus(FAILURE_MAXRETRY);
96 request.setChallengeSecrets(JsonSection());
97 return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE_MAXRETRY);
98 }
99 }
100}
101
102std::list<std::string>
103ChallengePin::getSelectRequirements()
104{
105 std::list<std::string> result;
106 return result;
107}
108
109std::list<std::string>
110ChallengePin::getValidateRequirements(const std::string& status)
111{
112 std::list<std::string> result;
113 if (status == NEED_CODE) {
114 result.push_back("Please input your verification code:");
115 }
116 else if (status == WRONG_CODE) {
117 result.push_back("Incorrect PIN code, please input your verification code:");
118 }
119 return result;
120}
121
122JsonSection
Zhiyi Zhangf72c0542017-03-16 14:45:30 -0700123ChallengePin::doGenSelectParamsJson(const std::string& status,
124 const std::list<std::string>& paramList)
Zhiyi Zhang65ba9322017-01-19 14:15:03 -0800125{
126 JsonSection result;
Zhiyi Zhang0a89b722017-04-28 17:56:01 -0700127 BOOST_ASSERT(status == WAIT_SELECTION);
Zhiyi Zhangf72c0542017-03-16 14:45:30 -0700128 BOOST_ASSERT(paramList.size() == 0);
129 return result;
130}
131
132JsonSection
133ChallengePin::doGenValidateParamsJson(const std::string& status,
134 const std::list<std::string>& paramList)
135{
136 JsonSection result;
137 BOOST_ASSERT(paramList.size() == 1);
138 result.put(JSON_PIN_CODE, paramList.front());
Zhiyi Zhang65ba9322017-01-19 14:15:03 -0800139 return result;
140}
141
142std::tuple<time::system_clock::TimePoint, std::string, int>
143ChallengePin::parseStoredSecrets(const JsonSection& storedSecrets)
144{
145 auto tp = time::fromIsoString(storedSecrets.get<std::string>(JSON_CODE_TP));
146 std::string rightCode= storedSecrets.get<std::string>(JSON_PIN_CODE);
147 int attemptTimes = std::stoi(storedSecrets.get<std::string>(JSON_ATTEMPT_TIMES));
148
149 return std::make_tuple(tp, rightCode, attemptTimes);
150}
151
152JsonSection
153ChallengePin::generateStoredSecrets(const time::system_clock::TimePoint& tp,
154 const std::string& secretCode, int attempTimes)
155{
156 JsonSection json;
157 json.put(JSON_CODE_TP, time::toIsoString(tp));
158 json.put(JSON_PIN_CODE, secretCode);
159 json.put(JSON_ATTEMPT_TIMES, std::to_string(attempTimes));
160 return json;
161}
162
Zhiyi Zhang65ba9322017-01-19 14:15:03 -0800163} // namespace ndncert
164} // namespace ndn