Delete created identities/keys if the client doesn't complete successfully; update client command line tool

Client command line tool:
* remove infinite loop asking for user input when input is of wrong format
* add signal handling

Refs: #4962
Change-Id: Ib4f8143f6efd45dee7232f99c5b791f09926bb46
diff --git a/src/client-module.cpp b/src/client-module.cpp
index 9ae71c0..0daa72c 100644
--- a/src/client-module.cpp
+++ b/src/client-module.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
  *
  * This file is part of ndncert, a certificate management system based on NDN.
  *
@@ -40,7 +40,10 @@
 {
 }
 
-ClientModule::~ClientModule() = default;
+ClientModule::~ClientModule()
+{
+  endSession();
+}
 
 shared_ptr<Interest>
 ClientModule::generateProbeInfoInterest(const Name& caName)
@@ -158,14 +161,22 @@
 
   // generate a newly key pair or use an existing key
   const auto& pib = m_keyChain.getPib();
+  security::pib::Identity identity;
   try {
-    auto identity = pib.getIdentity(m_identityName);
-    m_key = m_keyChain.createKey(identity);
+    identity = pib.getIdentity(m_identityName);
   }
   catch (const security::Pib::Error& e) {
-    auto identity = m_keyChain.createIdentity(m_identityName);
+    identity = m_keyChain.createIdentity(m_identityName);
+    m_isNewlyCreatedIdentity = true;
+    m_isNewlyCreatedKey = true;
+  }
+  try {
     m_key = identity.getDefaultKey();
   }
+  catch (const security::Pib::Error& e) {
+    m_key = m_keyChain.createKey(identity);
+    m_isNewlyCreatedKey = true;
+  }
 
   // generate certificate request
   security::v2::Certificate certRequest;
@@ -286,19 +297,20 @@
   return interest;
 }
 
-void
+shared_ptr<security::v2::Certificate>
 ClientModule::onDownloadResponse(const Data& reply)
 {
   try {
     security::v2::Certificate cert(reply.getContent().blockFromValue());
     m_keyChain.addCertificate(m_key, cert);
     _LOG_TRACE("Got DOWNLOAD response and installed the cert " << cert.getName());
+    m_isCertInstalled = true;
+    return make_shared<security::v2::Certificate>(cert);
   }
   catch (const std::exception& e) {
     _LOG_ERROR("Cannot add replied certificate into the keychain " << e.what());
-    return;
+    return nullptr;
   }
-  m_isCertInstalled = true;
 }
 
 void
@@ -307,6 +319,25 @@
   onDownloadResponse(reply);
 }
 
+void
+ClientModule::endSession()
+{
+  if (getApplicationStatus() == STATUS_SUCCESS || getApplicationStatus() == STATUS_ENDED) {
+    return;
+  }
+  if (m_isNewlyCreatedIdentity) {
+    // put the identity into the if scope is because it may cause an error
+    // outside since when endSession is called, identity may not have been created yet.
+    auto identity = m_keyChain.getPib().getIdentity(m_identityName);
+    m_keyChain.deleteIdentity(identity);
+  }
+  else if (m_isNewlyCreatedKey) {
+    auto identity = m_keyChain.getPib().getIdentity(m_identityName);
+    m_keyChain.deleteKey(identity, m_key);
+  }
+  m_status = STATUS_ENDED;
+}
+
 JsonSection
 ClientModule::getJsonFromData(const Data& data)
 {
diff --git a/src/client-module.hpp b/src/client-module.hpp
index b3655ef..fb20d4b 100644
--- a/src/client-module.hpp
+++ b/src/client-module.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
  *
  * This file is part of ndncert, a certificate management system based on NDN.
  *
@@ -22,8 +22,8 @@
 #define NDNCERT_CLIENT_MODULE_HPP
 
 #include "client-config.hpp"
-#include "crypto-support/crypto-helper.hpp"
 #include "certificate-request.hpp"
+#include "crypto-support/crypto-helper.hpp"
 
 namespace ndn {
 namespace ndncert {
@@ -47,7 +47,6 @@
 public:
   ClientModule(security::v2::KeyChain& keyChain);
 
-  virtual
   ~ClientModule();
 
   ClientConfig&
@@ -109,7 +108,7 @@
   shared_ptr<Interest>
   generateCertFetchInterest();
 
-  void
+  shared_ptr<security::v2::Certificate>
   onDownloadResponse(const Data& reply);
 
   void
@@ -125,6 +124,9 @@
   static std::vector<std::string>
   parseProbeComponents(const std::string& probe);
 
+  void
+  endSession();
+
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   const JsonSection
   genProbeRequestJson(const ClientCaItem& ca, const std::string& probeInfo);
@@ -148,6 +150,8 @@
   std::string m_certId = "";
   std::list<std::string> m_challengeList;
   bool m_isCertInstalled = false;
+  bool m_isNewlyCreatedIdentity = false;
+  bool m_isNewlyCreatedKey = false;
 
   int m_remainingTries = 0;
   time::system_clock::TimePoint m_freshBefore;
diff --git a/src/ndncert-common.hpp b/src/ndncert-common.hpp
index 9835578..860fc8c 100644
--- a/src/ndncert-common.hpp
+++ b/src/ndncert-common.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
  *
  * This file is part of ndncert, a certificate management system based on NDN.
  *
@@ -116,7 +116,8 @@
   STATUS_PENDING = 2,
   STATUS_SUCCESS = 3,
   STATUS_FAILURE = 4,
-  STATUS_NOT_STARTED = 5
+  STATUS_NOT_STARTED = 5,
+  STATUS_ENDED = 6
 };
 
 // Pre-defined challenge status