security: Add new v2::KeyChain

Change-Id: I5fdf51ecd96b50db2a7cbf730c6e8b1d9fbe09e9
Refs: #2926
diff --git a/src/security/pib/identity-container.hpp b/src/security/pib/identity-container.hpp
index 94cd370..9e45cf9 100644
--- a/src/security/pib/identity-container.hpp
+++ b/src/security/pib/identity-container.hpp
@@ -153,6 +153,7 @@
   mutable std::unordered_map<Name, shared_ptr<detail::IdentityImpl>> m_identities;
 
   shared_ptr<PibImpl> m_pibImpl;
+
   friend class Pib;
 };
 
diff --git a/src/security/pib/identity.cpp b/src/security/pib/identity.cpp
index 4797cb6..79cb090 100644
--- a/src/security/pib/identity.cpp
+++ b/src/security/pib/identity.cpp
@@ -40,13 +40,13 @@
 }
 
 Key
-Identity::addKey(const uint8_t* key, size_t keyLen, const Name& keyName)
+Identity::addKey(const uint8_t* key, size_t keyLen, const Name& keyName) const
 {
   return lock()->addKey(key, keyLen, keyName);
 }
 
 void
-Identity::removeKey(const Name& keyName)
+Identity::removeKey(const Name& keyName) const
 {
   return lock()->removeKey(keyName);
 }
@@ -64,13 +64,13 @@
 }
 
 const Key&
-Identity::setDefaultKey(const Name& keyName)
+Identity::setDefaultKey(const Name& keyName) const
 {
   return lock()->setDefaultKey(keyName);
 }
 
 const Key&
-Identity::setDefaultKey(const uint8_t* key, size_t keyLen, const Name& keyName)
+Identity::setDefaultKey(const uint8_t* key, size_t keyLen, const Name& keyName) const
 {
   return lock()->setDefaultKey(key, keyLen, keyName);
 }
diff --git a/src/security/pib/identity.hpp b/src/security/pib/identity.hpp
index 3d0117d..2bb1706 100644
--- a/src/security/pib/identity.hpp
+++ b/src/security/pib/identity.hpp
@@ -116,14 +116,14 @@
    * @throw Pib::Error a key with the same name already exists
    */
   Key
-  addKey(const uint8_t* key, size_t keyLen, const Name& keyName);
+  addKey(const uint8_t* key, size_t keyLen, const Name& keyName) const;
 
   /**
    * @brief Remove a key with @p keyName
    * @throw std::invalid_argument @p keyName does not match identity
    */
   void
-  removeKey(const Name& keyName);
+  removeKey(const Name& keyName) const;
 
   /**
    * @brief Set an existing key with @p keyName as the default key.
@@ -132,7 +132,7 @@
    * @return The default key
    */
   const Key&
-  setDefaultKey(const Name& keyName);
+  setDefaultKey(const Name& keyName) const;
 
   /**
    * @brief Add a @p key of @p keyLen bytes with @p keyName and set it as the default key
@@ -141,7 +141,7 @@
    * @return the default key
    */
   const Key&
-  setDefaultKey(const uint8_t* key, size_t keyLen, const Name& keyName);
+  setDefaultKey(const uint8_t* key, size_t keyLen, const Name& keyName) const;
 
 private:
   /**
@@ -154,6 +154,8 @@
 
 private:
   weak_ptr<detail::IdentityImpl> m_impl;
+
+  friend class v2::KeyChain;
 };
 
 } // namespace pib
diff --git a/src/security/pib/key.cpp b/src/security/pib/key.cpp
index b4e6daf..0d45140 100644
--- a/src/security/pib/key.cpp
+++ b/src/security/pib/key.cpp
@@ -59,13 +59,13 @@
 }
 
 void
-Key::addCertificate(const v2::Certificate& certificate)
+Key::addCertificate(const v2::Certificate& certificate) const
 {
   return lock()->addCertificate(certificate);
 }
 
 void
-Key::removeCertificate(const Name& certName)
+Key::removeCertificate(const Name& certName) const
 {
   return lock()->removeCertificate(certName);
 }
@@ -83,13 +83,13 @@
 }
 
 const v2::Certificate&
-Key::setDefaultCertificate(const Name& certName)
+Key::setDefaultCertificate(const Name& certName) const
 {
   return lock()->setDefaultCertificate(certName);
 }
 
 const v2::Certificate&
-Key::setDefaultCertificate(const v2::Certificate& certificate)
+Key::setDefaultCertificate(const v2::Certificate& certificate) const
 {
   return lock()->setDefaultCertificate(certificate);
 }
diff --git a/src/security/pib/key.hpp b/src/security/pib/key.hpp
index 69ceec8..4acc54a 100644
--- a/src/security/pib/key.hpp
+++ b/src/security/pib/key.hpp
@@ -28,7 +28,9 @@
 namespace ndn {
 namespace security {
 
+namespace v2 {
 class KeyChain;
+} // namespace v2
 
 namespace pib {
 
@@ -138,14 +140,14 @@
    * @throw Pib::Error a certificate with the same name already exists
    */
   void
