blob: 66801b2631ef789d255b6be69fb6c98f72c2e2b5 [file] [log] [blame]
Zhiyi Zhang08e0e982017-03-01 10:10:42 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
swa77020643ac2020-03-26 02:24:45 -07002/**
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -07003 * Copyright (c) 2017-2020, Regents of the University of California.
Zhiyi Zhang08e0e982017-03-01 10:10:42 -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
Zhiyi Zhang837406d2020-10-05 22:01:31 -070021#include "requester.hpp"
Zhiyi Zhang90c75782020-10-06 15:04:03 -070022#include <ndn-cxx/security/verification-helpers.hpp>
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -070023#include <boost/asio.hpp>
Davide Pesaventob48bbda2020-07-27 19:41:37 -040024#include <boost/program_options/options_description.hpp>
25#include <boost/program_options/parsers.hpp>
26#include <boost/program_options/variables_map.hpp>
Zhiyi Zhang48f23782020-09-28 12:11:24 -070027#include <iostream>
Zhiyi Zhang48f23782020-09-28 12:11:24 -070028#include <string>
29
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080030namespace ndn {
31namespace ndncert {
Zhiyi Zhang3002e6b2020-10-29 18:54:07 -070032namespace requester {
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080033
Zhiyi Zhang48f23782020-09-28 12:11:24 -070034static void
tylerliufeabfdc2020-10-03 15:09:58 -070035selectCaProfile(std::string configFilePath);
36static void
37runProbe(CaProfile profile);
38static void
39runNew(CaProfile profile, Name identityName);
40static void
41runChallenge(const std::string& challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070042
Zhiyi Zhang837406d2020-10-05 22:01:31 -070043size_t nStep = 1;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070044Face face;
tylerliua7bea662020-10-08 18:51:02 -070045security::KeyChain keyChain;
tylerliubb630362020-11-10 11:31:35 -080046shared_ptr<RequestState> requesterState = nullptr;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080047
Zhiyi Zhang46049832020-09-28 17:08:12 -070048static void
tylerliu40226332020-11-11 15:37:16 -080049captureParams(std::multimap<std::string, std::string>& requirement)
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080050{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070051 std::list<std::string> results;
Zhiyi Zhang46049832020-09-28 17:08:12 -070052 for (auto& item : requirement) {
53 std::cerr << std::get<1>(item) << std::endl;
54 std::string captured;
55 getline(std::cin, captured);
56 std::get<1>(item) = captured;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080057 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070058 std::cerr << "Got it. This is what you've provided:" << std::endl;
Zhiyi Zhang46049832020-09-28 17:08:12 -070059 for (const auto& item : requirement) {
60 std::cerr << std::get<0>(item) << " : " << std::get<1>(item) << std::endl;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080061 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070062}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080063
tylerliu40226332020-11-11 15:37:16 -080064static std::multimap<std::string, std::string>
Zhiyi Zhang2de4ea32020-12-13 17:45:25 -080065captureParams(const std::vector<std::string>& requirement)
Zhiyi Zhang547c8512019-06-18 23:46:14 -070066{
tylerliu40226332020-11-11 15:37:16 -080067 std::multimap<std::string, std::string> results;
tylerliufeabfdc2020-10-03 15:09:58 -070068 for (const auto& r : requirement) {
tylerliu40226332020-11-11 15:37:16 -080069 results.emplace(r, "Please input: " + r);
Zhiyi Zhang547c8512019-06-18 23:46:14 -070070 }
tylerliufeabfdc2020-10-03 15:09:58 -070071 captureParams(results);
Zhiyi Zhang547c8512019-06-18 23:46:14 -070072 return results;
73}
74
tylerliufeabfdc2020-10-03 15:09:58 -070075static int
Zhiyi Zhang36706832019-07-04 21:33:03 -070076captureValidityPeriod()
77{
Zhiyi Zhang837406d2020-10-05 22:01:31 -070078 std::cerr << "\n***************************************\n"
79 << "Step " << nStep++
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -070080 << ": Please type in your expected validity period of your certificate."
81 << " Type the number of hours (168 for week, 730 for month, 8760 for year)."
82 << " The CA may reject your application if your expected period is too long." << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -080083 size_t count = 0;
84 while (true && count < 3) {
tylerliufeabfdc2020-10-03 15:09:58 -070085 std::string periodStr = "";
86 getline(std::cin, periodStr);
87 try {
Zhiyi Zhang837406d2020-10-05 22:01:31 -070088 return std::stoul(periodStr);
tylerliufeabfdc2020-10-03 15:09:58 -070089 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -070090 catch (const std::exception& e) {
tylerliufeabfdc2020-10-03 15:09:58 -070091 std::cerr << "Your input is invalid. Try again: " << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -080092 count++;
tylerliufeabfdc2020-10-03 15:09:58 -070093 }
Zhiyi Zhang36706832019-07-04 21:33:03 -070094 }
Zhiyi Zhang87ded732021-01-08 14:05:24 -080095 std::cerr << "Invalid input for too many times, exit. " << std::endl;
96 exit(1);
Zhiyi Zhang36706832019-07-04 21:33:03 -070097}
98
99static void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700100onNackCb()
101{
102 std::cerr << "Got NACK\n";
103}
104
105static void
106timeoutCb()
107{
108 std::cerr << "Interest sent time out\n";
109}
110
111static void
swa770cf1d8f72020-04-21 23:12:39 -0700112certFetchCb(const Data& reply)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700113{
tylerliufeabfdc2020-10-03 15:09:58 -0700114 auto item = Requester::onCertFetchResponse(reply);
115 if (item) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700116 keyChain.addCertificate(keyChain.getPib().getIdentity(item->getIdentity()).getKey(item->getKeyName()), *item);
tylerliufeabfdc2020-10-03 15:09:58 -0700117 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700118 std::cerr << "\n***************************************\n"
119 << "Step " << nStep++
120 << ": DONE\nCertificate with Name: " << reply.getName().toUri()
121 << "has already been installed to your local keychain" << std::endl
122 << "Exit now";
123 face.getIoService().stop();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700124}
125
126static void
127challengeCb(const Data& reply)
128{
tylerliufeabfdc2020-10-03 15:09:58 -0700129 try {
130 Requester::onChallengeResponse(*requesterState, reply);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700131 }
132 catch (const std::exception& e) {
tylerliufeabfdc2020-10-03 15:09:58 -0700133 std::cerr << "Error when decoding challenge step: " << e.what() << std::endl;
134 exit(1);
135 }
tylerliuf2e6bb52020-12-13 13:23:05 -0800136 if (requesterState->status == Status::SUCCESS) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700137 std::cerr << "Certificate has already been issued, downloading certificate..." << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700138 face.expressInterest(*Requester::genCertFetchInterest(*requesterState), bind(&certFetchCb, _2),
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700139 bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700140 return;
141 }
tylerliuf2e6bb52020-12-13 13:23:05 -0800142 runChallenge(requesterState->challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700143}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800144
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700145static void
146newCb(const Data& reply)
147{
tylerliufeabfdc2020-10-03 15:09:58 -0700148 std::list<std::string> challengeList;
149 try {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700150 challengeList = Requester::onNewRenewRevokeResponse(*requesterState, reply);
151 }
152 catch (const std::exception& e) {
tylerliufeabfdc2020-10-03 15:09:58 -0700153 std::cerr << "Error on decoding NEW step reply because: " << e.what() << std::endl;
154 exit(1);
155 }
156
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700157 size_t challengeIndex = 0;
Zhiyi Zhang36706832019-07-04 21:33:03 -0700158 if (challengeList.size() < 1) {
159 std::cerr << "There is no available challenge provided by the CA. Exit" << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700160 exit(1);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800161 }
Zhiyi Zhang48f546f2020-12-24 17:31:02 -0800162 else if (challengeList.size() >= 1) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700163 std::cerr << "\n***************************************\n"
164 << "Step " << nStep++
165 << ": CHALLENGE SELECTION" << std::endl;
166 size_t count = 0;
Zhiyi Zhang36706832019-07-04 21:33:03 -0700167 std::string choice = "";
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700168 for (auto item : challengeList) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700169 std::cerr << "> Index: " << count++ << std::endl
170 << ">> Challenge:" << item << std::endl;
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700171 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700172 std::cerr << "Please type in the challenge index that you want to perform:" << std::endl;
Zhiyi Zhang17720f22021-01-08 14:12:56 -0800173 size_t inputCount = 0;
174 while (inputCount < 3) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700175 getline(std::cin, choice);
176 try {
177 challengeIndex = std::stoul(choice);
178 }
179 catch (const std::exception& e) {
180 std::cerr << "Your input is not valid. Try again:" << std::endl;
Zhiyi Zhang17720f22021-01-08 14:12:56 -0800181 inputCount++;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700182 continue;
183 }
184 if (challengeIndex >= count) {
185 std::cerr << "Your input index is out of range. Try again:" << std::endl;
Zhiyi Zhang17720f22021-01-08 14:12:56 -0800186 inputCount++;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700187 continue;
188 }
189 break;
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700190 }
Zhiyi Zhang17720f22021-01-08 14:12:56 -0800191 if (inputCount == 3) {
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800192 std::cerr << "Invalid input for too many times, exit. " << std::endl;
193 exit(1);
194 }
Zhiyi Zhang36706832019-07-04 21:33:03 -0700195 }
196 auto it = challengeList.begin();
197 std::advance(it, challengeIndex);
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700198 std::cerr << "The challenge has been selected: " << *it << std::endl;
199 runChallenge(*it);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700200}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800201
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700202static void
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700203InfoCb(const Data& reply, const Name& certFullName)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700204{
Zhiyi Zhang997669a2020-10-28 21:15:40 -0700205 optional<CaProfile> profile;
tylerliufeabfdc2020-10-03 15:09:58 -0700206 try {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700207 if (certFullName.empty()) {
208 profile = Requester::onCaProfileResponse(reply);
tylerliufeabfdc2020-10-03 15:09:58 -0700209 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700210 else {
211 profile = Requester::onCaProfileResponseAfterRedirection(reply, certFullName);
212 }
213 }
214 catch (const std::exception& e) {
215 std::cerr << "The fetched CA information cannot be used because: " << e.what() << std::endl;
216 return;
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700217 }
Zhiyi Zhang6bb1d082020-10-08 14:25:21 -0700218 std::cerr << "\n***************************************\n"
219 << "Step " << nStep++
220 << ": Will use a new trust anchor, please double check the identity info:" << std::endl
Zhiyi Zhang44c6a352020-12-14 10:57:17 -0800221 << "> New CA name: " << profile->caPrefix.toUri() << std::endl
tylerliua7bea662020-10-08 18:51:02 -0700222 << "> This trust anchor information is signed by: " << reply.getSignatureInfo().getKeyLocator() << std::endl
Zhiyi Zhangec4aa3a2021-01-08 14:26:37 -0800223 << "> The certificate: " << *profile->cert << std::endl
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400224 << "Do you trust the information? Type in YES or NO" << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700225
226 std::string answer;
227 getline(std::cin, answer);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700228 boost::algorithm::to_lower(answer);
229 if (answer == "yes") {
Zhiyi Zhang44c6a352020-12-14 10:57:17 -0800230 std::cerr << "You answered YES: new CA " << profile->caPrefix.toUri() << " will be used" << std::endl;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700231 runProbe(*profile);
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700232 // client.getClientConf().save(std::string(SYSCONFDIR) + "/ndncert/client.conf");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700233 }
234 else {
Zhiyi Zhang44c6a352020-12-14 10:57:17 -0800235 std::cerr << "You answered NO: new CA " << profile->caPrefix.toUri() << " will not be used" << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700236 exit(0);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700237 }
238}
239
240static void
tylerliufeabfdc2020-10-03 15:09:58 -0700241probeCb(const Data& reply, CaProfile profile)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700242{
tylerliub47dad72020-10-08 21:36:55 -0700243 std::vector<std::pair<Name, int>> names;
tylerliufeabfdc2020-10-03 15:09:58 -0700244 std::vector<Name> redirects;
245 Requester::onProbeResponse(reply, profile, names, redirects);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700246 size_t count = 0;
247 std::cerr << "\n***************************************\n"
248 << "Step " << nStep++
249 << ": You can either select one of the following names suggested by the CA: " << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700250 for (const auto& name : names) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700251 std::cerr << "> Index: " << count++ << std::endl
tylerliub47dad72020-10-08 21:36:55 -0700252 << ">> Suggested name: " << name.first.toUri() << std::endl
253 << ">> Corresponding Max sufiix length: " << name.second << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700254 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700255 std::cerr << "\nOr choose another trusted CA suggested by the CA: " << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700256 for (const auto& redirect : redirects) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700257 std::cerr << "> Index: " << count++ << std::endl
tylerliua7bea662020-10-08 18:51:02 -0700258 << ">> Suggested CA: " << security::extractIdentityFromCertName(redirect.getPrefix(-1)) << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700259 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700260 std::cerr << "Please type in the index of your choice:" << std::endl;
261 size_t index = 0;
tylerliufeabfdc2020-10-03 15:09:58 -0700262 try {
263 std::string input;
264 getline(std::cin, input);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700265 index = std::stoul(input);
tylerliufeabfdc2020-10-03 15:09:58 -0700266 }
267 catch (const std::exception& e) {
268 std::cerr << "Your input is Invalid. Exit" << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800269 exit(1);
tylerliufeabfdc2020-10-03 15:09:58 -0700270 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700271 if (index >= names.size() + redirects.size()) {
tylerliufeabfdc2020-10-03 15:09:58 -0700272 std::cerr << "Your input is not an existing index. Exit" << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800273 exit(1);
tylerliufeabfdc2020-10-03 15:09:58 -0700274 }
275 if (index < names.size()) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700276 //names
tylerliud82cc5c2020-12-21 23:58:39 -0800277 auto selectedName = names[index].first;
278 std::cerr << "You selected name: " << selectedName.toUri() << std::endl;
279 std::cerr << "Enter Suffix if you would like one (Enter to skip): ";
280 try {
281 std::string input;
282 getline(std::cin, input);
283 auto inputName = Name(input);
284 if (!inputName.empty()) {
285 selectedName.append(inputName);
286 std::cerr << "You are applying name: " << selectedName.toUri() << std::endl;
287 }
288 }
289 catch (const std::exception& e) {
290 std::cerr << "Your input is Invalid. Exit" << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800291 exit(1);
tylerliud82cc5c2020-12-21 23:58:39 -0800292 }
293 runNew(profile, selectedName);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700294 }
295 else {
296 //redirects
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700297 auto redirectedCaFullName = redirects[index - names.size()];
tylerliua7bea662020-10-08 18:51:02 -0700298 auto redirectedCaName = security::extractIdentityFromCertName(redirectedCaFullName.getPrefix(-1));
Zhiyi Zhang696cd042020-10-07 21:27:36 -0700299 std::cerr << "You selected to be redirected to CA: " << redirectedCaName.toUri() << std::endl;
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700300 face.expressInterest(
Zhiyi Zhang696cd042020-10-07 21:27:36 -0700301 *Requester::genCaProfileDiscoveryInterest(redirectedCaName),
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700302 [&](const Interest&, const Data& data) {
303 auto fetchingInterest = Requester::genCaProfileInterestFromDiscoveryResponse(data);
304 face.expressInterest(*fetchingInterest,
305 bind(&InfoCb, _2, redirectedCaFullName),
306 bind(&onNackCb),
307 bind(&timeoutCb));
308 },
309 bind(&onNackCb),
310 bind(&timeoutCb));
tylerliufeabfdc2020-10-03 15:09:58 -0700311 }
312}
313
314static void
315selectCaProfile(std::string configFilePath)
316{
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700317 ProfileStorage profileStorage;
tylerliufeabfdc2020-10-03 15:09:58 -0700318 try {
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700319 profileStorage.load(configFilePath);
tylerliufeabfdc2020-10-03 15:09:58 -0700320 }
321 catch (const std::exception& e) {
322 std::cerr << "Cannot load the configuration file: " << e.what() << std::endl;
323 exit(1);
324 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700325 size_t count = 0;
326 std::cerr << "***************************************\n"
327 << "Step " << nStep++ << ": CA SELECTION" << std::endl;
Zhiyi Zhang84e11842020-11-19 20:03:23 -0800328 for (auto item : profileStorage.getKnownProfiles()) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700329 std::cerr << "> Index: " << count++ << std::endl
Zhiyi Zhang44c6a352020-12-14 10:57:17 -0800330 << ">> CA prefix:" << item.caPrefix << std::endl
331 << ">> Introduction: " << item.caInfo << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700332 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700333 std::cerr << "Please type in the CA's index that you want to apply or type in NONE if your expected CA is not in the list:\n";
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700334
Zhiyi Zhang36706832019-07-04 21:33:03 -0700335 std::string caIndexS, caIndexSLower;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700336 getline(std::cin, caIndexS);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700337 caIndexSLower = caIndexS;
338 boost::algorithm::to_lower(caIndexSLower);
339 if (caIndexSLower == "none") {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700340 std::cerr << "\n***************************************\n"
341 << "Step " << nStep << ": ADD NEW CA\nPlease type in the CA's Name:" << std::endl;
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700342 std::string expectedCAName;
343 getline(std::cin, expectedCAName);
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700344 face.expressInterest(
345 *Requester::genCaProfileDiscoveryInterest(Name(expectedCAName)),
346 [&](const Interest&, const Data& data) {
347 auto fetchingInterest = Requester::genCaProfileInterestFromDiscoveryResponse(data);
348 face.expressInterest(*fetchingInterest,
349 bind(&InfoCb, _2, Name()),
350 bind(&onNackCb),
351 bind(&timeoutCb));
352 },
353 bind(&onNackCb),
354 bind(&timeoutCb));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700355 }
356 else {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700357 size_t caIndex;
Zhiyi Zhang36706832019-07-04 21:33:03 -0700358 try {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700359 caIndex = std::stoul(caIndexS);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700360 }
361 catch (const std::exception& e) {
362 std::cerr << "Your input is neither NONE nor a valid index. Exit" << std::endl;
363 return;
364 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700365 if (caIndex >= count) {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700366 std::cerr << "Your input is not an existing index. Exit" << std::endl;
367 return;
368 }
Zhiyi Zhang84e11842020-11-19 20:03:23 -0800369 auto itemIterator = profileStorage.getKnownProfiles().cbegin();
tylerliufeabfdc2020-10-03 15:09:58 -0700370 std::advance(itemIterator, caIndex);
371 auto targetCaItem = *itemIterator;
372 runProbe(targetCaItem);
373 }
374}
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700375
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700376static void
377runProbe(CaProfile profile)
tylerliufeabfdc2020-10-03 15:09:58 -0700378{
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700379 std::cerr << "\n***************************************\n"
Zhiyi Zhang6bb1d082020-10-08 14:25:21 -0700380 << "Step " << nStep++
381 << ": Do you know your identity name to be certified by CA "
Zhiyi Zhang44c6a352020-12-14 10:57:17 -0800382 << profile.caPrefix.toUri()
Zhiyi Zhang6bb1d082020-10-08 14:25:21 -0700383 << " already? Type in YES or NO" << std::endl;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700384 bool validAnswer = false;
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800385 size_t count = 0;
386 while (!validAnswer && count < 3) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700387 std::string answer;
388 getline(std::cin, answer);
389 boost::algorithm::to_lower(answer);
390 if (answer == "yes") {
391 validAnswer = true;
392 std::cerr << "You answered YES" << std::endl;
393 std::cerr << "\n***************************************\n"
394 << "Step " << nStep++
Zhiyi Zhang6bb1d082020-10-08 14:25:21 -0700395 << ": Please type in the full identity name you want to get (with CA prefix "
Zhiyi Zhang44c6a352020-12-14 10:57:17 -0800396 << profile.caPrefix.toUri()
Zhiyi Zhang6bb1d082020-10-08 14:25:21 -0700397 << "):" << std::endl;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700398 std::string identityNameStr;
399 getline(std::cin, identityNameStr);
400 runNew(profile, Name(identityNameStr));
tylerliufeabfdc2020-10-03 15:09:58 -0700401 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700402 else if (answer == "no") {
403 validAnswer = true;
404 std::cerr << "You answered NO" << std::endl;
405 std::cerr << "\n***************************************\n"
406 << "Step " << nStep++ << ": Please provide information for name assignment" << std::endl;
Zhiyi Zhang44c6a352020-12-14 10:57:17 -0800407 auto capturedParams = captureParams(profile.probeParameterKeys);
Zhiyi Zhangdb1ec762020-10-30 08:58:39 -0700408 face.expressInterest(*Requester::genProbeInterest(profile, std::move(capturedParams)),
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700409 bind(&probeCb, _2, profile), bind(&onNackCb), bind(&timeoutCb));
410 }
411 else {
412 std::cerr << "Invalid answer. Type in YES or NO" << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800413 count++;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700414 }
415 }
Zhiyi Zhang17720f22021-01-08 14:12:56 -0800416 if (count == 3) {
417 std::cerr << "Invalid input for too many times, exit. " << std::endl;
418 exit(1);
419 }
tylerliufeabfdc2020-10-03 15:09:58 -0700420}
421
422static void
423runNew(CaProfile profile, Name identityName)
424{
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700425 int validityPeriod = captureValidityPeriod();
426 auto now = time::system_clock::now();
427 std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
Zhiyi Zhang48f546f2020-12-24 17:31:02 -0800428 requesterState = std::make_shared<RequestState>(keyChain, profile, RequestType::NEW);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700429 auto interest = Requester::genNewInterest(*requesterState, identityName, now, now + time::hours(validityPeriod));
430 if (interest != nullptr) {
431 face.expressInterest(*interest, bind(&newCb, _2), bind(&onNackCb), bind(&timeoutCb));
432 }
433 else {
434 std::cerr << "Cannot generate the Interest for NEW step. Exit" << std::endl;
435 }
tylerliufeabfdc2020-10-03 15:09:58 -0700436}
437
438static void
439runChallenge(const std::string& challengeType)
440{
tylerliu40226332020-11-11 15:37:16 -0800441 std::multimap<std::string, std::string> requirement;
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700442 try {
443 requirement = Requester::selectOrContinueChallenge(*requesterState, challengeType);
444 }
445 catch (const std::exception& e) {
446 std::cerr << "Error. Cannot successfully load the Challenge Module with error: " << std::string(e.what())
447 << "Exit." << std::endl;
448 exit(1);
449 }
tylerliufeabfdc2020-10-03 15:09:58 -0700450 if (requirement.size() > 0) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700451 std::cerr << "\n***************************************\n"
452 << "Step " << nStep
453 << ": Please provide parameters used for Identity Verification Challenge" << std::endl;
454 captureParams(requirement);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700455 }
tylerliufeabfdc2020-10-03 15:09:58 -0700456 face.expressInterest(*Requester::genChallengeInterest(*requesterState, std::move(requirement)),
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700457 bind(&challengeCb, _2), bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700458}
459
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700460static void
461handleSignal(const boost::system::error_code& error, int signalNum)
462{
463 if (error) {
464 return;
465 }
466 const char* signalName = ::strsignal(signalNum);
467 std::cerr << "Exiting on signal ";
468 if (signalName == nullptr) {
469 std::cerr << signalNum;
470 }
471 else {
472 std::cerr << signalName;
473 }
474 std::cerr << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700475 if (requesterState) {
476 Requester::endSession(*requesterState);
477 }
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700478 face.getIoService().stop();
tylerliufeabfdc2020-10-03 15:09:58 -0700479 exit(1);
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700480}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800481
482int
483main(int argc, char* argv[])
484{
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700485 boost::asio::signal_set terminateSignals(face.getIoService());
486 terminateSignals.add(SIGINT);
487 terminateSignals.add(SIGTERM);
488 terminateSignals.async_wait(handleSignal);
489
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800490 namespace po = boost::program_options;
Zhiyi Zhang840afd92020-10-21 13:24:08 -0700491 std::string configFilePath = std::string(NDNCERT_SYSCONFDIR) + "/ndncert/client.conf";
Zhiyi Zhang36706832019-07-04 21:33:03 -0700492 po::options_description description("General Usage\n ndncert-client [-h] [-c] [-v]\n");
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700493 description.add_options()("help,h", "produce help message")("config-file,c", po::value<std::string>(&configFilePath), "configuration file name");
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800494 po::positional_options_description p;
495
496 po::variables_map vm;
497 try {
498 po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm);
499 po::notify(vm);
500 }
501 catch (const std::exception& e) {
502 std::cerr << "ERROR: " << e.what() << std::endl;
503 return 1;
504 }
505 if (vm.count("help") != 0) {
506 std::cerr << description << std::endl;
507 return 0;
508 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700509 selectCaProfile(configFilePath);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800510 face.processEvents();
511 return 0;
512}
513
Zhiyi Zhang3002e6b2020-10-29 18:54:07 -0700514} // namespace requester
Zhiyi Zhange4891b72020-10-10 15:11:57 -0700515} // namespace ndncert
516} // namespace ndn
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800517
Zhiyi Zhang48f23782020-09-28 12:11:24 -0700518int
519main(int argc, char* argv[])
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800520{
Zhiyi Zhang3002e6b2020-10-29 18:54:07 -0700521 return ndn::ndncert::requester::main(argc, argv);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800522}