blob: ea38694561af843262637ec1127fe9309e4c7b04 [file] [log] [blame]
Zhiyi Zhang08e0e982017-03-01 10:10:42 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -07003 * Copyright (c) 2017-2019, 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
21#include "client-module.hpp"
22#include "challenge-module.hpp"
Zhiyi Zhangb6fab0f2017-09-21 16:26:27 -070023#include <iostream>
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080024#include <string>
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080025#include <boost/program_options/options_description.hpp>
26#include <boost/program_options/variables_map.hpp>
27#include <boost/program_options/parsers.hpp>
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080028#include <ndn-cxx/security/verification-helpers.hpp>
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080029
30namespace ndn {
31namespace ndncert {
32
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070033static void startApplication();
34
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080035int nStep;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070036Face face;
37security::v2::KeyChain keyChain;
38std::string challengeType;
39ClientModule client(keyChain);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080040
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070041static std::list<std::string>
42captureParams(const JsonSection& requirement)
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080043{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070044 std::list<std::string> results;
45 for (auto& item : requirement) {
46 std::cerr << item.second.get<std::string>("") << std::endl;
47 std::cerr << "Please provide the argument: " << item.first << " : " << std::endl;
48 std::string tempParam;
49 getline(std::cin, tempParam);
50 results.push_back(tempParam);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080051 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070052 std::cerr << "Got it. This is what you've provided:" << std::endl;
53 auto it1 = results.begin();
54 auto it2 = requirement.begin();
55 for (; it1 != results.end() && it2 != requirement.end(); it1++, it2++) {
56 std::cerr << it2->first << " : " << *it1 << std::endl;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080057 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070058 return results;
59}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080060
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070061static void
62onNackCb()
63{
64 std::cerr << "Got NACK\n";
65}
66
67static void
68timeoutCb()
69{
70 std::cerr << "Interest sent time out\n";
71}
72
73static void
74downloadCb(const Data& reply)
75{
76 client.onDownloadResponse(reply);
77 std::cerr << "Step " << nStep++
78 << ": DONE! Certificate has already been installed to local keychain\n";
79 return;
80}
81
82static void
83challengeCb(const Data& reply)
84{
85 client.onChallengeResponse(reply);
86 if (client.getApplicationStatus() == STATUS_SUCCESS) {
87 std::cerr << "DONE! Certificate has already been issued \n";
88 face.expressInterest(*client.generateDownloadInterest(), bind(&downloadCb, _2),
89 bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -070090 return;
91 }
92
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070093 auto challenge = ChallengeModule::createChallengeModule(challengeType);
94 auto requirement = challenge->getRequirementForChallenge(client.getApplicationStatus(), client.getChallengeStatus());
95 if (requirement.size() > 0) {
Zhiyi Zhang916ba2d2018-02-01 18:16:27 -080096 std::cerr << "Step " << nStep++ << ": Please satisfy following instruction(s)\n";
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070097 std::string redo = "";
98 std::list<std::string> capturedParams;
99 do {
100 capturedParams = captureParams(requirement);
101 std::cerr << "If anything is wrong, please type in OK; otherwise, type in REDO" << std::endl;
102 getline(std::cin, redo);
103 } while (redo == "REDO");
104 auto it1 = capturedParams.begin();
105 auto it2 = requirement.begin();
106 for (; it1 != capturedParams.end() && it2 != requirement.end(); it1++, it2++) {
107 it2->second.put("", *it1);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800108 }
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800109 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700110 face.expressInterest(*client.generateChallengeInterest(
111 challenge->genChallengeRequestJson(
112 client.getApplicationStatus(),
113 client.getChallengeStatus(),
114 requirement)),
115 bind(&challengeCb, _2),
116 bind(&onNackCb),
117 bind(&timeoutCb));
118}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800119
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700120static void
121newCb(const Data& reply)
122{
123 auto challengeList = client.onNewResponse(reply);
124 std::cerr << "Step " << nStep++ << ": Please type in the challenge ID from the following challenges\n";
125 for (auto item : challengeList) {
126 std::cerr << "\t" << item << std::endl;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800127 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700128 std::string choice;
129 getline(std::cin, choice);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800130
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700131 auto challenge = ChallengeModule::createChallengeModule(choice);
132 if (challenge != nullptr) {
133 challengeType = choice;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800134 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700135 else {
136 std::cerr << "Cannot recognize the specified challenge. Exit";
137 return;
138 }
139 auto requirement = challenge->getRequirementForChallenge(client.getApplicationStatus(),
140 client.getChallengeStatus());
141 if (requirement.size() > 0) {
142 std::cerr << "Step " << nStep++ << ": Please satisfy following instruction(s)\n";
143 std::string redo = "";
144 std::list<std::string> capturedParams;
145 do {
146 capturedParams = captureParams(requirement);
147 std::cerr << "If anything is wrong, please type in OK; otherwise, type in REDO" << std::endl;
148 getline(std::cin, redo);
149 } while (redo == "REDO");
150 auto it1 = capturedParams.begin();
151 auto it2 = requirement.begin();
152 for (; it1 != capturedParams.end() && it2 != requirement.end(); it1++, it2++) {
153 it2->second.put("", *it1);
154 }
155 }
156 face.expressInterest(*client.generateChallengeInterest(
157 challenge->genChallengeRequestJson(
158 client.getApplicationStatus(),
159 client.getChallengeStatus(),
160 requirement)),
161 bind(&challengeCb, _2),
162 bind(&onNackCb),
163 bind(&timeoutCb));
164}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800165
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700166static void
167probeInfoCb(const Data& reply)
168{
169 auto contentJson = ClientModule::getJsonFromData(reply);
170 auto caItem = ClientConfig::extractCaItem(contentJson);
171
172 std::cerr << "Will install new trust anchor, please double check the identity info: \n"
173 << "This trust anchor packet is signed by " << reply.getSignature().getKeyLocator() << std::endl
174 << "The signing certificate is " << caItem.m_anchor << std::endl;
175 std::cerr << "Do you trust the information? Type in YES or NO" << std::endl;
176
177 std::string answer;
178 getline(std::cin, answer);
179 if (answer == "YES") {
180 client.onProbeInfoResponse(reply);
181 std::cerr << "You answered YES: new CA installed" << std::endl;
182 startApplication();
183 }
184 else {
185 std::cerr << "New CA not installed" << std::endl;
186 return;
187 }
188}
189
190static void
191probeCb(const Data& reply)
192{
193 std::cerr << "Step " << nStep++
194 << ": Please type in your expected validity period of your certificate."
195 << " Type in a number in unit of hour. The CA may change the validity"
196 << " period if your expected period is too long." << std::endl;
197 std::string periodStr;
198 getline(std::cin, periodStr);
199 int hours = std::stoi(periodStr);
200 face.expressInterest(*client.generateNewInterest(time::system_clock::now(),
201 time::system_clock::now() + time::hours(hours)),
202 bind(&newCb, _2),
203 bind(&onNackCb),
204 bind(&timeoutCb));
205}
206
207static void
208startApplication()
209{
210 nStep = 0;
211 auto caList = client.getClientConf().m_caItems;
212 int count = 0;
213 for (auto item : caList) {
214 std::cerr << "***************************************\n"
215 << "Index: " << count++ << "\n"
216 << "CA prefix:" << item.m_caName << "\n"
217 << "Introduction: " << item.m_caInfo << "\n"
218 << "***************************************\n";
219 }
220 std::vector<ClientCaItem> caVector{std::begin(caList), std::end(caList)};
221 std::cerr << "Step "
222 << nStep++ << ": Please type in the CA INDEX that you want to apply"
223 << " or type in NONE if your expected CA is not in the list\n";
224
225 std::string caIndexS;
226 getline(std::cin, caIndexS);
227 if (caIndexS == "NONE") {
228 std::cerr << "Step " << nStep << ": Please type in the CA Name\n";
229 face.expressInterest(*client.generateProbeInfoInterest(Name(caIndexS)),
230 bind(&probeInfoCb, _2),
231 bind(&onNackCb),
232 bind(&timeoutCb));
233 }
234 else {
235 int caIndex = std::stoi(caIndexS);
236 BOOST_ASSERT(caIndex <= count);
237 auto targetCaItem = caVector[caIndex];
238
239 if (targetCaItem.m_probe != "") {
240 std::cerr << "Step " << nStep++ << ": Probe Requirement-" << targetCaItem.m_probe << std::endl;
241 std::string probeInfo;
242 getline(std::cin, probeInfo);
243 face.expressInterest(*client.generateProbeInterest(targetCaItem, probeInfo),
244 bind(&probeCb, _2),
245 bind(&onNackCb),
246 bind(&timeoutCb));
247 }
248 else {
249 std::cerr << "Step " << nStep++ << ": Please type in the identity name you want to get (with CA prefix)\n";
250 std::string identityNameStr;
251 getline(std::cin, identityNameStr);
252 std::cerr << "Step "
253 << nStep++ << ": Please type in your expected validity period of your certificate."
254 << "Type in a number in unit of hour."
255 << " The CA may change the validity period if your expected period is too long.\n";
256 std::string periodStr;
257 getline(std::cin, periodStr);
258 int hours = std::stoi(periodStr);
259 face.expressInterest(*client.generateNewInterest(time::system_clock::now(),
260 time::system_clock::now() + time::hours(hours),
261 Name(identityNameStr)),
262 bind(&newCb, _2),
263 bind(&onNackCb),
264 bind(&timeoutCb));
265 }
266 }
267}
268
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800269
270int
271main(int argc, char* argv[])
272{
273 namespace po = boost::program_options;
274 std::string configFilePath = std::string(SYSCONFDIR) + "/ndncert/client.conf";
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700275 po::options_description description("General Usage\n ndncert-client [-h] [-f]\n");
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800276 description.add_options()
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700277 ("help,h", "produce help message")
278 ("config-file,f", po::value<std::string>(&configFilePath), "config file name");
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800279 po::positional_options_description p;
280
281 po::variables_map vm;
282 try {
283 po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm);
284 po::notify(vm);
285 }
286 catch (const std::exception& e) {
287 std::cerr << "ERROR: " << e.what() << std::endl;
288 return 1;
289 }
290 if (vm.count("help") != 0) {
291 std::cerr << description << std::endl;
292 return 0;
293 }
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800294 client.getClientConf().load(configFilePath);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700295 startApplication();
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800296 face.processEvents();
297 return 0;
298}
299
300} // namespace ndncert
301} // namespace ndn
302
Zhiyi Zhang916ba2d2018-02-01 18:16:27 -0800303int main(int argc, char* argv[])
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800304{
305 return ndn::ndncert::main(argc, argv);
306}