-  addCertificate(const v2::Certificate& certificate);
+  addCertificate(const v2::Certificate& certificate) const;
 
   /**
    * @brief Remove a certificate with @p certName
    * @throw std::invalid_argument @p certName does not match key name
    */
   void
-  removeCertificate(const Name& certName);
+  removeCertificate(const Name& certName) const;
 
   /**
    * @brief Set an existing certificate with @p certName as the default certificate
@@ -154,7 +156,7 @@
    * @return the default certificate
    */
   const v2::Certificate&
-  setDefaultCertificate(const Name& certName);
+  setDefaultCertificate(const Name& certName) const;
 
   /**
    * @brief Add @p certificate and set it as the default certificate of the key
@@ -163,7 +165,7 @@
    * @return the default certificate
    */
   const v2::Certificate&
-  setDefaultCertificate(const v2::Certificate& certificate);
+  setDefaultCertificate(const v2::Certificate& certificate) const;
 
 private:
   /**
@@ -176,6 +178,8 @@
 
 private:
   weak_ptr<detail::KeyImpl> m_impl;
+
+  friend class v2::KeyChain;
 };
 
 } // namespace pib
diff --git a/src/security/pib/pib-memory.cpp b/src/security/pib/pib-memory.cpp
index aa93ba7..2d6aa7d 100644
--- a/src/security/pib/pib-memory.cpp
+++ b/src/security/pib/pib-memory.cpp
@@ -27,11 +27,18 @@
 namespace security {
 namespace pib {
 
-PibMemory::PibMemory()
+PibMemory::PibMemory(const std::string&)
   : m_hasDefaultIdentity(false)
 {
 }
 
+const std::string&
+PibMemory::getScheme()
+{
+  static std::string scheme = "pib-memory";
+  return scheme;
+}
+
 void
 PibMemory::setTpmLocator(const std::string& tpmLocator)
 {
diff --git a/src/security/pib/pib-memory.hpp b/src/security/pib/pib-memory.hpp
index 192f000..1252909 100644
--- a/src/security/pib/pib-memory.hpp
+++ b/src/security/pib/pib-memory.hpp
@@ -48,7 +48,15 @@
   };
 
 public:
-  PibMemory();
+  /**
+   * @brief Create memory based PIB backend
+   * @param location Not used (required by the PIB-registration interface)
+   */
+  explicit
+  PibMemory(const std::string& location = "");
+
+  static const std::string&
+  getScheme();
 
 public: // TpmLocator management
   void
