blob: d85c839ad8350be680f66038a5c158e1165105c7 [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 Zhangc87d52b2020-09-28 22:07:18 -070021#include "challenge-module.hpp"
Zhiyi Zhang1d3dcd22020-10-01 22:25:43 -070022#include "requester.hpp"
Zhiyi Zhangc87d52b2020-09-28 22:07:18 -070023#include "protocol-detail/info.hpp"
24#include <ndn-cxx/security/verification-helpers.hpp>
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -070025#include <boost/asio.hpp>
Davide Pesaventob48bbda2020-07-27 19:41:37 -040026#include <boost/program_options/options_description.hpp>
27#include <boost/program_options/parsers.hpp>
28#include <boost/program_options/variables_map.hpp>
Zhiyi Zhang48f23782020-09-28 12:11:24 -070029#include <iostream>
Zhiyi Zhang48f23782020-09-28 12:11:24 -070030#include <string>
31
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080032namespace ndn {
33namespace ndncert {
34
Zhiyi Zhang48f23782020-09-28 12:11:24 -070035static void
tylerliufeabfdc2020-10-03 15:09:58 -070036selectCaProfile(std::string configFilePath);
37static void
38runProbe(CaProfile profile);
39static void
40runNew(CaProfile profile, Name identityName);
41static void
42runChallenge(const std::string& challengeType);
43static void
44startApplication(std::string configFilePath);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070045
Zhiyi Zhang1c0bd372017-12-18 18:32:55 +080046int nStep;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070047Face face;
tylerliu182bc532020-09-25 01:54:45 -070048security::v2::KeyChain keyChain;
tylerliufeabfdc2020-10-03 15:09:58 -070049shared_ptr<RequesterState> requesterState = nullptr;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080050
Zhiyi Zhang46049832020-09-28 17:08:12 -070051static void
52captureParams(std::vector<std::tuple<std::string, std::string>>& requirement)
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080053{
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070054 std::list<std::string> results;
Zhiyi Zhang46049832020-09-28 17:08:12 -070055 for (auto& item : requirement) {
56 std::cerr << std::get<1>(item) << std::endl;
57 std::string captured;
58 getline(std::cin, captured);
59 std::get<1>(item) = captured;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080060 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070061 std::cerr << "Got it. This is what you've provided:" << std::endl;
Zhiyi Zhang46049832020-09-28 17:08:12 -070062 for (const auto& item : requirement) {
63 std::cerr << std::get<0>(item) << " : " << std::get<1>(item) << std::endl;
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080064 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070065}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -080066
Zhiyi Zhang9829da92020-09-30 16:19:34 -070067static std::vector<std::tuple<std::string, std::string>>
68captureParams(const std::list<std::string>& requirement)
Zhiyi Zhang547c8512019-06-18 23:46:14 -070069{
Zhiyi Zhang9829da92020-09-30 16:19:34 -070070 std::vector<std::tuple<std::string, std::string>> results;
tylerliufeabfdc2020-10-03 15:09:58 -070071 for (const auto& r : requirement) {
72 results.emplace_back(r, "Please input: " + r);
Zhiyi Zhang547c8512019-06-18 23:46:14 -070073 }
tylerliufeabfdc2020-10-03 15:09:58 -070074 captureParams(results);
Zhiyi Zhang547c8512019-06-18 23:46:14 -070075 return results;
76}
77
tylerliufeabfdc2020-10-03 15:09:58 -070078static int
Zhiyi Zhang36706832019-07-04 21:33:03 -070079captureValidityPeriod()
80{
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -070081 std::cerr << "Step " << nStep++
82 << ": Please type in your expected validity period of your certificate."
83 << " Type the number of hours (168 for week, 730 for month, 8760 for year)."
84 << " The CA may reject your application if your expected period is too long." << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -070085 while (true) {
86 std::string periodStr = "";
87 getline(std::cin, periodStr);
88 try {
89 int validityPeriod = std::stoi(periodStr);
90 if (validityPeriod < 0) {
91 BOOST_THROW_EXCEPTION(std::runtime_error(""));
92 }
93 return validityPeriod;
94 }
95 catch (const std::exception &e) {
96 std::cerr << "Your input is invalid. Try again: " << std::endl;
97 }
Zhiyi Zhang36706832019-07-04 21:33:03 -070098 }
99}
100
101static void
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700102onNackCb()
103{
104 std::cerr << "Got NACK\n";
105}
106
107static void
108timeoutCb()
109{
110 std::cerr << "Interest sent time out\n";
111}
112
113static void
swa770cf1d8f72020-04-21 23:12:39 -0700114certFetchCb(const Data& reply)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700115{
tylerliufeabfdc2020-10-03 15:09:58 -0700116 auto item = Requester::onCertFetchResponse(reply);
117 if (item) {
118 keyChain.addCertificate(keyChain.getPib().getIdentity(item->getIdentity()).getKey(item->getKeyName()), *item);
119 }
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"
Zhiyi Zhangef6b36a2020-09-22 21:20:59 -0700122 << "Certificate Name: " << reply.getName().toUri() << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700123}
124
125static void
126challengeCb(const Data& reply)
127{
tylerliufeabfdc2020-10-03 15:09:58 -0700128 try {
129 Requester::onChallengeResponse(*requesterState, reply);
130 } catch (const std::exception& e) {
131 std::cerr << "Error when decoding challenge step: " << e.what() << std::endl;
132 exit(1);
133 }
134 if (requesterState->m_status == Status::SUCCESS) {
135 std::cerr << "Certificate has already been issued, downloading certificate... \n";
136 face.expressInterest(*Requester::genCertFetchInterest(*requesterState), bind(&certFetchCb, _2),
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700137 bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhang4d89fe02017-04-28 18:51:51 -0700138 return;
139 }
140
tylerliufeabfdc2020-10-03 15:09:58 -0700141 runChallenge(requesterState->m_challengeType);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700142}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800143
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700144static void
145newCb(const Data& reply)
146{
tylerliufeabfdc2020-10-03 15:09:58 -0700147 std::list<std::string> challengeList;
148 try {
149 challengeList = Requester::onNewRenewRevokeResponse(*requesterState, reply);
150 } catch (const std::exception& e) {
151 std::cerr << "Error on decoding NEW step reply because: " << e.what() << std::endl;
152 exit(1);
153 }
154
Zhiyi Zhang36706832019-07-04 21:33:03 -0700155 int challengeIndex = 0;
Zhiyi Zhang36706832019-07-04 21:33:03 -0700156 if (challengeList.size() < 1) {
157 std::cerr << "There is no available challenge provided by the CA. Exit" << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700158 exit(1);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800159 }
Zhiyi Zhang36706832019-07-04 21:33:03 -0700160 else if (challengeList.size() > 1) {
161 int count = 0;
162 std::string choice = "";
163 std::cerr << "Step " << nStep++ << ": Please type in the challenge index that you want to perform\n";
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700164 count = 0;
165 for (auto item : challengeList) {
Zhiyi Zhang48f23782020-09-28 12:11:24 -0700166 std::cerr << "\t" << count++ << " : " << item << std::endl;
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700167 }
tylerliufeabfdc2020-10-03 15:09:58 -0700168 while (true) {
169 getline(std::cin, choice);
170 try {
171 challengeIndex = std::stoi(choice);
172 }
173 catch (const std::exception &e) {
174 std::cerr << "Your input is not valid. Try again:" << std::endl;
175 continue;
176 }
177 if (challengeIndex < 0 || challengeIndex >= count) {
178 std::cerr << "Your input index is out of range. Try again:" << std::endl;
179 continue;
180 }
181 break;
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700182 }
Zhiyi Zhang36706832019-07-04 21:33:03 -0700183 }
184 auto it = challengeList.begin();
185 std::advance(it, challengeIndex);
186 unique_ptr<ChallengeModule> challenge = ChallengeModule::createChallengeModule(*it);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700187 if (challenge != nullptr) {
tylerliufeabfdc2020-10-03 15:09:58 -0700188 std::cerr << "The challenge has been selected: " << *it << std::endl;
189 runChallenge(*it);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800190 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700191 else {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700192 std::cerr << "Error. Cannot load selected Challenge Module. Exit." << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700193 exit(1);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700194 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700195}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800196
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700197static void
Suyong Won19fba4d2020-05-09 13:39:46 -0700198InfoCb(const Data& reply)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700199{
tylerliufeabfdc2020-10-03 15:09:58 -0700200 CaProfile profile;
201 try {
202 auto profileOpt = Requester::onCaProfileResponse(reply);
203 if (!profileOpt) {
204 BOOST_THROW_EXCEPTION(std::runtime_error("Invalid reply"));
205 }
206 profile = *profileOpt;
207 } catch(const std::exception& e) {
208 std::cerr << "The fetched CA information cannot be used because: "<< e.what() << std::endl;
209 return;
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700210 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700211
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700212 std::cerr << "Will use a new trust anchor, please double check the identity info: \n"
Zhiyi Zhangef6b36a2020-09-22 21:20:59 -0700213 << "This trust anchor information is signed by " << reply.getSignature().getKeyLocator()
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400214 << std::endl
tylerliufeabfdc2020-10-03 15:09:58 -0700215 << "The certificate is " << profile.m_cert << std::endl
Davide Pesaventob48bbda2020-07-27 19:41:37 -0400216 << "Do you trust the information? Type in YES or NO" << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700217
218 std::string answer;
219 getline(std::cin, answer);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700220 boost::algorithm::to_lower(answer);
221 if (answer == "yes") {
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700222 std::cerr << "You answered YES: new CA will be used" << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700223 runProbe(profile);
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700224 // client.getClientConf().save(std::string(SYSCONFDIR) + "/ndncert/client.conf");
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700225 }
226 else {
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700227 std::cerr << "You answered NO: new CA will not be used" << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700228 exit(0);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700229 }
230}
231
232static void
tylerliufeabfdc2020-10-03 15:09:58 -0700233probeCb(const Data& reply, CaProfile profile)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700234{
tylerliufeabfdc2020-10-03 15:09:58 -0700235 std::vector<Name> names;
236 std::vector<Name> redirects;
237 Requester::onProbeResponse(reply, profile, names, redirects);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700238 int count = 0;
tylerliufeabfdc2020-10-03 15:09:58 -0700239 std::cerr << "Here is CA's suggested names: " << std::endl;
240 for (const auto& name : names) {
241 std::cerr << count ++ << ": " << name.toUri() << std::endl;
242 }
243 std::cerr << "Here is CA's suggested redirects to other CAs: " << std::endl;
244 for (const auto& redirect : redirects) {
245 std::cerr << count ++ << ": " << redirect.toUri() << std::endl;
246 }
247 int index;
248 try {
249 std::string input;
250 getline(std::cin, input);
251 index = std::stoi(input);
252 }
253 catch (const std::exception& e) {
254 std::cerr << "Your input is Invalid. Exit" << std::endl;
255 exit(0);
256 }
257 if (index < 0 || index >= names.size() + redirects.size()) {
258 std::cerr << "Your input is not an existing index. Exit" << std::endl;
259 return;
260 }
261 if (index < names.size()) {
262 //names
263 std::cerr << "You selected name: " << names[index].toUri() << std::endl;
264 runNew(profile, names[index]);
265 } else {
266 //redirects
267 std::cerr << "You selected redirects with certificate: " << redirects[index - names.size()].toUri() << std::endl;
268 face.expressInterest(*Requester::genCaProfileInterest(redirects[index - names.size()]),
269 bind(&InfoCb, _2), bind(&onNackCb), bind(&timeoutCb));
270 }
271}
272
273static void
274selectCaProfile(std::string configFilePath)
275{
276 RequesterCaCache caCache;
277 try {
278 caCache.load(configFilePath);
279 }
280 catch (const std::exception& e) {
281 std::cerr << "Cannot load the configuration file: " << e.what() << std::endl;
282 exit(1);
283 }
284 int count = 0;
285 for (auto item : caCache.m_caItems) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700286 std::cerr << "***************************************\n"
287 << "Index: " << count++ << "\n"
Suyong Won256c9062020-05-11 02:45:56 -0700288 << "CA prefix:" << item.m_caPrefix << "\n"
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700289 << "Introduction: " << item.m_caInfo << "\n"
290 << "***************************************\n";
291 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700292 std::cerr << "Step "
293 << nStep++ << ": Please type in the CA INDEX that you want to apply"
294 << " or type in NONE if your expected CA is not in the list\n";
295
Zhiyi Zhang36706832019-07-04 21:33:03 -0700296 std::string caIndexS, caIndexSLower;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700297 getline(std::cin, caIndexS);
Zhiyi Zhang36706832019-07-04 21:33:03 -0700298 caIndexSLower = caIndexS;
299 boost::algorithm::to_lower(caIndexSLower);
300 if (caIndexSLower == "none") {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700301 std::cerr << "Step " << nStep << ": Please type in the CA Name\n";
Zhiyi Zhangcaab5462019-10-18 13:41:02 -0700302 std::string expectedCAName;
303 getline(std::cin, expectedCAName);
tylerliufeabfdc2020-10-03 15:09:58 -0700304 face.expressInterest(*Requester::genCaProfileInterest(Name(expectedCAName)),
Suyong Won19fba4d2020-05-09 13:39:46 -0700305 bind(&InfoCb, _2), bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700306 }
307 else {
Zhiyi Zhang36706832019-07-04 21:33:03 -0700308 int caIndex;
309 try {
310 caIndex = std::stoi(caIndexS);
311 }
312 catch (const std::exception& e) {
313 std::cerr << "Your input is neither NONE nor a valid index. Exit" << std::endl;
314 return;
315 }
316 if (caIndex < 0 || caIndex >= count) {
317 std::cerr << "Your input is not an existing index. Exit" << std::endl;
318 return;
319 }
tylerliufeabfdc2020-10-03 15:09:58 -0700320 auto itemIterator = caCache.m_caItems.cbegin();
321 std::advance(itemIterator, caIndex);
322 auto targetCaItem = *itemIterator;
323 runProbe(targetCaItem);
324 }
325}
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700326
tylerliufeabfdc2020-10-03 15:09:58 -0700327static void runProbe(CaProfile profile)
328{
329 std::cerr << "Do you have the identity name already? Type in YES or NO" << std::endl;
330 bool validAnswer = false;
331 while (!validAnswer) {
332 std::string answer;
333 getline(std::cin, answer);
334 boost::algorithm::to_lower(answer);
335 if (answer == "yes") {
336 validAnswer = true;
337 std::cerr << "You answered YES: " << std::endl;
338 std::cerr << "Step " << nStep++ << ": Please type in the full identity name you want to get (with CA prefix)\n";
339 std::string identityNameStr;
340 getline(std::cin, identityNameStr);
341 runNew(profile, Name(identityNameStr));
342 } else if (answer == "no") {
343 validAnswer = true;
344 std::cerr << "You answered NO: new CA will not be used" << std::endl;
345 std::cerr << "Step " << nStep++ << ": Please provide information for name assignment" << std::endl;
346 auto capturedParams = captureParams(profile.m_probeParameterKeys);
347 face.expressInterest(*Requester::genProbeInterest(profile, std::move(capturedParams)),
348 bind(&probeCb, _2, profile), bind(&onNackCb), bind(&timeoutCb));
349 } else {
350 std::cerr << "Invalid answer. Type in YES or NO" << std::endl;
351 }
352 }
353}
354
355static void
356runNew(CaProfile profile, Name identityName)
357{
358 int validityPeriod = captureValidityPeriod();
359 auto now = time::system_clock::now();
360 std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
361 requesterState = make_shared<RequesterState>(keyChain, profile, RequestType::NEW);
362 auto interest = Requester::genNewInterest(*requesterState, identityName, now, now + time::hours(validityPeriod));
363 if (interest != nullptr) {
364 face.expressInterest(*interest, bind(&newCb, _2), bind(&onNackCb), bind(&timeoutCb));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700365 }
366 else {
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700367 std::cerr << "Cannot generate the Interest for NEW step. Exit" << std::endl;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700368 }
tylerliufeabfdc2020-10-03 15:09:58 -0700369}
370
371static void
372runChallenge(const std::string& challengeType)
373{
374 auto requirement = Requester::selectOrContinueChallenge(*requesterState, challengeType);
375 if (requirement.size() > 0) {
376 std::cerr << "Step " << nStep++ << ": Please provide parameters used for Identity Verification Challenge\n";
377 captureParams(requirement);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700378 }
tylerliufeabfdc2020-10-03 15:09:58 -0700379 face.expressInterest(*Requester::genChallengeInterest(*requesterState, std::move(requirement)),
380 bind(&challengeCb, _2), bind(&onNackCb), bind(&timeoutCb));
381
382}
383
384
385static void
386startApplication(std::string configFilePath)
387{
388 selectCaProfile(configFilePath);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700389}
390
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700391static void
392handleSignal(const boost::system::error_code& error, int signalNum)
393{
394 if (error) {
395 return;
396 }
397 const char* signalName = ::strsignal(signalNum);
398 std::cerr << "Exiting on signal ";
399 if (signalName == nullptr) {
400 std::cerr << signalNum;
401 }
402 else {
403 std::cerr << signalName;
404 }
405 std::cerr << std::endl;
tylerliufeabfdc2020-10-03 15:09:58 -0700406 if (requesterState) {
407 Requester::endSession(*requesterState);
408 }
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700409 face.getIoService().stop();
tylerliufeabfdc2020-10-03 15:09:58 -0700410 exit(1);
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700411}
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800412
413int
414main(int argc, char* argv[])
415{
Zhiyi Zhangad9e04f2020-03-27 12:04:31 -0700416 boost::asio::signal_set terminateSignals(face.getIoService());
417 terminateSignals.add(SIGINT);
418 terminateSignals.add(SIGTERM);
419 terminateSignals.async_wait(handleSignal);
420
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800421 namespace po = boost::program_options;
422 std::string configFilePath = std::string(SYSCONFDIR) + "/ndncert/client.conf";
Zhiyi Zhang36706832019-07-04 21:33:03 -0700423 po::options_description description("General Usage\n ndncert-client [-h] [-c] [-v]\n");
tylerliufeabfdc2020-10-03 15:09:58 -0700424 description.add_options()
425 ("help,h", "produce help message")
426 ("config-file,c", po::value<std::string>(&configFilePath), "configuration file name");
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800427 po::positional_options_description p;
428
429 po::variables_map vm;
430 try {
431 po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm);
432 po::notify(vm);
433 }
434 catch (const std::exception& e) {
435 std::cerr << "ERROR: " << e.what() << std::endl;
436 return 1;
437 }
438 if (vm.count("help") != 0) {
439 std::cerr << description << std::endl;
440 return 0;
441 }
tylerliufeabfdc2020-10-03 15:09:58 -0700442 startApplication(configFilePath);
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800443 face.processEvents();
444 return 0;
445}
446
Zhiyi Zhang48f23782020-09-28 12:11:24 -0700447} // namespace ndncert
448} // namespace ndn
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800449
Zhiyi Zhang48f23782020-09-28 12:11:24 -0700450int
451main(int argc, char* argv[])
Zhiyi Zhang08e0e982017-03-01 10:10:42 -0800452{
453 return ndn::ndncert::main(argc, argv);
454}