security: Pair-up Tpm and Pib in KeyChain

In this commit, we also change the HOME setting for test cases.

Change-Id: I7fa15461555b3519d9d2005c6956c167ed07d66f
Refs: #2242
Refs: #2260
diff --git a/src/security/key-chain.cpp b/src/security/key-chain.cpp
index f22c5a9..9360671 100644
--- a/src/security/key-chain.cpp
+++ b/src/security/key-chain.cpp
@@ -41,96 +41,177 @@
 const RsaKeyParams KeyChain::DEFAULT_KEY_PARAMS;
 
 KeyChain::KeyChain()
-  : m_pib(0)
-  , m_tpm(0)
+  : m_pib(nullptr)
+  , m_tpm(nullptr)
   , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
 {
+  initialize("", "", false);
+}
 
-  ConfigFile config;
-  const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
-
-  std::string pibName;
-  try
-    {
-      pibName = parsed.get<std::string>("pib");
-    }
-  catch (boost::property_tree::ptree_bad_path& error)
-    {
-      // pib is not specified, take the default
-    }
-  catch (boost::property_tree::ptree_bad_data& error)
-    {
-      throw ConfigFile::Error(error.what());
-    }
-
-  std::string tpmName;
-  try
-    {
-      tpmName = parsed.get<std::string>("tpm");
-    }
-  catch (boost::property_tree::ptree_bad_path& error)
-    {
-      // tpm is not specified, take the default
-    }
-  catch (boost::property_tree::ptree_bad_data& error)
-    {
-      throw ConfigFile::Error(error.what());
-    }
-
-
-  if (pibName.empty() || pibName == "sqlite3")
-    m_pib = new SecPublicInfoSqlite3;
-  else
-    throw Error("PIB type '" + pibName + "' is not supported");
-
-  if (tpmName.empty())
-#if defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
-    m_tpm = new SecTpmOsx();
-#else
-    m_tpm = new SecTpmFile();
-#endif // defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
-  else if (tpmName == "osx-keychain")
-#if defined(NDN_CXX_HAVE_OSX_SECURITY)
-    m_tpm = new SecTpmOsx();
-#else
-    throw Error("TPM type '" + tpmName + "' is not supported on this platform");
-#endif // NDN_CXX_HAVE_OSX_SECURITY
-  else if (tpmName == "file")
-    m_tpm = new SecTpmFile();
-  else
-    throw Error("TPM type '" + tpmName + "' is not supported");
+template<class T>
+inline
+KeyChain::KeyChain(T traits)
+  : m_pib(new typename T::Pib)
+  , m_tpm(nullptr)
+  , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
+{
+  initialize(T::Pib::SCHEME, T::Tpm::SCHEME, false);
 }
 
 KeyChain::KeyChain(const std::string& pibName,
-                   const std::string& tpmName)
-  : m_pib(0)
-  , m_tpm(0)
+                   const std::string& tpmName,
+                   bool allowReset)
+  : m_pib(nullptr)
+  , m_tpm(nullptr)
   , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
 {
-  if (pibName == "sqlite3")
-    m_pib = new SecPublicInfoSqlite3;
-  else
-    throw Error("PIB type '" + pibName + "' is not supported");
+  std::string pibLocator;
+  std::string tpmLocator;
 
   if (tpmName == "file")
-    m_tpm = new SecTpmFile;
+    tpmLocator = SecTpmFile::SCHEME;
 #if defined(NDN_CXX_HAVE_OSX_SECURITY)
   else if (tpmName == "osx-keychain")
-    m_tpm = new SecTpmOsx();
+    tpmLocator = SecTpmOsx::SCHEME;
 #endif //NDN_CXX_HAVE_OSX_SECURITY
   else
-    throw Error("TPM type '" + tpmName + "' is not supported");
+    tpmLocator = tpmName;
+
+  if (pibName == "sqlite3")
+    pibLocator = SecPublicInfoSqlite3::SCHEME;
+  else
+    pibLocator = pibName;
+
+  initialize(pibLocator, tpmLocator, allowReset);
 }
 
 KeyChain::~KeyChain()
 {
-  if (m_pib != 0)
+  if (m_pib != nullptr)
     delete m_pib;
 
-  if (m_tpm != 0)
+  if (m_tpm != nullptr)
     delete m_tpm;
 }
 