diff --git a/src/security/pib/pib-sqlite3.cpp b/src/security/pib/pib-sqlite3.cpp
index b19f32c..238a0f8 100644
--- a/src/security/pib/pib-sqlite3.cpp
+++ b/src/security/pib/pib-sqlite3.cpp
@@ -32,171 +32,171 @@
 namespace security {
 namespace pib {
 
-using std::string;
 using util::Sqlite3Statement;
 
-static const string INITIALIZATION =
-  "CREATE TABLE IF NOT EXISTS                    \n"
-  "  tpmInfo(                                    \n"
-  "    tpm_locator           BLOB                \n"
-  "  );                                          \n"
-  "                                              \n"
-  "CREATE TABLE IF NOT EXISTS                    \n"
-  "  identities(                                 \n"
-  "    id                    INTEGER PRIMARY KEY,\n"
-  "    identity              BLOB NOT NULL,      \n"
-  "    is_default            INTEGER DEFAULT 0   \n"
-  "  );                                          \n"
-  "                                              \n"
-  "CREATE UNIQUE INDEX IF NOT EXISTS             \n"
-  "  identityIndex ON identities(identity);      \n"
-  "                                              \n"
-  "CREATE TRIGGER IF NOT EXISTS                  \n"
-  "  identity_default_before_insert_trigger      \n"
-  "  BEFORE INSERT ON identities                 \n"
-  "  FOR EACH ROW                                \n"
-  "  WHEN NEW.is_default=1                       \n"
-  "  BEGIN                                       \n"
-  "    UPDATE identities SET is_default=0;       \n"
-  "  END;                                        \n"
-  "                                              \n"
-  "CREATE TRIGGER IF NOT EXISTS                  \n"
-  "  identity_default_after_insert_trigger       \n"
-  "  AFTER INSERT ON identities                  \n"
-  "  FOR EACH ROW                                \n"
-  "  WHEN NOT EXISTS                             \n"
-  "    (SELECT id                                \n"
-  "       FROM identities                        \n"
-  "       WHERE is_default=1)                    \n"
-  "  BEGIN                                       \n"
-  "    UPDATE identities                         \n"
-  "      SET is_default=1                        \n"
-  "      WHERE identity=NEW.identity;            \n"
-  "  END;                                        \n"
-  "                                              \n"
-  "CREATE TRIGGER IF NOT EXISTS                  \n"
-  "  identity_default_update_trigger             \n"
-  "  BEFORE UPDATE ON identities                 \n"
-  "  FOR EACH ROW                                \n"
-  "  WHEN NEW.is_default=1 AND OLD.is_default=0  \n"
-  "  BEGIN                                       \n"
-  "    UPDATE identities SET is_default=0;       \n"
-  "  END;                                        \n"
-  "                                              \n"
-  "                                              \n"
-  "CREATE TABLE IF NOT EXISTS                    \n"
-  "  keys(                                       \n"
-  "    id                    INTEGER PRIMARY KEY,\n"
-  "    identity_id           INTEGER NOT NULL,   \n"
-  "    key_name              BLOB NOT NULL,      \n"
-  "    key_bits              BLOB NOT NULL,      \n"
-  "    is_default            INTEGER DEFAULT 0,  \n"
-  "    FOREIGN KEY(identity_id)                  \n"
-  "      REFERENCES identities(id)               \n"
-  "      ON DELETE CASCADE                       \n"
-  "      ON UPDATE CASCADE                       \n"
-  "  );                                          \n"
-  "                                              \n"
-  "CREATE UNIQUE INDEX IF NOT EXISTS             \n"
-  "  keyIndex ON keys(key_name);                 \n"
-  "                                              \n"
-  "CREATE TRIGGER IF NOT EXISTS                  \n"
-  "  key_default_before_insert_trigger           \n"
-  "  BEFORE INSERT ON keys                       \n"
-  "  FOR EACH ROW                                \n"
-  "  WHEN NEW.is_default=1                       \n"
-  "  BEGIN                                       \n"
-  "    UPDATE keys                               \n"
-  "      SET is_default=0                        \n"
-  "      WHERE identity_id=NEW.identity_id;      \n"
-  "  END;                                        \n"
-  "                                              \n"
-  "CREATE TRIGGER IF NOT EXISTS                  \n"
-  "  key_default_after_insert_trigger            \n"
-  "  AFTER INSERT ON keys                        \n"
-  "  FOR EACH ROW                                \n"
-  "  WHEN NOT EXISTS                             \n"
-  "    (SELECT id                                \n"
-  "       FROM keys                              \n"
-  "       WHERE is_default=1                     \n"
-  "         AND identity_id=NEW.identity_id)     \n"
-  "  BEGIN                                       \n"
-  "    UPDATE keys                               \n"
-  "      SET is_default=1                        \n"
-  "      WHERE key_name=NEW.key_name;            \n"
-  "  END;                                        \n"
-  "                                              \n"
-  "CREATE TRIGGER IF NOT EXISTS                  \n"
-  "  key_default_update_trigger                  \n"
-  "  BEFORE UPDATE ON keys                       \n"
-  "  FOR EACH ROW                                \n"
-  "  WHEN NEW.is_default=1 AND OLD.is_default=0  \n"
-  "  BEGIN                                       \n"
-  "    UPDATE keys                               \n"
-  "      SET is_default=0                        \n"
-  "      WHERE identity_id=NEW.identity_id;      \n"
-  "  END;                                        \n"
-  "                                              \n"
-  "                                              \n"
-  "CREATE TABLE IF NOT EXISTS                    \n"
-  "  certificates(                               \n"
-  "    id                    INTEGER PRIMARY KEY,\n"
-  "    key_id                INTEGER NOT NULL,   \n"
-  "    certificate_name      BLOB NOT NULL,      \n"
-  "    certificate_data      BLOB NOT NULL,      \n"
-  "    is_default            INTEGER DEFAULT 0,  \n"
-  "    FOREIGN KEY(key_id)                       \n"
-  "      REFERENCES keys(id)                     \n"
-  "      ON DELETE CASCADE                       \n"
-  "      ON UPDATE CASCADE                       \n"
-  "  );                                          \n"
-  "                                              \n"
-  "CREATE UNIQUE INDEX IF NOT EXISTS             \n"
-  "  certIndex ON certificates(certificate_name);\n"
-  "                                              \n"
-  "CREATE TRIGGER IF NOT EXISTS                  \n"
-  "  cert_default_before_insert_trigger          \n"
-  "  BEFORE INSERT ON certificates               \n"
-  "  FOR EACH ROW                                \n"
-  "  WHEN NEW.is_default=1                       \n"
-  "  BEGIN                                       \n"
-  "    UPDATE certificates                       \n"
-  "      SET is_default=0                        \n"
-  "      WHERE key_id=NEW.key_id;                \n"
-  "  END;                                        \n"
-  "                                              \n"
-  "CREATE TRIGGER IF NOT EXISTS                  \n"
-  "  cert_default_after_insert_trigger           \n"
-  "  AFTER INSERT ON certificates                \n"
-  "  FOR EACH ROW                                \n"
-  "  WHEN NOT EXISTS                             \n"
-  "    (SELECT id                                \n"
-  "       FROM certificates                      \n"
-  "       WHERE is_default=1                     \n"
-  "         AND key_id=NEW.key_id)               \n"
-  "  BEGIN                                       \n"
-  "    UPDATE certificates                       \n"
-  "      SET is_default=1                        \n"
-  "      WHERE certificate_name=NEW.certificate_name;\n"
-  "  END;                                        \n"
-  "                                              \n"
-  "CREATE TRIGGER IF NOT EXISTS                  \n"
-  "  cert_default_update_trigger                 \n"
-  "  BEFORE UPDATE ON certificates               \n"
-  "  FOR EACH ROW                                \n"
-  "  WHEN NEW.is_default=1 AND OLD.is_default=0  \n"
-  "  BEGIN                                       \n"
-  "    UPDATE certificates                       \n"
-  "      SET is_default=0                        \n"
-  "      WHERE key_id=NEW.key_id;                \n"
-  "  END;                                        \n";
+static const std::string INITIALIZATION = R"SQL(
+CREATE TABLE IF NOT EXISTS
+  tpmInfo(
+    tpm_locator           BLOB
+  );
 
-PibSqlite3::PibSqlite3(const string& dir)
+CREATE TABLE IF NOT EXISTS
+  identities(
+    id                    INTEGER PRIMARY KEY,
+    identity              BLOB NOT NULL,
+    is_default            INTEGER DEFAULT 0
+  );
+
+CREATE UNIQUE INDEX IF NOT EXISTS
+  identityIndex ON identities(identity);
+
+CREATE TRIGGER IF NOT EXISTS
+  identity_default_before_insert_trigger
+  BEFORE INSERT ON identities
+  FOR EACH ROW
+  WHEN NEW.is_default=1
+  BEGIN
+    UPDATE identities SET is_default=0;
+  END;
+
+CREATE TRIGGER IF NOT EXISTS
+  identity_default_after_insert_trigger
+  AFTER INSERT ON identities
+  FOR EACH ROW
+  WHEN NOT EXISTS
+    (SELECT id
+       FROM identities
+       WHERE is_default=1)
+  BEGIN
+    UPDATE identities
+      SET is_default=1
+      WHERE identity=NEW.identity;
+  END;
+
+CREATE TRIGGER IF NOT EXISTS
+  identity_default_update_trigger
+  BEFORE UPDATE ON identities
+  FOR EACH ROW
+  WHEN NEW.is_default=1 AND OLD.is_default=0
+  BEGIN
+    UPDATE identities SET is_default=0;
+  END;
+
+
+CREATE TABLE IF NOT EXISTS
+  keys(
+    id                    INTEGER PRIMARY KEY,
+    identity_id           INTEGER NOT NULL,
+    key_name              BLOB NOT NULL,
+    key_bits              BLOB NOT NULL,
+    is_default            INTEGER DEFAULT 0,
+    FOREIGN KEY(identity_id)
+      REFERENCES identities(id)
+      ON DELETE CASCADE
+      ON UPDATE CASCADE
+  );
+
+CREATE UNIQUE INDEX IF NOT EXISTS
+  keyIndex ON keys(key_name);
+
+CREATE TRIGGER IF NOT EXISTS
+  key_default_before_insert_trigger
+  BEFORE INSERT ON keys
+  FOR EACH ROW
+  WHEN NEW.is_default=1
+  BEGIN
+    UPDATE keys
+      SET is_default=0
+      WHERE identity_id=NEW.identity_id;
+  END;
+
+CREATE TRIGGER IF NOT EXISTS
+  key_default_after_insert_trigger
+  AFTER INSERT ON keys
+  FOR EACH ROW
+  WHEN NOT EXISTS
+    (SELECT id
+       FROM keys
+       WHERE is_default=1
+         AND identity_id=NEW.identity_id)
+  BEGIN
+    UPDATE keys
+      SET is_default=1
+      WHERE key_name=NEW.key_name;
+  END;
+
+CREATE TRIGGER IF NOT EXISTS
+  key_default_update_trigger
+  BEFORE UPDATE ON keys
+  FOR EACH ROW
+  WHEN NEW.is_default=1 AND OLD.is_default=0
+  BEGIN
+    UPDATE keys
+      SET is_default=0
+      WHERE identity_id=NEW.identity_id;
+  END;
+
+
+CREATE TABLE IF NOT EXISTS
+  certificates(
+    id                    INTEGER PRIMARY KEY,
+    key_id                INTEGER NOT NULL,
+    certificate_name      BLOB NOT NULL,
+    certificate_data      BLOB NOT NULL,
+    is_default            INTEGER DEFAULT 0,
+    FOREIGN KEY(key_id)
+      REFERENCES keys(id)
+      ON DELETE CASCADE
+      ON UPDATE CASCADE
+  );
+
+CREATE UNIQUE INDEX IF NOT EXISTS
+  certIndex ON certificates(certificate_name);
+
+CREATE TRIGGER IF NOT EXISTS
+  cert_default_before_insert_trigger
+  BEFORE INSERT ON certificates
+  FOR EACH ROW
+  WHEN NEW.is_default=1
+  BEGIN
+    UPDATE certificates
+      SET is_default=0
+      WHERE key_id=NEW.key_id;
+  END;
+
+CREATE TRIGGER IF NOT EXISTS
+  cert_default_after_insert_trigger
+  AFTER INSERT ON certificates
+  FOR EACH ROW
+  WHEN NOT EXISTS
+    (SELECT id
+       FROM certificates
+       WHERE is_default=1
+         AND key_id=NEW.key_id)
+  BEGIN
+    UPDATE certificates
+      SET is_default=1
+      WHERE certificate_name=NEW.certificate_name;
+  END;
+
+CREATE TRIGGER IF NOT EXISTS
+  cert_default_update_trigger
+  BEFORE UPDATE ON certificates
+  FOR EACH ROW
+  WHEN NEW.is_default=1 AND OLD.is_default=0
+  BEGIN
+    UPDATE certificates
+      SET is_default=0
+      WHERE key_id=NEW.key_id;
+  END;
+)SQL";
+
+PibSqlite3::PibSqlite3(const std::string& location)
 {
   // Determine the path of PIB DB
   boost::filesystem::path dbDir;
-  if (!dir.empty()) {
-    dbDir = boost::filesystem::path(dir);
+  if (!location.empty()) {
+    dbDir = boost::filesystem::path(location);
   }
 #ifdef NDN_CXX_HAVE_TESTS
   else if (getenv("TEST_HOME") != nullptr) {
@@ -222,7 +222,7 @@
                                );
 
   if (result != SQLITE_OK) {
-    BOOST_THROW_EXCEPTION(PibImpl::Error("PIB database cannot be opened/created in " + dir));
+    BOOST_THROW_EXCEPTION(PibImpl::Error("PIB database cannot be opened/created in " + location));
   }
 
   // enable foreign key
@@ -242,6 +242,13 @@
   sqlite3_close(m_database);
 }
 
+const std::string&
+PibSqlite3::getScheme()
+{
+  static std::string scheme = "pib-sqlite3";
+  return scheme;
+}
+
 void
 PibSqlite3::setTpmLocator(const std::string& tpmLocator)
 {
diff --git a/src/security/pib/pib-sqlite3.hpp b/src/security/pib/pib-sqlite3.hpp
index 5571657..d27dab6 100644
--- a/src/security/pib/pib-sqlite3.hpp
+++ b/src/security/pib/pib-sqlite3.hpp
@@ -40,25 +40,28 @@
 {
 public:
   /**
-   * @brief Constructor of PibSqlite3
+   * @brief Create sqlite3-based PIB backed
    *
-   * This method will create a SQLite3 database file under the directory @p dir.
+   * This method will create a SQLite3 database file under the directory @p location.
    * If the directory does not exist, it will be created automatically.
    * It assumes that the directory does not contain a PIB database of an older version,
    * It is user's responsibility to update the older version database or remove the database.
    *
-   * @param dir The directory where the database file is located. By default, it points to the
-   *        $HOME/.ndn directory.
+   * @param location The directory where the database file is located. By default, it points to the
+   *                 $HOME/.ndn directory.
    * @throw PibImpl::Error when initialization fails.
    */
   explicit
-  PibSqlite3(const std::string& dir = "");
+  PibSqlite3(const std::string& location = "");
 
   /**
    * @brief Destruct and cleanup internal state
    */
   ~PibSqlite3();
 
+  static const std::string&
+  getScheme();
+
 public: // TpmLocator management
   void
   setTpmLocator(const std::string& tpmLocator) final;
diff --git a/src/security/pib/pib.hpp b/src/security/pib/pib.hpp
index 47dbd5c..947e5a5 100644
--- a/src/security/pib/pib.hpp
+++ b/src/security/pib/pib.hpp
@@ -26,9 +26,6 @@
 
 namespace ndn {
 namespace security {
-
-class KeyChain;
-
 namespace pib {
 
 class PibImpl;
@@ -46,6 +43,10 @@
  * the Pib class provides access to identities, and allows setting a default identity. Properties of
  * an identity can be accessed after obtaining an Identity object.
  *
+ * @note Pib instance is created and managed only by v2::KeyChain.  v2::KeyChain::getPib()
+ *       returns a const reference to the managed Pib instance, through which it is possible to
+ *       retrieve information about identities, keys, and certificates.
+ *
  * @throw PibImpl::Error when underlying implementation has non-semantic error.
  */
 class Pib : noncopyable
@@ -184,7 +185,7 @@
 
   shared_ptr<PibImpl> m_impl;
 
-  friend class KeyChain;
+  friend class v2::KeyChain;
 };
 
 } // namespace pib