redone ndncert client & requester module fix
Change-Id: If8ba5a240ed2e970fe69d8b4208e7b8d4d3a611c
diff --git a/tools/ndncert-client.cpp b/tools/ndncert-client.cpp
index 5fbea9b..d85c839 100644
--- a/tools/ndncert-client.cpp
+++ b/tools/ndncert-client.cpp
@@ -33,14 +33,20 @@
namespace ndncert {
static void
-startApplication();
+selectCaProfile(std::string configFilePath);
+static void
+runProbe(CaProfile profile);
+static void
+runNew(CaProfile profile, Name identityName);
+static void
+runChallenge(const std::string& challengeType);
+static void
+startApplication(std::string configFilePath);
int nStep;
Face face;
security::v2::KeyChain keyChain;
-std::string challengeType;
-int validityPeriod = -1;
-Requester client(keyChain);
+shared_ptr<RequesterState> requesterState = nullptr;
static void
captureParams(std::vector<std::tuple<std::string, std::string>>& requirement)
@@ -62,36 +68,33 @@
captureParams(const std::list<std::string>& requirement)
{
std::vector<std::tuple<std::string, std::string>> results;
- for (const auto& item : requirement) {
- std::cerr << "Please provide the argument: " << item << " : " << std::endl;
- std::string captured;
- getline(std::cin, captured);
- results.push_back(std::make_tuple(item, captured));
+ for (const auto& r : requirement) {
+ results.emplace_back(r, "Please input: " + r);
}
- std::cerr << "Got it. This is what you've provided:" << std::endl;
- for (const auto& item : results) {
- std::cerr << std::get<0>(item) << " : " << std::get<1>(item) << std::endl;
- }
+ captureParams(results);
return results;
}
-static void
+static int
captureValidityPeriod()
{
- if (validityPeriod > 0) {
- return;
- }
std::cerr << "Step " << nStep++
<< ": Please type in your expected validity period of your certificate."
<< " Type the number of hours (168 for week, 730 for month, 8760 for year)."
<< " The CA may reject your application if your expected period is too long." << std::endl;
- std::string periodStr = "";
- getline(std::cin, periodStr);
- try {
- validityPeriod = std::stoi(periodStr);
- }
- catch (const std::exception& e) {
- validityPeriod = -1;
+ while (true) {
+ std::string periodStr = "";
+ getline(std::cin, periodStr);
+ try {
+ int validityPeriod = std::stoi(periodStr);
+ if (validityPeriod < 0) {
+ BOOST_THROW_EXCEPTION(std::runtime_error(""));
+ }
+ return validityPeriod;
+ }
+ catch (const std::exception &e) {
+ std::cerr << "Your input is invalid. Try again: " << std::endl;
+ }
}
}
@@ -110,7 +113,10 @@
static void
certFetchCb(const Data& reply)
{
- client.onCertFetchResponse(reply);
+ auto item = Requester::onCertFetchResponse(reply);
+ if (item) {
+ keyChain.addCertificate(keyChain.getPib().getIdentity(item->getIdentity()).getKey(item->getKeyName()), *item);
+ }
std::cerr << "Step " << nStep++
<< ": DONE! Certificate has already been installed to local keychain\n"
<< "Certificate Name: " << reply.getName().toUri() << std::endl;
@@ -119,35 +125,37 @@
static void
challengeCb(const Data& reply)
{
- client.onChallengeResponse(reply);
- if (client.getApplicationStatus() == Status::SUCCESS) {
- std::cerr << "DONE! Certificate has already been issued \n";
- face.expressInterest(*client.generateCertFetchInterest(), bind(&certFetchCb, _2),
+ try {
+ Requester::onChallengeResponse(*requesterState, reply);
+ } catch (const std::exception& e) {
+ std::cerr << "Error when decoding challenge step: " << e.what() << std::endl;
+ exit(1);
+ }
+ if (requesterState->m_status == Status::SUCCESS) {
+ std::cerr << "Certificate has already been issued, downloading certificate... \n";
+ face.expressInterest(*Requester::genCertFetchInterest(*requesterState), bind(&certFetchCb, _2),
bind(&onNackCb), bind(&timeoutCb));
return;
}
- auto challenge = ChallengeModule::createChallengeModule(challengeType);
- auto requirement = challenge->getRequestedParameterList(client.getApplicationStatus(),
- client.getChallengeStatus());
- if (requirement.size() > 0) {
- std::cerr << "Step " << nStep++ << ": Please satisfy following instruction(s)\n";
- captureParams(requirement);
- }
- face.expressInterest(*client.generateChallengeInterest(challenge->genChallengeRequestTLV(client.getApplicationStatus(),
- client.getChallengeStatus(),
- std::move(requirement))),
- bind(&challengeCb, _2), bind(&onNackCb), bind(&timeoutCb));
+ runChallenge(requesterState->m_challengeType);
}
static void
newCb(const Data& reply)
{
+ std::list<std::string> challengeList;
+ try {
+ challengeList = Requester::onNewRenewRevokeResponse(*requesterState, reply);
+ } catch (const std::exception& e) {
+ std::cerr << "Error on decoding NEW step reply because: " << e.what() << std::endl;
+ exit(1);
+ }
+
int challengeIndex = 0;
- auto challengeList = client.onNewRenewRevokeResponse(reply);
if (challengeList.size() < 1) {
std::cerr << "There is no available challenge provided by the CA. Exit" << std::endl;
- return;
+ exit(1);
}
else if (challengeList.size() > 1) {
int count = 0;
@@ -157,56 +165,54 @@
for (auto item : challengeList) {
std::cerr << "\t" << count++ << " : " << item << std::endl;
}
- getline(std::cin, choice);
- try {
- challengeIndex = std::stoi(choice);
- }
- catch (const std::exception& e) {
- challengeIndex = -1;
- }
- if (challengeIndex < 0 || challengeIndex >= count) {
- std::cerr << "Your input index is out of range. Exit." << std::endl;
- return;
+ while (true) {
+ getline(std::cin, choice);
+ try {
+ challengeIndex = std::stoi(choice);
+ }
+ catch (const std::exception &e) {
+ std::cerr << "Your input is not valid. Try again:" << std::endl;
+ continue;
+ }
+ if (challengeIndex < 0 || challengeIndex >= count) {
+ std::cerr << "Your input index is out of range. Try again:" << std::endl;
+ continue;
+ }
+ break;
}
}
auto it = challengeList.begin();
std::advance(it, challengeIndex);
unique_ptr<ChallengeModule> challenge = ChallengeModule::createChallengeModule(*it);
if (challenge != nullptr) {
- challengeType = *it;
- std::cerr << "The challenge has been selected: " << challengeType << std::endl;
+ std::cerr << "The challenge has been selected: " << *it << std::endl;
+ runChallenge(*it);
}
else {
std::cerr << "Error. Cannot load selected Challenge Module. Exit." << std::endl;
- return;
+ exit(1);
}
- auto requirement = challenge->getRequestedParameterList(client.getApplicationStatus(),
- client.getChallengeStatus());
- if (requirement.size() > 0) {
- std::cerr << "Step " << nStep++ << ": Please provide parameters used for Identity Verification Challenge\n";
- captureParams(requirement);
- }
- face.expressInterest(*client.generateChallengeInterest(challenge->genChallengeRequestTLV(client.getApplicationStatus(),
- client.getChallengeStatus(),
- std::move(requirement))),
- bind(&challengeCb, _2), bind(&onNackCb), bind(&timeoutCb));
}
static void
InfoCb(const Data& reply)
{
- const Block& contentBlock = reply.getContent();
-
- if (!client.verifyInfoResponse(reply)) {
- std::cerr << "The fetched CA information cannot be trusted because its integrity is broken" << std::endl;
- return;
+ CaProfile profile;
+ try {
+ auto profileOpt = Requester::onCaProfileResponse(reply);
+ if (!profileOpt) {
+ BOOST_THROW_EXCEPTION(std::runtime_error("Invalid reply"));
+ }
+ profile = *profileOpt;
+ } catch(const std::exception& e) {
+ std::cerr << "The fetched CA information cannot be used because: "<< e.what() << std::endl;
+ return;
}
- auto caItem = INFO::decodeDataContent(contentBlock);
std::cerr << "Will use a new trust anchor, please double check the identity info: \n"
<< "This trust anchor information is signed by " << reply.getSignature().getKeyLocator()
<< std::endl
- << "The certificate is " << *caItem.m_cert << std::endl
+ << "The certificate is " << profile.m_cert << std::endl
<< "Do you trust the information? Type in YES or NO" << std::endl;
std::string answer;
@@ -214,50 +220,75 @@
boost::algorithm::to_lower(answer);
if (answer == "yes") {
std::cerr << "You answered YES: new CA will be used" << std::endl;
- client.addCaFromInfoResponse(reply);
+ runProbe(profile);
// client.getClientConf().save(std::string(SYSCONFDIR) + "/ndncert/client.conf");
- startApplication();
}
else {
std::cerr << "You answered NO: new CA will not be used" << std::endl;
- return;
+ exit(0);
}
}
static void
-probeCb(const Data& reply)
+probeCb(const Data& reply, CaProfile profile)
{
- client.onProbeResponse(reply);
- captureValidityPeriod();
- if (validityPeriod <= 0) {
- std::cerr << "Invalid period time. Exit." << std::endl;
- return;
- }
- auto now = time::system_clock::now();
- std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
- auto interest = client.generateNewInterest(now, now + time::hours(validityPeriod), Name());
- if (interest != nullptr) {
- face.expressInterest(*interest, bind(&newCb, _2), bind(&onNackCb), bind(&timeoutCb));
- }
- else {
- std::cerr << "Cannot generate the Interest for NEW step. Exit" << std::endl;
- }
-}
-
-static void
-startApplication()
-{
- nStep = 0;
- auto caList = client.getClientConf().m_caItems;
+ std::vector<Name> names;
+ std::vector<Name> redirects;
+ Requester::onProbeResponse(reply, profile, names, redirects);
int count = 0;
- for (auto item : caList) {
+ std::cerr << "Here is CA's suggested names: " << std::endl;
+ for (const auto& name : names) {
+ std::cerr << count ++ << ": " << name.toUri() << std::endl;
+ }
+ std::cerr << "Here is CA's suggested redirects to other CAs: " << std::endl;
+ for (const auto& redirect : redirects) {
+ std::cerr << count ++ << ": " << redirect.toUri() << std::endl;
+ }
+ int index;
+ try {
+ std::string input;
+ getline(std::cin, input);
+ index = std::stoi(input);
+ }
+ catch (const std::exception& e) {
+ std::cerr << "Your input is Invalid. Exit" << std::endl;
+ exit(0);
+ }
+ if (index < 0 || index >= names.size() + redirects.size()) {
+ std::cerr << "Your input is not an existing index. Exit" << std::endl;
+ return;
+ }
+ if (index < names.size()) {
+ //names
+ std::cerr << "You selected name: " << names[index].toUri() << std::endl;
+ runNew(profile, names[index]);
+ } else {
+ //redirects
+ std::cerr << "You selected redirects with certificate: " << redirects[index - names.size()].toUri() << std::endl;
+ face.expressInterest(*Requester::genCaProfileInterest(redirects[index - names.size()]),
+ bind(&InfoCb, _2), bind(&onNackCb), bind(&timeoutCb));
+ }
+}
+
+static void
+selectCaProfile(std::string configFilePath)
+{
+ RequesterCaCache caCache;
+ try {
+ caCache.load(configFilePath);
+ }
+ catch (const std::exception& e) {
+ std::cerr << "Cannot load the configuration file: " << e.what() << std::endl;
+ exit(1);
+ }
+ int count = 0;
+ for (auto item : caCache.m_caItems) {
std::cerr << "***************************************\n"
<< "Index: " << count++ << "\n"
<< "CA prefix:" << item.m_caPrefix << "\n"
<< "Introduction: " << item.m_caInfo << "\n"
<< "***************************************\n";
}
- std::vector<CaProfile> caVector{std::begin(caList), std::end(caList)};
std::cerr << "Step "
<< nStep++ << ": Please type in the CA INDEX that you want to apply"
<< " or type in NONE if your expected CA is not in the list\n";
@@ -270,7 +301,7 @@
std::cerr << "Step " << nStep << ": Please type in the CA Name\n";
std::string expectedCAName;
getline(std::cin, expectedCAName);
- face.expressInterest(*client.generateInfoInterest(Name(expectedCAName)),
+ face.expressInterest(*Requester::genCaProfileInterest(Name(expectedCAName)),
bind(&InfoCb, _2), bind(&onNackCb), bind(&timeoutCb));
}
else {
@@ -286,35 +317,75 @@
std::cerr << "Your input is not an existing index. Exit" << std::endl;
return;
}
- auto targetCaItem = caVector[caIndex];
+ auto itemIterator = caCache.m_caItems.cbegin();
+ std::advance(itemIterator, caIndex);
+ auto targetCaItem = *itemIterator;
+ runProbe(targetCaItem);
+ }
+}
- if (!targetCaItem.m_probeParameterKeys.empty()) {
- std::cerr << "Step " << nStep++ << ": Please provide information for name assignment" << std::endl;
- auto capturedParams = captureParams(targetCaItem.m_probeParameterKeys);
- face.expressInterest(*client.generateProbeInterest(targetCaItem, std::move(capturedParams)),
- bind(&probeCb, _2), bind(&onNackCb), bind(&timeoutCb));
+static void runProbe(CaProfile profile)
+{
+ std::cerr << "Do you have the identity name already? Type in YES or NO" << std::endl;
+ bool validAnswer = false;
+ while (!validAnswer) {
+ std::string answer;
+ getline(std::cin, answer);
+ boost::algorithm::to_lower(answer);
+ if (answer == "yes") {
+ validAnswer = true;
+ std::cerr << "You answered YES: " << std::endl;
+ std::cerr << "Step " << nStep++ << ": Please type in the full identity name you want to get (with CA prefix)\n";
+ std::string identityNameStr;
+ getline(std::cin, identityNameStr);
+ runNew(profile, Name(identityNameStr));
+ } else if (answer == "no") {
+ validAnswer = true;
+ std::cerr << "You answered NO: new CA will not be used" << std::endl;
+ std::cerr << "Step " << nStep++ << ": Please provide information for name assignment" << std::endl;
+ auto capturedParams = captureParams(profile.m_probeParameterKeys);
+ face.expressInterest(*Requester::genProbeInterest(profile, std::move(capturedParams)),
+ bind(&probeCb, _2, profile), bind(&onNackCb), bind(&timeoutCb));
+ } else {
+ std::cerr << "Invalid answer. Type in YES or NO" << std::endl;
+ }
+ }
+}
+
+static void
+runNew(CaProfile profile, Name identityName)
+{
+ int validityPeriod = captureValidityPeriod();
+ auto now = time::system_clock::now();
+ std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
+ requesterState = make_shared<RequesterState>(keyChain, profile, RequestType::NEW);
+ auto interest = Requester::genNewInterest(*requesterState, identityName, now, now + time::hours(validityPeriod));
+ if (interest != nullptr) {
+ face.expressInterest(*interest, bind(&newCb, _2), bind(&onNackCb), bind(&timeoutCb));
}
else {
- std::cerr << "Step " << nStep++ << ": Please type in the full identity name you want to get (with CA prefix)\n";
- std::string identityNameStr;
- getline(std::cin, identityNameStr);
- captureValidityPeriod();
- if (validityPeriod <= 0) {
- std::cerr << "Invalid period time. Exit." << std::endl;
- return;
- }
- Name idName(identityNameStr);
- std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
- auto now = time::system_clock::now();
- auto interest = client.generateNewInterest(now, now + time::hours(validityPeriod), idName);
- if (interest != nullptr) {
- face.expressInterest(*interest, bind(&newCb, _2), bind(&onNackCb), bind(&timeoutCb));
- }
- else {
std::cerr << "Cannot generate the Interest for NEW step. Exit" << std::endl;
- }
}
+}
+
+static void
+runChallenge(const std::string& challengeType)
+{
+ auto requirement = Requester::selectOrContinueChallenge(*requesterState, challengeType);
+ if (requirement.size() > 0) {
+ std::cerr << "Step " << nStep++ << ": Please provide parameters used for Identity Verification Challenge\n";
+ captureParams(requirement);
}
+ face.expressInterest(*Requester::genChallengeInterest(*requesterState, std::move(requirement)),
+ bind(&challengeCb, _2), bind(&onNackCb), bind(&timeoutCb));
+
+}
+
+
+static void
+startApplication(std::string configFilePath)
+{
+ selectCaProfile(configFilePath);
}
static void
@@ -332,8 +403,11 @@
std::cerr << signalName;
}
std::cerr << std::endl;
- client.endSession();
+ if (requesterState) {
+ Requester::endSession(*requesterState);
+ }
face.getIoService().stop();
+ exit(1);
}
int
@@ -347,8 +421,9 @@
namespace po = boost::program_options;
std::string configFilePath = std::string(SYSCONFDIR) + "/ndncert/client.conf";
po::options_description description("General Usage\n ndncert-client [-h] [-c] [-v]\n");
- description.add_options()("help,h", "produce help message")("config-file,c", po::value<std::string>(&configFilePath), "configuration file name")("validity-period,v", po::value<int>(&validityPeriod)->default_value(-1),
- "desired validity period (hours) of the certificate being requested");
+ description.add_options()
+ ("help,h", "produce help message")
+ ("config-file,c", po::value<std::string>(&configFilePath), "configuration file name");
po::positional_options_description p;
po::variables_map vm;
@@ -364,14 +439,7 @@
std::cerr << description << std::endl;
return 0;
}
- try {
- client.getClientConf().load(configFilePath);
- }
- catch (const std::exception& e) {
- std::cerr << "Cannot load the configuration file: " << e.what() << std::endl;
- return 1;
- }
- startApplication();
+ startApplication(configFilePath);
face.processEvents();
return 0;
}