+void
+KeyChain::initialize(const std::string& pib,
+                     const std::string& tpm,
+                     bool allowReset)
+{
+  ConfigFile config;
+  const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
+
+  std::string defaultTpmLocator;
+  try {
+    defaultTpmLocator = parsed.get<std::string>("tpm");
+  }
+  catch (boost::property_tree::ptree_bad_path&) {
+    // tpm is not specified, take the default
+  }
+  catch (boost::property_tree::ptree_bad_data& error) {
+    throw ConfigFile::Error(error.what());
+  }
+
+  if (defaultTpmLocator.empty())
+#if defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
+    defaultTpmLocator = SecTpmOsx::SCHEME;
+#else
+    defaultTpmLocator = SecTpmFile::SCHEME;
+#endif // defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
+  else if (defaultTpmLocator == "osx-keychain")
+#if defined(NDN_CXX_HAVE_OSX_SECURITY)
+    defaultTpmLocator = SecTpmOsx::SCHEME;
+#else
+    throw Error("TPM Locator '" + defaultTpmLocator + "' is not supported on this platform");
+#endif // NDN_CXX_HAVE_OSX_SECURITY
+  else if (defaultTpmLocator == "file")
+    defaultTpmLocator = SecTpmFile::SCHEME;
+
+  std::string defaultPibLocator;
+  try {
+    defaultPibLocator = parsed.get<std::string>("pib");
+  }
+  catch (boost::property_tree::ptree_bad_path&) {
+    // pib is not specified, take the default
+  }
+  catch (boost::property_tree::ptree_bad_data& error) {
+    throw ConfigFile::Error(error.what());
+  }
+
+  if (defaultPibLocator.empty() || defaultPibLocator == "sqlite3")
+    defaultPibLocator = SecPublicInfoSqlite3::SCHEME;
+
+  std::string pibLocator = pib;
+  std::string tpmLocator = tpm;
+
+  if (pibLocator == "")
+    pibLocator = defaultPibLocator;
+
+  if (defaultPibLocator == pibLocator)
+    tpmLocator = defaultTpmLocator;
+
+  initializePib(pibLocator);
+
+  std::string currentTpmLocator;
+  try {
+    currentTpmLocator = m_pib->getTpmLocator();
+
+    if (currentTpmLocator != tpmLocator) {
+      if (!allowReset) {
+        // Tpm mismatch, but we do not want to reset PIB
+        throw MismatchError("TPM locator supplied and TPM locator in PIB mismatch: " +
+                            currentTpmLocator + " != " + tpmLocator);
+      }
+      else {
+        // reset is explicitly required
+        tpmLocator = currentTpmLocator;
+      }
+    }
+  }
+  catch (SecPublicInfo::Error&) {
+    // TPM locator is not set in PIB yet.
+  }
+
+  initializeTpm(tpmLocator); // note that key mismatch may still happen
+                             // if the TPM locator is initially set to a wrong one
+                             // or if the PIB was shared by more than one TPMs before.
+                             // This is due to the old PIB does not have TPM info,
+                             // new pib should not have this problem.
+
+  m_pib->setTpmLocator(tpmLocator);
+}
+
+void
+KeyChain::initializeTpm(const std::string& locator)
+{
+  size_t pos = locator.find(':');
+  std::string type = locator.substr(0, pos + 1);
+  std::string location = locator.substr(pos + 1);
+
+  if (type == SecTpmFile::SCHEME)
+    m_tpm = new SecTpmFile(location);
+#if defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
+  else if (type == SecTpmOsx::SCHEME)
+    m_tpm = new SecTpmOsx(location);
+#endif
+  else
+    throw Error("Tpm locator error: Unsupported Tpm type: " + type);
+}
+
+void
+KeyChain::initializePib(const std::string& locator)
+{
+  size_t pos = locator.find(':');
+  std::string type = locator.substr(0, pos + 1);
+  std::string location = locator.substr(pos + 1);
+
+  if (type == SecPublicInfoSqlite3::SCHEME)
+    m_pib = new SecPublicInfoSqlite3(location);
+  else
+    throw Error("Pib locator error: Unsupported Pib type: " + type);
+}
+
 Name
 KeyChain::createIdentity(const Name& identityName, const KeyParams& params)
 {
@@ -171,6 +252,20 @@
 }
 
 Name
+KeyChain::generateRsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
+{
+  RsaKeyParams params(keySize);
+  return generateKeyPair(identityName, isKsk, params);
+}
+
+Name
+KeyChain::generateEcdsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
+{
+  EcdsaKeyParams params(keySize);
+  return generateKeyPair(identityName, isKsk, params);
+}
+
+Name
 KeyChain::generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
 {
   RsaKeyParams params(keySize);
@@ -414,7 +509,7 @@
 
   shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
   // HACK! We should set key type according to the pkcs8 info.
-  m_pib->addPublicKey(keyName, KEY_TYPE_RSA, *pubKey);
+  m_pib->addKey(keyName, *pubKey);
   m_pib->setDefaultKeyNameForIdentity(keyName);
 
   // Add cert