blob: c99104aafa6797e8bc9cec8a8ef00f0ab001558b [file] [log] [blame]
Zhiyi Zhang08e0e982017-03-01 10:10:42 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoe5b43692021-11-15 22:05:03 -05002/*
Tianyuan Yuca23bb02022-03-09 14:09:14 -08003 * Copyright (c) 2017-2022, 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
tylerliu4140fe82021-01-27 15:45:44 -080021#include "requester-request.hpp"
Davide Pesaventoe5b43692021-11-15 22:05:03 -050022
Davide Pesavento0dc02012021-11-23 22:55:03 -050023#include <ndn-cxx/face.hpp>
24#include <ndn-cxx/security/key-chain.hpp>
Zhiyi Zhang90c75782020-10-06 15:04:03 -070025#include <ndn-cxx/security/verification-helpers.hpp>
Davide Pesaventoe5b43692021-11-15 22:05:03 -050026
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -070027#include <boost/asio.hpp>
Davide Pesaventob48bbda2020-07-27 19:41:37 -040028#include <boost/program_options/options_description.hpp>
29#include <boost/program_options/parsers.hpp>
30#include <boost/program_options/variables_map.hpp>
Davide Pesaventoe5b43692021-11-15 22:05:03 -050031
Zhiyi Zhang48f23782020-09-28 12:11:24 -070032#include <iostream>
Zhiyi Zhang48f23782020-09-28 12:11:24 -070033
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080034namespace ndncert {
Zhiyi Zhang3002e6b2020-10-29 18:54:07 -070035namespace requester {
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080036
Zhiyi Zhang48f23782020-09-28 12:11:24 -070037static void
tylerliufeabfdc2020-10-03 15:09:58 -070038selectCaProfile(std::string configFilePath);
Davide Pesaventoe5b43692021-11-15 22:05:03 -050039
tylerliufeabfdc2020-10-03 15:09:58 -070040static void
41runProbe(CaProfile profile);
Davide Pesaventoe5b43692021-11-15 22:05:03 -050042
tylerliufeabfdc2020-10-03 15:09:58 -070043static void
44runNew(CaProfile profile, Name identityName);
Davide Pesaventoe5b43692021-11-15 22:05:03 -050045
tylerliufeabfdc2020-10-03 15:09:58 -070046static void
47runChallenge(const std::string& challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070048
Davide Pesaventoe5b43692021-11-15 22:05:03 -050049static size_t nStep = 1;
Tianyuan Yuca23bb02022-03-09 14:09:14 -080050static const std::string defaultChallenge = "email";
Davide Pesavento0dc02012021-11-23 22:55:03 -050051static ndn::Face face;
52static ndn::KeyChain keyChain;
53static std::shared_ptr<Request> requesterState;
Tianyuan Yuca23bb02022-03-09 14:09:14 -080054static std::shared_ptr<std::multimap<std::string, std::string>> capturedProbeParams;
55static Name newlyCreatedIdentityName;
56static Name newlyCreatedKeyName;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080057
Zhiyi Zhang46049832020-09-28 17:08:12 -070058static void
tylerliu40226332020-11-11 15:37:16 -080059captureParams(std::multimap<std::string, std::string>& requirement)
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080060{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070061 std::list<std::string> results;
Zhiyi Zhang46049832020-09-28 17:08:12 -070062 for (auto& item : requirement) {
63 std::cerr << std::get<1>(item) << std::endl;
64 std::string captured;
65 getline(std::cin, captured);
66 std::get<1>(item) = captured;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080067 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070068 std::cerr << "Got it. This is what you've provided:" << std::endl;
Zhiyi Zhang46049832020-09-28 17:08:12 -070069 for (const auto& item : requirement) {
70 std::cerr << std::get<0>(item) << " : " << std::get<1>(item) << std::endl;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080071 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070072}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080073
tylerliu40226332020-11-11 15:37:16 -080074static std::multimap<std::string, std::string>
Zhiyi Zhang2de4ea32020-12-13 17:45:25 -080075captureParams(const std::vector<std::string>& requirement)
Zhiyi Zhang547c8512019-06-18 23:46:14 -070076{
tylerliu40226332020-11-11 15:37:16 -080077 std::multimap<std::string, std::string> results;
tylerliufeabfdc2020-10-03 15:09:58 -070078 for (const auto& r : requirement) {
tylerliu40226332020-11-11 15:37:16 -080079 results.emplace(r, "Please input: " + r);
Zhiyi Zhang547c8512019-06-18 23:46:14 -070080 }
tylerliufeabfdc2020-10-03 15:09:58 -070081 captureParams(results);
Zhiyi Zhang547c8512019-06-18 23:46:14 -070082 return results;
83}
84
tylerliufeabfdc2020-10-03 15:09:58 -070085static int
Tianyuan Yuca23bb02022-03-09 14:09:14 -080086captureValidityPeriod(time::hours maxValidityPeriod)
Zhiyi Zhang36706832019-07-04 21:33:03 -070087{
Zhiyi Zhang837406d2020-10-05 22:01:31 -070088 std::cerr << "\n***************************************\n"
89 << "Step " << nStep++
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -070090 << ": Please type in your expected validity period of your certificate."
91 << " Type the number of hours (168 for week, 730 for month, 8760 for year)."
Tianyuan Yuca23bb02022-03-09 14:09:14 -080092 << " The CA may reject your application if your expected period is too long."
93 << " The maximum validity period allowed by this CA is " << maxValidityPeriod << "."<< std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -080094 size_t count = 0;
95 while (true && count < 3) {
tylerliufeabfdc2020-10-03 15:09:58 -070096 std::string periodStr = "";
97 getline(std::cin, periodStr);
98 try {
Zhiyi Zhang837406d2020-10-05 22:01:31 -070099 return std::stoul(periodStr);
tylerliufeabfdc2020-10-03 15:09:58 -0700100 }
Davide Pesavento0dc02012021-11-23 22:55:03 -0500101 catch (const std::exception&) {
tylerliufeabfdc2020-10-03 15:09:58 -0700102 std::cerr << "Your input is invalid. Try again: " << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800103 count++;
tylerliufeabfdc2020-10-03 15:09:58 -0700104 }
Zhiyi Zhang36706832019-07-04 21:33:03 -0700105 }
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800106 std::cerr << "Invalid input for too many times, exit. " << std::endl;
107 exit(1);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700108}
109
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800110static Name
111captureKeyName(ndn::security::pib::Identity& identity, ndn::security::pib::Key& defaultKey)
112{
113 size_t count = 0;
114 std::cerr << "***************************************\n"
115 << "Step " << nStep++ << ": KEY SELECTION" << std::endl;
116 for (const auto& key : identity.getKeys()) {
117 std::cerr << "> Index: " << count++ << std::endl
118 << ">> Key Name:";
119 if (key == defaultKey) {
120 std::cerr << " +->* ";
121 }
122 else {
123 std::cerr << " +-> ";
124 }
125 std::cerr << key.getName() << std::endl;
126 }
127
128 std::cerr << "Please type in the key's index that you want to certify or type in NEW if you want to certify a new key:\n";
129 std::string indexStr = "";
130 std::string indexStrLower = "";
131 size_t keyIndex;
132 getline(std::cin, indexStr);
133
134 indexStrLower = indexStr;
135 boost::algorithm::to_lower(indexStrLower);
136 if (indexStrLower == "new") {
137 auto newlyCreatedKey = keyChain.createKey(identity);
138 newlyCreatedKeyName = newlyCreatedKey.getName();
139 std::cerr << "New key generated: " << newlyCreatedKeyName << std::endl;
140 return newlyCreatedKeyName;
141 }
142 else {
143 try {
144 keyIndex = std::stoul(indexStr);
145 }
146 catch (const std::exception&) {
147 std::cerr << "Your input is neither NEW nor a valid index. Exit" << std::endl;
148 exit(1);
149 }
150
151 if (keyIndex >= count) {
152 std::cerr << "Your input is not an existing index. Exit" << std::endl;
153 exit(1);
154 }
155 else {
156 auto itemIterator = identity.getKeys().begin();
157 std::advance(itemIterator, keyIndex);
158 auto targetKeyItem = *itemIterator;
159 return targetKeyItem.getName();
160 }
161 }
162}
163
Zhiyi Zhang36706832019-07-04 21:33:03 -0700164static void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700165onNackCb()
166{
167 std::cerr << "Got NACK\n";
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800168 exit(1);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700169}
170
171static void
172timeoutCb()
173{
174 std::cerr << "Interest sent time out\n";
175}
176
177static void
swa770cf1d8f72020-04-21 23:12:39 -0700178certFetchCb(const Data& reply)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700179{
tylerliu4140fe82021-01-27 15:45:44 -0800180 auto item = Request::onCertFetchResponse(reply);
tylerliufeabfdc2020-10-03 15:09:58 -0700181 if (item) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700182 keyChain.addCertificate(keyChain.getPib().getIdentity(item->getIdentity()).getKey(item->getKeyName()), *item);
tylerliufeabfdc2020-10-03 15:09:58 -0700183 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700184 std::cerr << "\n***************************************\n"
185 << "Step " << nStep++
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800186 << ": DONE\nCertificate with Name: " << reply.getName()
187 << " has been installed to your local keychain\n"
188 << "Exit now" << std::endl;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700189 face.getIoService().stop();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700190}
191
192static void
193challengeCb(const Data& reply)
194{
tylerliufeabfdc2020-10-03 15:09:58 -0700195 try {
tylerliu4140fe82021-01-27 15:45:44 -0800196 requesterState->onChallengeResponse(reply);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700197 }
198 catch (const std::exception& e) {
tylerliufeabfdc2020-10-03 15:09:58 -0700199 std::cerr << "Error when decoding challenge step: " << e.what() << std::endl;
200 exit(1);
201 }
Zhiyi Zhang6499edd2021-02-17 22:37:21 -0800202 if (requesterState->m_status == Status::SUCCESS) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700203 std::cerr << "Certificate has already been issued, downloading certificate..." << std::endl;
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500204 face.expressInterest(*requesterState->genCertFetchInterest(),
205 [] (const auto&, const auto& data) { certFetchCb(data); },
206 [] (auto&&...) { onNackCb(); },
207 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700208 return;
209 }
Zhiyi Zhang6499edd2021-02-17 22:37:21 -0800210 runChallenge(requesterState->m_challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700211}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800212
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700213static void
214newCb(const Data& reply)
215{
tylerliufeabfdc2020-10-03 15:09:58 -0700216 std::list<std::string> challengeList;
217 try {
tylerliu4140fe82021-01-27 15:45:44 -0800218 challengeList = requesterState->onNewRenewRevokeResponse(reply);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700219 }
220 catch (const std::exception& e) {
tylerliufeabfdc2020-10-03 15:09:58 -0700221 std::cerr << "Error on decoding NEW step reply because: " << e.what() << std::endl;
222 exit(1);
223 }
224
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700225 size_t challengeIndex = 0;
Zhiyi Zhang36706832019-07-04 21:33:03 -0700226 if (challengeList.size() < 1) {
227 std::cerr << "There is no available challenge provided by the CA. Exit" << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700228 exit(1);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800229 }
Zhiyi Zhang48f546f2020-12-24 17:31:02 -0800230 else if (challengeList.size() >= 1) {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800231 auto item = std::find(challengeList.begin(), challengeList.end(), defaultChallenge);
232 if (item != challengeList.end()) {
233 runChallenge(defaultChallenge);
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700234 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800235 else {
236 // default challenge not available
237 std::cerr << "\n***************************************\n"
238 << "Step " << nStep++
239 << ": CHALLENGE SELECTION" << std::endl;
240 size_t count = 0;
241 std::string choice = "";
242 for (auto item : challengeList) {
243 std::cerr << "> Index: " << count++ << std::endl
244 << ">> Challenge: " << item << std::endl;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700245 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800246 std::cerr << "Please type in the index of the challenge that you want to perform:" << std::endl;
247 size_t inputCount = 0;
248 while (inputCount < 3) {
249 getline(std::cin, choice);
250 try {
251 challengeIndex = std::stoul(choice);
252 }
253 catch (const std::exception&) {
254 std::cerr << "Your input is not valid. Try again:" << std::endl;
255 inputCount++;
256 continue;
257 }
258 if (challengeIndex >= count) {
259 std::cerr << "Your input index is out of range. Try again:" << std::endl;
260 inputCount++;
261 continue;
262 }
263 break;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700264 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800265 if (inputCount == 3) {
266 std::cerr << "Invalid input for too many times, exit. " << std::endl;
267 exit(1);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700268 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800269
270 auto it = challengeList.begin();
271 std::advance(it, challengeIndex);
272 std::cerr << "The challenge has been selected: " << *it << std::endl;
273 runChallenge(*it);
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800274 }
Zhiyi Zhang36706832019-07-04 21:33:03 -0700275 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700276}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800277
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700278static void
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500279infoCb(const Data& reply, const Name& certFullName)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700280{
Zhiyi Zhang997669a2020-10-28 21:15:40 -0700281 optional<CaProfile> profile;
tylerliufeabfdc2020-10-03 15:09:58 -0700282 try {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700283 if (certFullName.empty()) {
tylerliu4140fe82021-01-27 15:45:44 -0800284 profile = Request::onCaProfileResponse(reply);
tylerliufeabfdc2020-10-03 15:09:58 -0700285 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700286 else {
tylerliu4140fe82021-01-27 15:45:44 -0800287 profile = Request::onCaProfileResponseAfterRedirection(reply, certFullName);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700288 }
289 }
290 catch (const std::exception& e) {
291 std::cerr << "The fetched CA information cannot be used because: " << e.what() << std::endl;
292 return;
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700293 }
Zhiyi Zhang6bb1d082020-10-08 14:25:21 -0700294 std::cerr << "\n***************************************\n"
295 << "Step " << nStep++
296 << ": Will use a new trust anchor, please double check the identity info:" << std::endl
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800297 << "> New CA name: " << profile->caPrefix << std::endl
tylerliua7bea662020-10-08 18:51:02 -0700298 << "> This trust anchor information is signed by: " << reply.getSignatureInfo().getKeyLocator() << std::endl
Zhiyi Zhangec4aa3a2021-01-08 14:26:37 -0800299 << "> The certificate: " << *profile->cert << std::endl
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400300 << "Do you trust the information? Type in YES or NO" << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700301
302 std::string answer;
303 getline(std::cin, answer);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700304 boost::algorithm::to_lower(answer);
305 if (answer == "yes") {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800306 std::cerr << "You answered YES: new CA " << profile->caPrefix << " will be used" << std::endl;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700307 runProbe(*profile);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700308 }
309 else {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800310 std::cerr << "You answered NO: new CA " << profile->caPrefix << " will not be used" << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700311 exit(0);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700312 }
313}
314
315static void
tylerliufeabfdc2020-10-03 15:09:58 -0700316probeCb(const Data& reply, CaProfile profile)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700317{
tylerliub47dad72020-10-08 21:36:55 -0700318 std::vector<std::pair<Name, int>> names;
tylerliufeabfdc2020-10-03 15:09:58 -0700319 std::vector<Name> redirects;
tylerliufeabfdc2020-10-03 15:09:58 -0700320 try {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800321 Request::onProbeResponse(reply, profile, names, redirects);
tylerliufeabfdc2020-10-03 15:09:58 -0700322 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800323 catch (const std::exception& e) {
324 std::cerr << "The probed CA response cannot be used because: " << e.what() << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800325 exit(1);
tylerliufeabfdc2020-10-03 15:09:58 -0700326 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800327
328 size_t count = 0;
329 Name selectedName;
330 Name redirectedCaFullName;
331 // always prefer redirection over direct assignment
332 if (redirects.size() > 0) {
333 if (redirects.size() < 2) {
334 redirectedCaFullName = redirects.front();
335 }
336 else {
337 std::cerr << "\n***************************************\n"
338 << "Step " << nStep++
339 << " Choose another trusted CA suggested by the CA: " << std::endl;
340 for (const auto& redirect : redirects) {
341 std::cerr << "> Index: " << count++ << std::endl
342 << ">> Suggested CA: " << ndn::security::extractIdentityFromCertName(redirect.getPrefix(-1))
343 << std::endl;
tylerliud82cc5c2020-12-21 23:58:39 -0800344 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800345 std::cerr << "Please type in the index of your choice:" << std::endl;
346 size_t index = 0;
347 try {
348 std::string input;
349 getline(std::cin, input);
350 index = std::stoul(input);
351 }
352 catch (const std::exception&) {
353 std::cerr << "Your input is Invalid. Exit" << std::endl;
354 exit(1);
355 }
356 if (index >= redirects.size()) {
357 std::cerr << "Your input is not an existing index. Exit" << std::endl;
358 exit(1);
359 }
360 redirectedCaFullName = redirects[index];
tylerliud82cc5c2020-12-21 23:58:39 -0800361 }
Davide Pesavento0dc02012021-11-23 22:55:03 -0500362 auto redirectedCaName = ndn::security::extractIdentityFromCertName(redirectedCaFullName.getPrefix(-1));
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800363 std::cerr << "You will be redirected to CA: " << redirectedCaName << std::endl;
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700364 face.expressInterest(
tylerliu4140fe82021-01-27 15:45:44 -0800365 *Request::genCaProfileDiscoveryInterest(redirectedCaName),
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800366 [&, redirectedCaFullName] (const auto&, const auto& data) {
tylerliu4140fe82021-01-27 15:45:44 -0800367 auto fetchingInterest = Request::genCaProfileInterestFromDiscoveryResponse(data);
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700368 face.expressInterest(*fetchingInterest,
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800369 [=] (const auto&, const auto& data2) { infoCb(data2, redirectedCaFullName); },
370 [] (auto&&...) { onNackCb(); },
371 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700372 },
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500373 [] (auto&&...) { onNackCb(); },
374 [] (auto&&...) { timeoutCb(); });
tylerliufeabfdc2020-10-03 15:09:58 -0700375 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800376 else if (names.size() > 0) {
377 if (names.size() < 2) {
378 selectedName = names.front().first;
379 }
380 else {
381 std::cerr << "\n***************************************\n"
382 << "Step " << nStep++
383 << ": You can either select one of the following names suggested by the CA: " << std::endl;
384 for (const auto& name : names) {
385 std::cerr << "> Index: " << count++ << std::endl
386 << ">> Suggested name: " << name.first << std::endl
387 << ">> Corresponding max suffix length: " << name.second << std::endl;
388 }
389 std::cerr << "Please type in the index of your choice:" << std::endl;
390 size_t index = 0;
391 try {
392 std::string input;
393 getline(std::cin, input);
394 index = std::stoul(input);
395 }
396 catch (const std::exception&) {
397 std::cerr << "Your input is invalid. Exit" << std::endl;
398 exit(1);
399 }
400 if (index >= names.size()) {
401 std::cerr << "Your input is not an existing index. Exit" << std::endl;
402 exit(1);
403 }
404 selectedName = names[index].first;
405 }
406 std::cerr << "You are applying for name: " << selectedName << std::endl;
407 runNew(profile, selectedName);
408 }
409 else {
410 std::cerr << "Neither name assignment nor redirection is available, exit." << std::endl;
411 exit(1);
412 }
tylerliufeabfdc2020-10-03 15:09:58 -0700413}
414
415static void
416selectCaProfile(std::string configFilePath)
417{
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700418 ProfileStorage profileStorage;
tylerliufeabfdc2020-10-03 15:09:58 -0700419 try {
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700420 profileStorage.load(configFilePath);
tylerliufeabfdc2020-10-03 15:09:58 -0700421 }
422 catch (const std::exception& e) {
423 std::cerr << "Cannot load the configuration file: " << e.what() << std::endl;
424 exit(1);
425 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700426 size_t count = 0;
427 std::cerr << "***************************************\n"
428 << "Step " << nStep++ << ": CA SELECTION" << std::endl;
Zhiyi Zhang84e11842020-11-19 20:03:23 -0800429 for (auto item : profileStorage.getKnownProfiles()) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700430 std::cerr << "> Index: " << count++ << std::endl
Zhiyi Zhang44c6a352020-12-14 10:57:17 -0800431 << ">> CA prefix:" << item.caPrefix << std::endl
432 << ">> Introduction: " << item.caInfo << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700433 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700434 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 -0700435
Zhiyi Zhang36706832019-07-04 21:33:03 -0700436 std::string caIndexS, caIndexSLower;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700437 getline(std::cin, caIndexS);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700438 caIndexSLower = caIndexS;
439 boost::algorithm::to_lower(caIndexSLower);
440 if (caIndexSLower == "none") {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700441 std::cerr << "\n***************************************\n"
442 << "Step " << nStep << ": ADD NEW CA\nPlease type in the CA's Name:" << std::endl;
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700443 std::string expectedCAName;
444 getline(std::cin, expectedCAName);
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700445 face.expressInterest(
tylerliu4140fe82021-01-27 15:45:44 -0800446 *Request::genCaProfileDiscoveryInterest(Name(expectedCAName)),
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500447 [&] (const auto&, const auto& data) {
tylerliu4140fe82021-01-27 15:45:44 -0800448 auto fetchingInterest = Request::genCaProfileInterestFromDiscoveryResponse(data);
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700449 face.expressInterest(*fetchingInterest,
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500450 [] (const auto&, const auto& data2) { infoCb(data2, {}); },
451 [] (auto&&...) { onNackCb(); },
452 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700453 },
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500454 [] (auto&&...) { onNackCb(); },
455 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700456 }
457 else {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700458 size_t caIndex;
Zhiyi Zhang36706832019-07-04 21:33:03 -0700459 try {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700460 caIndex = std::stoul(caIndexS);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700461 }
Davide Pesavento0dc02012021-11-23 22:55:03 -0500462 catch (const std::exception&) {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700463 std::cerr << "Your input is neither NONE nor a valid index. Exit" << std::endl;
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800464 exit(1);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700465 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700466 if (caIndex >= count) {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700467 std::cerr << "Your input is not an existing index. Exit" << std::endl;
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800468 exit(1);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700469 }
Zhiyi Zhang84e11842020-11-19 20:03:23 -0800470 auto itemIterator = profileStorage.getKnownProfiles().cbegin();
tylerliufeabfdc2020-10-03 15:09:58 -0700471 std::advance(itemIterator, caIndex);
472 auto targetCaItem = *itemIterator;
473 runProbe(targetCaItem);
474 }
475}
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700476
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700477static void
478runProbe(CaProfile profile)
tylerliufeabfdc2020-10-03 15:09:58 -0700479{
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800480 if (!capturedProbeParams) {
481 std::cerr << "\n***************************************\n"
482 << "Step " << nStep++ << ": Please provide information for name assignment" << std::endl;
483 auto captured = captureParams(profile.probeParameterKeys);
484 capturedProbeParams = std::make_shared<std::multimap<std::string, std::string>>(captured);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700485 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800486 face.expressInterest(*Request::genProbeInterest(profile, std::move(*capturedProbeParams)),
487 [profile] (const auto&, const auto& data) { probeCb(data, profile); },
488 [] (auto&&...) { onNackCb(); },
489 [] (auto&&...) { timeoutCb(); });
tylerliufeabfdc2020-10-03 15:09:58 -0700490}
491
492static void
493runNew(CaProfile profile, Name identityName)
494{
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800495 int validityPeriod = captureValidityPeriod(time::duration_cast<time::hours>(profile.maxValidityPeriod));
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700496 auto now = time::system_clock::now();
497 std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
tylerliu4140fe82021-01-27 15:45:44 -0800498 requesterState = std::make_shared<Request>(keyChain, profile, RequestType::NEW);
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800499
500 // generate a newly key pair or choose an existing key
501 const auto& pib = keyChain.getPib();
502 ndn::security::pib::Identity identity;
503 ndn::security::pib::Key defaultKey;
504 try {
505 identity = pib.getIdentity(identityName);
506 }
507 catch (const ndn::security::Pib::Error&) {
508 identity = keyChain.createIdentity(identityName);
509 newlyCreatedIdentityName = identity.getName();
510 }
511 try {
512 defaultKey = identity.getDefaultKey();
513 }
514 catch (const ndn::security::Pib::Error&) {
515 defaultKey = keyChain.createKey(identity);
516 newlyCreatedKeyName = defaultKey.getName();
517 }
518
519 Name keyName;
520 if (newlyCreatedIdentityName.empty()) {
521 keyName = captureKeyName(identity, defaultKey);
522 }
523 else {
524 keyName = defaultKey.getName();
525 }
526 auto interest = requesterState->genNewInterest(keyName, now, now + time::hours(validityPeriod));
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700527 if (interest != nullptr) {
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500528 face.expressInterest(*interest,
529 [] (const auto&, const auto& data) { newCb(data); },
530 [] (auto&&...) { onNackCb(); },
531 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700532 }
533 else {
534 std::cerr << "Cannot generate the Interest for NEW step. Exit" << std::endl;
535 }
tylerliufeabfdc2020-10-03 15:09:58 -0700536}
537
538static void
539runChallenge(const std::string& challengeType)
540{
tylerliu40226332020-11-11 15:37:16 -0800541 std::multimap<std::string, std::string> requirement;
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700542 try {
tylerliu4140fe82021-01-27 15:45:44 -0800543 requirement = requesterState->selectOrContinueChallenge(challengeType);
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700544 }
545 catch (const std::exception& e) {
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500546 std::cerr << "Error. Cannot successfully load the Challenge Module with error: " << e.what()
547 << "\nExit." << std::endl;
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700548 exit(1);
549 }
tylerliufeabfdc2020-10-03 15:09:58 -0700550 if (requirement.size() > 0) {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800551 if (requesterState->m_status == Status::BEFORE_CHALLENGE && challengeType == defaultChallenge) {
552 requirement.find(challengeType)->second = capturedProbeParams->find(defaultChallenge)->second;
553 }
554 else {
555 std::cerr << "\n***************************************\n"
556 << "Step " << nStep
557 << ": Please provide parameters used for Identity Verification Challenge" << std::endl;
558 captureParams(requirement);
559 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700560 }
tylerliu4140fe82021-01-27 15:45:44 -0800561 face.expressInterest(*requesterState->genChallengeInterest(std::move(requirement)),
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500562 [] (const auto&, const auto& data) { challengeCb(data); },
563 [] (auto&&...) { onNackCb(); },
564 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700565}
566
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700567static void
568handleSignal(const boost::system::error_code& error, int signalNum)
569{
570 if (error) {
571 return;
572 }
573 const char* signalName = ::strsignal(signalNum);
574 std::cerr << "Exiting on signal ";
575 if (signalName == nullptr) {
576 std::cerr << signalNum;
577 }
578 else {
579 std::cerr << signalName;
580 }
581 std::cerr << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700582 if (requesterState) {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800583 if (!newlyCreatedIdentityName.empty()) {
584 auto identity = keyChain.getPib().getIdentity(newlyCreatedIdentityName);
585 keyChain.deleteIdentity(identity);
586 }
587 else if (!newlyCreatedKeyName.empty()) {
588 auto identity = keyChain.getPib().getIdentity(ndn::security::extractIdentityFromKeyName(newlyCreatedKeyName));
589 keyChain.deleteKey(identity, identity.getKey(newlyCreatedKeyName));
590 }
tylerliufeabfdc2020-10-03 15:09:58 -0700591 }
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700592 face.getIoService().stop();
tylerliufeabfdc2020-10-03 15:09:58 -0700593 exit(1);
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700594}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800595
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500596static int
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800597main(int argc, char* argv[])
598{
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700599 boost::asio::signal_set terminateSignals(face.getIoService());
600 terminateSignals.add(SIGINT);
601 terminateSignals.add(SIGTERM);
602 terminateSignals.async_wait(handleSignal);
603
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800604 namespace po = boost::program_options;
Zhiyi Zhang840afd92020-10-21 13:24:08 -0700605 std::string configFilePath = std::string(NDNCERT_SYSCONFDIR) + "/ndncert/client.conf";
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500606 po::options_description description("Usage: ndncert-client [-h] [-c FILE]\n");
607 description.add_options()
608 ("help,h", "produce help message")
609 ("config-file,c", po::value<std::string>(&configFilePath), "configuration file name")
610 ;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800611 po::positional_options_description p;
612
613 po::variables_map vm;
614 try {
615 po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm);
616 po::notify(vm);
617 }
618 catch (const std::exception& e) {
619 std::cerr << "ERROR: " << e.what() << std::endl;
620 return 1;
621 }
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500622
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800623 if (vm.count("help") != 0) {
624 std::cerr << description << std::endl;
625 return 0;
626 }
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500627
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700628 selectCaProfile(configFilePath);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800629 face.processEvents();
630 return 0;
631}
632
Zhiyi Zhang3002e6b2020-10-29 18:54:07 -0700633} // namespace requester
Zhiyi Zhange4891b72020-10-10 15:11:57 -0700634} // namespace ndncert
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800635
Zhiyi Zhang48f23782020-09-28 12:11:24 -0700636int
637main(int argc, char* argv[])
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800638{
Davide Pesavento0dc02012021-11-23 22:55:03 -0500639 return ndncert::requester::main(argc, argv);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800640}