security: Move KeyChain to security::v1 namespace and deprecated it

Change-Id: Ic4b6915ca15998a83b410f3f8fac027f797ee7ca
Refs: #3098
diff --git a/src/security/v1/key-chain.cpp b/src/security/v1/key-chain.cpp
new file mode 100644
index 0000000..f70bf05
--- /dev/null
+++ b/src/security/v1/key-chain.cpp
@@ -0,0 +1,846 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ */
+
+#include "key-chain.hpp"
+#include "../signing-helpers.hpp"
+
+#include "../../util/random.hpp"
+#include "../../util/config-file.hpp"
+
+#include "sec-public-info-sqlite3.hpp"
+
+#ifdef NDN_CXX_HAVE_OSX_SECURITY
+#include "sec-tpm-osx.hpp"
+#endif // NDN_CXX_HAVE_OSX_SECURITY
+
+#include "sec-tpm-file.hpp"
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+// Use a GUID as a magic number of KeyChain::DEFAULT_PREFIX identifier
+const Name KeyChain::DEFAULT_PREFIX("/723821fd-f534-44b3-80d9-44bf5f58bbbb");
+
+// Note: cannot use default constructor, as it depends on static variables which may or may not be
+// initialized at this point
+const SigningInfo KeyChain::DEFAULT_SIGNING_INFO(SigningInfo::SIGNER_TYPE_NULL, Name(), SignatureInfo());
+
+const RsaKeyParams KeyChain::DEFAULT_KEY_PARAMS;
+
+const std::string DEFAULT_PIB_SCHEME = "pib-sqlite3";
+
+#if defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
+const std::string DEFAULT_TPM_SCHEME = "tpm-osxkeychain";
+#else
+const std::string DEFAULT_TPM_SCHEME = "tpm-file";
+#endif // defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
+
+// When static library is used, not everything is compiled into the resulting binary.
+// Therefore, the following standard PIB and TPMs need to be registered here.
+// http://stackoverflow.com/q/9459980/2150331
+//
+// Also, cannot use Type::SCHEME, as its value may be uninitialized
+NDN_CXX_V1_KEYCHAIN_REGISTER_PIB(SecPublicInfoSqlite3, "pib-sqlite3", "sqlite3");
+
+#ifdef NDN_CXX_HAVE_OSX_SECURITY
+NDN_CXX_V1_KEYCHAIN_REGISTER_TPM(SecTpmOsx, "tpm-osxkeychain", "osx-keychain");
+#endif // NDN_CXX_HAVE_OSX_SECURITY
+
+NDN_CXX_V1_KEYCHAIN_REGISTER_TPM(SecTpmFile, "tpm-file", "file");
+
+template<class T>
+struct Factory
+{
+  Factory(const std::string& canonicalName, const T& create)
+    : canonicalName(canonicalName)
+    , create(create)
+  {
+  }
+
+  std::string canonicalName;
+  T create;
+};
+typedef Factory<KeyChain::PibCreateFunc> PibFactory;
+typedef Factory<KeyChain::TpmCreateFunc> TpmFactory;
+
+static std::map<std::string, PibFactory>&
+getPibFactories()
+{
+  static std::map<std::string, PibFactory> pibFactories;
+  return pibFactories;
+}
+
+static std::map<std::string, TpmFactory>&
+getTpmFactories()
+{
+  static std::map<std::string, TpmFactory> tpmFactories;
+  return tpmFactories;
+}
+
+void
+KeyChain::registerPibImpl(const std::string& canonicalName,
+                          std::initializer_list<std::string> aliases,
+                          KeyChain::PibCreateFunc createFunc)
+{
+  for (const std::string& alias : aliases) {
+    getPibFactories().insert(make_pair(alias, PibFactory(canonicalName, createFunc)));
+  }
+}
+
+void
+KeyChain::registerTpmImpl(const std::string& canonicalName,
+                          std::initializer_list<std::string> aliases,
+                          KeyChain::TpmCreateFunc createFunc)
+{
+  for (const std::string& alias : aliases) {
+    getTpmFactories().insert(make_pair(alias, TpmFactory(canonicalName, createFunc)));
+  }
+}
+
+KeyChain::KeyChain()
+  : m_pib(nullptr)
+  , m_tpm(nullptr)
+  , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
+{
+  std::string pibLocator;
+  std::string tpmLocator;
+
+  if (getenv("NDN_CLIENT_PIB") != nullptr) {
+    pibLocator = getenv("NDN_CLIENT_PIB");
+  }
+
+  if (getenv("NDN_CLIENT_TPM") != nullptr) {
+    tpmLocator = getenv("NDN_CLIENT_TPM");
+  }
+
+  if (pibLocator.empty() || tpmLocator.empty()) {
+    ConfigFile config;
+    const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
+
+    if (pibLocator.empty()) {
+      pibLocator = parsed.get<std::string>("pib", "");
+    }
+
+    if (tpmLocator.empty()) {
+      tpmLocator = parsed.get<std::string>("tpm", "");
+    }
+  }
+
+  initialize(pibLocator, tpmLocator, false);
+}
+
+KeyChain::KeyChain(const std::string& pibName,
+                   const std::string& tpmName,
+                   bool allowReset)
+  : m_pib(nullptr)
+  , m_tpm(nullptr)
+  , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
+{
+  initialize(pibName, tpmName, allowReset);
+}
+
+KeyChain::~KeyChain()
+{
+}
+
+static inline std::tuple<std::string/*type*/, std::string/*location*/>
+parseUri(const std::string& uri)
+{
+  size_t pos = uri.find(':');
+  if (pos != std::string::npos) {
+    return std::make_tuple(uri.substr(0, pos),
+                           uri.substr(pos + 1));
+  }
+  else {
+    return std::make_tuple(uri, "");
+  }
+}
+
+std::string
+KeyChain::getDefaultPibLocator()
+{
+  std::string defaultPibLocator = DEFAULT_PIB_SCHEME + ":";
+  return defaultPibLocator;
+}
+
+static inline std::tuple<std::string/*type*/, std::string/*location*/>
+getCanonicalPibLocator(const std::string& pibLocator)
+{
+  std::string pibScheme, pibLocation;
+  std::tie(pibScheme, pibLocation) = parseUri(pibLocator);
+
+  if (pibScheme.empty()) {
+    pibScheme = DEFAULT_PIB_SCHEME;
+  }
+
+  auto pibFactory = getPibFactories().find(pibScheme);
+  if (pibFactory == getPibFactories().end()) {
+    BOOST_THROW_EXCEPTION(KeyChain::Error("PIB scheme '" + pibScheme + "' is not supported"));
+  }
+  pibScheme = pibFactory->second.canonicalName;
+
+  return std::make_tuple(pibScheme, pibLocation);
+}
+
+unique_ptr<SecPublicInfo>
+KeyChain::createPib(const std::string& pibLocator)
+{
+  BOOST_ASSERT(!getPibFactories().empty());
+
+  std::string pibScheme, pibLocation;
+  std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator);
+  auto pibFactory = getPibFactories().find(pibScheme);
+  BOOST_ASSERT(pibFactory != getPibFactories().end());
+  return pibFactory->second.create(pibLocation);
+}
+
+std::string
+KeyChain::getDefaultTpmLocator()
+{
+  std::string defaultTpmLocator = DEFAULT_TPM_SCHEME + ":";
+  return defaultTpmLocator;
+}
+
+static inline std::tuple<std::string/*type*/, std::string/*location*/>
+getCanonicalTpmLocator(const std::string& tpmLocator)
+{
+  std::string tpmScheme, tpmLocation;
+  std::tie(tpmScheme, tpmLocation) = parseUri(tpmLocator);
+
+  if (tpmScheme.empty()) {
+    tpmScheme = DEFAULT_TPM_SCHEME;
+  }
+  auto tpmFactory = getTpmFactories().find(tpmScheme);
+  if (tpmFactory == getTpmFactories().end()) {
+    BOOST_THROW_EXCEPTION(KeyChain::Error("TPM scheme '" + tpmScheme + "' is not supported"));
+  }
+  tpmScheme = tpmFactory->second.canonicalName;
+
+  return std::make_tuple(tpmScheme, tpmLocation);
+}
+
+unique_ptr<SecTpm>
+KeyChain::createTpm(const std::string& tpmLocator)
+{
+  BOOST_ASSERT(!getTpmFactories().empty());
+
+  std::string tpmScheme, tpmLocation;
+  std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator);
+  auto tpmFactory = getTpmFactories().find(tpmScheme);
+  BOOST_ASSERT(tpmFactory != getTpmFactories().end());
+  return tpmFactory->second.create(tpmLocation);
+}
+
+void
+KeyChain::initialize(const std::string& pibLocator,
+                     const std::string& tpmLocator,
+                     bool allowReset)
+{
+  // PIB Locator
+  std::string pibScheme, pibLocation;
+  std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator);
+  std::string canonicalPibLocator = pibScheme + ":" + pibLocation;
+
+  // Create PIB
+  m_pib = createPib(canonicalPibLocator);
+
+  // TPM Locator
+  std::string tpmScheme, tpmLocation;
+  std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator);
+  std::string canonicalTpmLocator = tpmScheme + ":" + tpmLocation;
+
+  // Create TPM, checking that it matches to the previously associated one
+  try {
+    if (!allowReset &&
+        !m_pib->getTpmLocator().empty() && m_pib->getTpmLocator() != canonicalTpmLocator)
+      // Tpm mismatch, but we do not want to reset PIB
+      BOOST_THROW_EXCEPTION(MismatchError("TPM locator supplied does not match TPM locator in PIB: "
+                                          + m_pib->getTpmLocator() + " != " + canonicalTpmLocator));
+  }
+  catch (const SecPublicInfo::Error&) {
+    // TPM locator is not set in PIB yet.
+  }
+
+  // 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_tpm = createTpm(canonicalTpmLocator);
+  m_pib->setTpmLocator(canonicalTpmLocator);
+}
+
+Name
+KeyChain::createIdentity(const Name& identityName, const KeyParams& params)
+{
+  m_pib->addIdentity(identityName);
+
+  Name keyName;
+  try {
+    keyName = m_pib->getDefaultKeyNameForIdentity(identityName);
+
+    shared_ptr<PublicKey> key = m_pib->getPublicKey(keyName);
+
+    if (key->getKeyType() != params.getKeyType()) {
+      keyName = generateKeyPair(identityName, true, params);
+      m_pib->setDefaultKeyNameForIdentity(keyName);
+    }
+  }
+  catch (const SecPublicInfo::Error& e) {
+    keyName = generateKeyPair(identityName, true, params);
+    m_pib->setDefaultKeyNameForIdentity(keyName);
+  }
+
+  Name certName;
+  try {
+    certName = m_pib->getDefaultCertificateNameForKey(keyName);
+  }
+  catch (const SecPublicInfo::Error& e) {
+    shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
+    m_pib->addCertificateAsIdentityDefault(*selfCert);
+    certName = selfCert->getName();
+  }
+
+  return certName;
+}
+
+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);
+
+  Name keyName = generateKeyPair(identityName, isKsk, params);
+
+  m_pib->setDefaultKeyNameForIdentity(keyName);
+
+  return keyName;
+}
+
+Name
+KeyChain::generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
+{
+  EcdsaKeyParams params(keySize);
+
+  Name keyName = generateKeyPair(identityName, isKsk, params);
+
+  m_pib->setDefaultKeyNameForIdentity(keyName);
+
+  return keyName;
+}
+
+
+shared_ptr<IdentityCertificate>
+KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
+  const Name& signingIdentity,
+  const time::system_clock::TimePoint& notBefore,
+  const time::system_clock::TimePoint& notAfter,
+  const std::vector<CertificateSubjectDescription>& subjectDescription,
+  const Name& certPrefix)
+{
+  shared_ptr<PublicKey> publicKey;
+  try {
+    publicKey = m_pib->getPublicKey(keyName);
+  }
+  catch (const SecPublicInfo::Error& e) {
+    return nullptr;
+  }
+
+  return prepareUnsignedIdentityCertificate(keyName, *publicKey, signingIdentity,
+                                            notBefore, notAfter,
+                                            subjectDescription, certPrefix);
+}
+
+shared_ptr<IdentityCertificate>
+KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
+  const PublicKey& publicKey,
+  const Name& signingIdentity,
+  const time::system_clock::TimePoint& notBefore,
+  const time::system_clock::TimePoint& notAfter,
+  const std::vector<CertificateSubjectDescription>& subjectDescription,
+  const Name& certPrefix)
+{
+  if (keyName.size() < 1)
+    return nullptr;
+
+  std::string keyIdPrefix = keyName.get(-1).toUri().substr(0, 4);
+  if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
+    return nullptr;
+
+  Name certName;
+
+  if (certPrefix == KeyChain::DEFAULT_PREFIX) {
+    // No certificate prefix hint, infer the prefix
+    if (signingIdentity.isPrefixOf(keyName))
+      certName.append(signingIdentity)
+        .append("KEY")
+        .append(keyName.getSubName(signingIdentity.size()))
+        .append("ID-CERT")
+        .appendVersion();
+    else
+      certName.append(keyName.getPrefix(-1))
+        .append("KEY")
+        .append(keyName.get(-1))
+        .append("ID-CERT")
+        .appendVersion();
+  }
+  else {
+    // cert prefix hint is supplied, determine the cert name.
+    if (certPrefix.isPrefixOf(keyName) && certPrefix != keyName)
+      certName.append(certPrefix)
+        .append("KEY")
+        .append(keyName.getSubName(certPrefix.size()))
+        .append("ID-CERT")
+        .appendVersion();
+    else
+      return nullptr;
+  }
+
+  auto certificate = make_shared<IdentityCertificate>();
+  certificate->setName(certName);
+  certificate->setNotBefore(notBefore);
+  certificate->setNotAfter(notAfter);
+  certificate->setPublicKeyInfo(publicKey);
+
+  if (subjectDescription.empty()) {
+    CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri());
+    certificate->addSubjectDescription(subjectName);
+  }
+  else {
+    std::vector<CertificateSubjectDescription>::const_iterator sdIt = subjectDescription.begin();
+    std::vector<CertificateSubjectDescription>::const_iterator sdEnd = subjectDescription.end();
+    for(; sdIt != sdEnd; sdIt++)
+      certificate->addSubjectDescription(*sdIt);
+  }
+
+  certificate->encode();
+
+  return certificate;
+}
+
+std::tuple<Name, SignatureInfo>
+KeyChain::prepareSignatureInfo(const SigningInfo& params)
+{
+  SignatureInfo sigInfo = params.getSignatureInfo();
+
+  shared_ptr<IdentityCertificate> signingCert;
+
+  switch (params.getSignerType()) {
+    case SigningInfo::SIGNER_TYPE_NULL: {
+      if (m_pib->getDefaultCertificate() == nullptr)
+        setDefaultCertificateInternal();
+
+      signingCert = m_pib->getDefaultCertificate();
+      break;
+    }
+    case SigningInfo::SIGNER_TYPE_ID:  {
+      Name signingCertName;
+      try {
+        signingCertName = m_pib->getDefaultCertificateNameForIdentity(params.getSignerName());
+      }
+      catch (const SecPublicInfo::Error&) {
+        signingCertName = createIdentity(params.getSignerName(), getDefaultKeyParamsForIdentity(params.getSignerName()));
+      }
+
+      signingCert = m_pib->getCertificate(signingCertName);
+
+      break;
+    }
+    case SigningInfo::SIGNER_TYPE_KEY: {
+      Name signingCertName;
+      try {
+        signingCertName = m_pib->getDefaultCertificateNameForKey(params.getSignerName());
+      }
+      catch (const SecPublicInfo::Error&) {
+        BOOST_THROW_EXCEPTION(Error("signing certificate does not exist"));
+      }
+
+      signingCert = m_pib->getCertificate(signingCertName);
+
+      break;
+    }
+    case SigningInfo::SIGNER_TYPE_CERT: {
+      signingCert = m_pib->getCertificate(params.getSignerName());
+      if (signingCert == nullptr)
+        BOOST_THROW_EXCEPTION(Error("signing certificate does not exist"));
+
+      break;
+    }
+    case SigningInfo::SIGNER_TYPE_SHA256: {
+      sigInfo.setSignatureType(tlv::DigestSha256);
+      return std::make_tuple(SigningInfo::getDigestSha256Identity(), sigInfo);
+    }
+    default:
+      BOOST_THROW_EXCEPTION(Error("Unrecognized signer type"));
+  }
+
+  sigInfo.setSignatureType(getSignatureType(signingCert->getPublicKeyInfo().getKeyType(),
+                                            params.getDigestAlgorithm()));
+  sigInfo.setKeyLocator(KeyLocator(signingCert->getName().getPrefix(-1)));
+
+  return std::make_tuple(signingCert->getPublicKeyName(), sigInfo);
+}
+
+void
+KeyChain::sign(Data& data, const SigningInfo& params)
+{
+  signImpl(data, params);
+}
+
+void
+KeyChain::sign(Interest& interest, const SigningInfo& params)
+{
+  signImpl(interest, params);
+}
+
+Block
+KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params)
+{
+  Name keyName;
+  SignatureInfo sigInfo;
+  std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
+  return pureSign(buffer, bufferLength, keyName, DigestAlgorithm::SHA256);
+}
+
+Signature
+KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
+{
+  shared_ptr<IdentityCertificate> certificate = m_pib->getCertificate(certificateName);
+
+  if (certificate == nullptr) {
+    BOOST_THROW_EXCEPTION(SecPublicInfo::Error("certificate does not exist"));
+  }
+
+  Signature sig;
+
+  // For temporary usage, we support SHA256 only, but will support more.
+  sig.setValue(m_tpm->signInTpm(buffer, bufferLength,
+                                certificate->getPublicKeyName(),
+                                DigestAlgorithm::SHA256));
+
+  return sig;
+}
+
+shared_ptr<IdentityCertificate>
+KeyChain::selfSign(const Name& keyName)
+{
+  shared_ptr<PublicKey> pubKey;
+  try {
+    pubKey = m_pib->getPublicKey(keyName); // may throw an exception.
+  }
+  catch (const SecPublicInfo::Error&) {
+    return nullptr;
+  }
+
+  auto certificate = make_shared<IdentityCertificate>();
+
+  Name certificateName = keyName.getPrefix(-1);
+  certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
+
+  certificate->setName(certificateName);
+  certificate->setNotBefore(time::system_clock::now());
+  certificate->setNotAfter(time::system_clock::now() + time::days(7300)); // ~20 years
+  certificate->setPublicKeyInfo(*pubKey);
+  certificate->addSubjectDescription(CertificateSubjectDescription(oid::ATTRIBUTE_NAME,
+                                                                       keyName.toUri()));
+  certificate->encode();
+
+  certificate->setSignature(Signature(SignatureInfo()));
+
+  selfSign(*certificate);
+  return certificate;
+}
+
+void
+KeyChain::selfSign(IdentityCertificate& cert)
+{
+  Name keyName = cert.getPublicKeyName();
+
+  if (!m_tpm->doesKeyExistInTpm(keyName, KeyClass::PRIVATE))
+    BOOST_THROW_EXCEPTION(SecTpm::Error("Private key does not exist"));
+
+  SignatureInfo sigInfo(cert.getSignature().getInfo());
+  sigInfo.setKeyLocator(KeyLocator(cert.getName().getPrefix(-1)));
+  sigInfo.setSignatureType(getSignatureType(cert.getPublicKeyInfo().getKeyType(),
+                                            DigestAlgorithm::SHA256));
+
+  signPacketWrapper(cert, Signature(sigInfo), keyName, DigestAlgorithm::SHA256);
+}
+
+shared_ptr<SecuredBag>
+KeyChain::exportIdentity(const Name& identity, const std::string& passwordStr)
+{
+  if (!m_pib->doesIdentityExist(identity))
+    BOOST_THROW_EXCEPTION(SecPublicInfo::Error("Identity does not exist"));
+
+  Name keyName = m_pib->getDefaultKeyNameForIdentity(identity);
+
+  ConstBufferPtr pkcs5;
+  try {
+    pkcs5 = m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, passwordStr);
+  }
+  catch (const SecTpm::Error& e) {
+    BOOST_THROW_EXCEPTION(SecPublicInfo::Error("Fail to export PKCS5 of private key"));
+  }
+
+  shared_ptr<IdentityCertificate> cert;
+  try {
+    cert = m_pib->getCertificate(m_pib->getDefaultCertificateNameForKey(keyName));
+  }
+  catch (const SecPublicInfo::Error& e) {
+    cert = selfSign(keyName);
+    m_pib->addCertificateAsIdentityDefault(*cert);
+  }
+
+  // make_shared on OSX 10.9 has some strange problem here
+  return shared_ptr<SecuredBag>(new SecuredBag(*cert, pkcs5));
+}
+
+void
+KeyChain::importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
+{
+  Name certificateName = securedBag.getCertificate().getName();
+  Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
+  Name identity = keyName.getPrefix(-1);
+
+  // Add identity
+  m_pib->addIdentity(identity);
+
+  // Add key
+  m_tpm->importPrivateKeyPkcs5IntoTpm(keyName,
+                                      securedBag.getKey()->buf(),
+                                      securedBag.getKey()->size(),
+                                      passwordStr);
+
+  shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
+  // HACK! We should set key type according to the pkcs8 info.
+  m_pib->addKey(keyName, *pubKey);
+  m_pib->setDefaultKeyNameForIdentity(keyName);
+
+  // Add cert
+  m_pib->addCertificateAsIdentityDefault(securedBag.getCertificate());
+}
+
+const KeyParams&
+KeyChain::getDefaultKeyParamsForIdentity(const Name &identityName) const
+{
+  KeyType keyType = KeyType::NONE;
+  try {
+    keyType = m_pib->getPublicKeyType(m_pib->getDefaultKeyNameForIdentity(identityName));
+  }
+  catch (const SecPublicInfo::Error& e) { // @TODO Switch to Pib::Error
+    return DEFAULT_KEY_PARAMS;
+  }
+
+  switch (keyType) {
+    case KeyType::RSA: {
+      static RsaKeyParams defaultRsaParams;
+      return defaultRsaParams;
+    }
+    case KeyType::EC: {
+      static EcdsaKeyParams defaultEcdsaParams;
+      return defaultEcdsaParams;
+    }
+    case KeyType::NONE: {
+      return DEFAULT_KEY_PARAMS;
+    }
+    default:
+      BOOST_THROW_EXCEPTION(Error("Unsupported key type"));
+  }
+}
+
+void
+KeyChain::setDefaultCertificateInternal()
+{
+  m_pib->refreshDefaultCertificate();
+
+  if (m_pib->getDefaultCertificate() == nullptr) {
+    Name defaultIdentity;
+    try {
+      defaultIdentity = m_pib->getDefaultIdentity();
+    }
+    catch (const SecPublicInfo::Error& e) {
+      uint32_t random = random::generateWord32();
+      defaultIdentity.append("tmp-identity")
+        .append(reinterpret_cast<uint8_t*>(&random), 4);
+    }
+    createIdentity(defaultIdentity);
+    m_pib->setDefaultIdentity(defaultIdentity);
+    m_pib->refreshDefaultCertificate();
+  }
+}
+
+Name
+KeyChain::generateKeyPair(const Name& identityName, bool isKsk, const KeyParams& params)
+{
+  Name keyName = m_pib->getNewKeyName(identityName, isKsk);
+
+  m_tpm->generateKeyPairInTpm(keyName.toUri(), params);
+
+  shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
+  m_pib->addKey(keyName, *pubKey);
+
+  return keyName;
+}
+
+void
+KeyChain::signPacketWrapper(Data& data, const Signature& signature,
+                            const Name& keyName, DigestAlgorithm digestAlgorithm)
+{
+  data.setSignature(signature);
+
+  EncodingBuffer encoder;
+  data.wireEncode(encoder, true);
+
+  Block sigValue = pureSign(encoder.buf(), encoder.size(), keyName, digestAlgorithm);
+
+  data.wireEncode(encoder, sigValue);
+}
+
+void
+KeyChain::signPacketWrapper(Interest& interest, const Signature& signature,
+                            const Name& keyName, DigestAlgorithm digestAlgorithm)
+{
+  time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
+  if (timestamp <= m_lastTimestamp) {
+    timestamp = m_lastTimestamp + time::milliseconds(1);
+  }
+
+  Name signedName = interest.getName();
+  signedName
+    .append(name::Component::fromNumber(timestamp.count()))        // timestamp
+    .append(name::Component::fromNumber(random::generateWord64())) // nonce
+    .append(signature.getInfo());                                  // signatureInfo
+
+  Block sigValue = pureSign(signedName.wireEncode().value(),
+                            signedName.wireEncode().value_size(),
+                            keyName,
+                            digestAlgorithm);
+
+  sigValue.encode();
+  signedName.append(sigValue);                                     // signatureValue
+  interest.setName(signedName);
+}
+
+Block
+KeyChain::pureSign(const uint8_t* buf, size_t size,
+                   const Name& keyName, DigestAlgorithm digestAlgorithm) const
+{
+  if (keyName == SigningInfo::getDigestSha256Identity())
+    return Block(tlv::SignatureValue, crypto::computeSha256Digest(buf, size));
+
+  return m_tpm->signInTpm(buf, size, keyName, digestAlgorithm);
+}
+
+Signature
+KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
+{
+  Signature sig;
+  sig.setValue(sign(buffer, bufferLength, signingByIdentity(identityName)));
+  return sig;
+}
+
+void
+KeyChain::signWithSha256(Data& data)
+{
+  return sign(data, signingWithSha256());
+}
+
+void
+KeyChain::signWithSha256(Interest& interest)
+{
+  DigestSha256 sig;
+
+  time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
+  if (timestamp <= m_lastTimestamp)
+    timestamp = m_lastTimestamp + time::milliseconds(1);
+
+  Name signedName = interest.getName();
+  signedName
+    .append(name::Component::fromNumber(timestamp.count()))        // timestamp
+    .append(name::Component::fromNumber(random::generateWord64())) // nonce
+    .append(sig.getInfo());                                        // signatureInfo
+
+  Block sigValue(tlv::SignatureValue,
+                 crypto::computeSha256Digest(signedName.wireEncode().value(),
+                                             signedName.wireEncode().value_size()));
+
+  sigValue.encode();
+  signedName.append(sigValue);                                     // signatureValue
+  interest.setName(signedName);
+}
+
+void
+KeyChain::deleteCertificate(const Name& certificateName)
+{
+  m_pib->deleteCertificateInfo(certificateName);
+}
+
+void
+KeyChain::deleteKey(const Name& keyName)
+{
+  m_pib->deletePublicKeyInfo(keyName);
+  m_tpm->deleteKeyPairInTpm(keyName);
+}
+
+void
+KeyChain::deleteIdentity(const Name& identity)
+{
+  std::vector<Name> keyNames;
+  m_pib->getAllKeyNamesOfIdentity(identity, keyNames, true);
+  m_pib->getAllKeyNamesOfIdentity(identity, keyNames, false);
+
+  m_pib->deleteIdentityInfo(identity);
+
+  for (const auto& keyName : keyNames)
+    m_tpm->deleteKeyPairInTpm(keyName);
+}
+
+tlv::SignatureTypeValue
+KeyChain::getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm)
+{
+  switch (keyType) {
+    case KeyType::RSA:
+      return tlv::SignatureSha256WithRsa;
+    case KeyType::EC:
+      return tlv::SignatureSha256WithEcdsa;
+    default:
+      BOOST_THROW_EXCEPTION(Error("Unsupported key types"));
+  }
+}
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v1/key-chain.hpp b/src/security/v1/key-chain.hpp
new file mode 100644
index 0000000..73aab90
--- /dev/null
+++ b/src/security/v1/key-chain.hpp
@@ -0,0 +1,968 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ */
+
+#ifndef NDN_SECURITY_V1_KEY_CHAIN_HPP
+#define NDN_SECURITY_V1_KEY_CHAIN_HPP
+
+#include "sec-public-info.hpp"
+#include "sec-tpm.hpp"
+#include "secured-bag.hpp"
+#include "../key-params.hpp"
+#include "../signature-sha256-with-rsa.hpp"
+#include "../signature-sha256-with-ecdsa.hpp"
+#include "../digest-sha256.hpp"
+#include "../signing-info.hpp"
+
+#include "../../interest.hpp"
+#include "../../util/crypto.hpp"
+#include "../../util/random.hpp"
+#include <initializer_list>
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+/**
+ * @brief The packet signing interface.
+ *
+ * @deprecated Use v2::KeyChain
+ */
+class KeyChain : noncopyable
+{
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+  /**
+   * @brief Error thrown when the supplied TPM locator to KeyChain constructor does not match
+   *        the locator stored in PIB
+   */
+  class MismatchError : public Error
+  {
+  public:
+    explicit
+    MismatchError(const std::string& what)
+      : Error(what)
+    {
+    }
+  };
+
+  typedef function<unique_ptr<SecPublicInfo> (const std::string&)> PibCreateFunc;
+  typedef function<unique_ptr<SecTpm>(const std::string&)> TpmCreateFunc;
+
+  /**
+   * @brief Register a new PIB
+   * @param aliases List of schemes with which this PIB will be associated.
+   *        The first alias in the list is considered a canonical name of the PIB instance.
+   */
+  template<class PibType>
+  static void
+  registerPib(std::initializer_list<std::string> aliases);
+
+  /**
+   * @brief Register a new TPM
+   * @param aliases List of schemes with which this TPM will be associated
+   *        The first alias in the list is considered a canonical name of the TPM instance.
+   */
+  template<class TpmType>
+  static void
+  registerTpm(std::initializer_list<std::string> aliases);
+
+  /**
+   * @brief Get default PIB locator
+   */
+  static std::string
+  getDefaultPibLocator();
+
+  /**
+    * @brief Create a PIB according to @p pibLocator
+    */
+  static unique_ptr<SecPublicInfo>
+  createPib(const std::string& pibLocator);
+
+  /**
+   * @brief Get default TPM locator
+   */
+  static std::string
+  getDefaultTpmLocator();
+
+  /**
+    * @brief Create a TPM according to @p tpmLocator
+    */
+  static unique_ptr<SecTpm>
+  createTpm(const std::string& tpmLocator);
+
+  /**
+   * @brief Constructor to create KeyChain with default PIB and TPM
+   *
+   * Default PIB and TPM are platform-dependent and can be overriden system-wide or on
+   * per-use basis.
+   *
+   * @todo Add detailed description about config file behavior here
+   */
+  KeyChain();
+
+  /**
+   * @brief KeyChain constructor
+   *
+   * @sa  http://redmine.named-data.net/issues/2260
+   *
+   * @param pibLocator PIB locator
+   * @param tpmLocator TPM locator
+   * @param allowReset if true, the PIB will be reset when the supplied tpmLocator
+   *        mismatches the one in PIB
+   */
+  KeyChain(const std::string& pibLocator,
+           const std::string& tpmLocator,
+           bool allowReset = false);
+
+  virtual
+  ~KeyChain();
+
+  /**
+   * @brief Create an identity by creating a pair of Key-Signing-Key (KSK) for this identity and a
+   *        self-signed certificate of the KSK.
+   *
+   * @param identityName The name of the identity.
+   * @param params The key parameter if a key needs to be generated for the identity.
+   * @return The name of the default certificate of the identity.
+   */
+  Name
+  createIdentity(const Name& identityName, const KeyParams& params = DEFAULT_KEY_PARAMS);
+
+  /**
+   * @brief Generate a pair of RSA keys for the specified identity.
+   *
+   * @param identityName The name of the identity.
+   * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
+   * @param keySize The size of the key.
+   * @return The generated key name.
+   * @see generateEcdsaKeyPair
+   */
+  Name
+  generateRsaKeyPair(const Name& identityName, bool isKsk = false, uint32_t keySize = 2048);
+
+  /**
+   * @brief Generate a pair of ECDSA keys for the specified identity.
+   *
+   * @param identityName The name of the identity.
+   * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
+   * @param keySize The size of the key.
+   * @return The generated key name.
+   * @see generateRsaKeyPair
+   */
+  Name
+  generateEcdsaKeyPair(const Name& identityName, bool isKsk = false, uint32_t keySize = 256);
+
+  /**
+   * @brief Generate a pair of RSA keys for the specified identity and set it as default key for
+   *        the identity.
+   *
+   * @param identityName The name of the identity.
+   * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
+   * @param keySize The size of the key.
+   * @return The generated key name.
+   * @see generateRsaKeyPair, generateEcdsaKeyPair, generateEcdsaKeyPairAsDefault
+   */
+  Name
+  generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk = false, uint32_t keySize = 2048);
+
+  /**
+   * @brief Generate a pair of ECDSA keys for the specified identity and set it as default key for
+   *        the identity.
+   *
+   * @param identityName The name of the identity.
+   * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
+   * @param keySize The size of the key.
+   * @return The generated key name.
+   * @see generateRsaKeyPair, generateEcdsaKeyPair, generateRsaKeyPairAsDefault
+   */
+  Name
+  generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk = false, uint32_t keySize = 256);
+
+  /**
+   * @brief prepare an unsigned identity certificate
+   *
+   * @param keyName Key name, e.g., `/<identity_name>/ksk-123456`.
+   * @param signingIdentity The signing identity.
+   * @param notBefore Refer to IdentityCertificate.
+   * @param notAfter Refer to IdentityCertificate.
+   * @param subjectDescription Refer to IdentityCertificate.
+   * @param certPrefix Prefix before `KEY` component. By default, KeyChain will infer the
+   *                   certificate name according to the relation between the signingIdentity and
+   *                   the subject identity. If signingIdentity is a prefix of the subject identity,
+   *                   `KEY` will be inserted after the signingIdentity, otherwise `KEY` is inserted
+   *                   after subject identity (i.e., before `ksk-....`).
+   * @return IdentityCertificate.
+   */
+  shared_ptr<IdentityCertificate>
+  prepareUnsignedIdentityCertificate(const Name& keyName,
+    const Name& signingIdentity,
+    const time::system_clock::TimePoint& notBefore,
+    const time::system_clock::TimePoint& notAfter,
+    const std::vector<CertificateSubjectDescription>& subjectDescription,
+    const Name& certPrefix = DEFAULT_PREFIX);
+
+  /**
+   * @brief prepare an unsigned identity certificate
+   *
+   * @param keyName Key name, e.g., `/<identity_name>/ksk-123456`.
+   * @param publicKey Public key to sign.
+   * @param signingIdentity The signing identity.
+   * @param notBefore Refer to IdentityCertificate.
+   * @param notAfter Refer to IdentityCertificate.
+   * @param subjectDescription Refer to IdentityCertificate.
+   * @param certPrefix Prefix before `KEY` component. By default, KeyChain will infer the
+   *                   certificate name according to the relation between the signingIdentity and
+   *                   the subject identity. If signingIdentity is a prefix of the subject identity,
+   *                   `KEY` will be inserted after the signingIdentity, otherwise `KEY` is inserted
+   *                   after subject identity (i.e., before `ksk-....`).
+   * @return IdentityCertificate.
+   */
+  shared_ptr<IdentityCertificate>
+  prepareUnsignedIdentityCertificate(const Name& keyName,
+    const PublicKey& publicKey,
+    const Name& signingIdentity,
+    const time::system_clock::TimePoint& notBefore,
+    const time::system_clock::TimePoint& notAfter,
+    const std::vector<CertificateSubjectDescription>& subjectDescription,
+    const Name& certPrefix = DEFAULT_PREFIX);
+
+  /**
+   * @brief Sign data according to the supplied signing information
+   *
+   * This method uses the supplied signing information @p params to create the SignatureInfo block:
+   * - it selects a private key and its certificate to sign the packet
+   * - sets the KeyLocator field with the certificate name, and
+   * - adds other requested information to the SignatureInfo block).
+   *
+   * After that, the method assigns the created SignatureInfo to the data packets, generate a
+   * signature and sets as part of the SignatureValue block.
+   *
+   * @param data The data to sign
+   * @param params The signing parameters.
+   * @throws Error if signing fails.
+   * @see SigningInfo
+   */
+  void
+  sign(Data& data, const SigningInfo& params = DEFAULT_SIGNING_INFO);
+
+  /**
+   * @brief Sign interest according to the supplied signing information
+   *
+   * This method uses the supplied signing information @p params to create the SignatureInfo block:
+   * - it selects a private key and its certificate to sign the packet
+   * - sets the KeyLocator field with the certificate name, and
+   * - adds other requested information to the SignatureInfo block).
+   *
+   * After that, the method appends the created SignatureInfo to the interest name, generate a
+   * signature and appends it as part of the SignatureValue block to the interest name.
+   *
+   * @param interest The interest to sign
+   * @param params The signing parameters.
+   * @throws Error if signing fails.
+   * @see SigningInfo
+   */
+  void
+  sign(Interest& interest, const SigningInfo& params = DEFAULT_SIGNING_INFO);
+
+  /**
+   * @brief Sign buffer according to the supplied signing information
+   *
+   * @param buffer The buffer to sign
+   * @param bufferLength The buffer size
+   * @param params The signing parameters.
+   * @return a SignatureValue TLV block
+   * @throws Error if signing fails.
+   * @see SigningInfo
+   */
+  Block
+  sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params);
+
+  /**
+   * @deprecated use sign sign(T&, const SigningInfo&)
+   * @brief Sign packet with a particular certificate.
+   *
+   * @param packet The packet to be signed.
+   * @param certificateName The certificate name of the key to use for signing.
+   * @throws SecPublicInfo::Error if certificate does not exist.
+   */
+  template<typename T>
+  void
+  sign(T& packet, const Name& certificateName);
+
+  /**
+   * @deprecated Use sign(const uint8_t*, size_t, const SigningInfo&) instead
+   * @brief Sign the byte array using a particular certificate.
+   *
+   * @param buffer The byte array to be signed.
+   * @param bufferLength the length of buffer.
+   * @param certificateName The certificate name of the signing key.
+   * @return The Signature.
+   * @throws SecPublicInfo::Error if certificate does not exist.
+   */
+  Signature
+  sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName);
+
+  /**
+   * @deprecated use sign sign(T&, const SigningInfo&)
+   * @brief Sign packet using the default certificate of a particular identity.
+   *
+   * If there is no default certificate of that identity, this method will create a self-signed
+   * certificate.
+   *
+   * @param packet The packet to be signed.
+   * @param identityName The signing identity name.
+   */
+  template<typename T>
+  void
+  signByIdentity(T& packet, const Name& identityName);
+
+  /**
+   * @deprecated use sign(const uint8_t*, size_t, const SigningInfo&) instead
+   * @brief Sign the byte array using the default certificate of a particular identity.
+   *
+   * @param buffer The byte array to be signed.
+   * @param bufferLength the length of buffer.
+   * @param identityName The identity name.
+   * @return The Signature.
+   */
+  Signature
+  signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName);
+
+  /**
+   * @deprecated use sign(Data&, SigningInfo(SigningInfo::SIGNER_TYPE_SHA256))
+   * @brief Set Sha256 weak signature for @p data
+   */
+  void
+  signWithSha256(Data& data);
+
+  /**
+   * @deprecated use sign(Interest&, SigningInfo(SigningInfo::SIGNER_TYPE_SHA256))
+   * @brief Set Sha256 weak signature for @p interest
+   */
+  void
+  signWithSha256(Interest& interest);
+
+  /**
+   * @brief Generate a self-signed certificate for a public key.
+   *
+   * @param keyName The name of the public key
+   * @return The generated certificate, shared_ptr<IdentityCertificate>() if selfSign fails
+   */
+  shared_ptr<IdentityCertificate>
+  selfSign(const Name& keyName);
+
+  /**
+   * @brief Self-sign the supplied identity certificate.
+   *
+   * @param cert The supplied cert.
+   * @throws SecTpm::Error if the private key does not exist.
+   */
+  void
+  selfSign(IdentityCertificate& cert);
+
+  /**
+   * @brief delete a certificate.
+   *
+   * @param certificateName The certificate to be deleted.
+   * @throws KeyChain::Error if certificate cannot be deleted.
+   */
+  void
+  deleteCertificate(const Name& certificateName);
+
+  /**
+   * @brief delete a key.
+   *
+   * @param keyName The key to be deleted.
+   * @throws KeyChain::Error if key cannot be deleted.
+   */
+  void
+  deleteKey(const Name& keyName);
+
+  /**
+   * @brief delete an identity.
+   *
+   * @param identity The identity to be deleted.
+   * @throws KeyChain::Error if identity cannot be deleted.
+   */
+  void
+  deleteIdentity(const Name& identity);
+
+  /**
+   * @brief export an identity.
+   *
+   * @param identity The identity to export.
+   * @param passwordStr The password to secure the private key.
+   * @return The encoded export data.
+   * @throws SecPublicInfo::Error if anything goes wrong in exporting.
+   */
+  shared_ptr<SecuredBag>
+  exportIdentity(const Name& identity, const std::string& passwordStr);
+
+  /**
+   * @brief import an identity.
+   *
+   * @param securedBag The encoded import data.
+   * @param passwordStr The password to secure the private key.
+   */
+  void
+  importIdentity(const SecuredBag& securedBag, const std::string& passwordStr);
+
+  SecPublicInfo&
+  getPib()
+  {
+    return *m_pib;
+  }
+
+  const SecPublicInfo&
+  getPib() const
+  {
+    return *m_pib;
+  }
+
+  SecTpm&
+  getTpm()
+  {
+    return *m_tpm;
+  }
+
+  const SecTpm&
+  getTpm() const
+  {
+    return *m_tpm;
+  }
+
+  /*******************************
+   *  Wrapper of SecPublicInfo   *
+   *******************************/
+  bool
+  doesIdentityExist(const Name& identityName) const
+  {
+    return m_pib->doesIdentityExist(identityName);
+  }
+
+  void
+  addIdentity(const Name& identityName)
+  {
+    return m_pib->addIdentity(identityName);
+  }
+
+  bool
+  doesPublicKeyExist(const Name& keyName) const
+  {
+    return m_pib->doesPublicKeyExist(keyName);
+  }
+
+  void
+  addPublicKey(const Name& keyName, KeyType keyType, const PublicKey& publicKeyDer)
+  {
+    return m_pib->addKey(keyName, publicKeyDer);
+  }
+
+  void
+  addKey(const Name& keyName, const PublicKey& publicKeyDer)
+  {
+    return m_pib->addKey(keyName, publicKeyDer);
+  }
+
+  shared_ptr<PublicKey>
+  getPublicKey(const Name& keyName) const
+  {
+    return m_pib->getPublicKey(keyName);
+  }
+
+  bool
+  doesCertificateExist(const Name& certificateName) const
+  {
+    return m_pib->doesCertificateExist(certificateName);
+  }
+
+  void
+  addCertificate(const IdentityCertificate& certificate)
+  {
+    return m_pib->addCertificate(certificate);
+  }
+
+  shared_ptr<IdentityCertificate>
+  getCertificate(const Name& certificateName) const
+  {
+    return m_pib->getCertificate(certificateName);
+  }
+
+  Name
+  getDefaultIdentity() const
+  {
+    return m_pib->getDefaultIdentity();
+  }
+
+  Name
+  getDefaultKeyNameForIdentity(const Name& identityName) const
+  {
+    return m_pib->getDefaultKeyNameForIdentity(identityName);
+  }
+
+  /**
+   * @brief Get default key parameters for the specified identity
+   *
+   * If identity has a previously generated key, the returned parameters
+   * will include the same type of the key.  If there are no existing
+   * keys, DEFAULT_KEY_PARAMS is used.
+   */
+  const KeyParams&
+  getDefaultKeyParamsForIdentity(const Name& identityName) const;
+
+  Name
+  getDefaultCertificateNameForKey(const Name& keyName) const
+  {
+    return m_pib->getDefaultCertificateNameForKey(keyName);
+  }
+
+  void
+  getAllIdentities(std::vector<Name>& nameList, bool isDefault) const
+  {
+    return m_pib->getAllIdentities(nameList, isDefault);
+  }
+
+  void
+  getAllKeyNames(std::vector<Name>& nameList, bool isDefault) const
+  {
+    return m_pib->getAllKeyNames(nameList, isDefault);
+  }
+
+  void
+  getAllKeyNamesOfIdentity(const Name& identity, std::vector<Name>& nameList, bool isDefault) const
+  {
+    return m_pib->getAllKeyNamesOfIdentity(identity, nameList, isDefault);
+  }
+
+  void
+  getAllCertificateNames(std::vector<Name>& nameList, bool isDefault) const
+  {
+    return m_pib->getAllCertificateNames(nameList, isDefault);
+  }
+
+  void
+  getAllCertificateNamesOfKey(const Name& keyName,
+                              std::vector<Name>& nameList,
+                              bool isDefault) const
+  {
+    return m_pib->getAllCertificateNamesOfKey(keyName, nameList, isDefault);
+  }
+
+  void
+  deleteCertificateInfo(const Name& certificateName)
+  {
+    return m_pib->deleteCertificateInfo(certificateName);
+  }
+
+  void
+  deletePublicKeyInfo(const Name& keyName)
+  {
+    return m_pib->deletePublicKeyInfo(keyName);
+  }
+
+  void
+  deleteIdentityInfo(const Name& identity)
+  {
+    return m_pib->deleteIdentityInfo(identity);
+  }
+
+  void
+  setDefaultIdentity(const Name& identityName)
+  {
+    return m_pib->setDefaultIdentity(identityName);
+  }
+
+  void
+  setDefaultKeyNameForIdentity(const Name& keyName)
+  {
+    return m_pib->setDefaultKeyNameForIdentity(keyName);
+  }
+
+  void
+  setDefaultCertificateNameForKey(const Name& certificateName)
+  {
+    return m_pib->setDefaultCertificateNameForKey(certificateName);
+  }
+
+  Name
+  getNewKeyName(const Name& identityName, bool useKsk)
+  {
+    return m_pib->getNewKeyName(identityName, useKsk);
+  }
+
+  Name
+  getDefaultCertificateNameForIdentity(const Name& identityName) const
+  {
+    return m_pib->getDefaultCertificateNameForIdentity(identityName);
+  }
+
+  Name
+  getDefaultCertificateName() const
+  {
+    return m_pib->getDefaultCertificateName();
+  }
+
+  void
+  addCertificateAsKeyDefault(const IdentityCertificate& certificate)
+  {
+    return m_pib->addCertificateAsKeyDefault(certificate);
+  }
+
+  void
+  addCertificateAsIdentityDefault(const IdentityCertificate& certificate)
+  {
+    return m_pib->addCertificateAsIdentityDefault(certificate);
+  }
+
+  void
+  addCertificateAsSystemDefault(const IdentityCertificate& certificate)
+  {
+    return m_pib->addCertificateAsSystemDefault(certificate);
+  }
+
+  shared_ptr<IdentityCertificate>
+  getDefaultCertificate() const
+  {
+    if (!static_cast<bool>(m_pib->getDefaultCertificate()))
+      const_cast<KeyChain*>(this)->setDefaultCertificateInternal();
+
+    return m_pib->getDefaultCertificate();
+  }
+
+  void
+  refreshDefaultCertificate()
+  {
+    return m_pib->refreshDefaultCertificate();
+  }
+
+  /*******************************
+   *  Wrapper of SecTpm          *
+   *******************************/
+
+  void
+  setTpmPassword(const uint8_t* password, size_t passwordLength)
+  {
+    return m_tpm->setTpmPassword(password, passwordLength);
+  }
+
+  void
+  resetTpmPassword()
+  {
+    return m_tpm->resetTpmPassword();
+  }
+
+  void
+  setInTerminal(bool inTerminal)
+  {
+    return m_tpm->setInTerminal(inTerminal);
+  }
+
+  bool
+  getInTerminal() const
+  {
+    return m_tpm->getInTerminal();
+  }
+
+  bool
+  isLocked() const
+  {
+    return m_tpm->isLocked();
+  }
+
+  bool
+  unlockTpm(const char* password, size_t passwordLength, bool usePassword)
+  {
+    return m_tpm->unlockTpm(password, passwordLength, usePassword);
+  }
+
+  void
+  generateKeyPairInTpm(const Name& keyName, const KeyParams& params)
+  {
+    return m_tpm->generateKeyPairInTpm(keyName, params);
+  }
+
+  void
+  deleteKeyPairInTpm(const Name& keyName)
+  {
+    return m_tpm->deleteKeyPairInTpm(keyName);
+  }
+
+  shared_ptr<PublicKey>
+  getPublicKeyFromTpm(const Name& keyName) const
+  {
+    return m_tpm->getPublicKeyFromTpm(keyName);
+  }
+
+  Block
+  signInTpm(const uint8_t* data, size_t dataLength,
+            const Name& keyName,
+            DigestAlgorithm digestAlgorithm)
+  {
+    return m_tpm->signInTpm(data, dataLength, keyName, digestAlgorithm);
+  }
+
+  ConstBufferPtr
+  decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric)
+  {
+    return m_tpm->decryptInTpm(data, dataLength, keyName, isSymmetric);
+  }
+
+  ConstBufferPtr
+  encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric)
+  {
+    return m_tpm->encryptInTpm(data, dataLength, keyName, isSymmetric);
+  }
+
+  void
+  generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
+  {
+    return m_tpm->generateSymmetricKeyInTpm(keyName, params);
+  }
+
+  bool
+  doesKeyExistInTpm(const Name& keyName, KeyClass keyClass) const
+  {
+    return m_tpm->doesKeyExistInTpm(keyName, keyClass);
+  }
+
+  bool
+  generateRandomBlock(uint8_t* res, size_t size) const
+  {
+    return m_tpm->generateRandomBlock(res, size);
+  }
+
+  void
+  addAppToAcl(const Name& keyName, KeyClass keyClass, const std::string& appPath, AclType acl)
+  {
+    return m_tpm->addAppToAcl(keyName, keyClass, appPath, acl);
+  }
+
+  ConstBufferPtr
+  exportPrivateKeyPkcs5FromTpm(const Name& keyName, const std::string& password)
+  {
+    return m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, password);
+  }
+
+  bool
+  importPrivateKeyPkcs5IntoTpm(const Name& keyName,
+                               const uint8_t* buf, size_t size,
+                               const std::string& password)
+  {
+    return m_tpm->importPrivateKeyPkcs5IntoTpm(keyName, buf, size, password);
+  }
+
+private:
+  void
+  initialize(const std::string& pibLocatorUri,
+             const std::string& tpmLocatorUri,
+             bool needReset);
+
+  /**
+   * @brief Prepare a SignatureInfo TLV according to signing information and return the signing key name
+   *
+   * @param params The signing parameters.
+   * @return The signing key name and prepared SignatureInfo.
+   * @throw Error when the requested signing method cannot be satisfied.
+   */
+  std::tuple<Name, SignatureInfo>
+  prepareSignatureInfo(const SigningInfo& params);
+
+  /**
+   * @brief Internal abstraction of packet signing.
+   *
+   * @param packet The packet to sign
+   * @param params The signing parameters.
+   * @throw Error when the signing fails.
+   */
+  template<typename T>
+  void
+  signImpl(T& packet, const SigningInfo& params);
+
+  /**
+   * @brief Set default certificate if it is not initialized
+   */
+  void
+  setDefaultCertificateInternal();
+
+  /**
+   * @brief Generate a key pair for the specified identity.
+   *
+   * @param identityName The name of the specified identity.
+   * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
+   * @param params The parameter of the key.
+   * @return The name of the generated key.
+   */
+  Name
+  generateKeyPair(const Name& identityName, bool isKsk = false,
+                  const KeyParams& params = DEFAULT_KEY_PARAMS);
+
+  /**
+   * @brief Sign the data using a particular key.
+   *
+   * @param data Reference to the data packet.
+   * @param signature Signature to be added.
+   * @param keyName The name of the signing key.
+   * @param digestAlgorithm the digest algorithm.
+   * @throws Tpm::Error
+   */
+  void
+  signPacketWrapper(Data& data, const Signature& signature,
+                    const Name& keyName, DigestAlgorithm digestAlgorithm);
+
+  /**
+   * @brief Sign the interest using a particular key.
+   *
+   * @param interest Reference to the interest packet.
+   * @param signature Signature to be added.
+   * @param keyName The name of the signing key.
+   * @param digestAlgorithm the digest algorithm.
+   * @throws Tpm::Error
+   */
+  void
+  signPacketWrapper(Interest& interest, const Signature& signature,
+                    const Name& keyName, DigestAlgorithm digestAlgorithm);
+
+  /**
+   * @brief Generate a SignatureValue block for a buffer @p buf with size @p size using
+   *        a key with name @p keyName and digest algorithm @p digestAlgorithm.
+   */
+  Block
+  pureSign(const uint8_t* buf, size_t size, const Name& keyName, DigestAlgorithm digestAlgorithm) const;
+
+  static void
+  registerPibImpl(const std::string& canonicalName,
+                  std::initializer_list<std::string> aliases, PibCreateFunc createFunc);
+
+  static void
+  registerTpmImpl(const std::string& canonicalName,
+                  std::initializer_list<std::string> aliases, TpmCreateFunc createFunc);
+
+public:
+  static tlv::SignatureTypeValue
+  getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm);
+
+public:
+  static const Name DEFAULT_PREFIX;
+  static const SigningInfo DEFAULT_SIGNING_INFO;
+
+  // RsaKeyParams is set to be default for backward compatibility.
+  static const RsaKeyParams DEFAULT_KEY_PARAMS;
+
+  typedef std::map<std::string, Block> SignParams;
+
+private:
+  std::unique_ptr<SecPublicInfo> m_pib;
+  std::unique_ptr<SecTpm> m_tpm;
+  time::milliseconds m_lastTimestamp;
+};
+
+template<typename T>
+void
+KeyChain::signImpl(T& packet, const SigningInfo& params)
+{
+  Name keyName;
+  SignatureInfo sigInfo;
+  std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
+
+  signPacketWrapper(packet, Signature(sigInfo),
+                    keyName, params.getDigestAlgorithm());
+}
+
+template<typename T>
+void
+KeyChain::sign(T& packet, const Name& certificateName)
+{
+  signImpl(packet, SigningInfo(SigningInfo::SIGNER_TYPE_CERT, certificateName));
+}
+
+template<typename T>
+void
+KeyChain::signByIdentity(T& packet, const Name& identityName)
+{
+  signImpl(packet, SigningInfo(SigningInfo::SIGNER_TYPE_ID, identityName));
+}
+
+template<class PibType>
+inline void
+KeyChain::registerPib(std::initializer_list<std::string> aliases)
+{
+  registerPibImpl(*aliases.begin(), aliases, [] (const std::string& locator) {
+      return make_unique<PibType>(locator);
+    });
+}
+
+template<class TpmType>
+inline void
+KeyChain::registerTpm(std::initializer_list<std::string> aliases)
+{
+  registerTpmImpl(*aliases.begin(), aliases, [] (const std::string& locator) {
+      return make_unique<TpmType>(locator);
+    });
+}
+
+/**
+ * \brief Register SecPib class in ndn-cxx KeyChain
+ *
+ * This macro should be placed once in the implementation file of the
+ * SecPib type within the namespace where the type is declared.
+ */
+#define NDN_CXX_V1_KEYCHAIN_REGISTER_PIB(PibType, ...)     \
+static class NdnCxxAuto ## PibType ## PibRegistrationClass    \
+{                                                             \
+public:                                                       \
+  NdnCxxAuto ## PibType ## PibRegistrationClass()             \
+  {                                                           \
+    ::ndn::security::v1::KeyChain::registerPib<PibType>({__VA_ARGS__});     \
+  }                                                           \
+} ndnCxxAuto ## PibType ## PibRegistrationVariable
+
+/**
+ * \brief Register SecTpm class in ndn-cxx KeyChain
+ *
+ * This macro should be placed once in the implementation file of the
+ * SecTpm type within the namespace where the type is declared.
+ */
+#define NDN_CXX_V1_KEYCHAIN_REGISTER_TPM(TpmType, ...)     \
+static class NdnCxxAuto ## TpmType ## TpmRegistrationClass    \
+{                                                             \
+public:                                                       \
+  NdnCxxAuto ## TpmType ## TpmRegistrationClass()             \
+  {                                                           \
+    ::ndn::security::v1::KeyChain::registerTpm<TpmType>({__VA_ARGS__});     \
+  }                                                           \
+} ndnCxxAuto ## TpmType ## TpmRegistrationVariable
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V1_KEY_CHAIN_HPP
diff --git a/src/security/v1/sec-public-info-sqlite3.cpp b/src/security/v1/sec-public-info-sqlite3.cpp
new file mode 100644
index 0000000..efb4e0f
--- /dev/null
+++ b/src/security/v1/sec-public-info-sqlite3.cpp
@@ -0,0 +1,958 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ * @author Jeff Thompson <jefft0@remap.ucla.edu>
+ */
+
+#include "sec-public-info-sqlite3.hpp"
+#include "identity-certificate.hpp"
+#include "../signature-sha256-with-rsa.hpp"
+#include "../signature-sha256-with-ecdsa.hpp"
+#include "../../data.hpp"
+
+#include <sqlite3.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sstream>
+#include <fstream>
+#include <boost/filesystem.hpp>
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+using std::string;
+using std::vector;
+
+const std::string SecPublicInfoSqlite3::SCHEME("pib-sqlite3");
+
+static const string INIT_TPM_INFO_TABLE =
+  "CREATE TABLE IF NOT EXISTS                "
+  "  TpmInfo(                                "
+  "      tpm_locator           BLOB NOT NULL,"
+  "      PRIMARY KEY (tpm_locator)           "
+  "  );                                      ";
+
+static const string INIT_ID_TABLE =
+  "CREATE TABLE IF NOT EXISTS                             "
+  "  Identity(                                            "
+  "      identity_name     BLOB NOT NULL,                 "
+  "      default_identity  INTEGER DEFAULT 0,             "
+  "      PRIMARY KEY (identity_name)                      "
+  "  );                                                   "
+  "CREATE INDEX identity_index ON Identity(identity_name);";
+
+static const string INIT_KEY_TABLE =
+  "CREATE TABLE IF NOT EXISTS                       "
+  "  Key(                                           "
+  "      identity_name     BLOB NOT NULL,           "
+  "      key_identifier    BLOB NOT NULL,           "
+  "      key_type          INTEGER,                 "
+  "      public_key        BLOB,                    "
+  "      default_key       INTEGER DEFAULT 0,       "
+  "      active            INTEGER DEFAULT 0,       "
+  "      PRIMARY KEY (identity_name, key_identifier)"
+  "  );                                             "
+  "CREATE INDEX key_index ON Key(identity_name);    ";
+
+
+static const string INIT_CERT_TABLE =
+  "CREATE TABLE IF NOT EXISTS                         "
+  "  Certificate(                                     "
+  "      cert_name         BLOB NOT NULL,             "
+  "      cert_issuer       BLOB NOT NULL,             "
+  "      identity_name     BLOB NOT NULL,             "
+  "      key_identifier    BLOB NOT NULL,             "
+  "      not_before        TIMESTAMP,                 "
+  "      not_after         TIMESTAMP,                 "
+  "      certificate_data  BLOB NOT NULL,             "
+  "      valid_flag        INTEGER DEFAULT 1,         "
+  "      default_cert      INTEGER DEFAULT 0,         "
+  "      PRIMARY KEY (cert_name)                      "
+  "  );                                               "
+  "CREATE INDEX cert_index ON Certificate(cert_name); "
+  "CREATE INDEX subject ON Certificate(identity_name);";
+
+/**
+ * A utility function to call the normal sqlite3_bind_text where the value and length are
+ * value.c_str() and value.size().
+ */
+static int
+sqlite3_bind_string(sqlite3_stmt* statement,
+                    int index,
+                    const string& value,
+                    void(*destructor)(void*))
+{
+  return sqlite3_bind_text(statement, index, value.c_str(), value.size(), destructor);
+}
+
+static string
+sqlite3_column_string(sqlite3_stmt* statement, int column)
+{
+  return string(reinterpret_cast<const char*>(sqlite3_column_text(statement, column)),
+                sqlite3_column_bytes(statement, column));
+}
+
+SecPublicInfoSqlite3::SecPublicInfoSqlite3(const std::string& dir)
+  : SecPublicInfo(dir)
+  , m_database(nullptr)
+{
+  boost::filesystem::path identityDir;
+  if (dir == "") {
+#ifdef NDN_CXX_HAVE_TESTS
+    if (getenv("TEST_HOME") != nullptr) {
+      identityDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn";
+    }
+    else
+#endif // NDN_CXX_HAVE_TESTS
+    if (getenv("HOME") != nullptr) {
+      identityDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
+    }
+    else {
+      identityDir = boost::filesystem::path(".") / ".ndn";
+    }
+  }
+  else {
+    identityDir = boost::filesystem::path(dir);
+  }
+  boost::filesystem::create_directories(identityDir);
+
+  /// @todo Add define for windows/unix in wscript. The following may completely fail on windows
+  int res = sqlite3_open_v2((identityDir / "ndnsec-public-info.db").c_str(), &m_database,
+                            SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
+#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING
+                                                       "unix-dotfile"
+#else
+                            0
+#endif
+                            );
+  if (res != SQLITE_OK)
+    BOOST_THROW_EXCEPTION(Error("identity DB cannot be opened/created"));
+
+
+  BOOST_ASSERT(m_database != nullptr);
+
+  initializeTable("TpmInfo", INIT_TPM_INFO_TABLE); // Check if TpmInfo table exists;
+  initializeTable("Identity", INIT_ID_TABLE);      // Check if Identity table exists;
+  initializeTable("Key", INIT_KEY_TABLE);          // Check if Key table exists;
+  initializeTable("Certificate", INIT_CERT_TABLE); // Check if Certificate table exists;
+}
+
+SecPublicInfoSqlite3::~SecPublicInfoSqlite3()
+{
+  sqlite3_close(m_database);
+  m_database = nullptr;
+}
+
+bool
+SecPublicInfoSqlite3::doesTableExist(const string& tableName)
+{
+  // Check if the table exists;
+  bool doesTableExist = false;
+  string checkingString =
+    "SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "'";
+
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database, checkingString.c_str(), -1, &statement, 0);
+
+  int result = sqlite3_step(statement);
+  if (result == SQLITE_ROW)
+    doesTableExist = true;
+  sqlite3_finalize(statement);
+
+  return doesTableExist;
+}
+
+bool
+SecPublicInfoSqlite3::initializeTable(const string& tableName, const string& initCommand)
+{
+  // Create the table if it does not exist
+  if (!doesTableExist(tableName)) {
+    char* errorMessage = 0;
+    int result = sqlite3_exec(m_database, initCommand.c_str(), NULL, NULL, &errorMessage);
+
+    if (result != SQLITE_OK && errorMessage != 0) {
+      sqlite3_free(errorMessage);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void
+SecPublicInfoSqlite3::deleteTable(const string& tableName)
+{
+  string query = "DROP TABLE IF EXISTS " + tableName;
+
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database, query.c_str(), -1, &statement, 0);
+
+  sqlite3_step(statement);
+  sqlite3_finalize(statement);
+}
+
+void
+SecPublicInfoSqlite3::setTpmLocator(const string& tpmLocator)
+{
+  string currentTpm;
+  try {
+    currentTpm = getTpmLocator();
+  }
+  catch (SecPublicInfo::Error&) {
+    setTpmLocatorInternal(tpmLocator, false); // set tpmInfo without resetting
+    return;
+  }
+
+  if (currentTpm == tpmLocator)
+    return; // if the same, nothing will be changed
+
+  setTpmLocatorInternal(tpmLocator, true); // set tpmInfo and reset pib
+}
+
+string
+SecPublicInfoSqlite3::getTpmLocator()
+{
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database, "SELECT tpm_locator FROM TpmInfo", -1, &statement, 0);
+
+  int res = sqlite3_step(statement);
+
+  if (res == SQLITE_ROW) {
+    string tpmLocator = sqlite3_column_string(statement, 0);
+    sqlite3_finalize(statement);
+    return tpmLocator;
+  }
+  else {
+    sqlite3_finalize(statement);
+    BOOST_THROW_EXCEPTION(SecPublicInfo::Error("TPM info does not exist"));
+  }
+}
+
+void
+SecPublicInfoSqlite3::setTpmLocatorInternal(const string& tpmLocator, bool needReset)
+{
+  sqlite3_stmt* statement = nullptr;
+
+  if (needReset) {
+    deleteTable("Identity");
+    deleteTable("Key");
+    deleteTable("Certificate");
+
+    initializeTable("Identity", INIT_ID_TABLE);
+    initializeTable("Key", INIT_KEY_TABLE);
+    initializeTable("Certificate", INIT_CERT_TABLE);
+
+    sqlite3_prepare_v2(m_database, "UPDATE TpmInfo SET tpm_locator = ?",
+                       -1, &statement, 0);
+    sqlite3_bind_string(statement, 1, tpmLocator, SQLITE_TRANSIENT);
+  }
+  else {
+    // no reset implies there is no tpmLocator record, insert one
+    sqlite3_prepare_v2(m_database, "INSERT INTO TpmInfo (tpm_locator) VALUES (?)",
+                       -1, &statement, 0);
+    sqlite3_bind_string(statement, 1, tpmLocator, SQLITE_TRANSIENT);
+  }
+
+  sqlite3_step(statement);
+  sqlite3_finalize(statement);
+}
+
+std::string
+SecPublicInfoSqlite3::getPibLocator()
+{
+  return string("pib-sqlite3:").append(m_location);
+}
+
+bool
+SecPublicInfoSqlite3::doesIdentityExist(const Name& identityName)
+{
+  bool result = false;
+
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT count(*) FROM Identity WHERE identity_name=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+  int res = sqlite3_step(statement);
+
+  if (res == SQLITE_ROW) {
+    int countAll = sqlite3_column_int(statement, 0);
+    if (countAll > 0)
+      result = true;
+  }
+
+  sqlite3_finalize(statement);
+
+  return result;
+}
+
+void
+SecPublicInfoSqlite3::addIdentity(const Name& identityName)
+{
+  if (doesIdentityExist(identityName))
+    return;
+
+  sqlite3_stmt* statement = nullptr;
+
+  sqlite3_prepare_v2(m_database,
+                     "INSERT OR REPLACE INTO Identity (identity_name) values (?)",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+
+  sqlite3_step(statement);
+
+  sqlite3_finalize(statement);
+}
+
+bool
+SecPublicInfoSqlite3::revokeIdentity()
+{
+  //TODO:
+  return false;
+}
+
+bool
+SecPublicInfoSqlite3::doesPublicKeyExist(const Name& keyName)
+{
+  if (keyName.empty())
+    BOOST_THROW_EXCEPTION(Error("Incorrect key name " + keyName.toUri()));
+
+  string keyId = keyName.get(-1).toUri();
+  Name identityName = keyName.getPrefix(-1);
+
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT count(*) FROM Key WHERE identity_name=? AND key_identifier=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+  sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT);
+
+  int res = sqlite3_step(statement);
+
+  bool keyIdExist = false;
+  if (res == SQLITE_ROW) {
+    int countAll = sqlite3_column_int(statement, 0);
+    if (countAll > 0)
+      keyIdExist = true;
+  }
+
+  sqlite3_finalize(statement);
+
+  return keyIdExist;
+}
+
+void
+SecPublicInfoSqlite3::addKey(const Name& keyName,
+                             const PublicKey& publicKeyDer)
+{
+  if (keyName.empty())
+    return;
+
+  if (doesPublicKeyExist(keyName))
+    return;
+
+  string keyId = keyName.get(-1).toUri();
+  Name identityName = keyName.getPrefix(-1);
+
+  addIdentity(identityName);
+
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database,
+                     "INSERT OR REPLACE INTO Key \
+                      (identity_name, key_identifier, key_type, public_key) \
+                      values (?, ?, ?, ?)",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+  sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT);
+  sqlite3_bind_int(statement, 3, static_cast<int>(publicKeyDer.getKeyType()));
+  sqlite3_bind_blob(statement, 4,
+                    publicKeyDer.get().buf(),
+                    publicKeyDer.get().size(),
+                    SQLITE_STATIC);
+
+  sqlite3_step(statement);
+
+  sqlite3_finalize(statement);
+}
+
+shared_ptr<PublicKey>
+SecPublicInfoSqlite3::getPublicKey(const Name& keyName)
+{
+  if (keyName.empty())
+    BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getPublicKey  Empty keyName"));
+
+  string keyId = keyName.get(-1).toUri();
+  Name identityName = keyName.getPrefix(-1);
+
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT public_key FROM Key WHERE identity_name=? AND key_identifier=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+  sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT);
+
+  int res = sqlite3_step(statement);
+
+  shared_ptr<PublicKey> result;
+  if (res == SQLITE_ROW) {
+    result = make_shared<PublicKey>(static_cast<const uint8_t*>(sqlite3_column_blob(statement, 0)),
+                                        sqlite3_column_bytes(statement, 0));
+    sqlite3_finalize(statement);
+    return result;
+  }
+  else {
+    sqlite3_finalize(statement);
+    BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getPublicKey  public key does not exist"));
+  }
+}
+
+KeyType
+SecPublicInfoSqlite3::getPublicKeyType(const Name& keyName)
+{
+  if (keyName.empty())
+    return KeyType::NONE;
+
+  string keyId = keyName.get(-1).toUri();
+  Name identityName = keyName.getPrefix(-1);
+
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT key_type FROM Key WHERE identity_name=? AND key_identifier=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+  sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT);
+
+  int res = sqlite3_step(statement);
+
+  if (res == SQLITE_ROW) {
+    int typeValue = sqlite3_column_int(statement, 0);
+    sqlite3_finalize(statement);
+    return static_cast<KeyType>(typeValue);
+  }
+  else {
+    sqlite3_finalize(statement);
+    return KeyType::NONE;
+  }
+}
+
+bool
+SecPublicInfoSqlite3::doesCertificateExist(const Name& certificateName)
+{
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT count(*) FROM Certificate WHERE cert_name=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, certificateName.toUri(), SQLITE_TRANSIENT);
+
+  int res = sqlite3_step(statement);
+
+  bool certExist = false;
+  if (res == SQLITE_ROW) {
+    int countAll = sqlite3_column_int(statement, 0);
+    if (countAll > 0)
+      certExist = true;
+  }
+
+  sqlite3_finalize(statement);
+
+  return certExist;
+}
+
+void
+SecPublicInfoSqlite3::addCertificate(const IdentityCertificate& certificate)
+{
+  const Name& certificateName = certificate.getName();
+  // KeyName is from IdentityCertificate name, so should be qualified.
+  Name keyName =
+    IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
+
+  addKey(keyName, certificate.getPublicKeyInfo());
+
+  if (doesCertificateExist(certificateName))
+    return;
+
+  string keyId = keyName.get(-1).toUri();
+  Name identity = keyName.getPrefix(-1);
+
+  // Insert the certificate
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database,
+                     "INSERT OR REPLACE INTO Certificate \
+                      (cert_name, cert_issuer, identity_name, key_identifier, \
+                       not_before, not_after, certificate_data) \
+                      values (?, ?, ?, ?, datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?)",
+                      -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, certificateName.toUri(), SQLITE_TRANSIENT);
+
+  try {
+    // this will throw an exception if the signature is not the standard one
+    // or there is no key locator present
+    std::string signerName = certificate.getSignature().getKeyLocator().getName().toUri();
+    sqlite3_bind_string(statement, 2, signerName, SQLITE_TRANSIENT);
+  }
+  catch (tlv::Error&) {
+    return;
+  }
+
+  sqlite3_bind_string(statement, 3, identity.toUri(), SQLITE_TRANSIENT);
+  sqlite3_bind_string(statement, 4, keyId, SQLITE_STATIC);
+
+  sqlite3_bind_int64(statement, 5,
+    static_cast<sqlite3_int64>(time::toUnixTimestamp(certificate.getNotBefore()).count()));
+  sqlite3_bind_int64(statement, 6,
+    static_cast<sqlite3_int64>(time::toUnixTimestamp(certificate.getNotAfter()).count()));
+
+  sqlite3_bind_blob(statement, 7,
+                    certificate.wireEncode().wire(),
+                    certificate.wireEncode().size(),
+                    SQLITE_TRANSIENT);
+
+  sqlite3_step(statement);
+
+  sqlite3_finalize(statement);
+}
+
+shared_ptr<IdentityCertificate>
+SecPublicInfoSqlite3::getCertificate(const Name& certificateName)
+{
+  sqlite3_stmt* statement = nullptr;
+
+  sqlite3_prepare_v2(m_database,
+                     "SELECT certificate_data FROM Certificate WHERE cert_name=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, certificateName.toUri(), SQLITE_TRANSIENT);
+
+  int res = sqlite3_step(statement);
+
+  if (res == SQLITE_ROW) {
+    shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
+    try {
+      certificate->wireDecode(Block(static_cast<const uint8_t*>(sqlite3_column_blob(statement, 0)),
+                                    sqlite3_column_bytes(statement, 0)));
+    }
+    catch (tlv::Error&) {
+      sqlite3_finalize(statement);
+      BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getCertificate  certificate cannot be "
+                                  "decoded"));
+    }
+
+    sqlite3_finalize(statement);
+    return certificate;
+  }
+  else {
+    sqlite3_finalize(statement);
+    BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getCertificate  certificate does not "
+                                "exist"));
+  }
+}
+
+
+Name
+SecPublicInfoSqlite3::getDefaultIdentity()
+{
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT identity_name FROM Identity WHERE default_identity=1",
+                     -1, &statement, 0);
+
+  int res = sqlite3_step(statement);
+
+  if (res == SQLITE_ROW) {
+    Name identity(sqlite3_column_string(statement, 0));
+    sqlite3_finalize(statement);
+    return identity;
+  }
+  else {
+    sqlite3_finalize(statement);
+    BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getDefaultIdentity  no default identity"));
+  }
+}
+
+void
+SecPublicInfoSqlite3::setDefaultIdentityInternal(const Name& identityName)
+{
+  addIdentity(identityName);
+
+  sqlite3_stmt* statement = nullptr;
+
+  //Reset previous default identity
+  sqlite3_prepare_v2(m_database,
+                     "UPDATE Identity SET default_identity=0 WHERE default_identity=1",
+                     -1, &statement, 0);
+
+  while (sqlite3_step(statement) == SQLITE_ROW)
+    ;
+
+  sqlite3_finalize(statement);
+
+  //Set current default identity
+  sqlite3_prepare_v2(m_database,
+                     "UPDATE Identity SET default_identity=1 WHERE identity_name=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+
+  sqlite3_step(statement);
+
+  sqlite3_finalize(statement);
+}
+
+Name
+SecPublicInfoSqlite3::getDefaultKeyNameForIdentity(const Name& identityName)
+{
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT key_identifier FROM Key WHERE identity_name=? AND default_key=1",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+
+  int res = sqlite3_step(statement);
+
+  if (res == SQLITE_ROW) {
+    Name keyName = identityName;
+    keyName.append(string(reinterpret_cast<const char*>(sqlite3_column_text(statement, 0)),
+                          sqlite3_column_bytes(statement, 0)));
+    sqlite3_finalize(statement);
+    return keyName;
+  }
+  else {
+    sqlite3_finalize(statement);
+    BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getDefaultKeyNameForIdentity key not "
+                                "found"));
+  }
+}
+
+void
+SecPublicInfoSqlite3::setDefaultKeyNameForIdentityInternal(const Name& keyName)
+{
+  if (!doesPublicKeyExist(keyName))
+    BOOST_THROW_EXCEPTION(Error("Key does not exist:" + keyName.toUri()));
+
+  string keyId = keyName.get(-1).toUri();
+  Name identityName = keyName.getPrefix(-1);
+
+  sqlite3_stmt* statement = nullptr;
+
+  //Reset previous default Key
+  sqlite3_prepare_v2(m_database,
+                     "UPDATE Key SET default_key=0 WHERE default_key=1 and identity_name=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+
+  while (sqlite3_step(statement) == SQLITE_ROW)
+    ;
+
+  sqlite3_finalize(statement);
+
+  //Set current default Key
+  sqlite3_prepare_v2(m_database,
+                     "UPDATE Key SET default_key=1 WHERE identity_name=? AND key_identifier=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+  sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT);
+
+  sqlite3_step(statement);
+
+  sqlite3_finalize(statement);
+}
+
+Name
+SecPublicInfoSqlite3::getDefaultCertificateNameForKey(const Name& keyName)
+{
+  if (keyName.empty())
+    BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getDefaultCertificateNameForKey wrong key"));
+
+  string keyId = keyName.get(-1).toUri();
+  Name identityName = keyName.getPrefix(-1);
+
+  sqlite3_stmt* statement = nullptr;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT cert_name FROM Certificate \
+                      WHERE identity_name=? AND key_identifier=? AND default_cert=1",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+  sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT);
+
+  int res = sqlite3_step(statement);
+
+  if (res == SQLITE_ROW) {
+    Name certName(string(reinterpret_cast<const char*>(sqlite3_column_text(statement, 0)),
+                         sqlite3_column_bytes(statement, 0)));
+    sqlite3_finalize(statement);
+    return certName;
+  }
+  else {
+    sqlite3_finalize(statement);
+    BOOST_THROW_EXCEPTION(Error("certificate not found"));
+  }
+}
+
+void
+SecPublicInfoSqlite3::setDefaultCertificateNameForKeyInternal(const Name& certificateName)
+{
+  if (!doesCertificateExist(certificateName))
+    BOOST_THROW_EXCEPTION(Error("certificate does not exist:" + certificateName.toUri()));
+
+  Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
+  string keyId = keyName.get(-1).toUri();
+  Name identityName = keyName.getPrefix(-1);
+
+  sqlite3_stmt* statement = nullptr;
+
+  //Reset previous default Key
+  sqlite3_prepare_v2(m_database,
+                     "UPDATE Certificate SET default_cert=0 \
+                      WHERE default_cert=1 AND identity_name=? AND key_identifier=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+  sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT);
+
+  while (sqlite3_step(statement) == SQLITE_ROW)
+    ;
+
+  sqlite3_finalize(statement);
+
+  //Set current default Key
+  sqlite3_prepare_v2(m_database,
+                     "UPDATE Certificate SET default_cert=1 \
+                      WHERE identity_name=? AND key_identifier=? AND cert_name=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+  sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT);
+  sqlite3_bind_string(statement, 3, certificateName.toUri(), SQLITE_TRANSIENT);
+
+  sqlite3_step(statement);
+
+  sqlite3_finalize(statement);
+}
+
+void
+SecPublicInfoSqlite3::getAllIdentities(vector<Name>& nameList, bool isDefault)
+{
+  sqlite3_stmt* stmt;
+  if (isDefault)
+    sqlite3_prepare_v2(m_database,
+                       "SELECT identity_name FROM Identity WHERE default_identity=1",
+                       -1, &stmt, 0);
+  else
+    sqlite3_prepare_v2(m_database,
+                       "SELECT identity_name FROM Identity WHERE default_identity=0",
+                       -1, &stmt, 0);
+
+  while (sqlite3_step(stmt) == SQLITE_ROW)
+    nameList.push_back(Name(string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)),
+                                   sqlite3_column_bytes(stmt, 0))));
+
+  sqlite3_finalize(stmt);
+}
+
+void
+SecPublicInfoSqlite3::getAllKeyNames(vector<Name>& nameList, bool isDefault)
+{
+  sqlite3_stmt* stmt;
+
+  if (isDefault)
+    sqlite3_prepare_v2(m_database,
+                       "SELECT identity_name, key_identifier FROM Key WHERE default_key=1",
+                       -1, &stmt, 0);
+  else
+    sqlite3_prepare_v2(m_database,
+                       "SELECT identity_name, key_identifier FROM Key WHERE default_key=0",
+                       -1, &stmt, 0);
+
+  while (sqlite3_step(stmt) == SQLITE_ROW) {
+    Name keyName(string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)),
+                        sqlite3_column_bytes(stmt, 0)));
+    keyName.append(string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1)),
+                          sqlite3_column_bytes(stmt, 1)));
+    nameList.push_back(keyName);
+  }
+  sqlite3_finalize(stmt);
+}
+
+void
+SecPublicInfoSqlite3::getAllKeyNamesOfIdentity(const Name& identity,
+                                               vector<Name>& nameList,
+                                               bool isDefault)
+{
+  sqlite3_stmt* stmt;
+
+  if (isDefault)
+    sqlite3_prepare_v2(m_database,
+                       "SELECT key_identifier FROM Key WHERE default_key=1 and identity_name=?",
+                       -1, &stmt, 0);
+  else
+    sqlite3_prepare_v2(m_database,
+                       "SELECT key_identifier FROM Key WHERE default_key=0 and identity_name=?",
+                       -1, &stmt, 0);
+
+  sqlite3_bind_string(stmt, 1, identity.toUri(), SQLITE_TRANSIENT);
+
+  while (sqlite3_step(stmt) == SQLITE_ROW) {
+    Name keyName(identity);
+    keyName.append(string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)),
+                          sqlite3_column_bytes(stmt, 0)));
+    nameList.push_back(keyName);
+  }
+  sqlite3_finalize(stmt);
+}
+
+void
+SecPublicInfoSqlite3::getAllCertificateNames(vector<Name>& nameList, bool isDefault)
+{
+  sqlite3_stmt* stmt;
+
+  if (isDefault)
+    sqlite3_prepare_v2(m_database,
+                       "SELECT cert_name FROM Certificate WHERE default_cert=1",
+                       -1, &stmt, 0);
+  else
+    sqlite3_prepare_v2(m_database,
+                       "SELECT cert_name FROM Certificate WHERE default_cert=0",
+                       -1, &stmt, 0);
+
+  while (sqlite3_step(stmt) == SQLITE_ROW)
+    nameList.push_back(string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)),
+                              sqlite3_column_bytes(stmt, 0)));
+
+  sqlite3_finalize(stmt);
+}
+
+void
+SecPublicInfoSqlite3::getAllCertificateNamesOfKey(const Name& keyName,
+                                                  vector<Name>& nameList,
+                                                  bool isDefault)
+{
+  if (keyName.empty())
+    return;
+
+  sqlite3_stmt* stmt;
+  if (isDefault)
+    sqlite3_prepare_v2(m_database,
+                       "SELECT cert_name FROM Certificate \
+                        WHERE default_cert=1 and identity_name=? and key_identifier=?",
+                       -1, &stmt, 0);
+  else
+    sqlite3_prepare_v2(m_database,
+                       "SELECT cert_name FROM Certificate \
+                        WHERE default_cert=0 and identity_name=? and key_identifier=?",
+                       -1, &stmt, 0);
+
+  Name identity = keyName.getPrefix(-1);
+  sqlite3_bind_string(stmt, 1, identity.toUri(), SQLITE_TRANSIENT);
+
+  std::string baseKeyName = keyName.get(-1).toUri();
+  sqlite3_bind_string(stmt, 2, baseKeyName, SQLITE_TRANSIENT);
+
+  while (sqlite3_step(stmt) == SQLITE_ROW)
+    nameList.push_back(string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)),
+                              sqlite3_column_bytes(stmt, 0)));
+
+  sqlite3_finalize(stmt);
+}
+
+void
+SecPublicInfoSqlite3::deleteCertificateInfo(const Name& certName)
+{
+  if (certName.empty())
+    return;
+
+  sqlite3_stmt* stmt;
+  sqlite3_prepare_v2(m_database, "DELETE FROM Certificate WHERE cert_name=?", -1, &stmt, 0);
+  sqlite3_bind_string(stmt, 1, certName.toUri(), SQLITE_TRANSIENT);
+  sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+}
+
+void
+SecPublicInfoSqlite3::deletePublicKeyInfo(const Name& keyName)
+{
+  if (keyName.empty())
+    return;
+
+  string identity = keyName.getPrefix(-1).toUri();
+  string keyId = keyName.get(-1).toUri();
+
+  sqlite3_stmt* stmt;
+  sqlite3_prepare_v2(m_database,
+                     "DELETE FROM Certificate WHERE identity_name=? and key_identifier=?",
+                     -1, &stmt, 0);
+  sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
+  sqlite3_bind_string(stmt, 2, keyId, SQLITE_TRANSIENT);
+  sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+
+  sqlite3_prepare_v2(m_database,
+                     "DELETE FROM Key WHERE identity_name=? and key_identifier=?",
+                     -1, &stmt, 0);
+  sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
+  sqlite3_bind_string(stmt, 2, keyId, SQLITE_TRANSIENT);
+  sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+}
+
+void
+SecPublicInfoSqlite3::deleteIdentityInfo(const Name& identityName)
+{
+  string identity = identityName.toUri();
+
+  sqlite3_stmt* stmt;
+  sqlite3_prepare_v2(m_database, "DELETE FROM Certificate WHERE identity_name=?", -1, &stmt, 0);
+  sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
+  sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+
+  sqlite3_prepare_v2(m_database, "DELETE FROM Key WHERE identity_name=?", -1, &stmt, 0);
+  sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
+  sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+
+  sqlite3_prepare_v2(m_database, "DELETE FROM Identity WHERE identity_name=?", -1, &stmt, 0);
+  sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
+  sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+}
+
+std::string
+SecPublicInfoSqlite3::getScheme()
+{
+  return SCHEME;
+}
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v1/sec-public-info-sqlite3.hpp b/src/security/v1/sec-public-info-sqlite3.hpp
new file mode 100644
index 0000000..6e9dfd7
--- /dev/null
+++ b/src/security/v1/sec-public-info-sqlite3.hpp
@@ -0,0 +1,171 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ * @author Jeff Thompson <jefft0@remap.ucla.edu>
+ */
+
+#ifndef NDN_SECURITY_V1_SEC_PUBLIC_INFO_SQLITE3_HPP
+#define NDN_SECURITY_V1_SEC_PUBLIC_INFO_SQLITE3_HPP
+
+#include "../../common.hpp"
+#include "sec-public-info.hpp"
+
+struct sqlite3;
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+class SecPublicInfoSqlite3 : public SecPublicInfo
+{
+public:
+  class Error : public SecPublicInfo::Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : SecPublicInfo::Error(what)
+    {
+    }
+  };
+
+  explicit
+  SecPublicInfoSqlite3(const std::string& dir = "");
+
+  virtual
+  ~SecPublicInfoSqlite3();
+
+  /**********************
+   * from SecPublicInfo *
+   **********************/
+
+  virtual void
+  setTpmLocator(const std::string& tpmLocator);
+
+  virtual std::string
+  getTpmLocator();
+
+  virtual std::string
+  getPibLocator();
+
+  virtual bool
+  doesIdentityExist(const Name& identityName);
+
+  virtual void
+  addIdentity(const Name& identityName);
+
+  virtual bool
+  revokeIdentity();
+
+  virtual bool
+  doesPublicKeyExist(const Name& keyName);
+
+  virtual void
+  addKey(const Name& keyName, const PublicKey& publicKeyDer);
+
+  virtual shared_ptr<PublicKey>
+  getPublicKey(const Name& keyName);
+
+  virtual KeyType
+  getPublicKeyType(const Name& keyName);
+
+  virtual bool
+  doesCertificateExist(const Name& certificateName);
+
+  virtual void
+  addCertificate(const IdentityCertificate& certificate);
+
+  virtual shared_ptr<IdentityCertificate>
+  getCertificate(const Name& certificateName);
+
+
+
+  virtual Name
+  getDefaultIdentity();
+
+  virtual Name
+  getDefaultKeyNameForIdentity(const Name& identityName);
+
+  virtual Name
+  getDefaultCertificateNameForKey(const Name& keyName);
+
+  virtual void
+  getAllIdentities(std::vector<Name>& nameList, bool isDefault);
+
+  virtual void
+  getAllKeyNames(std::vector<Name>& nameList, bool isDefault);
+
+  virtual void
+  getAllKeyNamesOfIdentity(const Name& identity, std::vector<Name>& nameList, bool isDefault);
+
+  virtual void
+  getAllCertificateNames(std::vector<Name>& nameList, bool isDefault);
+
+  virtual void
+  getAllCertificateNamesOfKey(const Name& keyName, std::vector<Name>& nameList, bool isDefault);
+
+  virtual void
+  deleteCertificateInfo(const Name& certificateName);
+
+  virtual void
+  deletePublicKeyInfo(const Name& keyName);
+
+  virtual void
+  deleteIdentityInfo(const Name& identity);
+
+private:
+  bool
+  initializeTable(const std::string& tableName, const std::string& initCommand);
+
+  void
+  deleteTable(const std::string& tableName);
+
+  void
+  setTpmLocatorInternal(const std::string& tpmLocator, bool needReset);
+
+  void
+  setDefaultIdentityInternal(const Name& identityName);
+
+  void
+  setDefaultKeyNameForIdentityInternal(const Name& keyName);
+
+  void
+  setDefaultCertificateNameForKeyInternal(const Name& certificateName);
+
+  std::string
+  getScheme();
+
+NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  bool
+  doesTableExist(const std::string& tableName);
+
+public:
+  static const std::string SCHEME;
+
+private:
+  sqlite3* m_database;
+};
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V1_SEC_PUBLIC_INFO_SQLITE3_HPP
diff --git a/src/security/v1/sec-public-info.cpp b/src/security/v1/sec-public-info.cpp
new file mode 100644
index 0000000..96c4441
--- /dev/null
+++ b/src/security/v1/sec-public-info.cpp
@@ -0,0 +1,165 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "sec-public-info.hpp"
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+SecPublicInfo::SecPublicInfo(const std::string& location)
+  : m_location(location)
+{
+}
+
+SecPublicInfo::~SecPublicInfo()
+{
+}
+
+std::string
+SecPublicInfo::getPibLocator()
+{
+  return this->getScheme() + ":" + m_location;
+}
+
+void
+SecPublicInfo::addPublicKey(const Name& keyName, KeyType keyType, const PublicKey& publicKey)
+{
+  addKey(keyName, publicKey);
+}
+
+void
+SecPublicInfo::setDefaultIdentity(const Name& identityName)
+{
+  setDefaultIdentityInternal(identityName);
+  refreshDefaultCertificate();
+}
+
+void
+SecPublicInfo::setDefaultKeyNameForIdentity(const Name& keyName)
+{
+  setDefaultKeyNameForIdentityInternal(keyName);
+  refreshDefaultCertificate();
+}
+
+void
+SecPublicInfo::setDefaultCertificateNameForKey(const Name& certificateName)
+{
+  setDefaultCertificateNameForKeyInternal(certificateName);
+  refreshDefaultCertificate();
+}
+
+Name
+SecPublicInfo::getDefaultCertificateNameForIdentity(const Name& identityName)
+{
+  return getDefaultCertificateNameForKey(getDefaultKeyNameForIdentity(identityName));
+}
+
+Name
+SecPublicInfo::getDefaultCertificateName()
+{
+  if (m_defaultCertificate == nullptr)
+    refreshDefaultCertificate();
+
+  if (m_defaultCertificate == nullptr)
+    BOOST_THROW_EXCEPTION(Error("No default certificate is set"));
+
+  return m_defaultCertificate->getName();
+}
+
+Name
+SecPublicInfo::getNewKeyName(const Name& identityName, bool useKsk)
+{
+  std::ostringstream oss;
+
+  if (useKsk)
+    oss << "ksk-";
+  else
+    oss << "dsk-";
+
+  oss << time::toUnixTimestamp(time::system_clock::now()).count();
+
+  Name keyName = Name(identityName).append(oss.str());
+
+  if (doesPublicKeyExist(keyName))
+    BOOST_THROW_EXCEPTION(Error("Key name already exists: " + keyName.toUri()));
+
+  return keyName;
+}
+
+void
+SecPublicInfo::addCertificateAsKeyDefault(const IdentityCertificate& certificate)
+{
+  addCertificate(certificate);
+  setDefaultCertificateNameForKeyInternal(certificate.getName());
+  refreshDefaultCertificate();
+}
+
+void
+SecPublicInfo::addCertificateAsIdentityDefault(const IdentityCertificate& certificate)
+{
+  addCertificate(certificate);
+  Name certName = certificate.getName();
+  Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certName);
+  setDefaultKeyNameForIdentityInternal(keyName);
+  setDefaultCertificateNameForKeyInternal(certName);
+  refreshDefaultCertificate();
+}
+
+void
+SecPublicInfo::addCertificateAsSystemDefault(const IdentityCertificate& certificate)
+{
+  addCertificate(certificate);
+  Name certName = certificate.getName();
+  Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certName);
+  setDefaultIdentityInternal(keyName.getPrefix(-1));
+  setDefaultKeyNameForIdentityInternal(keyName);
+  setDefaultCertificateNameForKeyInternal(certName);
+  refreshDefaultCertificate();
+}
+
+shared_ptr<IdentityCertificate>
+SecPublicInfo::defaultCertificate()
+{
+  return getDefaultCertificate();
+}
+
+shared_ptr<IdentityCertificate>
+SecPublicInfo::getDefaultCertificate()
+{
+  return m_defaultCertificate;
+}
+
+void
+SecPublicInfo::refreshDefaultCertificate()
+{
+  try {
+    Name certName = getDefaultCertificateNameForIdentity(getDefaultIdentity());
+    m_defaultCertificate = getCertificate(certName);
+  }
+  catch (SecPublicInfo::Error&) {
+    m_defaultCertificate.reset();
+  }
+}
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v1/sec-public-info.hpp b/src/security/v1/sec-public-info.hpp
new file mode 100644
index 0000000..7ed6ef4
--- /dev/null
+++ b/src/security/v1/sec-public-info.hpp
@@ -0,0 +1,473 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_SECURITY_V1_SEC_PUBLIC_INFO_HPP
+#define NDN_SECURITY_V1_SEC_PUBLIC_INFO_HPP
+
+#include "../../name.hpp"
+#include "../security-common.hpp"
+#include "public-key.hpp"
+#include "identity-certificate.hpp"
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+/**
+ * @brief SecPublicInfo is a base class for the storage of public information.
+ *
+ * It specify interfaces related to public information, such as identity, public keys and
+ * certificates.
+ */
+class SecPublicInfo : noncopyable
+{
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+  explicit
+  SecPublicInfo(const std::string& location);
+
+  /**
+   * @brief The virtual Destructor
+   */
+  virtual
+  ~SecPublicInfo();
+
+  /**
+   * @brief Set the corresponding TPM information to @p tpmLocator
+   *
+   * If the provided @p tpmLocator is different from the existing one, the PIB will be reset,
+   * otherwise nothing will be changed.
+   *
+   * For legacy issue, the TPM info may not exist (some old PIB content may not have this info),
+   * this method will simply set the TPM info as provided without changing anything else. Thus an
+   * ideal process of handling old PIB is to check if TPM info exists. If it does not exist,
+   * then set it to the default value according to configuration.
+   */
+  virtual void
+  setTpmLocator(const std::string& tpmLocator) = 0;
+
+  /**
+   * @brief Get TPM Locator
+   *
+   * @throws SecPublicInfo::Error if the TPM info does not exist
+   */
+  virtual std::string
+  getTpmLocator() = 0;
+
+  /**
+   * @brief Get PIB Locator
+   */
+  std::string
+  getPibLocator();
+
+  /**
+   * @brief Check if the specified identity already exists
+   *
+   * @param identityName The identity name
+   * @return true if the identity exists, otherwise false
+   */
+  virtual bool
+  doesIdentityExist(const Name& identityName) = 0;
+
+  /**
+   * @brief Add a new identity
+   *
+   * if identity already exist, do not add it again
+   *
+   * @param identityName The identity name to be added
+   */
+  virtual void
+  addIdentity(const Name& identityName) = 0;
+
+  /**
+   * @brief Revoke the identity
+   *
+   * @return true if the identity was revoked, otherwise false
+   */
+  virtual bool
+  revokeIdentity() = 0;
+
+  /**
+   * @brief Check if the specified key already exists
+   *
+   * @param keyName The name of the key
+   * @return true if the key exists, otherwise false
+   */
+  virtual bool
+  doesPublicKeyExist(const Name& keyName) = 0;
+
+  /**
+   * @brief Add a public key to the identity storage.
+   *
+   * @param keyName The name of the public key to be added
+   * @param keyType Type of the public key to be added
+   * @param publicKey Reference to the PublicKey object
+   * @deprecated Use addKey instead
+   */
+  DEPRECATED(
+  void
+  addPublicKey(const Name& keyName, KeyType keyType, const PublicKey& publicKey));
+
+  /**
+   * @brief Add a public key to the identity storage.
+   *
+   * @param keyName The name of the public key to be added
+   * @param publicKey Reference to the PublicKey object
+   */
+  virtual void
+  addKey(const Name& keyName, const PublicKey& publicKey) = 0;
+
+  /**
+   * @brief Get shared pointer to PublicKey object from the identity storage
+   *
+   * @param keyName The name of the requested public key
+   * @throws SecPublicInfo::Error if public key does not exist
+   */
+  virtual shared_ptr<PublicKey>
+  getPublicKey(const Name& keyName) = 0;
+
+  /**
+   * @brief Get the type of the queried public key
+   *
+   * @note KeyType is also available from PublicKey instance.
+   *       This method is more efficient if only KeyType is needed.
+   *
+   * @param keyName The name of the requested public key
+   * @return the type of the key. If the queried key does not exist, KeyType::NONE will be returned
+   */
+  virtual KeyType
+  getPublicKeyType(const Name& keyName) = 0;
+
+  /**
+   * @brief Check if the specified certificate already exists
+   *
+   * @param certificateName The name of the certificate
+   */
+  virtual bool
+  doesCertificateExist(const Name& certificateName) = 0;
+
+  /**
+   * @brief Add a certificate to the identity storage.
+   *
+   * It will add the corresponding public key and identity if they do not exist
+   *
+   * @param certificate The certificate to be added
+   */
+  virtual void
+  addCertificate(const IdentityCertificate& certificate) = 0;
+
+  /**
+   * @brief Get a shared pointer to identity certificate object from the identity storage
+   *
+   * @param certificateName The name of the requested certificate
+   * @throws SecPublicInfo::Error if the certificate does not exist
+   */
+  virtual shared_ptr<IdentityCertificate>
+  getCertificate(const Name& certificateName) = 0;
+
+
+  /*****************************************
+   *            Default Getter             *
+   *****************************************/
+
+  /**
+   * @brief Get name of the default identity
+   *
+   * @throws SecPublicInfo::Error if there is no default.
+   */
+  virtual Name
+  getDefaultIdentity() = 0;
+
+  /**
+   * @brief Get name of the default key name for the specified identity
+   *
+   * @param identityName The identity name
+   * @throws SecPublicInfo::Error if there is no default
+   */
+  virtual Name
+  getDefaultKeyNameForIdentity(const Name& identityName) = 0;
+
+  /**
+   * @brief Get name of the default certificate name for the specified key
+   *
+   * @param keyName The key name.
+   * @throws SecPublicInfo::Error if there is no default.
+   */
+  virtual Name
+  getDefaultCertificateNameForKey(const Name& keyName) = 0;
+
+  /**
+   * @brief Get all the identities from public info
+   *
+   * @param [out] nameList On return, the identity list
+   * @param isDefault      If specified, only the default identity is returned
+   */
+  virtual void
+  getAllIdentities(std::vector<Name>& nameList, bool isDefault) = 0;
+
+  /**
+   * @brief Get all the key names from public info
+   *
+   * @param [out] nameList On return, the key name list.
+   * @param isDefault      If specified, only the default keys are returned
+   */
+  virtual void
+  getAllKeyNames(std::vector<Name>& nameList, bool isDefault) = 0;
+
+  /**
+   * @brief Get all the key names of a particular identity
+   *
+   * @param identity       The specified identity name
+   * @param [out] nameList On return, the key name list
+   * @param isDefault      If specified, only the default key is returned
+   */
+  virtual void
+  getAllKeyNamesOfIdentity(const Name& identity, std::vector<Name>& nameList, bool isDefault) = 0;
+
+  /**
+   * @brief Get all the certificate name in public info
+   *
+   * @param [out] nameList On return, the certificate name list
+   * @param isDefault      If specified, only the default certificates are returned
+   */
+  virtual void
+  getAllCertificateNames(std::vector<Name>& nameList, bool isDefault) = 0;
+
+  /**
+   * @brief Get all the certificate name of a particular key name
+   *
+   * @param keyName        The specified key name
+   * @param [out] nameList On return, the certificate name list
+   * @param isDefault      If specified, only the default certificate is returned
+   */
+  virtual void
+  getAllCertificateNamesOfKey(const Name& keyName, std::vector<Name>& nameList, bool isDefault) = 0;
+
+  /*****************************************
+   *            Delete Methods             *
+   *****************************************/
+
+  /**
+   * @brief Delete a certificate
+   *
+   * @param certificateName The certificate name
+   */
+  virtual void
+  deleteCertificateInfo(const Name& certificateName) = 0;
+
+  /**
+   * @brief Delete a public key and related certificates
+   *
+   * @param keyName The key name
+   */
+  virtual void
+  deletePublicKeyInfo(const Name& keyName) = 0;
+
+  /**
+   * @brief Delete an identity and related public keys and certificates
+   *
+   * @param identity The identity name
+   */
+  virtual void
+  deleteIdentityInfo(const Name& identity) = 0;
+
+protected:
+
+  /*****************************************
+   *            Default Setter             *
+   *****************************************/
+
+  /**
+   * @brief Set the default identity
+   *
+   * @param identityName The default identity name
+   */
+  virtual void
+  setDefaultIdentityInternal(const Name& identityName) = 0;
+
+  /**
+   * @brief Set the default key name for the corresponding identity
+   *
+   * @param keyName The key name
+   * @throws SecPublicInfo::Error if the key does not exist
+   */
+  virtual void
+  setDefaultKeyNameForIdentityInternal(const Name& keyName) = 0;
+
+  /**
+   * @brief Set the default certificate name for the corresponding key
+   *
+   * @param certificateName The certificate name
+   * @throws SecPublicInfo::Error if the certificate does not exist
+   */
+  virtual void
+  setDefaultCertificateNameForKeyInternal(const Name& certificateName) = 0;
+
+  /**
+   * @brief return the scheme of the PibLocator
+   */
+  virtual std::string
+  getScheme() = 0;
+
+public:
+
+  /*****************************************
+   *            Helper Methods             *
+   *****************************************/
+
+  /**
+   * @brief Set the default identity
+   *
+   * @param identityName The default identity name
+   * @throws SecPublicInfo::Error if the identity does not exist
+   */
+  void
+  setDefaultIdentity(const Name& identityName);
+
+  /**
+   * @brief Set the default key name for the corresponding identity
+   *
+   * @param keyName The key name
+   * @throws SecPublicInfo::Error if either the identity or key does not exist
+   */
+  void
+  setDefaultKeyNameForIdentity(const Name& keyName);
+
+  /**
+   * @brief Set the default certificate name for the corresponding key
+   *
+   * @param certificateName The certificate name
+   * @throws SecPublicInfo::Error if either the certificate or key does not exist
+   */
+  void
+  setDefaultCertificateNameForKey(const Name& certificateName);
+
+  /**
+   * @brief Generate a key name for the identity
+   *
+   * @param identityName The identity name
+   * @param useKsk If true, generate a KSK name, otherwise a DSK name
+   * @return The generated key name
+   */
+  Name
+  getNewKeyName(const Name& identityName, bool useKsk);
+
+  /**
+   * @brief Get the default certificate name for the specified identity
+   *
+   * @param identityName The identity name
+   * @return The default certificate name
+   * @throws SecPublicInfo::Error if no certificate is found
+   */
+  Name
+  getDefaultCertificateNameForIdentity(const Name& identityName);
+
+  /**
+   * @brief Get the default certificate name of the default identity
+   *
+   * @return The requested certificate name
+   * @throws SecPublicInfo::Error if no certificate is found
+   */
+  Name
+  getDefaultCertificateName();
+
+  /**
+   * @brief Add a certificate and set the certificate as the default one of its corresponding key
+   *
+   * @param certificate The certificate to be added
+   * @throws SecPublicInfo::Error if the certificate cannot be added (though it is really rare)
+   */
+  void
+  addCertificateAsKeyDefault(const IdentityCertificate& certificate);
+
+  /**
+   * @brief Add a certificate into the public key identity storage and set the certificate as the
+   *        default one of its corresponding identity
+   *
+   * @param certificate The certificate to be added
+   * @throws SecPublicInfo::Error if the certificate cannot be added (though it is really rare)
+   */
+  void
+  addCertificateAsIdentityDefault(const IdentityCertificate& certificate);
+
+  /**
+   * @brief Add a certificate into the public key identity storage and set the certificate as the
+   *        default one of the default identity
+   *
+   * @param certificate The certificate to be added
+   * @throws SecPublicInfo::Error if the certificate cannot be added (though it is really rare)
+   */
+  void
+  addCertificateAsSystemDefault(const IdentityCertificate& certificate);
+
+  /**
+   * @brief Get cached default certificate of the default identity
+   *
+   * @return The certificate which might be empty shared_ptr<IdentityCertificate>()
+   * @deprecated Use getDefaultCertificate instead
+   */
+  DEPRECATED(
+  shared_ptr<IdentityCertificate>
+  defaultCertificate());
+
+  /**
+   * @brief Get cached default certificate of the default identity
+   *
+   * @return The certificate which might be empty shared_ptr<IdentityCertificate>()
+   */
+  shared_ptr<IdentityCertificate>
+  getDefaultCertificate();
+
+  /**
+   * @brief try to get the default certificate of the default identity from the public info
+   */
+  void
+  refreshDefaultCertificate();
+
+protected:
+  shared_ptr<IdentityCertificate> m_defaultCertificate;
+  std::string m_location;
+};
+
+} // namespace v1
+
+#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES
+using v1::SecPublicInfo;
+#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES
+
+} // namespace security
+
+#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES
+using security::v1::SecPublicInfo;
+#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES
+
+} // namespace ndn
+
+#endif // NDN_SECURITY_V1_SEC_PUBLIC_INFO_HPP
diff --git a/src/security/v1/sec-tpm-file.cpp b/src/security/v1/sec-tpm-file.cpp
new file mode 100644
index 0000000..adda17f
--- /dev/null
+++ b/src/security/v1/sec-tpm-file.cpp
@@ -0,0 +1,593 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Xingyu Ma <http://www.linkedin.com/pub/xingyu-ma/1a/384/5a8>
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
+ */
+
+#include "sec-tpm-file.hpp"
+
+#include "../../encoding/buffer-stream.hpp"
+
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include "cryptopp.hpp"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <algorithm>
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+using std::string;
+using std::ostringstream;
+using std::ofstream;
+
+const std::string SecTpmFile::SCHEME("tpm-file");
+
+class SecTpmFile::Impl
+{
+public:
+  explicit
+  Impl(const string& dir)
+  {
+    boost::filesystem::path actualDir;
+    if (dir.empty()) {
+#ifdef NDN_CXX_HAVE_TESTS
+      if (getenv("TEST_HOME") != nullptr) {
+        actualDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn";
+      }
+      else
+#endif // NDN_CXX_HAVE_TESTS
+      if (getenv("HOME") != nullptr) {
+        actualDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
+      }
+      else {
+        actualDir = boost::filesystem::path(".") / ".ndn";
+      }
+    }
+    else {
+      actualDir = boost::filesystem::path(dir);
+    }
+
+    m_keystorePath = actualDir / "ndnsec-tpm-file";
+    boost::filesystem::create_directories(m_keystorePath);
+  }
+
+  boost::filesystem::path
+  transformName(const string& keyName, const string& extension)
+  {
+    using namespace CryptoPP;
+    string digest;
+    SHA256 hash;
+    StringSource src(keyName,
+                     true,
+                     new HashFilter(hash,
+                                    new Base64Encoder(new CryptoPP::StringSink(digest))));
+
+    boost::algorithm::trim(digest);
+    std::replace(digest.begin(), digest.end(), '/', '%');
+
+    return m_keystorePath / (digest + extension);
+  }
+
+  string
+  maintainMapping(const string& keyName)
+  {
+    string keyFileName = transformName(keyName, "").string();
+
+    ofstream outfile;
+    string dirFile = (m_keystorePath / "mapping.txt").string();
+
+    outfile.open(dirFile.c_str(), std::ios_base::app);
+    outfile << keyName << ' ' << keyFileName << '\n';
+    outfile.close();
+
+    return keyFileName;
+  }
+
+public:
+  boost::filesystem::path m_keystorePath;
+};
+
+
+SecTpmFile::SecTpmFile(const string& location)
+  : SecTpm(location)
+  , m_impl(new Impl(location))
+  , m_inTerminal(false)
+{
+}
+
+SecTpmFile::~SecTpmFile()
+{
+}
+
+void
+SecTpmFile::generateKeyPairInTpm(const Name& keyName, const KeyParams& params)
+{
+  string keyURI = keyName.toUri();
+
+  if (doesKeyExistInTpm(keyName, KeyClass::PUBLIC))
+    BOOST_THROW_EXCEPTION(Error("public key exists"));
+  if (doesKeyExistInTpm(keyName, KeyClass::PRIVATE))
+    BOOST_THROW_EXCEPTION(Error("private key exists"));
+
+  string keyFileName = m_impl->maintainMapping(keyURI);
+
+  try {
+    switch (params.getKeyType()) {
+      case KeyType::RSA: {
+        using namespace CryptoPP;
+
+        const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
+        AutoSeededRandomPool rng;
+        InvertibleRSAFunction privateKey;
+        privateKey.Initialize(rng, rsaParams.getKeySize());
+
+        string privateKeyFileName = keyFileName + ".pri";
+        Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
+        privateKey.DEREncode(privateKeySink);
+        privateKeySink.MessageEnd();
+
+        RSAFunction publicKey(privateKey);
+        string publicKeyFileName = keyFileName + ".pub";
+        Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
+        publicKey.DEREncode(publicKeySink);
+        publicKeySink.MessageEnd();
+
+        // set file permission
+        chmod(privateKeyFileName.c_str(), 0000400);
+        chmod(publicKeyFileName.c_str(), 0000444);
+        return;
+      }
+
+      case KeyType::EC: {
+        using namespace CryptoPP;
+
+        const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
+
+        CryptoPP::OID curveName;
+        switch (ecdsaParams.getKeySize()) {
+        case 256:
+          curveName = ASN1::secp256r1();
+          break;
+        case 384:
+          curveName = ASN1::secp384r1();
+          break;
+        default:
+          curveName = ASN1::secp256r1();
+          break;
+        }
+
+        AutoSeededRandomPool rng;
+
+        ECDSA<ECP, SHA256>::PrivateKey privateKey;
+        DL_GroupParameters_EC<ECP> cryptoParams(curveName);
+        cryptoParams.SetEncodeAsOID(true);
+        privateKey.Initialize(rng, cryptoParams);
+
+        ECDSA<ECP, SHA256>::PublicKey publicKey;
+        privateKey.MakePublicKey(publicKey);
+        publicKey.AccessGroupParameters().SetEncodeAsOID(true);
+
+        string privateKeyFileName = keyFileName + ".pri";
+        Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
+        privateKey.DEREncode(privateKeySink);
+        privateKeySink.MessageEnd();
+
+        string publicKeyFileName = keyFileName + ".pub";
+        Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
+        publicKey.Save(publicKeySink);
+        publicKeySink.MessageEnd();
+
+        // set file permission
+        chmod(privateKeyFileName.c_str(), 0000400);
+        chmod(publicKeyFileName.c_str(), 0000444);
+        return;
+      }
+
+      default:
+        BOOST_THROW_EXCEPTION(Error("Unsupported key type"));
+    }
+  }
+  catch (const KeyParams::Error& e) {
+    BOOST_THROW_EXCEPTION(Error(e.what()));
+  }
+  catch (const CryptoPP::Exception& e) {
+    BOOST_THROW_EXCEPTION(Error(e.what()));
+  }
+}
+
+void
+SecTpmFile::deleteKeyPairInTpm(const Name& keyName)
+{
+  boost::filesystem::path publicKeyPath(m_impl->transformName(keyName.toUri(), ".pub"));
+  boost::filesystem::path privateKeyPath(m_impl->transformName(keyName.toUri(), ".pri"));
+
+  if (boost::filesystem::exists(publicKeyPath))
+    boost::filesystem::remove(publicKeyPath);
+
+  if (boost::filesystem::exists(privateKeyPath))
+    boost::filesystem::remove(privateKeyPath);
+}
+
+shared_ptr<PublicKey>
+SecTpmFile::getPublicKeyFromTpm(const Name&  keyName)
+{
+  string keyURI = keyName.toUri();
+
+  if (!doesKeyExistInTpm(keyName, KeyClass::PUBLIC))
+    BOOST_THROW_EXCEPTION(Error("Public Key does not exist"));
+
+  ostringstream os;
+  try {
+    using namespace CryptoPP;
+    FileSource(m_impl->transformName(keyURI, ".pub").string().c_str(),
+               true,
+               new Base64Decoder(new FileSink(os)));
+  }
+  catch (const CryptoPP::Exception& e) {
+    BOOST_THROW_EXCEPTION(Error(e.what()));
+  }
+
+  return make_shared<PublicKey>(reinterpret_cast<const uint8_t*>(os.str().c_str()),
+                                os.str().size());
+}
+
+std::string
+SecTpmFile::getScheme()
+{
+  return SCHEME;
+}
+
+ConstBufferPtr
+SecTpmFile::exportPrivateKeyPkcs8FromTpm(const Name& keyName)
+{
+  OBufferStream privateKeyOs;
+  CryptoPP::FileSource(m_impl->transformName(keyName.toUri(), ".pri").string().c_str(), true,
+                       new CryptoPP::Base64Decoder(new CryptoPP::FileSink(privateKeyOs)));
+
+  return privateKeyOs.buf();
+}
+
+bool
+SecTpmFile::importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+  try {
+    using namespace CryptoPP;
+
+    string keyFileName = m_impl->maintainMapping(keyName.toUri());
+    keyFileName.append(".pri");
+    StringSource(buf, size,
+                 true,
+                 new Base64Encoder(new FileSink(keyFileName.c_str())));
+    return true;
+  }
+  catch (const CryptoPP::Exception& e) {
+    return false;
+  }
+}
+
+bool
+SecTpmFile::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+  try {
+    using namespace CryptoPP;
+
+    string keyFileName = m_impl->maintainMapping(keyName.toUri());
+    keyFileName.append(".pub");
+    StringSource(buf, size,
+                 true,
+                 new Base64Encoder(new FileSink(keyFileName.c_str())));
+    return true;
+  }
+  catch (const CryptoPP::Exception& e) {
+    return false;
+  }
+}
+
+Block
+SecTpmFile::signInTpm(const uint8_t* data, size_t dataLength,
+                      const Name& keyName, DigestAlgorithm digestAlgorithm)
+{
+  string keyURI = keyName.toUri();
+
+  if (!doesKeyExistInTpm(keyName, KeyClass::PRIVATE))
+    BOOST_THROW_EXCEPTION(Error("private key doesn't exist"));
+
+  try {
+    using namespace CryptoPP;
+    AutoSeededRandomPool rng;
+
+    // Read public key
+    shared_ptr<PublicKey> pubkeyPtr;
+    pubkeyPtr = getPublicKeyFromTpm(keyName);
+
+    switch (pubkeyPtr->getKeyType()) {
+      case KeyType::RSA: {
+        // Read private key
+        ByteQueue bytes;
+        FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(),
+                        true, new Base64Decoder);
+        file.TransferTo(bytes);
+        bytes.MessageEnd();
+        RSA::PrivateKey privateKey;
+        privateKey.Load(bytes);
+
+        // Sign message
+        switch (digestAlgorithm) {
+          case DigestAlgorithm::SHA256: {
+            RSASS<PKCS1v15, SHA256>::Signer signer(privateKey);
+
+            OBufferStream os;
+            StringSource(data, dataLength,
+                         true,
+                         new SignerFilter(rng, signer, new FileSink(os)));
+
+            return Block(tlv::SignatureValue, os.buf());
+          }
+
+          default:
+            BOOST_THROW_EXCEPTION(Error("Unsupported digest algorithm"));
+        }
+      }
+
+      case KeyType::EC: {
+        // Read private key
+        ByteQueue bytes;
+        FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(),
+                        true, new Base64Decoder);
+        file.TransferTo(bytes);
+        bytes.MessageEnd();
+
+        // Sign message
+        switch (digestAlgorithm) {
+          case DigestAlgorithm::SHA256: {
+            ECDSA<ECP, SHA256>::PrivateKey privateKey;
+            privateKey.Load(bytes);
+            ECDSA<ECP, SHA256>::Signer signer(privateKey);
+
+            OBufferStream os;
+            StringSource(data, dataLength,
+                         true,
+                         new SignerFilter(rng, signer, new FileSink(os)));
+
+            uint8_t buf[200];
+            size_t bufSize = DSAConvertSignatureFormat(buf, sizeof(buf), DSA_DER,
+                                                       os.buf()->buf(), os.buf()->size(),
+                                                       DSA_P1363);
+
+            shared_ptr<Buffer> sigBuffer = make_shared<Buffer>(buf, bufSize);
+
+            return Block(tlv::SignatureValue, sigBuffer);
+          }
+
+          default:
+            BOOST_THROW_EXCEPTION(Error("Unsupported digest algorithm"));
+        }
+      }
+
+      default:
+        BOOST_THROW_EXCEPTION(Error("Unsupported key type"));
+    }
+  }
+  catch (const CryptoPP::Exception& e) {
+    BOOST_THROW_EXCEPTION(Error(e.what()));
+  }
+}
+
+
+ConstBufferPtr
+SecTpmFile::decryptInTpm(const uint8_t* data, size_t dataLength,
+                         const Name& keyName, bool isSymmetric)
+{
+  BOOST_THROW_EXCEPTION(Error("SecTpmFile::decryptInTpm is not supported"));
+  // string keyURI = keyName.toUri();
+  // if (!isSymmetric)
+  //   {
+  //     if (!doesKeyExistInTpm(keyName, KeyClass::PRIVATE))
+  //       throw Error("private key doesn't exist");
+
+  //     try{
+  //       using namespace CryptoPP;
+  //       AutoSeededRandomPool rng;
+
+  //       //Read private key
+  //       ByteQueue bytes;
+  //       FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
+  //       file.TransferTo(bytes);
+  //       bytes.MessageEnd();
+  //       RSA::PrivateKey privateKey;
+  //       privateKey.Load(bytes);
+  //       RSAES_PKCS1v15_Decryptor decryptor(privateKey);
+
+  //       OBufferStream os;
+  //       StringSource(data, dataLength, true, new PK_DecryptorFilter(rng, decryptor, new FileSink(os)));
+
+  //       return os.buf();
+  //     }
+  //     catch (const CryptoPP::Exception& e){
+  //       throw Error(e.what());
+  //     }
+  //   }
+  // else
+  //   {
+  //     throw Error("Symmetric encryption is not implemented!");
+  //     // if (!doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC))
+  //     //     throw Error("symmetric key doesn't exist");
+
+  //     // try{
+  //     //     string keyBits;
+  //     //     string symKeyFileName = m_impl->transformName(keyURI, ".key");
+  //     //     FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
+
+  //     //     using CryptoPP::AES;
+  //     //     AutoSeededRandomPool rnd;
+  //     //     byte iv[AES::BLOCKSIZE];
+  //     //     rnd.GenerateBlock(iv, AES::BLOCKSIZE);
+
+  //     //     CFB_Mode<AES>::Decryption decryptor;
+  //     //     decryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
+
+  //     //     OBufferStream os;
+  //     //     StringSource(data, dataLength, true, new StreamTransformationFilter(decryptor,new FileSink(os)));
+  //     //     return os.buf();
+
+  //     // }
+  //     // catch (const CryptoPP::Exception& e){
+  //     //     throw Error(e.what());
+  //     // }
+  //   }
+}
+
+ConstBufferPtr
+SecTpmFile::encryptInTpm(const uint8_t* data, size_t dataLength,
+                         const Name& keyName, bool isSymmetric)
+{
+  BOOST_THROW_EXCEPTION(Error("SecTpmFile::encryptInTpm is not supported"));
+  // string keyURI = keyName.toUri();
+
+  // if (!isSymmetric)
+  //   {
+  //     if (!doesKeyExistInTpm(keyName, KeyClass::PUBLIC))
+  //       throw Error("public key doesn't exist");
+  //     try
+  //       {
+  //         using namespace CryptoPP;
+  //         AutoSeededRandomPool rng;
+
+  //         //Read private key
+  //         ByteQueue bytes;
+  //         FileSource file(m_impl->transformName(keyURI, ".pub").string().c_str(), true, new Base64Decoder);
+  //         file.TransferTo(bytes);
+  //         bytes.MessageEnd();
+  //         RSA::PublicKey publicKey;
+  //         publicKey.Load(bytes);
+
+  //         OBufferStream os;
+  //         RSAES_PKCS1v15_Encryptor encryptor(publicKey);
+
+  //         StringSource(data, dataLength, true, new PK_EncryptorFilter(rng, encryptor, new FileSink(os)));
+  //         return os.buf();
+  //       }
+  //     catch (const CryptoPP::Exception& e){
+  //       throw Error(e.what());
+  //     }
+  //   }
+  // else
+  //   {
+  //     throw Error("Symmetric encryption is not implemented!");
+  //     // if (!doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC))
+  //     //     throw Error("symmetric key doesn't exist");
+
+  //     // try{
+  //     //     string keyBits;
+  //     //     string symKeyFileName = m_impl->transformName(keyURI, ".key");
+  //     //     FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
+
+  //     //     using CryptoPP::AES;
+  //     //     AutoSeededRandomPool rnd;
+  //     //     byte iv[AES::BLOCKSIZE];
+  //     //     rnd.GenerateBlock(iv, AES::BLOCKSIZE);
+
+  //     //     CFB_Mode<AES>::Encryption encryptor;
+  //     //     encryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
+
+  //     //     OBufferStream os;
+  //     //     StringSource(data, dataLength, true, new StreamTransformationFilter(encryptor, new FileSink(os)));
+  //     //     return os.buf();
+  //     // } catch (const CryptoPP::Exception& e){
+  //     //     throw Error(e.what());
+  //     // }
+  //   }
+}
+
+void
+SecTpmFile::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
+{
+  BOOST_THROW_EXCEPTION(Error("SecTpmFile::generateSymmetricKeyInTpm is not supported"));
+  // string keyURI = keyName.toUri();
+
+  // if (doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC))
+  //   throw Error("symmetric key exists");
+
+  // string keyFileName = m_impl->maintainMapping(keyURI);
+  // string symKeyFileName = keyFileName + ".key";
+
+  // try{
+  //   switch (keyType){
+  //   case KeyType::AES:
+  //     {
+  //       using namespace CryptoPP;
+  //       AutoSeededRandomPool rng;
+
+  //       SecByteBlock key(0x00, keySize);
+  //       rng.GenerateBlock(key, keySize);
+
+  //       StringSource(key, key.size(), true, new HexEncoder(new FileSink(symKeyFileName.c_str())));
+
+  //       chmod(symKeyFileName.c_str(), 0000400);
+  //       return;
+  //     }
+  //   default:
+  //     throw Error("Unsupported symmetric key type!");
+  //   }
+  // } catch (const CryptoPP::Exception& e){
+  //   throw Error(e.what());
+  // }
+}
+
+bool
+SecTpmFile::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
+{
+  string keyURI = keyName.toUri();
+  if (keyClass == KeyClass::PUBLIC) {
+    return boost::filesystem::exists(m_impl->transformName(keyURI, ".pub"));
+  }
+  if (keyClass == KeyClass::PRIVATE) {
+    return boost::filesystem::exists(m_impl->transformName(keyURI, ".pri"));
+  }
+  if (keyClass == KeyClass::SYMMETRIC) {
+    return boost::filesystem::exists(m_impl->transformName(keyURI, ".key"));
+  }
+  return false;
+}
+
+bool
+SecTpmFile::generateRandomBlock(uint8_t* res, size_t size)
+{
+  try {
+    CryptoPP::AutoSeededRandomPool rng;
+    rng.GenerateBlock(res, size);
+    return true;
+  }
+  catch (const CryptoPP::Exception& e) {
+    return false;
+  }
+}
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v1/sec-tpm-file.hpp b/src/security/v1/sec-tpm-file.hpp
new file mode 100644
index 0000000..aaaa4ce
--- /dev/null
+++ b/src/security/v1/sec-tpm-file.hpp
@@ -0,0 +1,152 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Xingyu Ma <http://www.linkedin.com/pub/xingyu-ma/1a/384/5a8>
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
+ */
+
+#ifndef NDN_SECURITY_V1_SEC_TPM_FILE_HPP
+#define NDN_SECURITY_V1_SEC_TPM_FILE_HPP
+
+#include "../../common.hpp"
+
+#include "sec-tpm.hpp"
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+class SecTpmFile : public SecTpm
+{
+public:
+  class Error : public SecTpm::Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : SecTpm::Error(what)
+    {
+    }
+  };
+
+  explicit
+  SecTpmFile(const std::string& dir = "");
+
+  virtual
+  ~SecTpmFile();
+
+  virtual void
+  setTpmPassword(const uint8_t* password, size_t passwordLength)
+  {
+  }
+
+  virtual void
+  resetTpmPassword()
+  {
+  }
+
+  virtual void
+  setInTerminal(bool inTerminal)
+  {
+    m_inTerminal = inTerminal;
+  }
+
+  virtual bool
+  getInTerminal() const
+  {
+    return m_inTerminal;
+  }
+
+  virtual bool
+  isLocked()
+  {
+    return false;
+  }
+
+  virtual bool
+  unlockTpm(const char* password, size_t passwordLength, bool usePassword)
+  {
+    return !isLocked();
+  }
+
+  virtual void
+  generateKeyPairInTpm(const Name& keyName, const KeyParams& params);
+
+  virtual void
+  deleteKeyPairInTpm(const Name& keyName);
+
+  virtual shared_ptr<PublicKey>
+  getPublicKeyFromTpm(const Name&  keyName);
+
+  virtual Block
+  signInTpm(const uint8_t* data, size_t dataLength,
+            const Name& keyName, DigestAlgorithm digestAlgorithm);
+
+  virtual ConstBufferPtr
+  decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric);
+
+  virtual ConstBufferPtr
+  encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric);
+
+  virtual void
+  generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params);
+
+  virtual bool
+  doesKeyExistInTpm(const Name& keyName, KeyClass keyClass);
+
+  virtual bool
+  generateRandomBlock(uint8_t* res, size_t size);
+
+  virtual void
+  addAppToAcl(const Name& keyName, KeyClass keyClass, const std::string& appPath, AclType acl)
+  {
+  }
+
+protected:
+  ////////////////////////////////
+  // From TrustedPlatformModule //
+  ////////////////////////////////
+  virtual std::string
+  getScheme();
+
+  virtual ConstBufferPtr
+  exportPrivateKeyPkcs8FromTpm(const Name& keyName);
+
+  virtual bool
+  importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size);
+
+  virtual bool
+  importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size);
+
+public:
+  static const std::string SCHEME;
+
+private:
+  class Impl;
+  unique_ptr<Impl> m_impl;
+  bool m_inTerminal;
+};
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V1_SEC_TPM_FILE_HPP
diff --git a/src/security/v1/sec-tpm-osx.cpp b/src/security/v1/sec-tpm-osx.cpp
new file mode 100644
index 0000000..f3c3029
--- /dev/null
+++ b/src/security/v1/sec-tpm-osx.cpp
@@ -0,0 +1,1145 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ */
+
+#include "sec-tpm-osx.hpp"
+#include "public-key.hpp"
+
+#include "../../encoding/oid.hpp"
+#include "../../encoding/buffer-stream.hpp"
+#include "cryptopp.hpp"
+
+#include <pwd.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+#include <Security/SecRandom.h>
+#include <CoreServices/CoreServices.h>
+
+#include <Security/SecDigestTransform.h>
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+using std::string;
+
+const std::string SecTpmOsx::SCHEME("tpm-osxkeychain");
+
+/**
+ * @brief Helper class to wrap CoreFoundation object pointers
+ *
+ * The class is similar in spirit to shared_ptr, but uses CoreFoundation
+ * mechanisms to retain/release object.
+ *
+ * Original implementation by Christopher Hunt and it was borrowed from
+ * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html
+ */
+template<class T>
+class CFReleaser
+{
+public:
+  //////////////////////////////
+  // Construction/destruction //
+
+  CFReleaser()
+    : m_typeRef(nullptr)
+  {
+  }
+
+  CFReleaser(const T& typeRef)
+    : m_typeRef(typeRef)
+  {
+  }
+
+  CFReleaser(const CFReleaser& inReleaser)
+    : m_typeRef(nullptr)
+  {
+    retain(inReleaser.m_typeRef);
+  }
+
+  CFReleaser&
+  operator=(const T& typeRef)
+  {
+    if (typeRef != m_typeRef) {
+      release();
+      m_typeRef = typeRef;
+    }
+    return *this;
+  }
+
+  CFReleaser&
+  operator=(const CFReleaser& inReleaser)
+  {
+    retain(inReleaser.m_typeRef);
+    return *this;
+  }
+
+  ~CFReleaser()
+  {
+    release();
+  }
+
+  ////////////
+  // Access //
+
+  // operator const T&() const
+  // {
+  //   return m_typeRef;
+  // }
+
+  // operator T&()
+  // {
+  //   return m_typeRef;
+  // }
+
+  const T&
+  get() const
+  {
+    return m_typeRef;
+  }
+
+  T&
+  get()
+  {
+    return m_typeRef;
+  }
+
+  ///////////////////
+  // Miscellaneous //
+
+  void
+  retain(const T& typeRef)
+  {
+    if (typeRef != nullptr) {
+      CFRetain(typeRef);
+    }
+    release();
+    m_typeRef = typeRef;
+  }
+
+  void
+  release()
+  {
+    if (m_typeRef != nullptr) {
+      CFRelease(m_typeRef);
+      m_typeRef = nullptr;
+    }
+  };
+
+  bool
+  operator==(std::nullptr_t)
+  {
+    return get() == nullptr;
+  }
+
+  bool
+  operator!=(std::nullptr_t)
+  {
+    return get() != nullptr;
+  }
+
+private:
+  T m_typeRef;
+};
+
+
+class SecTpmOsx::Impl
+{
+public:
+  Impl()
+    : m_passwordSet(false)
+    , m_inTerminal(false)
+  {
+  }
+
+  /**
+   * @brief Convert NDN name of a key to internal name of the key.
+   *
+   * @return the internal key name
+   */
+  std::string
+  toInternalKeyName(const Name& keyName, KeyClass keyClass);
+
+  /**
+   * @brief Get key.
+   *
+   * @returns pointer to the key
+   */
+  CFReleaser<SecKeychainItemRef>
+  getKey(const Name& keyName, KeyClass keyClass);
+
+  /**
+   * @brief Convert keyType to MAC OS symmetric key key type
+   *
+   * @returns MAC OS key type
+   */
+  CFTypeRef
+  getSymKeyType(KeyType keyType);
+
+  /**
+   * @brief Convert keyType to MAC OS asymmetirc key type
+   *
+   * @returns MAC OS key type
+   */
+  CFTypeRef
+  getAsymKeyType(KeyType keyType);
+
+  /**
+   * @brief Convert keyClass to MAC OS key class
+   *
+   * @returns MAC OS key class
+   */
+  CFTypeRef
+  getKeyClass(KeyClass keyClass);
+
+  /**
+   * @brief Convert digestAlgo to MAC OS algorithm id
+   *
+   * @returns MAC OS algorithm id
+   */
+  CFStringRef
+  getDigestAlgorithm(DigestAlgorithm digestAlgo);
+
+  /**
+   * @brief Get the digest size of the corresponding algorithm
+   *
+   * @return digest size
+   */
+  long
+  getDigestSize(DigestAlgorithm digestAlgo);
+
+  ///////////////////////////////////////////////
+  // everything here is public, including data //
+  ///////////////////////////////////////////////
+public:
+  SecKeychainRef m_keyChainRef;
+  bool m_passwordSet;
+  string m_password;
+  bool m_inTerminal;
+};
+
+SecTpmOsx::SecTpmOsx(const std::string& location)
+  : SecTpm(location)
+  , m_impl(new Impl)
+{
+  // TODO: add location support
+  if (m_impl->m_inTerminal)
+    SecKeychainSetUserInteractionAllowed(false);
+  else
+    SecKeychainSetUserInteractionAllowed(true);
+
+  OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
+
+  if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
+    BOOST_THROW_EXCEPTION(Error("No default keychain, please create one first"));
+}
+
+SecTpmOsx::~SecTpmOsx()
+{
+}
+
+void
+SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
+{
+  m_impl->m_passwordSet = true;
+  std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
+  m_impl->m_password.clear();
+  m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
+}
+
+void
+SecTpmOsx::resetTpmPassword()
+{
+  m_impl->m_passwordSet = false;
+  std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
+  m_impl->m_password.clear();
+}
+
+void
+SecTpmOsx::setInTerminal(bool inTerminal)
+{
+  m_impl->m_inTerminal = inTerminal;
+  if (inTerminal)
+    SecKeychainSetUserInteractionAllowed(false);
+  else
+    SecKeychainSetUserInteractionAllowed(true);
+}
+
+bool
+SecTpmOsx::getInTerminal() const
+{
+  return m_impl->m_inTerminal;
+}
+
+bool
+SecTpmOsx::isLocked()
+{
+  SecKeychainStatus keychainStatus;
+
+  OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
+  if (res != errSecSuccess)
+    return true;
+  else
+    return ((kSecUnlockStateStatus & keychainStatus) == 0);
+}
+
+bool
+SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
+{
+  OSStatus res;
+
+  // If the default key chain is already unlocked, return immediately.
+  if (!isLocked())
+    return true;
+
+  // If the default key chain is locked, unlock the key chain.
+  if (usePassword) {
+    // Use the supplied password.
+    res = SecKeychainUnlock(m_impl->m_keyChainRef,
+                            passwordLength,
+                            password,
+                            true);
+  }
+  else if (m_impl->m_passwordSet) {
+    // If no password supplied, then use the configured password if exists.
+    SecKeychainUnlock(m_impl->m_keyChainRef,
+                      m_impl->m_password.size(),
+                      m_impl->m_password.c_str(),
+                      true);
+  }
+#ifdef NDN_CXX_HAVE_GETPASS
+  else if (m_impl->m_inTerminal) {
+    // If no configured password, get password from terminal if inTerminal set.
+    bool isLocked = true;
+    const char* fmt = "Password to unlock the default keychain: ";
+    int count = 0;
+
+    while (isLocked) {
+      if (count > 2)
+        break;
+
+      char* getPassword = nullptr;
+      getPassword = getpass(fmt);
+      count++;
+
+      if (!getPassword)
+        continue;
+
+      res = SecKeychainUnlock(m_impl->m_keyChainRef,
+                              strlen(getPassword),
+                              getPassword,
+                              true);
+
+      memset(getPassword, 0, strlen(getPassword));
+
+      if (res == errSecSuccess)
+        break;
+    }
+  }
+#endif // NDN_CXX_HAVE_GETPASS
+  else {
+    // If inTerminal is not set, get the password from GUI.
+    SecKeychainUnlock(m_impl->m_keyChainRef, 0, nullptr, false);
+  }
+
+  return !isLocked();
+}
+
+void
+SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName,
+                                        const KeyParams& params,
+                                        bool needRetry)
+{
+
+  if (doesKeyExistInTpm(keyName, KeyClass::PUBLIC)) {
+    BOOST_THROW_EXCEPTION(Error("keyName already exists"));
+  }
+
+  string keyNameUri = m_impl->toInternalKeyName(keyName, KeyClass::PUBLIC);
+
+  CFReleaser<CFStringRef> keyLabel =
+    CFStringCreateWithCString(0,
+                              keyNameUri.c_str(),
+                              kCFStringEncodingUTF8);
+
+  CFReleaser<CFMutableDictionaryRef> attrDict =
+    CFDictionaryCreateMutable(0,
+                              3,
+                              &kCFTypeDictionaryKeyCallBacks,
+                              0);
+
+  KeyType keyType = params.getKeyType();
+  uint32_t keySize = 0;
+  switch (keyType) {
+    case KeyType::RSA: {
+      const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
+      keySize = rsaParams.getKeySize();
+      break;
+    }
+
+    case KeyType::EC: {
+      const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
+      keySize = ecdsaParams.getKeySize();
+      break;
+    }
+
+    default:
+      BOOST_THROW_EXCEPTION(Error("Fail to create a key pair: Unsupported key type"));
+  }
+
+  CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
+
+  CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
+  CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
+  CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
+
+  CFReleaser<SecKeyRef> publicKey, privateKey;
+  // C-style cast is used as per Apple convention
+  OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
+                                    &publicKey.get(), &privateKey.get());
+
+  if (res == errSecSuccess) {
+    return;
+  }
+
+  if (res == errSecAuthFailed && !needRetry) {
+    if (unlockTpm(nullptr, 0, false))
+      generateKeyPairInTpmInternal(keyName, params, true);
+    else
+      BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("Fail to create a key pair"));
+  }
+}
+
+void
+SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
+{
+  CFReleaser<CFStringRef> keyLabel =
+    CFStringCreateWithCString(0,
+                              keyName.toUri().c_str(),
+                              kCFStringEncodingUTF8);
+
+  CFReleaser<CFMutableDictionaryRef> searchDict =
+    CFDictionaryCreateMutable(0, 5,
+                              &kCFTypeDictionaryKeyCallBacks,
+                              &kCFTypeDictionaryValueCallBacks);
+
+  CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
+  CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
+  CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
+  OSStatus res = SecItemDelete(searchDict.get());
+
+  if (res == errSecSuccess)
+    return;
+
+  if (res == errSecAuthFailed && !needRetry) {
+    if (unlockTpm(nullptr, 0, false))
+      deleteKeyPairInTpmInternal(keyName, true);
+  }
+}
+
+void
+SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
+{
+  BOOST_THROW_EXCEPTION(Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported"));
+  // if (doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC))
+  //   throw Error("keyName has existed!");
+
+  // string keyNameUri =  m_impl->toInternalKeyName(keyName, KeyClass::SYMMETRIC);
+
+  // CFReleaser<CFMutableDictionaryRef> attrDict =
+  //   CFDictionaryCreateMutable(kCFAllocatorDefault,
+  //                             0,
+  //                             &kCFTypeDictionaryKeyCallBacks,
+  //                             &kCFTypeDictionaryValueCallBacks);
+
+  // CFReleaser<CFStringRef> keyLabel =
+  //   CFStringCreateWithCString(0,
+  //                             keyNameUri.c_str(),
+  //                             kCFStringEncodingUTF8);
+
+  // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
+
+  // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
+  // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
+  // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
+  // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
+
+  // CFErrorRef error = 0;
+
+  // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
+
+  // if (error)
+  //   throw Error("Fail to create a symmetric key");
+}
+
+shared_ptr<PublicKey>
+SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
+{
+  CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KeyClass::PUBLIC);
+  if (publicKey == nullptr) {
+    BOOST_THROW_EXCEPTION(Error("Requested public key [" + keyName.toUri() + "] does not exist "
+                                "in OSX Keychain"));
+  }
+
+  CFReleaser<CFDataRef> exportedKey;
+  OSStatus res = SecItemExport(publicKey.get(),
+                               kSecFormatOpenSSL,
+                               0,
+                               nullptr,
+                               &exportedKey.get());
+  if (res != errSecSuccess) {
+    BOOST_THROW_EXCEPTION(Error("Cannot export requested public key from OSX Keychain"));
+  }
+
+  shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
+                                                             CFDataGetLength(exportedKey.get()));
+  return key;
+}
+
+std::string
+SecTpmOsx::getScheme()
+{
+  return SCHEME;
+}
+
+ConstBufferPtr
+SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
+{
+  using namespace CryptoPP;
+
+  CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KeyClass::PRIVATE);
+  if (privateKey == nullptr) {
+    /// @todo Can this happen because of keychain is locked?
+    BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
+                                "in OSX Keychain"));
+  }
+
+  shared_ptr<PublicKey> publicKey = getPublicKeyFromTpm(keyName);
+
+  CFReleaser<CFDataRef> exportedKey;
+  OSStatus res = SecItemExport(privateKey.get(),
+                               kSecFormatOpenSSL,
+                               0,
+                               nullptr,
+                               &exportedKey.get());
+
+  if (res != errSecSuccess) {
+    if (res == errSecAuthFailed && !needRetry) {
+      if (unlockTpm(nullptr, 0, false))
+        return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
+      else
+        return nullptr;
+    }
+    else
+      return nullptr;
+  }
+
+  uint32_t version = 0;
+  Oid algorithm;
+  bool hasParameters = false;
+  Oid algorithmParameter;
+  switch (publicKey->getKeyType()) {
+    case KeyType::RSA: {
+      algorithm = oid::RSA; // "RSA encryption"
+      hasParameters = false;
+      break;
+    }
+
+    case KeyType::EC: {
+      // "ECDSA encryption"
+      StringSource src(publicKey->get().buf(), publicKey->get().size(), true);
+      BERSequenceDecoder subjectPublicKeyInfo(src);
+      {
+        BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
+        {
+          algorithm.decode(algorithmInfo);
+          algorithmParameter.decode(algorithmInfo);
+        }
+      }
+      hasParameters = true;
+      break;
+    }
+
+    default:
+      BOOST_THROW_EXCEPTION(Error("Unsupported key type" +
+                                  boost::lexical_cast<std::string>(publicKey->getKeyType())));
+  }
+
+  OBufferStream pkcs8Os;
+  FileSink sink(pkcs8Os);
+
+  SecByteBlock rawKeyBits;
+  // PrivateKeyInfo ::= SEQUENCE {
+  //   version              INTEGER,
+  //   privateKeyAlgorithm  SEQUENCE,
+  //   privateKey           OCTECT STRING}
+  DERSequenceEncoder privateKeyInfo(sink);
+  {
+    DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
+    DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
+    {
+      algorithm.encode(privateKeyAlgorithm);
+      if (hasParameters)
+        algorithmParameter.encode(privateKeyAlgorithm);
+      else
+        DEREncodeNull(privateKeyAlgorithm);
+    }
+    privateKeyAlgorithm.MessageEnd();
+    DEREncodeOctetString(privateKeyInfo,
+                         CFDataGetBytePtr(exportedKey.get()),
+                         CFDataGetLength(exportedKey.get()));
+  }
+  privateKeyInfo.MessageEnd();
+
+  return pkcs8Os.buf();
+}
+
+#ifdef __GNUC__
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic push
+#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif // __GNUC__
+
+bool
+SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
+                                                const uint8_t* buf, size_t size,
+                                                bool needRetry)
+{
+  using namespace CryptoPP;
+
+  StringSource privateKeySource(buf, size, true);
+  SecByteBlock rawKeyBits;
+  // PrivateKeyInfo ::= SEQUENCE {
+  //   INTEGER,
+  //   SEQUENCE,
+  //   OCTECT STRING}
+  BERSequenceDecoder privateKeyInfo(privateKeySource);
+  {
+    uint32_t versionNum;
+    BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
+    BERSequenceDecoder sequenceDecoder(privateKeyInfo);
+    {
+      Oid keyTypeOid;
+      keyTypeOid.decode(sequenceDecoder);
+
+      if (keyTypeOid == oid::RSA)
+        BERDecodeNull(sequenceDecoder);
+      else if (keyTypeOid == oid::ECDSA) {
+        Oid parameterOid;
+        parameterOid.decode(sequenceDecoder);
+      }
+      else
+        return false; // Unsupported key type;
+    }
+    BERDecodeOctetString(privateKeyInfo, rawKeyBits);
+  }
+  privateKeyInfo.MessageEnd();
+
+  CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
+                                                                  rawKeyBits.BytePtr(),
+                                                                  rawKeyBits.size(),
+                                                                  kCFAllocatorNull);
+
+  SecExternalFormat externalFormat = kSecFormatOpenSSL;
+  SecExternalItemType externalType = kSecItemTypePrivateKey;
+  SecKeyImportExportParameters keyParams;
+  memset(&keyParams, 0, sizeof(keyParams));
+  keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+  keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
+  CFReleaser<SecAccessRef> access;
+  CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
+                                                               keyName.toUri().c_str(),
+                                                               kCFStringEncodingUTF8);
+  SecAccessCreate(keyLabel.get(), 0, &access.get());
+  keyParams.accessRef = access.get();
+  CFReleaser<CFArrayRef> outItems;
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif // __clang__
+
+  OSStatus res = SecKeychainItemImport(importedKey.get(),
+                                       0,
+                                       &externalFormat,
+                                       &externalType,
+                                       0,
+                                       &keyParams,
+                                       m_impl->m_keyChainRef,
+                                       &outItems.get());
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif // __clang__
+
+  if (res != errSecSuccess) {
+    if (res == errSecAuthFailed && !needRetry) {
+      if (unlockTpm(nullptr, 0, false))
+        return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
+      else
+        return false;
+    }
+    else
+      return false;
+  }
+
+  // C-style cast is used as per Apple convention
+  SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
+  SecKeychainAttribute attrs[1]; // maximum number of attributes
+  SecKeychainAttributeList attrList = {0, attrs};
+  string keyUri = keyName.toUri();
+  {
+    attrs[attrList.count].tag = kSecKeyPrintName;
+    attrs[attrList.count].length = keyUri.size();
+    attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
+    attrList.count++;
+  }
+
+  res = SecKeychainItemModifyAttributesAndData(privateKey,
+                                               &attrList,
+                                               0,
+                                               nullptr);
+
+  if (res != errSecSuccess) {
+    return false;
+  }
+
+  return true;
+}
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic pop
+#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+
+bool
+SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+  CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
+                                                                  buf,
+                                                                  size,
+                                                                  kCFAllocatorNull);
+
+  SecExternalFormat externalFormat = kSecFormatOpenSSL;
+  SecExternalItemType externalType = kSecItemTypePublicKey;
+  CFReleaser<CFArrayRef> outItems;
+
+  OSStatus res = SecItemImport(importedKey.get(),
+                               0,
+                               &externalFormat,
+                               &externalType,
+                               0,
+                               0,
+                               m_impl->m_keyChainRef,
+                               &outItems.get());
+
+  if (res != errSecSuccess)
+    return false;
+
+  // C-style cast is used as per Apple convention
+  SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
+  SecKeychainAttribute attrs[1]; // maximum number of attributes
+  SecKeychainAttributeList attrList = { 0, attrs };
+  string keyUri = keyName.toUri();
+  {
+    attrs[attrList.count].tag = kSecKeyPrintName;
+    attrs[attrList.count].length = keyUri.size();
+    attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
+    attrList.count++;
+  }
+
+  res = SecKeychainItemModifyAttributesAndData(publicKey,
+                                               &attrList,
+                                               0,
+                                               0);
+
+  if (res != errSecSuccess)
+    return false;
+
+  return true;
+}
+
+Block
+SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
+                             const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
+{
+  CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
+                                                              data,
+                                                              dataLength,
+                                                              kCFAllocatorNull);
+
+  CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KeyClass::PRIVATE);
+  if (privateKey == nullptr) {
+    BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
+                                "in OSX Keychain"));
+  }
+
+  CFReleaser<CFErrorRef> error;
+  // C-style cast is used as per Apple convention
+  CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
+                                                              &error.get());
+  if (error != nullptr)
+    BOOST_THROW_EXCEPTION(Error("Fail to create signer"));
+
+  // Set input
+  SecTransformSetAttribute(signer.get(),
+                           kSecTransformInputAttributeName,
+                           dataRef.get(),
+                           &error.get());
+  if (error != nullptr)
+    BOOST_THROW_EXCEPTION(Error("Fail to configure input of signer"));
+
+  // Enable use of padding
+  SecTransformSetAttribute(signer.get(),
+                           kSecPaddingKey,
+                           kSecPaddingPKCS1Key,
+                           &error.get());
+  if (error != nullptr)
+    BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
+
+  // Set padding type
+  SecTransformSetAttribute(signer.get(),
+                           kSecDigestTypeAttribute,
+                           m_impl->getDigestAlgorithm(digestAlgorithm),
+                           &error.get());
+  if (error != nullptr)
+    BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
+
+  // Set padding attribute
+  long digestSize = m_impl->getDigestSize(digestAlgorithm);
+  CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
+  SecTransformSetAttribute(signer.get(),
+                           kSecDigestLengthAttribute,
+                           cfDigestSize.get(),
+                           &error.get());
+  if (error != nullptr)
+    BOOST_THROW_EXCEPTION(Error("Fail to configure digest size of signer"));
+
+  // Actually sign
+  // C-style cast is used as per Apple convention
+  CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
+  if (error != nullptr) {
+    if (!needRetry) {
+      if (unlockTpm(nullptr, 0, false))
+        return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
+      else
+        BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
+    }
+    else {
+      CFShow(error.get());
+      BOOST_THROW_EXCEPTION(Error("Fail to sign data"));
+    }
+  }
+
+  if (signature == nullptr)
+    BOOST_THROW_EXCEPTION(Error("Signature is NULL!\n"));
+
+  return Block(tlv::SignatureValue,
+               make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
+                                   CFDataGetLength(signature.get())));
+}
+
+ConstBufferPtr
+SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
+{
+  BOOST_THROW_EXCEPTION(Error("SecTpmOsx::decryptInTpm is not supported"));
+
+  // KeyClass keyClass;
+  // if (sym)
+  //   keyClass = KeyClass::SYMMETRIC;
+  // else
+  //   keyClass = KeyClass::PRIVATE;
+
+  // CFDataRef dataRef = CFDataCreate(0,
+  //                                  reinterpret_cast<const unsigned char*>(data),
+  //                                  dataLength
+  //                                  );
+
+  // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
+  // if (decryptKey == nullptr)
+  //   {
+  //     /// @todo Can this happen because of keychain is locked?
+  //     throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
+  //   }
+
+  // CFErrorRef error;
+  // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
+  // if (error) throw Error("Fail to create decrypt");
+
+  // Boolean set_res = SecTransformSetAttribute(decrypt,
+  //                                            kSecTransformInputAttributeName,
+  //                                            dataRef,
+  //                                            &error);
+  // if (error) throw Error("Fail to configure decrypt");
+
+  // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
+  // if (error)
+  //   {
+  //     CFShow(error);
+  //     throw Error("Fail to decrypt data");
+  //   }
+  // if (!output) throw Error("Output is NULL!\n");
+
+  // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
+}
+
+void
+SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
+{
+  if (keyClass == KeyClass::PRIVATE && acl == AclType::PRIVATE) {
+    CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
+    if (privateKey == nullptr) {
+      BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
+                                  "in OSX Keychain"));
+    }
+
+    CFReleaser<SecAccessRef> accRef;
+    SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
+
+    CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
+                                                                  kSecACLAuthorizationSign);
+
+    // C-style cast is used as per Apple convention
+    SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
+
+    CFReleaser<CFArrayRef> appList;
+    CFReleaser<CFStringRef> description;
+    SecKeychainPromptSelector promptSelector;
+    SecACLCopyContents(aclRef,
+                       &appList.get(),
+                       &description.get(),
+                       &promptSelector);
+
+    CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
+                                                                        0,
+                                                                        appList.get());
+
+    CFReleaser<SecTrustedApplicationRef> trustedApp;
+    SecTrustedApplicationCreateFromPath(appPath.c_str(),
+                                        &trustedApp.get());
+
+    CFArrayAppendValue(newAppList.get(), trustedApp.get());
+
+    SecACLSetContents(aclRef,
+                      newAppList.get(),
+                      description.get(),
+                      promptSelector);
+
+    SecKeychainItemSetAccess(privateKey.get(), accRef.get());
+  }
+}
+
+ConstBufferPtr
+SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
+{
+  BOOST_THROW_EXCEPTION(Error("SecTpmOsx::encryptInTpm is not supported"));
+
+  // KeyClass keyClass;
+  // if (sym)
+  //   keyClass = KeyClass::SYMMETRIC;
+  // else
+  //   keyClass = KeyClass::PUBLIC;
+
+  // CFDataRef dataRef = CFDataCreate(0,
+  //                                  reinterpret_cast<const unsigned char*>(data),
+  //                                  dataLength
+  //                                  );
+
+  // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
+  // if (encryptKey == nullptr)
+  //   {
+  //     throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
+  //   }
+
+  // CFErrorRef error;
+  // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
+  // if (error) throw Error("Fail to create encrypt");
+
+  // Boolean set_res = SecTransformSetAttribute(encrypt,
+  //                                            kSecTransformInputAttributeName,
+  //                                            dataRef,
+  //                                            &error);
+  // if (error) throw Error("Fail to configure encrypt");
+
+  // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
+  // if (error) throw Error("Fail to encrypt data");
+
+  // if (!output) throw Error("Output is NULL!\n");
+
+  // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
+}
+
+bool
+SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
+{
+  string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
+
+  CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
+                                                               keyNameUri.c_str(),
+                                                               kCFStringEncodingUTF8);
+
+  CFReleaser<CFMutableDictionaryRef> attrDict =
+    CFDictionaryCreateMutable(0,
+                              4,
+                              &kCFTypeDictionaryKeyCallBacks,
+                              0);
+
+  CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
+  // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
+  CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
+  CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
+
+  CFReleaser<SecKeychainItemRef> itemRef;
+  // C-style cast is used as per Apple convention
+  OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
+
+  if (res == errSecSuccess)
+    return true;
+  else
+    return false;
+
+}
+
+bool
+SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
+{
+  return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
+}
+
+////////////////////////////////
+// OSXPrivateKeyStorage::Impl //
+////////////////////////////////
+
+CFReleaser<SecKeychainItemRef>
+SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
+{
+  string keyNameUri = toInternalKeyName(keyName, keyClass);
+
+  CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
+                                                               keyNameUri.c_str(),
+                                                               kCFStringEncodingUTF8);
+
+  CFReleaser<CFMutableDictionaryRef> attrDict =
+    CFDictionaryCreateMutable(0,
+                              5,
+                              &kCFTypeDictionaryKeyCallBacks,
+                              0);
+
+  CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
+  CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
+  CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
+  CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
+
+  CFReleaser<SecKeychainItemRef> keyItem;
+  // C-style cast is used as per Apple convention
+  OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
+
+  if (res != errSecSuccess)
+    return 0;
+  else
+    return keyItem;
+}
+
+string
+SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
+{
+  string keyUri = keyName.toUri();
+
+  if (KeyClass::SYMMETRIC == keyClass)
+    return keyUri + "/symmetric";
+  else
+    return keyUri;
+}
+
+CFTypeRef
+SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
+{
+  switch (keyType) {
+  case KeyType::RSA:
+    return kSecAttrKeyTypeRSA;
+  case KeyType::EC:
+    return kSecAttrKeyTypeECDSA;
+  default:
+    return 0;
+  }
+}
+
+CFTypeRef
+SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
+{
+  switch (keyType) {
+  case KeyType::AES:
+    return kSecAttrKeyTypeAES;
+  default:
+    return 0;
+  }
+}
+
+CFTypeRef
+SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
+{
+  switch (keyClass) {
+  case KeyClass::PRIVATE:
+    return kSecAttrKeyClassPrivate;
+  case KeyClass::PUBLIC:
+    return kSecAttrKeyClassPublic;
+  case KeyClass::SYMMETRIC:
+    return kSecAttrKeyClassSymmetric;
+  default:
+    return 0;
+  }
+}
+
+CFStringRef
+SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
+{
+  switch (digestAlgo) {
+  case DigestAlgorithm::SHA256:
+    return kSecDigestSHA2;
+  default:
+    return 0;
+  }
+}
+
+long
+SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
+{
+  switch (digestAlgo) {
+  case DigestAlgorithm::SHA256:
+    return 256;
+  default:
+    return -1;
+  }
+}
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v1/sec-tpm-osx.hpp b/src/security/v1/sec-tpm-osx.hpp
new file mode 100644
index 0000000..7641514
--- /dev/null
+++ b/src/security/v1/sec-tpm-osx.hpp
@@ -0,0 +1,169 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ */
+
+#ifndef NDN_SECURITY_V1_SEC_TPM_OSX_HPP
+#define NDN_SECURITY_V1_SEC_TPM_OSX_HPP
+
+#include "../../common.hpp"
+
+#ifndef NDN_CXX_HAVE_OSX_SECURITY
+#error "This files should not be compiled ..."
+#endif
+
+#include "sec-tpm.hpp"
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+class SecTpmOsx : public SecTpm
+{
+public:
+  class Error : public SecTpm::Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : SecTpm::Error(what)
+    {
+    }
+  };
+
+  explicit
+  SecTpmOsx(const std::string& location = "");
+
+  virtual
+  ~SecTpmOsx();
+
+  // Following methods are inherited from SecTpm
+  virtual void
+  setTpmPassword(const uint8_t* password, size_t passwordLength);
+
+  virtual void
+  resetTpmPassword();
+
+  virtual void
+  setInTerminal(bool inTerminal);
+
+  virtual bool
+  getInTerminal() const;
+
+  virtual bool
+  isLocked();
+
+  virtual bool
+  unlockTpm(const char* password, size_t passwordLength, bool usePassword);
+
+  virtual void
+  generateKeyPairInTpm(const Name& keyName, const KeyParams& params)
+  {
+    generateKeyPairInTpmInternal(keyName, params, false);
+  }
+
+  virtual void
+  deleteKeyPairInTpm(const Name& keyName)
+  {
+    deleteKeyPairInTpmInternal(keyName, false);
+  }
+
+  virtual shared_ptr<v1::PublicKey>
+  getPublicKeyFromTpm(const Name& keyName);
+
+  virtual Block
+  signInTpm(const uint8_t* data, size_t dataLength,
+            const Name& keyName, DigestAlgorithm digestAlgorithm)
+  {
+    return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, false);
+  }
+
+  virtual ConstBufferPtr
+  decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric);
+
+  virtual ConstBufferPtr
+  encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric);
+
+  virtual void
+  generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params);
+
+  virtual bool
+  doesKeyExistInTpm(const Name& keyName, KeyClass keyClass);
+
+  virtual bool
+  generateRandomBlock(uint8_t* res, size_t size);
+
+  virtual void
+  addAppToAcl(const Name& keyName, KeyClass keyClass, const std::string& appPath, AclType acl);
+
+protected:
+  // Following methods are inherited from SecTpm
+  virtual std::string
+  getScheme();
+
+  virtual ConstBufferPtr
+  exportPrivateKeyPkcs8FromTpm(const Name& keyName)
+  {
+    return exportPrivateKeyPkcs8FromTpmInternal(keyName, false);
+  }
+
+  virtual bool
+  importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+  {
+    return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, false);
+  }
+
+  virtual bool
+  importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size);
+
+  // Following methods are OSX-specific
+  void
+  generateKeyPairInTpmInternal(const Name& keyName, const KeyParams& params, bool needRetry);
+
+  void
+  deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry);
+
+  ConstBufferPtr
+  exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry);
+
+  bool
+  importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
+                                       const uint8_t* buf, size_t size,
+                                       bool needRetry);
+
+  Block
+  signInTpmInternal(const uint8_t* data, size_t dataLength,
+                    const Name& keyName, DigestAlgorithm digestAlgorithm,
+                    bool needRetry);
+
+public:
+  static const std::string SCHEME;
+
+private:
+  class Impl;
+  shared_ptr<Impl> m_impl;
+};
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V1_SEC_TPM_OSX_HPP
diff --git a/src/security/v1/sec-tpm.cpp b/src/security/v1/sec-tpm.cpp
new file mode 100644
index 0000000..fae3b7e
--- /dev/null
+++ b/src/security/v1/sec-tpm.cpp
@@ -0,0 +1,387 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ */
+
+#include "sec-tpm.hpp"
+
+#include "../../encoding/oid.hpp"
+#include "../../encoding/buffer-stream.hpp"
+#include "cryptopp.hpp"
+#include <unistd.h>
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+SecTpm::SecTpm(const std::string& location)
+  : m_location(location)
+{
+}
+
+SecTpm::~SecTpm()
+{
+}
+
+std::string
+SecTpm::getTpmLocator()
+{
+  return this->getScheme() + ":" + m_location;
+}
+
+ConstBufferPtr
+SecTpm::exportPrivateKeyPkcs5FromTpm(const Name& keyName, const std::string& passwordStr)
+{
+  using namespace CryptoPP;
+
+  uint8_t salt[8] = {0};
+  uint8_t iv[8] = {0};
+
+  // derive key
+  if (!generateRandomBlock(salt, 8) || !generateRandomBlock(iv, 8))
+    BOOST_THROW_EXCEPTION(Error("Cannot generate salt or iv"));
+
+  uint32_t iterationCount = 2048;
+
+  PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
+  size_t derivedLen = 24; // For DES-EDE3-CBC-PAD
+  byte derived[24] = {0};
+  byte purpose = 0;
+
+  try {
+    keyGenerator.DeriveKey(derived, derivedLen, purpose,
+                           reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
+                           salt, 8, iterationCount);
+  }
+  catch (const CryptoPP::Exception& e) {
+    BOOST_THROW_EXCEPTION(Error("Cannot derived the encryption key"));
+  }
+
+  // encrypt
+  CBC_Mode< DES_EDE3 >::Encryption e;
+  e.SetKeyWithIV(derived, derivedLen, iv);
+
+  ConstBufferPtr pkcs8PrivateKey = exportPrivateKeyPkcs8FromTpm(keyName);
+
+  if (pkcs8PrivateKey == nullptr)
+    BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #1"));
+
+  OBufferStream encryptedOs;
+  try {
+    StringSource stringSource(pkcs8PrivateKey->buf(), pkcs8PrivateKey->size(), true,
+                              new StreamTransformationFilter(e, new FileSink(encryptedOs)));
+  }
+  catch (const CryptoPP::Exception& e) {
+    BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #2"));
+  }
+
+  // encode
+  Oid pbes2Id("1.2.840.113549.1.5.13");
+  Oid pbkdf2Id("1.2.840.113549.1.5.12");
+  Oid pbes2encsId("1.2.840.113549.3.7");
+
+  OBufferStream pkcs8Os;
+  try {
+    FileSink sink(pkcs8Os);
+
+    // EncryptedPrivateKeyInfo ::= SEQUENCE {
+    //   encryptionAlgorithm  EncryptionAlgorithmIdentifier,
+    //   encryptedData        OCTET STRING }
+    DERSequenceEncoder encryptedPrivateKeyInfo(sink);
+    {
+      // EncryptionAlgorithmIdentifier ::= SEQUENCE {
+      //   algorithm      OBJECT IDENTIFIER {{PBES2-id}},
+      //   parameters     SEQUENCE {{PBES2-params}} }
+      DERSequenceEncoder encryptionAlgorithm(encryptedPrivateKeyInfo);
+      {
+        pbes2Id.encode(encryptionAlgorithm);
+        // PBES2-params ::= SEQUENCE {
+        //   keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+        //   encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
+        DERSequenceEncoder pbes2Params(encryptionAlgorithm);
+        {
+          // AlgorithmIdentifier ::= SEQUENCE {
+          //   algorithm      OBJECT IDENTIFIER {{PBKDF2-id}},
+          //   parameters     SEQUENCE {{PBKDF2-params}} }
+          DERSequenceEncoder pbes2KDFs(pbes2Params);
+          {
+            pbkdf2Id.encode(pbes2KDFs);
+            // AlgorithmIdentifier ::= SEQUENCE {
+            //   salt           OCTET STRING,
+            //   iterationCount INTEGER (1..MAX),
+            //   keyLength      INTEGER (1..MAX) OPTIONAL,
+            //   prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
+            DERSequenceEncoder pbkdf2Params(pbes2KDFs);
+            {
+              DEREncodeOctetString(pbkdf2Params, salt, 8);
+              DEREncodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
+            }
+            pbkdf2Params.MessageEnd();
+          }
+          pbes2KDFs.MessageEnd();
+
+          // AlgorithmIdentifier ::= SEQUENCE {
+          //   algorithm   OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
+          //   parameters  OCTET STRING} {{iv}} }
+          DERSequenceEncoder pbes2Encs(pbes2Params);
+          {
+            pbes2encsId.encode(pbes2Encs);
+            DEREncodeOctetString(pbes2Encs, iv, 8);
+          }
+          pbes2Encs.MessageEnd();
+        }
+        pbes2Params.MessageEnd();
+      }
+      encryptionAlgorithm.MessageEnd();
+
+      DEREncodeOctetString(encryptedPrivateKeyInfo,
+                           encryptedOs.buf()->buf(), encryptedOs.buf()->size());
+    }
+    encryptedPrivateKeyInfo.MessageEnd();
+
+    return pkcs8Os.buf();
+  }
+  catch (const CryptoPP::Exception& e) {
+    BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #3"));
+  }
+}
+
+bool
+SecTpm::importPrivateKeyPkcs5IntoTpm(const Name& keyName,
+                                     const uint8_t* buf, size_t size,
+                                     const std::string& passwordStr)
+{
+  using namespace CryptoPP;
+
+  Oid pbes2Id;
+  Oid pbkdf2Id;
+  SecByteBlock saltBlock;
+  uint32_t iterationCount;
+  Oid pbes2encsId;
+  SecByteBlock ivBlock;
+  SecByteBlock encryptedDataBlock;
+
+  try {
+    // decode some decoding processes are not necessary for now,
+    // because we assume only one encryption scheme.
+    StringSource source(buf, size, true);
+
+    // EncryptedPrivateKeyInfo ::= SEQUENCE {
+    //   encryptionAlgorithm  EncryptionAlgorithmIdentifier,
+    //   encryptedData        OCTET STRING }
+    BERSequenceDecoder encryptedPrivateKeyInfo(source);
+    {
+      // EncryptionAlgorithmIdentifier ::= SEQUENCE {
+      //   algorithm      OBJECT IDENTIFIER {{PBES2-id}},
+      //   parameters     SEQUENCE {{PBES2-params}} }
+      BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo);
+      {
+        pbes2Id.decode(encryptionAlgorithm);
+        // PBES2-params ::= SEQUENCE {
+        //   keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+        //   encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
+        BERSequenceDecoder pbes2Params(encryptionAlgorithm);
+        {
+          // AlgorithmIdentifier ::= SEQUENCE {
+          //   algorithm      OBJECT IDENTIFIER {{PBKDF2-id}},
+          //   parameters     SEQUENCE {{PBKDF2-params}} }
+          BERSequenceDecoder pbes2KDFs(pbes2Params);
+          {
+            pbkdf2Id.decode(pbes2KDFs);
+            // AlgorithmIdentifier ::= SEQUENCE {
+            //   salt           OCTET STRING,
+            //   iterationCount INTEGER (1..MAX),
+            //   keyLength      INTEGER (1..MAX) OPTIONAL,
+            //   prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
+            BERSequenceDecoder pbkdf2Params(pbes2KDFs);
+            {
+              BERDecodeOctetString(pbkdf2Params, saltBlock);
+              BERDecodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
+            }
+            pbkdf2Params.MessageEnd();
+          }
+          pbes2KDFs.MessageEnd();
+
+          // AlgorithmIdentifier ::= SEQUENCE {
+          //   algorithm   OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
+          //   parameters  OCTET STRING} {{iv}} }
+          BERSequenceDecoder pbes2Encs(pbes2Params);
+          {
+            pbes2encsId.decode(pbes2Encs);
+            BERDecodeOctetString(pbes2Encs, ivBlock);
+          }
+          pbes2Encs.MessageEnd();
+        }
+        pbes2Params.MessageEnd();
+      }
+      encryptionAlgorithm.MessageEnd();
+
+      BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock);
+    }
+    encryptedPrivateKeyInfo.MessageEnd();
+  }
+  catch (const CryptoPP::Exception& e) {
+    return false;
+  }
+
+  PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
+  size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
+  byte derived[24] = {0};
+  byte purpose = 0;
+
+  try {
+    keyGenerator.DeriveKey(derived, derivedLen,
+                           purpose,
+                           reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
+                           saltBlock.BytePtr(), saltBlock.size(),
+                           iterationCount);
+  }
+  catch (const CryptoPP::Exception& e) {
+    return false;
+  }
+
+  //decrypt
+  CBC_Mode< DES_EDE3 >::Decryption d;
+  d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr());
+
+  OBufferStream privateKeyOs;
+  try {
+    StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true,
+                                 new StreamTransformationFilter(d,  new FileSink(privateKeyOs)));
+  }
+  catch (const CryptoPP::Exception& e) {
+    return false;
+  }
+
+  if (!importPrivateKeyPkcs8IntoTpm(keyName,
+                                    privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()))
+    return false;
+
+  // determine key type
+  StringSource privateKeySource(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size(), true);
+
+  KeyType publicKeyType = KeyType::NONE;
+  SecByteBlock rawKeyBits;
+  // PrivateKeyInfo ::= SEQUENCE {
+  //   INTEGER,
+  //   SEQUENCE,
+  //   OCTECT STRING}
+  BERSequenceDecoder privateKeyInfo(privateKeySource);
+  {
+    uint32_t versionNum;
+    BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
+    BERSequenceDecoder sequenceDecoder(privateKeyInfo);
+    {
+      Oid keyTypeOid;
+      keyTypeOid.decode(sequenceDecoder);
+      if (keyTypeOid == oid::RSA)
+        publicKeyType = KeyType::RSA;
+      else if (keyTypeOid == oid::ECDSA)
+        publicKeyType = KeyType::EC;
+      else
+        return false; // Unsupported key type;
+    }
+  }
+
+
+  // derive public key
+  OBufferStream publicKeyOs;
+
+  try {
+    switch (publicKeyType) {
+      case KeyType::RSA: {
+        RSA::PrivateKey privateKey;
+        privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
+        RSAFunction publicKey(privateKey);
+
+        FileSink publicKeySink(publicKeyOs);
+        publicKey.DEREncode(publicKeySink);
+        publicKeySink.MessageEnd();
+        break;
+      }
+
+      case KeyType::EC: {
+        ECDSA<ECP, SHA256>::PrivateKey privateKey;
+        privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
+
+        ECDSA<ECP, SHA256>::PublicKey publicKey;
+        privateKey.MakePublicKey(publicKey);
+        publicKey.AccessGroupParameters().SetEncodeAsOID(true);
+
+        FileSink publicKeySink(publicKeyOs);
+        publicKey.DEREncode(publicKeySink);
+        publicKeySink.MessageEnd();
+        break;
+      }
+
+      default:
+        return false;
+    }
+  }
+  catch (const CryptoPP::Exception& e) {
+    return false;
+  }
+
+  if (!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size()))
+    return false;
+
+  return true;
+}
+
+bool
+SecTpm::getImpExpPassWord(std::string& password, const std::string& prompt)
+{
+  bool isInitialized = false;
+
+#ifdef NDN_CXX_HAVE_GETPASS
+  char* pw0 = nullptr;
+
+  pw0 = getpass(prompt.c_str());
+  if (pw0 == nullptr)
+    return false;
+  std::string password1 = pw0;
+  memset(pw0, 0, strlen(pw0));
+
+  pw0 = getpass("Confirm:");
+  if (pw0 == nullptr) {
+    std::fill(password1.begin(), password1.end(), 0);
+    return false;
+  }
+
+  if (password1.compare(pw0) == 0) {
+    isInitialized = true;
+    password.swap(password1);
+  }
+
+  std::fill(password1.begin(), password1.end(), 0);
+  memset(pw0, 0, strlen(pw0));
+
+  if (password.empty())
+    return false;
+
+#endif // NDN_CXX_HAVE_GETPASS
+
+  return isInitialized;
+}
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v1/sec-tpm.hpp b/src/security/v1/sec-tpm.hpp
new file mode 100644
index 0000000..5acb0c3
--- /dev/null
+++ b/src/security/v1/sec-tpm.hpp
@@ -0,0 +1,319 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ */
+
+#ifndef NDN_SECURITY_V1_SEC_TPM_HPP
+#define NDN_SECURITY_V1_SEC_TPM_HPP
+
+#include "../../common.hpp"
+#include "../security-common.hpp"
+#include "../../name.hpp"
+#include "../../data.hpp"
+#include "../key-params.hpp"
+#include "public-key.hpp"
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+/**
+ * @brief SecTpm is the base class of the TPM classes.
+ *
+ * It specifies the interfaces of private/secret key related operations.
+ */
+class SecTpm : noncopyable
+{
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+  explicit
+  SecTpm(const std::string& location);
+
+  virtual
+  ~SecTpm();
+
+  std::string
+  getTpmLocator();
+
+  /**
+   * @brief set password of TPM
+   *
+   * Password is used to unlock TPM when it is locked.
+   * You should be cautious when using this method, because remembering password is kind of
+   * dangerous.
+   *
+   * @param password The password
+   * @param passwordLength The length of password
+   */
+  virtual void
+  setTpmPassword(const uint8_t* password, size_t passwordLength) = 0;
+
+  /**
+   * @brief reset password of TPM
+   */
+  virtual void
+  resetTpmPassword() = 0;
+
+  /**
+   * @brief Set inTerminal flag to @p inTerminal
+   *
+   * If the inTerminal flag is set, and password is not set, TPM may ask for password via terminal.
+   * inTerminal flag is set by default.
+   */
+  virtual void
+  setInTerminal(bool inTerminal) = 0;
+
+  /**
+   * @brief Get value of inTerminal flag
+   */
+  virtual bool
+  getInTerminal() const = 0;
+
+  /**
+   * @brief Check if TPM is locked
+   */
+  virtual bool
+  isLocked() = 0;
+
+  /**
+   * @brief Unlock the TPM
+   *
+   * @param password The password.
+   * @param passwordLength The password size. 0 indicates no password.
+   * @param usePassword True if we want to use the supplied password to unlock the TPM.
+   * @return true if TPM is unlocked, otherwise false.
+   */
+  virtual bool
+  unlockTpm(const char* password, size_t passwordLength, bool usePassword) = 0;
+
+  /**
+   * @brief Generate a pair of asymmetric keys.
+   *
+   * @param keyName The name of the key pair.
+   * @param params The parameters of key.
+   * @throws SecTpm::Error if fails.
+   */
+  virtual void
+  generateKeyPairInTpm(const Name& keyName, const KeyParams& params) = 0;
+
+  /**
+   * @brief Delete a key pair of asymmetric keys.
+   *
+   * @param keyName The name of the key pair.
+   */
+  virtual void
+  deleteKeyPairInTpm(const Name& keyName) = 0;
+
+  /**
+   * @brief Get a public key.
+   *
+   * @param keyName The public key name.
+   * @return The public key.
+   * @throws SecTpm::Error if public key does not exist in TPM.
+   */
+  virtual shared_ptr<v1::PublicKey>
+  getPublicKeyFromTpm(const Name& keyName) = 0;
+
+  /**
+   * @brief Sign data.
+   *
+   * @param data Pointer to the byte array to be signed.
+   * @param dataLength The length of data.
+   * @param keyName The name of the signing key.
+   * @param digestAlgorithm the digest algorithm.
+   * @return The signature block.
+   * @throws SecTpm::Error if signing fails.
+   */
+  virtual Block
+  signInTpm(const uint8_t* data, size_t dataLength,
+            const Name& keyName,
+            DigestAlgorithm digestAlgorithm) = 0;
+
+  /**
+   * @brief Decrypt data.
+   *
+   * @param data Pointer to the byte arry to be decrypted.
+   * @param dataLength The length of data.
+   * @param keyName The name of the decrypting key.
+   * @param isSymmetric If true symmetric encryption is used, otherwise asymmetric encryption.
+   * @return The decrypted data.
+   * @throws SecTpm::Error if decryption fails.
+   */
+  virtual ConstBufferPtr
+  decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric) = 0;
+
+  /**
+   * @brief Encrypt data.
+   *
+   * @param data Pointer to the byte arry to be decrypted.
+   * @param dataLength The length of data.
+   * @param keyName The name of the encrypting key.
+   * @param isSymmetric If true symmetric encryption is used, otherwise asymmetric encryption.
+   * @return The encrypted data.
+   * @throws SecTpm::Error if encryption fails.
+   */
+  virtual ConstBufferPtr
+  encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric) = 0;
+
+  /**
+   * @brief Generate a symmetric key.
+   *
+   * @param keyName The name of the key.
+   * @param params The parameter of the key.
+   * @throws SecTpm::Error if key generating fails.
+   */
+  virtual void
+  generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params) = 0;
+
+  /**
+   * @brief Check if a particular key exists.
+   *
+   * @param keyName The name of the key.
+   * @param keyClass The class of the key, e.g. KeyClass::PUBLIC, KeyClass::PRIVATE.
+   * @return True if the key exists, otherwise false.
+   */
+  virtual bool
+  doesKeyExistInTpm(const Name& keyName, KeyClass keyClass) = 0;
+
+  /**
+   * @brief Generate a random block
+   *
+   * @param res The pointer to the generated block
+   * @param size The random block size
+   * @return true for success, otherwise false
+   */
+  virtual bool
+  generateRandomBlock(uint8_t* res, size_t size) = 0;
+
+  /**
+   * @brief Add the application into the ACL of a particular key
+   *
+   * @param keyName the name of key
+   * @param keyClass the class of key, e.g. Private Key
+   * @param appPath the absolute path to the application
+   * @param acl the new acl of the key
+   */
+  virtual void
+  addAppToAcl(const Name& keyName, KeyClass keyClass, const std::string& appPath, AclType acl) = 0;
+
+  /**
+   * @brief Export a private key in PKCS#5 format
+   *
+   * @param keyName  The private key name
+   * @param password The password to encrypt the private key
+   * @return The private key info (in PKCS8 format) if exist
+   * @throws SecTpm::Error if private key cannot be exported
+   */
+  ConstBufferPtr
+  exportPrivateKeyPkcs5FromTpm(const Name& keyName, const std::string& password);
+
+  /**
+   * @brief Import a private key in PKCS#5 formatted buffer of size @p bufferSize
+   *
+   * Also recover the public key and installed it in TPM.
+   *
+   * @param keyName    The private key name
+   * @param buffer     Pointer to the first byte of the buffer containing PKCS#5-encoded
+   *                   private key info
+   * @param bufferSize Size of the buffer
+   * @param password   The password to encrypt the private key
+   * @return false if import fails
+   */
+  bool
+  importPrivateKeyPkcs5IntoTpm(const Name& keyName,
+                               const uint8_t* buffer, size_t bufferSize,
+                               const std::string& password);
+
+protected:
+  virtual std::string
+  getScheme() = 0;
+
+  /**
+   * @brief Export a private key in PKCS#8 format.
+   *
+   * @param keyName The private key name.
+   * @return The private key info (in PKCS#8 format) if exist, otherwise a NULL pointer.
+   */
+  virtual ConstBufferPtr
+  exportPrivateKeyPkcs8FromTpm(const Name& keyName) = 0;
+
+  /**
+   * @brief Import a private key from PKCS#8 formatted buffer of size @p bufferSize
+   *
+   * @param keyName    The private key name.
+   * @param buffer     Pointer to the first byte of the buffer containing PKCS#8-encoded
+   *                   private key info
+   * @param bufferSize Size of the buffer
+   * @return false if import fails
+   */
+  virtual bool
+  importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buffer, size_t bufferSize) = 0;
+
+  /**
+   * @brief Import a public key in PKCS#1 formatted buffer of size @p bufferSize
+   *
+   * @param keyName    The public key name
+   * @param buffer     Pointer to the first byte of the buffer containing PKCS#1-encoded
+   *                   private key info
+   * @param bufferSize Size of the buffer
+   * @return false if import fails
+   */
+  virtual bool
+  importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buffer, size_t bufferSize) = 0;
+
+  /**
+   * @brief Get import/export password.
+   *
+   * @param password On return, the password.
+   * @param prompt Prompt for password, i.e., "Password for key:"
+   * @return true if password has been obtained.
+   */
+  virtual bool
+  getImpExpPassWord(std::string& password, const std::string& prompt);
+
+protected:
+  std::string m_location;
+};
+
+} // namespace v1
+
+#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES
+using v1::SecTpm;
+#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES
+
+} // namespace security
+
+#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES
+using security::v1::SecTpm;
+#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES
+
+} // namespace ndn
+
+#endif // NDN_SECURITY_V1_SEC_TPM_HPP
diff --git a/src/security/v1/secured-bag.cpp b/src/security/v1/secured-bag.cpp
new file mode 100644
index 0000000..8fccbc6
--- /dev/null
+++ b/src/security/v1/secured-bag.cpp
@@ -0,0 +1,83 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "secured-bag.hpp"
+#include "../../encoding/tlv-security.hpp"
+#include "../../util/concepts.hpp"
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+//BOOST_CONCEPT_ASSERT((boost::EqualityComparable<SecuredBag>));
+BOOST_CONCEPT_ASSERT((WireEncodable<SecuredBag>));
+BOOST_CONCEPT_ASSERT((WireDecodable<SecuredBag>));
+static_assert(std::is_base_of<tlv::Error, SecuredBag::Error>::value,
+              "SecuredBag::Error must inherit from tlv::Error");
+
+SecuredBag::SecuredBag()
+  : m_wire(tlv::security::IdentityPackage)
+{
+}
+
+SecuredBag::SecuredBag(const Block& wire)
+{
+  this->wireDecode(wire);
+}
+
+SecuredBag::SecuredBag(const IdentityCertificate& cert, ConstBufferPtr key)
+  : m_cert(cert)
+  , m_key(key)
+  , m_wire(tlv::security::IdentityPackage)
+{
+  Block wireKey(tlv::security::KeyPackage, m_key);
+  Block wireCert(tlv::security::CertificatePackage, cert.wireEncode());
+  m_wire.push_back(wireCert);
+  m_wire.push_back(wireKey);
+}
+
+SecuredBag::~SecuredBag()
+{
+}
+
+void
+SecuredBag::wireDecode(const Block& wire)
+{
+  m_wire = wire;
+  m_wire.parse();
+
+  m_cert.wireDecode(m_wire.get(tlv::security::CertificatePackage).blockFromValue());
+
+  Block wireKey = m_wire.get(tlv::security::KeyPackage);
+  shared_ptr<Buffer> key = make_shared<Buffer>(wireKey.value(), wireKey.value_size());
+  m_key = key;
+}
+
+const Block&
+SecuredBag::wireEncode() const
+{
+  m_wire.encode();
+  return m_wire;
+}
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v1/secured-bag.hpp b/src/security/v1/secured-bag.hpp
new file mode 100644
index 0000000..fbfb151
--- /dev/null
+++ b/src/security/v1/secured-bag.hpp
@@ -0,0 +1,85 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_SECURITY_V1_SECURED_BAG_HPP
+#define NDN_SECURITY_V1_SECURED_BAG_HPP
+
+#include "../../common.hpp"
+#include "identity-certificate.hpp"
+
+namespace ndn {
+namespace security {
+namespace v1 {
+
+class SecuredBag
+{
+public:
+  class Error : public tlv::Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : tlv::Error(what)
+    {
+    }
+  };
+
+  SecuredBag();
+
+  explicit
+  SecuredBag(const Block& wire);
+
+  SecuredBag(const IdentityCertificate& cert,
+             ConstBufferPtr key);
+
+  virtual
+  ~SecuredBag();
+
+  void
+  wireDecode(const Block& wire);
+
+  const Block&
+  wireEncode() const;
+
+  const IdentityCertificate&
+  getCertificate() const
+  {
+    return m_cert;
+  }
+
+  ConstBufferPtr
+  getKey() const
+  {
+    return m_key;
+  }
+
+private:
+  IdentityCertificate m_cert;
+  ConstBufferPtr m_key;
+
+  mutable Block m_wire;
+};
+
+} // namespace v1
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V1_SECURED_BAG_HPP