blob: ee22db5a3f7cdf671274e3d2da0d5daf181b7798 [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
Davide Pesavento0d1d11c2022-04-11 22:11:34 -040034namespace ndncert::requester {
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080035
Zhiyi Zhang48f23782020-09-28 12:11:24 -070036static void
Davide Pesavento0d1d11c2022-04-11 22:11:34 -040037selectCaProfile(const std::string& configFilePath);
Davide Pesaventoe5b43692021-11-15 22:05:03 -050038
tylerliufeabfdc2020-10-03 15:09:58 -070039static void
40runProbe(CaProfile profile);
Davide Pesaventoe5b43692021-11-15 22:05:03 -050041
tylerliufeabfdc2020-10-03 15:09:58 -070042static void
43runNew(CaProfile profile, Name identityName);
Davide Pesaventoe5b43692021-11-15 22:05:03 -050044
tylerliufeabfdc2020-10-03 15:09:58 -070045static void
46runChallenge(const std::string& challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070047
Davide Pesaventoe5b43692021-11-15 22:05:03 -050048static size_t nStep = 1;
Tianyuan Yuca23bb02022-03-09 14:09:14 -080049static const std::string defaultChallenge = "email";
Davide Pesavento0dc02012021-11-23 22:55:03 -050050static ndn::Face face;
51static ndn::KeyChain keyChain;
52static std::shared_ptr<Request> requesterState;
Tianyuan Yuca23bb02022-03-09 14:09:14 -080053static std::shared_ptr<std::multimap<std::string, std::string>> capturedProbeParams;
54static Name newlyCreatedIdentityName;
55static Name newlyCreatedKeyName;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080056
Zhiyi Zhang46049832020-09-28 17:08:12 -070057static void
tylerliu40226332020-11-11 15:37:16 -080058captureParams(std::multimap<std::string, std::string>& requirement)
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080059{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070060 std::list<std::string> results;
Zhiyi Zhang46049832020-09-28 17:08:12 -070061 for (auto& item : requirement) {
62 std::cerr << std::get<1>(item) << std::endl;
63 std::string captured;
64 getline(std::cin, captured);
65 std::get<1>(item) = captured;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080066 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070067 std::cerr << "Got it. This is what you've provided:" << std::endl;
Zhiyi Zhang46049832020-09-28 17:08:12 -070068 for (const auto& item : requirement) {
69 std::cerr << std::get<0>(item) << " : " << std::get<1>(item) << std::endl;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080070 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070071}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080072
tylerliu40226332020-11-11 15:37:16 -080073static std::multimap<std::string, std::string>
Zhiyi Zhang2de4ea32020-12-13 17:45:25 -080074captureParams(const std::vector<std::string>& requirement)
Zhiyi Zhang547c8512019-06-18 23:46:14 -070075{
tylerliu40226332020-11-11 15:37:16 -080076 std::multimap<std::string, std::string> results;
tylerliufeabfdc2020-10-03 15:09:58 -070077 for (const auto& r : requirement) {
tylerliu40226332020-11-11 15:37:16 -080078 results.emplace(r, "Please input: " + r);
Zhiyi Zhang547c8512019-06-18 23:46:14 -070079 }
tylerliufeabfdc2020-10-03 15:09:58 -070080 captureParams(results);
Zhiyi Zhang547c8512019-06-18 23:46:14 -070081 return results;
82}
83
tylerliufeabfdc2020-10-03 15:09:58 -070084static int
Tianyuan Yuca23bb02022-03-09 14:09:14 -080085captureValidityPeriod(time::hours maxValidityPeriod)
Zhiyi Zhang36706832019-07-04 21:33:03 -070086{
Zhiyi Zhang837406d2020-10-05 22:01:31 -070087 std::cerr << "\n***************************************\n"
88 << "Step " << nStep++
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -070089 << ": Please type in your expected validity period of your certificate."
90 << " Type the number of hours (168 for week, 730 for month, 8760 for year)."
Tianyuan Yuca23bb02022-03-09 14:09:14 -080091 << " The CA may reject your application if your expected period is too long."
92 << " The maximum validity period allowed by this CA is " << maxValidityPeriod << "."<< std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -080093 size_t count = 0;
Davide Pesavento0d1d11c2022-04-11 22:11:34 -040094 while (count < 3) {
tylerliufeabfdc2020-10-03 15:09:58 -070095 std::string periodStr = "";
96 getline(std::cin, periodStr);
97 try {
Zhiyi Zhang837406d2020-10-05 22:01:31 -070098 return std::stoul(periodStr);
tylerliufeabfdc2020-10-03 15:09:58 -070099 }
Davide Pesavento0dc02012021-11-23 22:55:03 -0500100 catch (const std::exception&) {
tylerliufeabfdc2020-10-03 15:09:58 -0700101 std::cerr << "Your input is invalid. Try again: " << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800102 count++;
tylerliufeabfdc2020-10-03 15:09:58 -0700103 }
Zhiyi Zhang36706832019-07-04 21:33:03 -0700104 }
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800105 std::cerr << "Invalid input for too many times, exit. " << std::endl;
106 exit(1);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700107}
108
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800109static Name
110captureKeyName(ndn::security::pib::Identity& identity, ndn::security::pib::Key& defaultKey)
111{
112 size_t count = 0;
113 std::cerr << "***************************************\n"
114 << "Step " << nStep++ << ": KEY SELECTION" << std::endl;
115 for (const auto& key : identity.getKeys()) {
116 std::cerr << "> Index: " << count++ << std::endl
117 << ">> Key Name:";
118 if (key == defaultKey) {
119 std::cerr << " +->* ";
120 }
121 else {
122 std::cerr << " +-> ";
123 }
124 std::cerr << key.getName() << std::endl;
125 }
126
127 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";
128 std::string indexStr = "";
129 std::string indexStrLower = "";
130 size_t keyIndex;
131 getline(std::cin, indexStr);
132
133 indexStrLower = indexStr;
134 boost::algorithm::to_lower(indexStrLower);
135 if (indexStrLower == "new") {
136 auto newlyCreatedKey = keyChain.createKey(identity);
137 newlyCreatedKeyName = newlyCreatedKey.getName();
138 std::cerr << "New key generated: " << newlyCreatedKeyName << std::endl;
139 return newlyCreatedKeyName;
140 }
141 else {
142 try {
143 keyIndex = std::stoul(indexStr);
144 }
145 catch (const std::exception&) {
146 std::cerr << "Your input is neither NEW nor a valid index. Exit" << std::endl;
147 exit(1);
148 }
149
150 if (keyIndex >= count) {
151 std::cerr << "Your input is not an existing index. Exit" << std::endl;
152 exit(1);
153 }
154 else {
155 auto itemIterator = identity.getKeys().begin();
156 std::advance(itemIterator, keyIndex);
157 auto targetKeyItem = *itemIterator;
158 return targetKeyItem.getName();
159 }
160 }
161}
162
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400163[[noreturn]] static void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700164onNackCb()
165{
166 std::cerr << "Got NACK\n";
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800167 exit(1);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700168}
169
170static void
171timeoutCb()
172{
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400173 std::cerr << "Interest timeout\n";
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700174}
175
176static void
swa770cf1d8f72020-04-21 23:12:39 -0700177certFetchCb(const Data& reply)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700178{
tylerliu4140fe82021-01-27 15:45:44 -0800179 auto item = Request::onCertFetchResponse(reply);
tylerliufeabfdc2020-10-03 15:09:58 -0700180 if (item) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700181 keyChain.addCertificate(keyChain.getPib().getIdentity(item->getIdentity()).getKey(item->getKeyName()), *item);
tylerliufeabfdc2020-10-03 15:09:58 -0700182 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700183 std::cerr << "\n***************************************\n"
184 << "Step " << nStep++
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800185 << ": DONE\nCertificate with Name: " << reply.getName()
186 << " has been installed to your local keychain\n"
187 << "Exit now" << std::endl;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700188 face.getIoService().stop();
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700189}
190
191static void
192challengeCb(const Data& reply)
193{
tylerliufeabfdc2020-10-03 15:09:58 -0700194 try {
tylerliu4140fe82021-01-27 15:45:44 -0800195 requesterState->onChallengeResponse(reply);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700196 }
197 catch (const std::exception& e) {
tylerliufeabfdc2020-10-03 15:09:58 -0700198 std::cerr << "Error when decoding challenge step: " << e.what() << std::endl;
199 exit(1);
200 }
Zhiyi Zhang6499edd2021-02-17 22:37:21 -0800201 if (requesterState->m_status == Status::SUCCESS) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700202 std::cerr << "Certificate has already been issued, downloading certificate..." << std::endl;
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500203 face.expressInterest(*requesterState->genCertFetchInterest(),
204 [] (const auto&, const auto& data) { certFetchCb(data); },
205 [] (auto&&...) { onNackCb(); },
206 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700207 return;
208 }
Zhiyi Zhang6499edd2021-02-17 22:37:21 -0800209 runChallenge(requesterState->m_challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700210}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800211
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700212static void
213newCb(const Data& reply)
214{
tylerliufeabfdc2020-10-03 15:09:58 -0700215 std::list<std::string> challengeList;
216 try {
tylerliu4140fe82021-01-27 15:45:44 -0800217 challengeList = requesterState->onNewRenewRevokeResponse(reply);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700218 }
219 catch (const std::exception& e) {
tylerliufeabfdc2020-10-03 15:09:58 -0700220 std::cerr << "Error on decoding NEW step reply because: " << e.what() << std::endl;
221 exit(1);
222 }
223
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700224 size_t challengeIndex = 0;
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400225 if (challengeList.empty()) {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700226 std::cerr << "There is no available challenge provided by the CA. Exit" << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700227 exit(1);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800228 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800229
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400230 auto item = std::find(challengeList.begin(), challengeList.end(), defaultChallenge);
231 if (item != challengeList.end()) {
232 runChallenge(defaultChallenge);
233 }
234 else {
235 // default challenge not available
236 std::cerr << "\n***************************************\n"
237 << "Step " << nStep++
238 << ": CHALLENGE SELECTION" << std::endl;
239 size_t count = 0;
240 std::string choice = "";
241 for (const auto& item : challengeList) {
242 std::cerr << "> Index: " << count++ << std::endl
243 << ">> Challenge: " << item << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800244 }
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400245 std::cerr << "Please type in the index of the challenge that you want to perform:" << std::endl;
246 size_t inputCount = 0;
247 while (inputCount < 3) {
248 getline(std::cin, choice);
249 try {
250 challengeIndex = std::stoul(choice);
251 }
252 catch (const std::exception&) {
253 std::cerr << "Your input is not valid. Try again:" << std::endl;
254 inputCount++;
255 continue;
256 }
257 if (challengeIndex >= count) {
258 std::cerr << "Your input index is out of range. Try again:" << std::endl;
259 inputCount++;
260 continue;
261 }
262 break;
263 }
264 if (inputCount == 3) {
265 std::cerr << "Invalid input for too many times, exit. " << std::endl;
266 exit(1);
267 }
268
269 auto it = challengeList.begin();
270 std::advance(it, challengeIndex);
271 std::cerr << "The challenge has been selected: " << *it << std::endl;
272 runChallenge(*it);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700273 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700274}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800275
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700276static void
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500277infoCb(const Data& reply, const Name& certFullName)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700278{
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400279 std::optional<CaProfile> profile;
tylerliufeabfdc2020-10-03 15:09:58 -0700280 try {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700281 if (certFullName.empty()) {
tylerliu4140fe82021-01-27 15:45:44 -0800282 profile = Request::onCaProfileResponse(reply);
tylerliufeabfdc2020-10-03 15:09:58 -0700283 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700284 else {
tylerliu4140fe82021-01-27 15:45:44 -0800285 profile = Request::onCaProfileResponseAfterRedirection(reply, certFullName);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700286 }
287 }
288 catch (const std::exception& e) {
289 std::cerr << "The fetched CA information cannot be used because: " << e.what() << std::endl;
290 return;
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700291 }
Zhiyi Zhang6bb1d082020-10-08 14:25:21 -0700292 std::cerr << "\n***************************************\n"
293 << "Step " << nStep++
294 << ": Will use a new trust anchor, please double check the identity info:" << std::endl
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800295 << "> New CA name: " << profile->caPrefix << std::endl
tylerliua7bea662020-10-08 18:51:02 -0700296 << "> This trust anchor information is signed by: " << reply.getSignatureInfo().getKeyLocator() << std::endl
Zhiyi Zhangec4aa3a2021-01-08 14:26:37 -0800297 << "> The certificate: " << *profile->cert << std::endl
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400298 << "Do you trust the information? Type in YES or NO" << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700299
300 std::string answer;
301 getline(std::cin, answer);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700302 boost::algorithm::to_lower(answer);
303 if (answer == "yes") {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800304 std::cerr << "You answered YES: new CA " << profile->caPrefix << " will be used" << std::endl;
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700305 runProbe(*profile);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700306 }
307 else {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800308 std::cerr << "You answered NO: new CA " << profile->caPrefix << " will not be used" << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700309 exit(0);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700310 }
311}
312
313static void
tylerliufeabfdc2020-10-03 15:09:58 -0700314probeCb(const Data& reply, CaProfile profile)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700315{
tylerliub47dad72020-10-08 21:36:55 -0700316 std::vector<std::pair<Name, int>> names;
tylerliufeabfdc2020-10-03 15:09:58 -0700317 std::vector<Name> redirects;
tylerliufeabfdc2020-10-03 15:09:58 -0700318 try {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800319 Request::onProbeResponse(reply, profile, names, redirects);
tylerliufeabfdc2020-10-03 15:09:58 -0700320 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800321 catch (const std::exception& e) {
322 std::cerr << "The probed CA response cannot be used because: " << e.what() << std::endl;
Zhiyi Zhang87ded732021-01-08 14:05:24 -0800323 exit(1);
tylerliufeabfdc2020-10-03 15:09:58 -0700324 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800325
326 size_t count = 0;
327 Name selectedName;
328 Name redirectedCaFullName;
329 // always prefer redirection over direct assignment
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400330 if (!redirects.empty()) {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800331 if (redirects.size() < 2) {
332 redirectedCaFullName = redirects.front();
333 }
334 else {
335 std::cerr << "\n***************************************\n"
336 << "Step " << nStep++
337 << " Choose another trusted CA suggested by the CA: " << std::endl;
338 for (const auto& redirect : redirects) {
339 std::cerr << "> Index: " << count++ << std::endl
340 << ">> Suggested CA: " << ndn::security::extractIdentityFromCertName(redirect.getPrefix(-1))
341 << std::endl;
tylerliud82cc5c2020-12-21 23:58:39 -0800342 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800343 std::cerr << "Please type in the index of your choice:" << std::endl;
344 size_t index = 0;
345 try {
346 std::string input;
347 getline(std::cin, input);
348 index = std::stoul(input);
349 }
350 catch (const std::exception&) {
351 std::cerr << "Your input is Invalid. Exit" << std::endl;
352 exit(1);
353 }
354 if (index >= redirects.size()) {
355 std::cerr << "Your input is not an existing index. Exit" << std::endl;
356 exit(1);
357 }
358 redirectedCaFullName = redirects[index];
tylerliud82cc5c2020-12-21 23:58:39 -0800359 }
Davide Pesavento0dc02012021-11-23 22:55:03 -0500360 auto redirectedCaName = ndn::security::extractIdentityFromCertName(redirectedCaFullName.getPrefix(-1));
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800361 std::cerr << "You will be redirected to CA: " << redirectedCaName << std::endl;
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700362 face.expressInterest(
tylerliu4140fe82021-01-27 15:45:44 -0800363 *Request::genCaProfileDiscoveryInterest(redirectedCaName),
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800364 [&, redirectedCaFullName] (const auto&, const auto& data) {
tylerliu4140fe82021-01-27 15:45:44 -0800365 auto fetchingInterest = Request::genCaProfileInterestFromDiscoveryResponse(data);
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700366 face.expressInterest(*fetchingInterest,
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800367 [=] (const auto&, const auto& data2) { infoCb(data2, redirectedCaFullName); },
368 [] (auto&&...) { onNackCb(); },
369 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700370 },
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500371 [] (auto&&...) { onNackCb(); },
372 [] (auto&&...) { timeoutCb(); });
tylerliufeabfdc2020-10-03 15:09:58 -0700373 }
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400374 else if (!names.empty()) {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800375 if (names.size() < 2) {
376 selectedName = names.front().first;
377 }
378 else {
379 std::cerr << "\n***************************************\n"
380 << "Step " << nStep++
381 << ": You can either select one of the following names suggested by the CA: " << std::endl;
382 for (const auto& name : names) {
383 std::cerr << "> Index: " << count++ << std::endl
384 << ">> Suggested name: " << name.first << std::endl
385 << ">> Corresponding max suffix length: " << name.second << std::endl;
386 }
387 std::cerr << "Please type in the index of your choice:" << std::endl;
388 size_t index = 0;
389 try {
390 std::string input;
391 getline(std::cin, input);
392 index = std::stoul(input);
393 }
394 catch (const std::exception&) {
395 std::cerr << "Your input is invalid. Exit" << std::endl;
396 exit(1);
397 }
398 if (index >= names.size()) {
399 std::cerr << "Your input is not an existing index. Exit" << std::endl;
400 exit(1);
401 }
402 selectedName = names[index].first;
403 }
404 std::cerr << "You are applying for name: " << selectedName << std::endl;
405 runNew(profile, selectedName);
406 }
407 else {
408 std::cerr << "Neither name assignment nor redirection is available, exit." << std::endl;
409 exit(1);
410 }
tylerliufeabfdc2020-10-03 15:09:58 -0700411}
412
413static void
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400414selectCaProfile(const std::string& configFilePath)
tylerliufeabfdc2020-10-03 15:09:58 -0700415{
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700416 ProfileStorage profileStorage;
tylerliufeabfdc2020-10-03 15:09:58 -0700417 try {
Zhiyi Zhanga16b7582020-10-29 18:59:46 -0700418 profileStorage.load(configFilePath);
tylerliufeabfdc2020-10-03 15:09:58 -0700419 }
420 catch (const std::exception& e) {
421 std::cerr << "Cannot load the configuration file: " << e.what() << std::endl;
422 exit(1);
423 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700424 size_t count = 0;
425 std::cerr << "***************************************\n"
426 << "Step " << nStep++ << ": CA SELECTION" << std::endl;
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400427 for (const auto& item : profileStorage.getKnownProfiles()) {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700428 std::cerr << "> Index: " << count++ << std::endl
Zhiyi Zhang44c6a352020-12-14 10:57:17 -0800429 << ">> CA prefix:" << item.caPrefix << std::endl
430 << ">> Introduction: " << item.caInfo << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700431 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700432 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 -0700433
Zhiyi Zhang36706832019-07-04 21:33:03 -0700434 std::string caIndexS, caIndexSLower;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700435 getline(std::cin, caIndexS);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700436 caIndexSLower = caIndexS;
437 boost::algorithm::to_lower(caIndexSLower);
438 if (caIndexSLower == "none") {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700439 std::cerr << "\n***************************************\n"
440 << "Step " << nStep << ": ADD NEW CA\nPlease type in the CA's Name:" << std::endl;
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700441 std::string expectedCAName;
442 getline(std::cin, expectedCAName);
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700443 face.expressInterest(
tylerliu4140fe82021-01-27 15:45:44 -0800444 *Request::genCaProfileDiscoveryInterest(Name(expectedCAName)),
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500445 [&] (const auto&, const auto& data) {
tylerliu4140fe82021-01-27 15:45:44 -0800446 auto fetchingInterest = Request::genCaProfileInterestFromDiscoveryResponse(data);
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700447 face.expressInterest(*fetchingInterest,
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500448 [] (const auto&, const auto& data2) { infoCb(data2, {}); },
449 [] (auto&&...) { onNackCb(); },
450 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhangfbcab842020-10-07 15:17:13 -0700451 },
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500452 [] (auto&&...) { onNackCb(); },
453 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700454 }
455 else {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700456 size_t caIndex;
Zhiyi Zhang36706832019-07-04 21:33:03 -0700457 try {
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700458 caIndex = std::stoul(caIndexS);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700459 }
Davide Pesavento0dc02012021-11-23 22:55:03 -0500460 catch (const std::exception&) {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700461 std::cerr << "Your input is neither NONE nor a valid index. Exit" << std::endl;
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800462 exit(1);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700463 }
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700464 if (caIndex >= count) {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700465 std::cerr << "Your input is not an existing index. Exit" << std::endl;
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800466 exit(1);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700467 }
Zhiyi Zhang84e11842020-11-19 20:03:23 -0800468 auto itemIterator = profileStorage.getKnownProfiles().cbegin();
tylerliufeabfdc2020-10-03 15:09:58 -0700469 std::advance(itemIterator, caIndex);
470 auto targetCaItem = *itemIterator;
471 runProbe(targetCaItem);
472 }
473}
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700474
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700475static void
476runProbe(CaProfile profile)
tylerliufeabfdc2020-10-03 15:09:58 -0700477{
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800478 if (!capturedProbeParams) {
479 std::cerr << "\n***************************************\n"
480 << "Step " << nStep++ << ": Please provide information for name assignment" << std::endl;
481 auto captured = captureParams(profile.probeParameterKeys);
Tianyuan Yub5d3a4f2022-03-11 17:03:24 -0800482 auto it = captured.find(defaultChallenge);
483 if (it != captured.end()) {
484 it->second = boost::algorithm::to_lower_copy(it->second);
485 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800486 capturedProbeParams = std::make_shared<std::multimap<std::string, std::string>>(captured);
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700487 }
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800488 face.expressInterest(*Request::genProbeInterest(profile, std::move(*capturedProbeParams)),
489 [profile] (const auto&, const auto& data) { probeCb(data, profile); },
490 [] (auto&&...) { onNackCb(); },
491 [] (auto&&...) { timeoutCb(); });
tylerliufeabfdc2020-10-03 15:09:58 -0700492}
493
494static void
495runNew(CaProfile profile, Name identityName)
496{
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800497 int validityPeriod = captureValidityPeriod(time::duration_cast<time::hours>(profile.maxValidityPeriod));
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700498 auto now = time::system_clock::now();
499 std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
tylerliu4140fe82021-01-27 15:45:44 -0800500 requesterState = std::make_shared<Request>(keyChain, profile, RequestType::NEW);
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800501
502 // generate a newly key pair or choose an existing key
503 const auto& pib = keyChain.getPib();
504 ndn::security::pib::Identity identity;
505 ndn::security::pib::Key defaultKey;
506 try {
507 identity = pib.getIdentity(identityName);
508 }
509 catch (const ndn::security::Pib::Error&) {
510 identity = keyChain.createIdentity(identityName);
511 newlyCreatedIdentityName = identity.getName();
512 }
513 try {
514 defaultKey = identity.getDefaultKey();
515 }
516 catch (const ndn::security::Pib::Error&) {
517 defaultKey = keyChain.createKey(identity);
518 newlyCreatedKeyName = defaultKey.getName();
519 }
520
521 Name keyName;
522 if (newlyCreatedIdentityName.empty()) {
523 keyName = captureKeyName(identity, defaultKey);
524 }
525 else {
526 keyName = defaultKey.getName();
527 }
528 auto interest = requesterState->genNewInterest(keyName, now, now + time::hours(validityPeriod));
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700529 if (interest != nullptr) {
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500530 face.expressInterest(*interest,
531 [] (const auto&, const auto& data) { newCb(data); },
532 [] (auto&&...) { onNackCb(); },
533 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700534 }
535 else {
536 std::cerr << "Cannot generate the Interest for NEW step. Exit" << std::endl;
537 }
tylerliufeabfdc2020-10-03 15:09:58 -0700538}
539
540static void
541runChallenge(const std::string& challengeType)
542{
tylerliu40226332020-11-11 15:37:16 -0800543 std::multimap<std::string, std::string> requirement;
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700544 try {
tylerliu4140fe82021-01-27 15:45:44 -0800545 requirement = requesterState->selectOrContinueChallenge(challengeType);
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700546 }
547 catch (const std::exception& e) {
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500548 std::cerr << "Error. Cannot successfully load the Challenge Module with error: " << e.what()
549 << "\nExit." << std::endl;
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700550 exit(1);
551 }
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400552 if (!requirement.empty()) {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800553 if (requesterState->m_status == Status::BEFORE_CHALLENGE && challengeType == defaultChallenge) {
554 requirement.find(challengeType)->second = capturedProbeParams->find(defaultChallenge)->second;
555 }
556 else {
557 std::cerr << "\n***************************************\n"
558 << "Step " << nStep
559 << ": Please provide parameters used for Identity Verification Challenge" << std::endl;
560 captureParams(requirement);
561 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700562 }
tylerliu4140fe82021-01-27 15:45:44 -0800563 face.expressInterest(*requesterState->genChallengeInterest(std::move(requirement)),
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500564 [] (const auto&, const auto& data) { challengeCb(data); },
565 [] (auto&&...) { onNackCb(); },
566 [] (auto&&...) { timeoutCb(); });
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700567}
568
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700569static void
570handleSignal(const boost::system::error_code& error, int signalNum)
571{
572 if (error) {
573 return;
574 }
575 const char* signalName = ::strsignal(signalNum);
576 std::cerr << "Exiting on signal ";
577 if (signalName == nullptr) {
578 std::cerr << signalNum;
579 }
580 else {
581 std::cerr << signalName;
582 }
583 std::cerr << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700584 if (requesterState) {
Tianyuan Yuca23bb02022-03-09 14:09:14 -0800585 if (!newlyCreatedIdentityName.empty()) {
586 auto identity = keyChain.getPib().getIdentity(newlyCreatedIdentityName);
587 keyChain.deleteIdentity(identity);
588 }
589 else if (!newlyCreatedKeyName.empty()) {
590 auto identity = keyChain.getPib().getIdentity(ndn::security::extractIdentityFromKeyName(newlyCreatedKeyName));
591 keyChain.deleteKey(identity, identity.getKey(newlyCreatedKeyName));
592 }
tylerliufeabfdc2020-10-03 15:09:58 -0700593 }
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700594 face.getIoService().stop();
tylerliufeabfdc2020-10-03 15:09:58 -0700595 exit(1);
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700596}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800597
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500598static int
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800599main(int argc, char* argv[])
600{
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700601 boost::asio::signal_set terminateSignals(face.getIoService());
602 terminateSignals.add(SIGINT);
603 terminateSignals.add(SIGTERM);
604 terminateSignals.async_wait(handleSignal);
605
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800606 namespace po = boost::program_options;
Zhiyi Zhang840afd92020-10-21 13:24:08 -0700607 std::string configFilePath = std::string(NDNCERT_SYSCONFDIR) + "/ndncert/client.conf";
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500608 po::options_description description("Usage: ndncert-client [-h] [-c FILE]\n");
609 description.add_options()
610 ("help,h", "produce help message")
611 ("config-file,c", po::value<std::string>(&configFilePath), "configuration file name")
612 ;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800613 po::positional_options_description p;
614
615 po::variables_map vm;
616 try {
617 po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm);
618 po::notify(vm);
619 }
620 catch (const std::exception& e) {
621 std::cerr << "ERROR: " << e.what() << std::endl;
622 return 1;
623 }
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500624
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800625 if (vm.count("help") != 0) {
626 std::cerr << description << std::endl;
627 return 0;
628 }
Davide Pesaventoe5b43692021-11-15 22:05:03 -0500629
Zhiyi Zhang837406d2020-10-05 22:01:31 -0700630 selectCaProfile(configFilePath);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800631 face.processEvents();
632 return 0;
633}
634
Davide Pesavento0d1d11c2022-04-11 22:11:34 -0400635} // namespace ndncert::requester
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800636
Zhiyi Zhang48f23782020-09-28 12:11:24 -0700637int
638main(int argc, char* argv[])
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800639{
Davide Pesavento0dc02012021-11-23 22:55:03 -0500640 return ndncert::requester::main(argc, argv);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800641}