blob: 76531fe22a696366ae54f582d5c7e9ecec7f2951 [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 Zhang08e0e982017-03-01 10:10:42 -080021#include "challenge-module.hpp"
Suyong Won19fba4d2020-05-09 13:39:46 -070022#include "protocol-detail/info.hpp"
Zhiyi Zhangb6fab0f2017-09-21 16:26:27 -070023#include <iostream>
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080024#include <string>
Davide Pesaventob48bbda2020-07-27 19:41:37 -040025
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -070026#include <boost/asio.hpp>
Davide Pesaventob48bbda2020-07-27 19:41:37 -040027#include <boost/program_options/options_description.hpp>
28#include <boost/program_options/parsers.hpp>
29#include <boost/program_options/variables_map.hpp>
30
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080031#include <ndn-cxx/security/verification-helpers.hpp>
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080032
33namespace ndn {
34namespace ndncert {
35
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070036static void startApplication();
37
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080038int nStep;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070039Face face;
Davide Pesaventob48bbda2020-07-27 19:41:37 -040040security::KeyChain keyChain;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070041std::string challengeType;
Zhiyi Zhang36706832019-07-04 21:33:03 -070042int validityPeriod = -1;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070043ClientModule client(keyChain);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080044
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070045static std::list<std::string>
46captureParams(const JsonSection& requirement)
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080047{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070048 std::list<std::string> results;
Zhiyi Zhang547c8512019-06-18 23:46:14 -070049 for (const auto& item : requirement) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070050 std::cerr << item.second.get<std::string>("") << std::endl;
51 std::cerr << "Please provide the argument: " << item.first << " : " << std::endl;
52 std::string tempParam;
53 getline(std::cin, tempParam);
54 results.push_back(tempParam);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080055 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070056 std::cerr << "Got it. This is what you've provided:" << std::endl;
57 auto it1 = results.begin();
58 auto it2 = requirement.begin();
59 for (; it1 != results.end() && it2 != requirement.end(); it1++, it2++) {
60 std::cerr << it2->first << " : " << *it1 << std::endl;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080061 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070062 return results;
63}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080064
Zhiyi Zhang547c8512019-06-18 23:46:14 -070065static std::list<std::string>
66captureParams(const std::vector<std::string>& requirement)
67{
68 std::list<std::string> results;
69 for (const auto& item : requirement) {
70 std::cerr << "Please provide the argument: " << item << " : " << std::endl;
71 std::string tempParam;
72 getline(std::cin, tempParam);
73 results.push_back(tempParam);
74 }
75 std::cerr << "Got it. This is what you've provided:" << std::endl;
76 auto it1 = results.begin();
77 auto it2 = requirement.begin();
78 for (; it1 != results.end() && it2 != requirement.end(); it1++, it2++) {
79 std::cerr << *it2 << " : " << *it1 << std::endl;
80 }
81 return results;
82}
83
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070084static void
Zhiyi Zhang36706832019-07-04 21:33:03 -070085captureValidityPeriod()
86{
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -070087 if (validityPeriod > 0) {
88 return;
89 }
90 std::cerr << "Step " << nStep++
91 << ": Please type in your expected validity period of your certificate."
92 << " Type the number of hours (168 for week, 730 for month, 8760 for year)."
93 << " The CA may reject your application if your expected period is too long." << std::endl;
94 std::string periodStr = "";
95 getline(std::cin, periodStr);
96 try {
97 validityPeriod = std::stoi(periodStr);
98 }
99 catch (const std::exception& e) {
100 validityPeriod = -1;
Zhiyi Zhang36706832019-07-04 21:33:03 -0700101 }
102}
103
104static void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700105onNackCb()
106{
107 std::cerr << "Got NACK\n";
108}
109
110static void
111timeoutCb()
112{
113 std::cerr << "Interest sent time out\n";
114}
115
116static void
swa770cf1d8f72020-04-21 23:12:39 -0700117certFetchCb(const Data& reply)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700118{
swa770cf1d8f72020-04-21 23:12:39 -0700119 client.onCertFetchResponse(reply);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700120 std::cerr << "Step " << nStep++
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700121 << ": DONE! Certificate has already been installed to local keychain\n"
122 << "Certificate Name: " << cert->getName().toUri() << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700123}
124
125static void
126challengeCb(const Data& reply)
127{
128 client.onChallengeResponse(reply);
129 if (client.getApplicationStatus() == STATUS_SUCCESS) {
130 std::cerr << "DONE! Certificate has already been issued \n";
swa770cf1d8f72020-04-21 23:12:39 -0700131 face.expressInterest(*client.generateCertFetchInterest(), bind(&certFetchCb, _2),
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700132 bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700133 return;
134 }
135
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700136 auto challenge = ChallengeModule::createChallengeModule(challengeType);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700137 auto requirement = challenge->getRequirementForChallenge(client.getApplicationStatus(),
138 client.getChallengeStatus());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700139 if (requirement.size() > 0) {
Zhiyi Zhang916ba2d2018-02-01 18:16:27 -0800140 std::cerr << "Step " << nStep++ << ": Please satisfy following instruction(s)\n";
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700141 std::string redo = "";
142 std::list<std::string> capturedParams;
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700143 capturedParams = captureParams(requirement);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700144 auto it1 = capturedParams.begin();
145 auto it2 = requirement.begin();
146 for (; it1 != capturedParams.end() && it2 != requirement.end(); it1++, it2++) {
147 it2->second.put("", *it1);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800148 }
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800149 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700150 face.expressInterest(*client.generateChallengeInterest(challenge->genChallengeRequestTLV(client.getApplicationStatus(),
Zhiyi Zhang36706832019-07-04 21:33:03 -0700151 client.getChallengeStatus(),
152 requirement)),
153 bind(&challengeCb, _2), bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700154}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800155
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700156static void
157newCb(const Data& reply)
158{
Zhiyi Zhang36706832019-07-04 21:33:03 -0700159 int challengeIndex = 0;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700160 auto challengeList = client.onNewResponse(reply);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700161 if (challengeList.size() < 1) {
162 std::cerr << "There is no available challenge provided by the CA. Exit" << std::endl;
163 return;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800164 }
Zhiyi Zhang36706832019-07-04 21:33:03 -0700165 else if (challengeList.size() > 1) {
166 int count = 0;
167 std::string choice = "";
168 std::cerr << "Step " << nStep++ << ": Please type in the challenge index that you want to perform\n";
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700169 count = 0;
170 for (auto item : challengeList) {
171 std::cerr << "\t" << count++ << " : "<< item << std::endl;
172 }
173 getline(std::cin, choice);
174 try {
175 challengeIndex = std::stoi(choice);
176 }
177 catch (const std::exception& e) {
178 challengeIndex = -1;
179 }
180 if (challengeIndex < 0 || challengeIndex >= count) {
181 std::cerr << "Your input index is out of range. Exit." << std::endl;
182 return;
183 }
Zhiyi Zhang36706832019-07-04 21:33:03 -0700184 }
185 auto it = challengeList.begin();
186 std::advance(it, challengeIndex);
187 unique_ptr<ChallengeModule> challenge = ChallengeModule::createChallengeModule(*it);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700188 if (challenge != nullptr) {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700189 challengeType = *it;
190 std::cerr << "The challenge has been selected: " << challengeType << std::endl;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800191 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700192 else {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700193 std::cerr << "Error. Cannot load selected Challenge Module. Exit." << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700194 return;
195 }
196 auto requirement = challenge->getRequirementForChallenge(client.getApplicationStatus(),
197 client.getChallengeStatus());
198 if (requirement.size() > 0) {
199 std::cerr << "Step " << nStep++ << ": Please satisfy following instruction(s)\n";
200 std::string redo = "";
201 std::list<std::string> capturedParams;
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700202 capturedParams = captureParams(requirement);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700203 auto it1 = capturedParams.begin();
204 auto it2 = requirement.begin();
205 for (; it1 != capturedParams.end() && it2 != requirement.end(); it1++, it2++) {
206 it2->second.put("", *it1);
207 }
208 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700209 face.expressInterest(*client.generateChallengeInterest(challenge->genChallengeRequestTLV(client.getApplicationStatus(),
Zhiyi Zhang36706832019-07-04 21:33:03 -0700210 client.getChallengeStatus(),
211 requirement)),
212 bind(&challengeCb, _2), bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700213}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800214
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700215static void
Suyong Won19fba4d2020-05-09 13:39:46 -0700216InfoCb(const Data& reply)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700217{
Suyong Won19fba4d2020-05-09 13:39:46 -0700218 const Block& contentBlock = reply.getContent();
219
220 if (!client.verifyInfoResponse(reply)) {
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700221 std::cerr << "The fetched CA information cannot be trusted because its integrity is broken" << std::endl;
222 return;
223 }
Suyong Won19fba4d2020-05-09 13:39:46 -0700224 auto caItem = INFO::decodeClientConfigFromContent(contentBlock);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700225
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700226 std::cerr << "Will use a new trust anchor, please double check the identity info: \n"
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400227 << "This trust anchor information is signed by " << reply.getSignatureInfo().getKeyLocator()
228 << std::endl
229 << "The certificate is " << caItem.m_anchor << std::endl
230 << "Do you trust the information? Type in YES or NO" << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700231
232 std::string answer;
233 getline(std::cin, answer);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700234 boost::algorithm::to_lower(answer);
235 if (answer == "yes") {
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700236 std::cerr << "You answered YES: new CA will be used" << std::endl;
Suyong Won19fba4d2020-05-09 13:39:46 -0700237 client.addCaFromInfoResponse(reply);
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700238 // client.getClientConf().save(std::string(SYSCONFDIR) + "/ndncert/client.conf");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700239 startApplication();
240 }
241 else {
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700242 std::cerr << "You answered NO: new CA will not be used" << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700243 return;
244 }
245}
246
247static void
248probeCb(const Data& reply)
249{
Zhiyi Zhang781a5602019-06-26 19:05:04 -0700250 client.onProbeResponse(reply);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700251 captureValidityPeriod();
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700252 if (validityPeriod <= 0) {
253 std::cerr << "Invalid period time. Exit." << std::endl;
254 return;
255 }
Zhiyi Zhang781a5602019-06-26 19:05:04 -0700256 auto probeToken = make_shared<Data>(reply);
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700257 auto now = time::system_clock::now();
Zhiyi Zhang36706832019-07-04 21:33:03 -0700258 std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700259 auto interest = client.generateNewInterest(now, now + time::hours(validityPeriod), Name(), probeToken);
260 if (interest != nullptr) {
261 face.expressInterest(*interest, bind(&newCb, _2), bind(&onNackCb), bind(&timeoutCb));
262 }
263 else {
264 std::cerr << "Cannot generate the Interest for NEW step. Exit" << std::endl;
265 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700266}
267
268static void
269startApplication()
270{
271 nStep = 0;
272 auto caList = client.getClientConf().m_caItems;
273 int count = 0;
274 for (auto item : caList) {
275 std::cerr << "***************************************\n"
276 << "Index: " << count++ << "\n"
277 << "CA prefix:" << item.m_caName << "\n"
278 << "Introduction: " << item.m_caInfo << "\n"
279 << "***************************************\n";
280 }
281 std::vector<ClientCaItem> caVector{std::begin(caList), std::end(caList)};
282 std::cerr << "Step "
283 << nStep++ << ": Please type in the CA INDEX that you want to apply"
284 << " or type in NONE if your expected CA is not in the list\n";
285
Zhiyi Zhang36706832019-07-04 21:33:03 -0700286 std::string caIndexS, caIndexSLower;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700287 getline(std::cin, caIndexS);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700288 caIndexSLower = caIndexS;
289 boost::algorithm::to_lower(caIndexSLower);
290 if (caIndexSLower == "none") {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700291 std::cerr << "Step " << nStep << ": Please type in the CA Name\n";
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700292 std::string expectedCAName;
293 getline(std::cin, expectedCAName);
swa77020643ac2020-03-26 02:24:45 -0700294 face.expressInterest(*client.generateInfoInterest(Name(expectedCAName)),
Suyong Won19fba4d2020-05-09 13:39:46 -0700295 bind(&InfoCb, _2), bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700296 }
297 else {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700298 int caIndex;
299 try {
300 caIndex = std::stoi(caIndexS);
301 }
302 catch (const std::exception& e) {
303 std::cerr << "Your input is neither NONE nor a valid index. Exit" << std::endl;
304 return;
305 }
306 if (caIndex < 0 || caIndex >= count) {
307 std::cerr << "Your input is not an existing index. Exit" << std::endl;
308 return;
309 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700310 auto targetCaItem = caVector[caIndex];
311
312 if (targetCaItem.m_probe != "") {
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700313 std::cerr << "Step " << nStep++ << ": Please provide information for name assignment" << std::endl;
314 std::vector<std::string> probeFields = ClientModule::parseProbeComponents(targetCaItem.m_probe);
315 std::string redo = "";
316 std::list<std::string> capturedParams;
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700317 capturedParams = captureParams(probeFields);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700318 std::string probeInfo;
Zhiyi Zhang547c8512019-06-18 23:46:14 -0700319 for (const auto& item : capturedParams) {
320 probeInfo += item;
321 probeInfo += ":";
322 }
323 probeInfo = probeInfo.substr(0, probeInfo.size() - 1);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700324 face.expressInterest(*client.generateProbeInterest(targetCaItem, probeInfo),
Zhiyi Zhang36706832019-07-04 21:33:03 -0700325 bind(&probeCb, _2), bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700326 }
327 else {
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700328 std::cerr << "Step " << nStep++ << ": Please type in the full identity name you want to get (with CA prefix)\n";
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700329 std::string identityNameStr;
330 getline(std::cin, identityNameStr);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700331 captureValidityPeriod();
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700332 if (validityPeriod <= 0) {
333 std::cerr << "Invalid period time. Exit." << std::endl;
334 return;
335 }
336 Name idName(identityNameStr);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700337 std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
Zhiyi Zhang1a735bc2019-07-04 21:36:49 -0700338 auto now = time::system_clock::now();
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700339 auto interest = client.generateNewInterest(now, now + time::hours(validityPeriod), idName);
340 if (interest != nullptr) {
341 face.expressInterest(*interest, bind(&newCb, _2), bind(&onNackCb), bind(&timeoutCb));
342 }
343 else {
344 std::cerr << "Cannot generate the Interest for NEW step. Exit" << std::endl;
345 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700346 }
347 }
348}
349
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700350static void
351handleSignal(const boost::system::error_code& error, int signalNum)
352{
353 if (error) {
354 return;
355 }
356 const char* signalName = ::strsignal(signalNum);
357 std::cerr << "Exiting on signal ";
358 if (signalName == nullptr) {
359 std::cerr << signalNum;
360 }
361 else {
362 std::cerr << signalName;
363 }
364 std::cerr << std::endl;
365 client.endSession();
366 face.getIoService().stop();
367}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800368
369int
370main(int argc, char* argv[])
371{
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700372 boost::asio::signal_set terminateSignals(face.getIoService());
373 terminateSignals.add(SIGINT);
374 terminateSignals.add(SIGTERM);
375 terminateSignals.async_wait(handleSignal);
376
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800377 namespace po = boost::program_options;
378 std::string configFilePath = std::string(SYSCONFDIR) + "/ndncert/client.conf";
Zhiyi Zhang36706832019-07-04 21:33:03 -0700379 po::options_description description("General Usage\n ndncert-client [-h] [-c] [-v]\n");
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800380 description.add_options()
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700381 ("help,h", "produce help message")
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400382 ("config-file,c", po::value<std::string>(&configFilePath), "configuration file name")
383 ("validity-period,v", po::value<int>(&validityPeriod)->default_value(-1),
384 "desired validity period (hours) of the certificate being requested");
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800385 po::positional_options_description p;
386
387 po::variables_map vm;
388 try {
389 po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm);
390 po::notify(vm);
391 }
392 catch (const std::exception& e) {
393 std::cerr << "ERROR: " << e.what() << std::endl;
394 return 1;
395 }
396 if (vm.count("help") != 0) {
397 std::cerr << description << std::endl;
398 return 0;
399 }
Zhiyi Zhangd8993b92019-07-04 21:58:10 -0700400 try {
401 client.getClientConf().load(configFilePath);
402 }
403 catch (const std::exception& e) {
404 std::cerr << "Cannot load the configuration file: " << e.what() << std::endl;
405 return 1;
406 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700407 startApplication();
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800408 face.processEvents();
409 return 0;
410}
411
412} // namespace ndncert
413} // namespace ndn
414
Zhiyi Zhang916ba2d2018-02-01 18:16:27 -0800415int main(int argc, char* argv[])
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800416{
417 return ndn::ndncert::main(argc, argv);
418}