security: Add new TPM framework
The TPM framework is separated into two parts:
1) The front end class Tpm provides the interface to KeyChain. The public
interface of Tpm is read-only.
2) The back end classes represent concrete implementations, such as
tpm::BackEndFile and tpm::BackEndOsx which may also provide
implementation-specific management interfaces.
New TPM supports different key id type when generating new key. The
default type is changed to 64-bit random number.
Change-Id: I41154c2ded4b65fb0bef2f4a0d2c5b77843be05d
Refs: #2948
diff --git a/src/security/pib/key.cpp b/src/security/pib/key.cpp
index c59a39d..51f368c 100644
--- a/src/security/pib/key.cpp
+++ b/src/security/pib/key.cpp
@@ -22,6 +22,7 @@
#include "key.hpp"
#include "pib-impl.hpp"
#include "pib.hpp"
+#include "../v2/certificate.hpp"
namespace ndn {
namespace security {
@@ -196,5 +197,19 @@
BOOST_THROW_EXCEPTION(std::domain_error("Invalid Key instance"));
}
+namespace v2 {
+
+Name
+constructKeyName(const Name& identity, const name::Component& keyId)
+{
+ Name keyName = identity;
+ keyName
+ .append(Certificate::KEY_COMPONENT)
+ .append(keyId);
+ return keyName;
+}
+
+} // namespace v2
+
} // namespace security
} // namespace ndn
diff --git a/src/security/pib/key.hpp b/src/security/pib/key.hpp
index 7118149..53a0ba1 100644
--- a/src/security/pib/key.hpp
+++ b/src/security/pib/key.hpp
@@ -201,7 +201,17 @@
shared_ptr<PibImpl> m_impl;
};
+namespace v2 {
+
+/**
+ * @brief Construct key name based on the appropriate naming conventions
+ */
+Name
+constructKeyName(const Name& identity, const name::Component& keyId);
+
+} // namespace v2
+
} // namespace security
} // namespace ndn
-#endif // NDN_SECURITY_PIB_PIB_HPP
+#endif // NDN_SECURITY_PIB_KEY_HPP
diff --git a/src/security/tpm/back-end-file.cpp b/src/security/tpm/back-end-file.cpp
new file mode 100644
index 0000000..f16d7cf
--- /dev/null
+++ b/src/security/tpm/back-end-file.cpp
@@ -0,0 +1,192 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 "back-end-file.hpp"
+#include "key-handle-mem.hpp"
+#include "../transform.hpp"
+#include "../transform/private-key.hpp"
+#include "../../encoding/buffer-stream.hpp"
+#include <unordered_map>
+#include <fstream>
+#include <cstdlib>
+#include <boost/filesystem.hpp>
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+using transform::PrivateKey;
+
+class BackEndFile::Impl
+{
+public:
+ explicit
+ Impl(const std::string& dir)
+ {
+ if (!dir.empty()) {
+ keystorePath = boost::filesystem::path(dir);
+ }
+#ifdef NDN_CXX_HAVE_TESTS
+ else if (getenv("TEST_HOME") != nullptr) {
+ keystorePath = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn";
+ }
+#endif // NDN_CXX_HAVE_TESTS
+ else if (getenv("HOME") != nullptr) {
+ keystorePath = boost::filesystem::path(getenv("HOME")) / ".ndn";
+ }
+ else {
+ keystorePath = boost::filesystem::current_path() / ".ndn";
+ }
+
+ keystorePath /= "ndnsec-key-file";
+ boost::filesystem::create_directories(keystorePath);
+ }
+
+ boost::filesystem::path
+ toFileName(const Name& keyName)
+ {
+ std::stringstream os;
+ {
+ using namespace transform;
+ bufferSource(keyName.wireEncode().wire(), keyName.wireEncode().size()) >>
+ digestFilter(DigestAlgorithm::SHA256) >> hexEncode() >> streamSink(os);
+ }
+ return keystorePath / (os.str() + ".privkey");
+ }
+
+public:
+ boost::filesystem::path keystorePath;
+};
+
+BackEndFile::BackEndFile(const std::string& location)
+ : m_impl(new Impl(location))
+{
+}
+
+BackEndFile::~BackEndFile() = default;
+
+bool
+BackEndFile::doHasKey(const Name& keyName) const
+{
+ if (!boost::filesystem::exists(m_impl->toFileName(keyName)))
+ return false;
+
+ try {
+ loadKey(keyName);
+ return true;
+ }
+ catch (const std::runtime_error&) {
+ return false;
+ }
+}
+
+unique_ptr<KeyHandle>
+BackEndFile::doGetKeyHandle(const Name& keyName) const
+{
+ if (!doHasKey(keyName))
+ return nullptr;
+
+ return make_unique<KeyHandleMem>(loadKey(keyName));
+}
+
+unique_ptr<KeyHandle>
+BackEndFile::doCreateKey(const Name& identityName, const KeyParams& params)
+{
+ shared_ptr<PrivateKey> key(transform::generatePrivateKey(params).release());
+ unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleMem>(key);
+
+ setKeyName(*keyHandle, identityName, params);
+
+ try {
+ saveKey(keyHandle->getKeyName(), key);
+ return keyHandle;
+ }
+ catch (const std::runtime_error& e) {
+ BOOST_THROW_EXCEPTION(Error(std::string("Cannot write key to disk: ") + e.what()));
+ }
+}
+
+void
+BackEndFile::doDeleteKey(const Name& keyName)
+{
+ boost::filesystem::path keyPath(m_impl->toFileName(keyName));
+
+ if (boost::filesystem::exists(keyPath)) {
+ try {
+ boost::filesystem::remove(keyPath);
+ }
+ catch (const boost::filesystem::filesystem_error&) {
+ BOOST_THROW_EXCEPTION(Error("Cannot delete key"));
+ }
+ }
+}
+
+ConstBufferPtr
+BackEndFile::doExportKey(const Name& keyName, const char* pw, size_t pwLen)
+{
+ shared_ptr<PrivateKey> key;
+ try {
+ key = loadKey(keyName);
+ }
+ catch (const PrivateKey::Error&) {
+ BOOST_THROW_EXCEPTION(Error("Cannot export private key"));
+ }
+ OBufferStream os;
+ key->savePkcs8(os, pw, pwLen);
+ return os.buf();
+}
+
+void
+BackEndFile::doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
+{
+ try {
+ auto key = make_shared<PrivateKey>();
+ key->loadPkcs8(buf, size, pw, pwLen);
+ saveKey(keyName, key);
+ }
+ catch (const PrivateKey::Error&) {
+ BOOST_THROW_EXCEPTION(Error("Cannot import private key"));
+ }
+}
+
+shared_ptr<PrivateKey>
+BackEndFile::loadKey(const Name& keyName) const
+{
+ auto key = make_shared<PrivateKey>();
+ std::fstream is(m_impl->toFileName(keyName).string(), std::ios_base::in);
+ key->loadPkcs1Base64(is);
+ return key;
+}
+
+void
+BackEndFile::saveKey(const Name& keyName, shared_ptr<PrivateKey> key)
+{
+ std::string fileName = m_impl->toFileName(keyName).string();
+ std::fstream os(fileName, std::ios_base::out);
+ key->savePkcs1Base64(os);
+
+ // set file permission
+ chmod(fileName.c_str(), 0000400);
+}
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
diff --git a/src/security/tpm/back-end-file.hpp b/src/security/tpm/back-end-file.hpp
new file mode 100644
index 0000000..02b575f
--- /dev/null
+++ b/src/security/tpm/back-end-file.hpp
@@ -0,0 +1,137 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TPM_BACK_END_FILE_HPP
+#define NDN_SECURITY_TPM_BACK_END_FILE_HPP
+
+#include "back-end.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+class PrivateKey;
+} // namespace transform
+
+namespace tpm {
+
+/**
+ * @brief The back-end implementation of file-based TPM.
+ *
+ * In this TPM, each private key is stored in a separate file with permission 0400, i.e.,
+ * owner read-only. The key is stored in PKCS #1 format in base64 encoding.
+ */
+class BackEndFile : public BackEnd
+{
+public:
+ class Error : public BackEnd::Error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : BackEnd::Error(what)
+ {
+ }
+ };
+
+public:
+ explicit
+ BackEndFile(const std::string& location = "");
+
+ ~BackEndFile() override;
+
+private: // inherited from tpm::BackEnd
+ /**
+ * @return True if a key with name @p keyName exists in TPM.
+ */
+ bool
+ doHasKey(const Name& keyName) const final;
+
+ /**
+ * @return The handle of a key with name @p keyName, or nullptr if the key does not exist
+ */
+ unique_ptr<KeyHandle>
+ doGetKeyHandle(const Name& keyName) const final;
+
+ /**
+ * @brief Create key for @p identityName according to @p params.
+ *
+ * The created key is named as: /<identityName>/[keyId]/KEY
+ * The key name is set in the returned KeyHandle.
+ *
+ * If the key with the same name exists, the old key will be overwritten.
+ * The behavior of using KeyHandler of removed key is undefined.
+ *
+ * @return The handle of the created key.
+ */
+ unique_ptr<KeyHandle>
+ doCreateKey(const Name& identityName, const KeyParams& params) final;
+
+ /**
+ * @brief Delete a key with name @p keyName.
+ *
+ * @throws Error if the deletion fails.
+ */
+ void
+ doDeleteKey(const Name& keyName) final;
+
+ /**
+ * @return A private key with name @p keyName in encrypted PKCS #8 format using password @p pw
+ * @throws Error if the key cannot be exported, e.g., not enough privilege
+ */
+ ConstBufferPtr
+ doExportKey(const Name& keyName, const char* pw, size_t pwLen) final;
+
+ /**
+ * @brief Import a private key in encrypted PKCS #8 format
+ *
+ * @param keyName The name of imported private key
+ * @param buf Pointer to the key in encrypted PKCS #8 format
+ * @param size The size of the key in encrypted PKCS #8 format
+ * @param pw The password to decrypt the key
+ * @param pwLen The length of the password
+ * @throws Error if import fails.
+ */
+ void
+ doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) final;
+
+private:
+ /**
+ * @brief Load a private key with name @p keyName from the key file directory
+ */
+ shared_ptr<transform::PrivateKey>
+ loadKey(const Name& keyName) const;
+
+ /**
+ * @brief Save a private key with name @p keyName into the key file directory
+ */
+ void
+ saveKey(const Name& keyName, shared_ptr<transform::PrivateKey> key);
+
+private:
+ class Impl;
+ unique_ptr<Impl> m_impl;
+};
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_TPM_BACK_END_FILE_HPP
diff --git a/src/security/tpm/back-end-mem.cpp b/src/security/tpm/back-end-mem.cpp
new file mode 100644
index 0000000..beac9db
--- /dev/null
+++ b/src/security/tpm/back-end-mem.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 "back-end-mem.hpp"
+#include "key-handle-mem.hpp"
+#include "../transform/private-key.hpp"
+#include "../../encoding/buffer-stream.hpp"
+#include <unordered_map>
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+using transform::PrivateKey;
+
+class BackEndMem::Impl
+{
+public:
+ std::unordered_map<Name, shared_ptr<PrivateKey>> keys;
+};
+
+BackEndMem::BackEndMem()
+ : m_impl(new Impl)
+{
+}
+
+BackEndMem::~BackEndMem() = default;
+
+bool
+BackEndMem::doHasKey(const Name& keyName) const
+{
+ return (m_impl->keys.count(keyName) > 0);
+}
+
+unique_ptr<KeyHandle>
+BackEndMem::doGetKeyHandle(const Name& keyName) const
+{
+ auto it = m_impl->keys.find(keyName);
+ if (it == m_impl->keys.end())
+ return nullptr;
+ return make_unique<KeyHandleMem>(it->second);
+}
+
+unique_ptr<KeyHandle>
+BackEndMem::doCreateKey(const Name& identityName, const KeyParams& params)
+{
+ shared_ptr<PrivateKey> key(transform::generatePrivateKey(params).release());
+ unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleMem>(key);
+
+ setKeyName(*keyHandle, identityName, params);
+
+ m_impl->keys[keyHandle->getKeyName()] = key;
+ return keyHandle;
+}
+
+void
+BackEndMem::doDeleteKey(const Name& keyName)
+{
+ m_impl->keys.erase(keyName);
+}
+
+ConstBufferPtr
+BackEndMem::doExportKey(const Name& keyName, const char* pw, size_t pwLen)
+{
+ OBufferStream os;
+ m_impl->keys[keyName]->savePkcs8(os, pw, pwLen);
+ return os.buf();
+}
+
+void
+BackEndMem::doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
+{
+ try {
+ auto key = make_shared<PrivateKey>();
+ key->loadPkcs8(buf, size, pw, pwLen);
+ m_impl->keys[keyName] = key;
+ }
+ catch (const PrivateKey::Error& e) {
+ BOOST_THROW_EXCEPTION(Error(std::string("Cannot import private key: ") + e.what()));
+ }
+}
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
diff --git a/src/security/tpm/back-end-mem.hpp b/src/security/tpm/back-end-mem.hpp
new file mode 100644
index 0000000..4253b5e
--- /dev/null
+++ b/src/security/tpm/back-end-mem.hpp
@@ -0,0 +1,117 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TPM_BACK_END_MEM_HPP
+#define NDN_SECURITY_TPM_BACK_END_MEM_HPP
+
+#include "back-end.hpp"
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+/**
+ * @brief The back-end implementation of in-memory TPM.
+ */
+class BackEndMem : public BackEnd
+{
+public:
+ class Error : public BackEnd::Error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : BackEnd::Error(what)
+ {
+ }
+ };
+
+public:
+ explicit
+ BackEndMem();
+
+ ~BackEndMem() override;
+
+private: // inherited from tpm::BackEnd
+
+ /**
+ * @return True if a key with name @p keyName exists in TPM.
+ */
+ bool
+ doHasKey(const Name& keyName) const final;
+
+ /**
+ * @return The handle of a key with name @p keyName, or nullptr if the key does not exist
+ */
+ unique_ptr<KeyHandle>
+ doGetKeyHandle(const Name& keyName) const final;
+
+ /**
+ * @brief Create key for @p identityName according to @p params.
+ *
+ * The created key is named as: /<identityName>/[keyId]/KEY
+ * The key name is set in the returned KeyHandle.
+ * If the key with the same name is created, the old one will be removed.
+ * The behavior of using KeyHandler of removed key is undefined.
+ *
+ * @return The handle of the created key.
+ */
+ unique_ptr<KeyHandle>
+ doCreateKey(const Name& identityName, const KeyParams& params) final;
+
+ /**
+ * @brief Delete a key with name @p keyName.
+ *
+ * @throws Error if the deletion fails.
+ */
+ void
+ doDeleteKey(const Name& keyName) final;
+
+ /**
+ * @return A private key with name @p keyName in encrypted PKCS #8 format using password @p pw
+ * @throws Error if the key cannot be exported, e.g., not enough privilege
+ */
+ ConstBufferPtr
+ doExportKey(const Name& keyName, const char* pw, size_t pwLen) final;
+
+ /**
+ * @brief Import a private key in encrypted PKCS #8 format
+ *
+ * @param keyName The name of imported private key
+ * @param buf Pointer to the key in encrypted PKCS #8 format
+ * @param size The size of the key in encrypted PKCS #8 format
+ * @param pw The password to decrypt the key
+ * @param pwLen The length of password
+ * @throws Error if import fails.
+ */
+ void
+ doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) final;
+
+private:
+ class Impl;
+ unique_ptr<Impl> m_impl;
+};
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_TPM_BACK_END_MEM_HPP
diff --git a/src/security/tpm/back-end-osx.cpp b/src/security/tpm/back-end-osx.cpp
new file mode 100644
index 0000000..d423b10
--- /dev/null
+++ b/src/security/tpm/back-end-osx.cpp
@@ -0,0 +1,514 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 "back-end-osx.hpp"
+#include "key-handle-osx.hpp"
+#include "helper-osx.hpp"
+#include "../transform/private-key.hpp"
+#include "tpm.hpp"
+
+#include <CoreServices/CoreServices.h>
+#include <Security/Security.h>
+#include <Security/SecRandom.h>
+#include <Security/SecDigestTransform.h>
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+class BackEndOsx::Impl
+{
+public:
+ Impl()
+ : isTerminalMode(false)
+ {
+ }
+
+ /**
+ * @brief Get private key reference with name @p keyName.
+ *
+ * @param keyName
+ * @returns reference to the key
+ */
+ CFReleaser<SecKeychainItemRef>
+ getKey(const Name& keyName)
+ {
+ CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(nullptr, keyName.toUri().c_str(), kCFStringEncodingUTF8);
+
+ CFReleaser<CFMutableDictionaryRef> attrDict =
+ CFDictionaryCreateMutable(nullptr, 5, &kCFTypeDictionaryKeyCallBacks, nullptr);
+
+ CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
+ CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
+ CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, kSecAttrKeyClassPrivate);
+ 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());
+ keyItem.retain();
+
+ if (res != errSecSuccess) {
+ if (res == errSecAuthFailed) {
+ BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
+ }
+ BOOST_THROW_EXCEPTION(std::domain_error("Key does not exist"));
+ }
+
+ return keyItem;
+ }
+
+public:
+ SecKeychainRef keyChainRef;
+ bool isTerminalMode;
+};
+
+
+static CFTypeRef
+getAsymKeyType(KeyType keyType)
+{
+ switch (keyType) {
+ case KeyType::RSA:
+ return kSecAttrKeyTypeRSA;
+ case KeyType::EC:
+ return kSecAttrKeyTypeECDSA;
+ default:
+ BOOST_THROW_EXCEPTION(Tpm::Error("Unsupported key type"));
+ }
+}
+
+static CFTypeRef
+getDigestAlgorithm(DigestAlgorithm digestAlgo)
+{
+ switch (digestAlgo) {
+ case DigestAlgorithm::SHA256:
+ return kSecDigestSHA2;
+ default:
+ return 0;
+ }
+}
+
+static long
+getDigestSize(DigestAlgorithm digestAlgo)
+{
+ switch (digestAlgo) {
+ case DigestAlgorithm::SHA256:
+ return 256;
+ default:
+ return -1;
+ }
+}
+
+BackEndOsx::BackEndOsx()
+ : m_impl(new Impl)
+{
+ SecKeychainSetUserInteractionAllowed(!m_impl->isTerminalMode);
+
+ OSStatus res = SecKeychainCopyDefault(&m_impl->keyChainRef);
+
+ if (res == errSecNoDefaultKeychain) { //If no default key chain, create one.
+ BOOST_THROW_EXCEPTION(Error("No default keychain, create one first"));
+ }
+}
+
+BackEndOsx::~BackEndOsx() = default;
+
+void
+BackEndOsx::setTerminalMode(bool isTerminal)
+{
+ m_impl->isTerminalMode = isTerminal;
+ SecKeychainSetUserInteractionAllowed(!isTerminal);
+}
+
+bool
+BackEndOsx::isTerminalMode() const
+{
+ return m_impl->isTerminalMode;
+}
+
+bool
+BackEndOsx::isLocked() const
+{
+ SecKeychainStatus keychainStatus;
+
+ OSStatus res = SecKeychainGetStatus(m_impl->keyChainRef, &keychainStatus);
+ if (res != errSecSuccess)
+ return true;
+ else
+ return ((kSecUnlockStateStatus & keychainStatus) == 0);
+}
+
+bool
+BackEndOsx::unlockTpm(const char* password, size_t passwordLength)
+{
+ // If the default key chain is already unlocked, return immediately.
+ if (!isLocked())
+ return true;
+
+ if (m_impl->isTerminalMode) {
+ // Use the supplied password.
+ SecKeychainUnlock(m_impl->keyChainRef, passwordLength, password, true);
+ }
+ else {
+ // If inTerminal is not set, get the password from GUI.
+ SecKeychainUnlock(m_impl->keyChainRef, 0, nullptr, false);
+ }
+
+ return !isLocked();
+}
+
+ConstBufferPtr
+BackEndOsx::sign(const KeyRefOsx& key, DigestAlgorithm digestAlgorithm,
+ const uint8_t* buf, size_t size) const
+{
+ CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(nullptr, buf, size, kCFAllocatorNull);
+
+ CFReleaser<CFErrorRef> error;
+ // C-style cast is used as per Apple convention
+ CFReleaser<SecTransformRef> signer = SecSignTransformCreate(key.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, getDigestAlgorithm(digestAlgorithm), &error.get());
+ if (error != nullptr) {
+ BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
+ }
+
+ // Set digest attribute
+ long digestSize = getDigestSize(digestAlgorithm);
+ CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(nullptr, 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) {
+ CFShow(error.get());
+ BOOST_THROW_EXCEPTION(Error("Fail to sign data"));
+ }
+
+ if (signature == nullptr) {
+ BOOST_THROW_EXCEPTION(Error("Signature is NULL!\n"));
+ }
+
+ return make_shared<Buffer>(CFDataGetBytePtr(signature.get()), CFDataGetLength(signature.get()));
+}
+
+ConstBufferPtr
+BackEndOsx::decrypt(const KeyRefOsx& key, const uint8_t* cipherText, size_t cipherSize) const
+{
+ CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(nullptr, cipherText, cipherSize, kCFAllocatorNull);
+
+ CFReleaser<CFErrorRef> error;
+ CFReleaser<SecTransformRef> decryptor = SecDecryptTransformCreate(key.get(), &error.get());
+ if (error != nullptr) {
+ BOOST_THROW_EXCEPTION(Error("Fail to create decrypt"));
+ }
+
+ SecTransformSetAttribute(decryptor.get(), kSecTransformInputAttributeName, dataRef.get(), &error.get());
+ if (error != nullptr) {
+ BOOST_THROW_EXCEPTION(Error("Fail to configure decrypt"));
+ }
+
+ SecTransformSetAttribute(decryptor.get(), kSecPaddingKey, kSecPaddingOAEPKey, &error.get());
+ if (error != nullptr) {
+ BOOST_THROW_EXCEPTION(Error("Fail to configure decrypt #2"));
+ }
+
+ CFReleaser<CFDataRef> output = (CFDataRef)SecTransformExecute(decryptor.get(), &error.get());
+ if (error != nullptr) {
+ // CFShow(error);
+ BOOST_THROW_EXCEPTION(Error("Fail to decrypt data"));
+ }
+
+ if (output == nullptr) {
+ BOOST_THROW_EXCEPTION(Error("Output is NULL!\n"));
+ }
+ return make_shared<Buffer>(CFDataGetBytePtr(output.get()), CFDataGetLength(output.get()));
+}
+
+ConstBufferPtr
+BackEndOsx::derivePublicKey(const KeyRefOsx& key) const
+{
+ CFReleaser<CFDataRef> exportedKey;
+ OSStatus res = SecItemExport(key.get(), // secItemOrArray
+ kSecFormatOpenSSL, // outputFormat
+ 0, // flags
+ nullptr, // keyParams
+ &exportedKey.get()); // exportedData
+
+ if (res != errSecSuccess) {
+ if (res == errSecAuthFailed) {
+ BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
+ }
+ else {
+ BOOST_THROW_EXCEPTION(Error("Fail to export private key"));
+ }
+ }
+
+ transform::PrivateKey privateKey;
+ privateKey.loadPkcs1(CFDataGetBytePtr(exportedKey.get()), CFDataGetLength(exportedKey.get()));
+ return privateKey.derivePublicKey();
+}
+
+bool
+BackEndOsx::doHasKey(const Name& keyName) const
+{
+ CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(nullptr, keyName.toUri().c_str(), kCFStringEncodingUTF8);
+
+ CFReleaser<CFMutableDictionaryRef> attrDict =
+ CFDictionaryCreateMutable(nullptr, 4, &kCFTypeDictionaryKeyCallBacks, nullptr);
+
+ CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
+ 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());
+ itemRef.retain();
+
+ return (res == errSecSuccess);
+}
+
+unique_ptr<KeyHandle>
+BackEndOsx::doGetKeyHandle(const Name& keyName) const
+{
+ CFReleaser<SecKeychainItemRef> keyItem;
+ try {
+ keyItem = m_impl->getKey(keyName);
+ }
+ catch (const std::domain_error&) {
+ return nullptr;
+ }
+
+ return make_unique<KeyHandleOsx>(*this, (SecKeyRef)keyItem.get());
+}
+
+unique_ptr<KeyHandle>
+BackEndOsx::doCreateKey(const Name& identityName, const KeyParams& params)
+{
+ KeyType keyType = params.getKeyType();
+ uint32_t keySize;
+ 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(Tpm::Error("Fail to create a key pair: Unsupported key type"));
+ }
+ }
+ CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(nullptr, kCFNumberIntType, &keySize);
+
+ CFReleaser<CFMutableDictionaryRef> attrDict =
+ CFDictionaryCreateMutable(nullptr, 2, &kCFTypeDictionaryKeyCallBacks, nullptr);
+ CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, getAsymKeyType(keyType));
+ CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
+
+ KeyRefOsx publicKey, privateKey;
+ // C-style cast is used as per Apple convention
+ OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(), &publicKey.get(), &privateKey.get());
+
+ BOOST_ASSERT(privateKey != nullptr);
+
+ publicKey.retain();
+ privateKey.retain();
+
+ BOOST_ASSERT(privateKey != nullptr);
+
+ if (res != errSecSuccess) {
+ if (res == errSecAuthFailed) {
+ BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
+ }
+ else {
+ BOOST_THROW_EXCEPTION(Error("Fail to create a key pair"));
+ }
+ }
+
+ unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleOsx>(*this, privateKey.get());
+ setKeyName(*keyHandle, identityName, params);
+
+ SecKeychainAttribute attrs[1]; // maximum number of attributes
+ SecKeychainAttributeList attrList = { 0, attrs };
+ std::string keyUri = keyHandle->getKeyName().toUri();
+ {
+ attrs[attrList.count].tag = kSecKeyPrintName;
+ attrs[attrList.count].length = keyUri.size();
+ attrs[attrList.count].data = const_cast<char*>(keyUri.data());
+ attrList.count++;
+ }
+
+ SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)privateKey.get(), &attrList, 0, nullptr);
+ SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)publicKey.get(), &attrList, 0, nullptr);
+
+ return keyHandle;
+}
+
+void
+BackEndOsx::doDeleteKey(const Name& keyName)
+{
+ CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(nullptr, keyName.toUri().c_str(), kCFStringEncodingUTF8);
+
+ CFReleaser<CFMutableDictionaryRef> searchDict =
+ CFDictionaryCreateMutable(nullptr, 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) {
+ if (res == errSecAuthFailed) {
+ BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
+ }
+ else if (res != errSecItemNotFound) {
+ BOOST_THROW_EXCEPTION(Error("Fail to delete a key pair"));
+ }
+ }
+}
+
+ConstBufferPtr
+BackEndOsx::doExportKey(const Name& keyName, const char* pw, size_t pwLen)
+{
+ CFReleaser<SecKeychainItemRef> privateKey;
+
+ try {
+ privateKey = m_impl->getKey(keyName);
+ }
+ catch (const std::domain_error&) {
+ BOOST_THROW_EXCEPTION(Tpm::Error("Private key does not exist in OSX Keychain"));
+ }
+
+ CFReleaser<CFDataRef> exportedKey;
+ SecItemImportExportKeyParameters keyParams;
+ memset(&keyParams, 0, sizeof(keyParams));
+ CFReleaser<CFStringRef> passphrase =
+ CFStringCreateWithBytes(0, reinterpret_cast<const uint8_t*>(pw), pwLen, kCFStringEncodingUTF8, false);
+ keyParams.passphrase = passphrase.get();
+ OSStatus res = SecItemExport(privateKey.get(), // secItemOrArray
+ kSecFormatWrappedPKCS8, // outputFormat
+ 0, // flags
+ &keyParams, // keyParams
+ &exportedKey.get()); // exportedData
+
+ if (res != errSecSuccess) {
+ if (res == errSecAuthFailed) {
+ BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
+ }
+ else {
+ BOOST_THROW_EXCEPTION(Error("Fail to export private key"));
+ }
+ }
+
+ return make_shared<Buffer>(CFDataGetBytePtr(exportedKey.get()), CFDataGetLength(exportedKey.get()));
+}
+
+void
+BackEndOsx::doImportKey(const Name& keyName, const uint8_t* buf, size_t size,
+ const char* pw, size_t pwLen)
+{
+ CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(nullptr, buf, size, kCFAllocatorNull);
+
+ SecExternalFormat externalFormat = kSecFormatWrappedPKCS8;
+ SecExternalItemType externalType = kSecItemTypePrivateKey;
+
+ CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(nullptr, keyName.toUri().c_str(), kCFStringEncodingUTF8);
+ CFReleaser<CFStringRef> passphrase =
+ CFStringCreateWithBytes(nullptr, reinterpret_cast<const uint8_t*>(pw), pwLen, kCFStringEncodingUTF8, false);
+ CFReleaser<SecAccessRef> access;
+ SecAccessCreate(keyLabel.get(), nullptr, &access.get());
+
+ CFArrayRef attributes = nullptr;
+
+ const SecItemImportExportKeyParameters keyParams{
+ SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION, // version
+ 0, // flags
+ passphrase.get(), // passphrase
+ nullptr, // alert title
+ nullptr, // alert prompt
+ access.get(), // access ref
+ nullptr, // key usage
+ attributes // key attributes
+ };
+
+ CFReleaser<CFArrayRef> outItems;
+ OSStatus res = SecItemImport(importedKey.get(), // importedData
+ nullptr, // fileNameOrExtension
+ &externalFormat, // inputFormat
+ &externalType, // itemType
+ 0, // flags
+ &keyParams, // keyParams
+ m_impl->keyChainRef, // importKeychain
+ &outItems.get()); // outItems
+
+ if (res != errSecSuccess) {
+ if (res == errSecAuthFailed) {
+ BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
+ }
+ else {
+ BOOST_THROW_EXCEPTION(Error("Cannot import the private key"));
+ }
+ }
+
+ // 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 };
+ std::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);
+}
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
diff --git a/src/security/tpm/back-end-osx.hpp b/src/security/tpm/back-end-osx.hpp
new file mode 100644
index 0000000..0fcd49f
--- /dev/null
+++ b/src/security/tpm/back-end-osx.hpp
@@ -0,0 +1,162 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TPM_BACK_END_OSX_HPP
+#define NDN_SECURITY_TPM_BACK_END_OSX_HPP
+
+#include "back-end.hpp"
+#include "helper-osx.hpp"
+
+#ifndef NDN_CXX_HAVE_OSX_SECURITY
+#error "This file should not be compiled ..."
+#endif
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+/**
+ * @brief The back-end implementation of TPM based on OS X KeyChain service.
+ */
+class BackEndOsx : public BackEnd
+{
+public:
+ class Error : public BackEnd::Error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : BackEnd::Error(what)
+ {
+ }
+ };
+
+public:
+ BackEndOsx();
+
+ ~BackEndOsx() override;
+
+public: // management
+ /**
+ * @brief Set the terminal mode of TPM.
+ *
+ * In terminal mode, TPM will not ask user permission from GUI.
+ */
+ void
+ setTerminalMode(bool isTerminal);
+
+ /**
+ * @brief Check if TPM is in terminal mode
+ */
+ bool
+ isTerminalMode() const;
+
+ /**
+ * @return True if TPM is locked, otherwise false
+ */
+ bool
+ isLocked() const;
+
+ /**
+ * @brief Unlock TPM
+ *
+ * @param password The password to unlock TPM
+ * @param passwordLength The password size.
+ */
+ bool
+ unlockTpm(const char* password = nullptr, size_t passwordLength = 0);
+
+public: // crypto transformation
+ /**
+ * @brief Sign @p buf with @p key using @p digestAlgorithm.
+ */
+ ConstBufferPtr
+ sign(const KeyRefOsx& key, DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const;
+
+ ConstBufferPtr
+ decrypt(const KeyRefOsx& key, const uint8_t* cipherText, size_t cipherSize) const;
+
+ ConstBufferPtr
+ derivePublicKey(const KeyRefOsx& key) const;
+
+private: // inherited from tpm::BackEnd
+
+ /**
+ * @return True if a key with name @p keyName exists in TPM.
+ */
+ bool
+ doHasKey(const Name& keyName) const final;
+
+ /**
+ * @return The handle of a key with name @p keyName, or nullptr if the key does not exist
+ */
+ unique_ptr<KeyHandle>
+ doGetKeyHandle(const Name& keyName) const final;
+
+ /**
+ * @brief Create key for @p identityName according to @p params.
+ *
+ * The created key is named as: /<identityName>/[keyId]/KEY
+ * The key name is set in the returned KeyHandle.
+ *
+ * @return The handle of the created key.
+ */
+ unique_ptr<KeyHandle>
+ doCreateKey(const Name& identityName, const KeyParams& params) final;
+
+ /**
+ * @brief Delete a key with name @p keyName.
+ *
+ * @throws Error if the deletion fails.
+ */
+ void
+ doDeleteKey(const Name& keyName) final;
+
+ /**
+ * @return A private key with name @p keyName in encrypted PKCS #8 format using password @p pw
+ * @throws Error if the key cannot be exported, e.g., not enough privilege
+ */
+ ConstBufferPtr
+ doExportKey(const Name& keyName, const char* pw, size_t pwLen) final;
+
+ /**
+ * @brief Import a private key in encrypted PKCS #8 format
+ *
+ * @param keyName The name of imported private key
+ * @param buf Pointer to the key in encrypted PKCS #8 format
+ * @param size The size of the key in encrypted PKCS #8 format
+ * @param pw The password to decrypt the private key
+ * @param pwLen The length of the password
+ * @throws Error if import fails
+ */
+ void
+ doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) final;
+
+private:
+ class Impl;
+ unique_ptr<Impl> m_impl;
+};
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_TPM_BACK_END_OSX_HPP
diff --git a/src/security/tpm/back-end.cpp b/src/security/tpm/back-end.cpp
new file mode 100644
index 0000000..18df659
--- /dev/null
+++ b/src/security/tpm/back-end.cpp
@@ -0,0 +1,138 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 "back-end.hpp"
+#include "key-handle.hpp"
+#include "tpm.hpp"
+#include "../transform.hpp"
+#include "../../encoding/buffer-stream.hpp"
+#include "../../util/random.hpp"
+#include "../pib/key.hpp"
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+BackEnd::~BackEnd() = default;
+
+bool
+BackEnd::hasKey(const Name& keyName) const
+{
+ return doHasKey(keyName);
+}
+
+unique_ptr<KeyHandle>
+BackEnd::getKeyHandle(const Name& keyName) const
+{
+ return doGetKeyHandle(keyName);
+}
+
+unique_ptr<KeyHandle>
+BackEnd::createKey(const Name& identity, const KeyParams& params)
+{
+ // key name checking
+ switch (params.getKeyIdType()) {
+ case KeyIdType::USER_SPECIFIED: { // keyId is pre-set.
+ Name keyName = v2::constructKeyName(identity, params.getKeyId());
+ if (hasKey(keyName)) {
+ BOOST_THROW_EXCEPTION(Tpm::Error("Key `" + keyName.toUri() + "` already exists"));
+ }
+ break;
+ }
+ case KeyIdType::SHA256: {
+ // KeyName will be assigned in setKeyName after key is generated
+ break;
+ }
+ case KeyIdType::RANDOM: {
+ Name keyName;
+ name::Component keyId;
+ do {
+ keyId = name::Component::fromNumber(random::generateSecureWord64());
+ keyName = v2::constructKeyName(identity, params.getKeyId());
+ } while (hasKey(keyName));
+
+ const_cast<KeyParams&>(params).setKeyId(keyId);
+ break;
+ }
+ default: {
+ BOOST_THROW_EXCEPTION(Error("Unsupported key id type"));
+ }
+ }
+
+ return doCreateKey(identity, params);
+}
+
+void
+BackEnd::deleteKey(const Name& keyName)
+{
+ doDeleteKey(keyName);
+}
+
+ConstBufferPtr
+BackEnd::exportKey(const Name& keyName, const char* pw, size_t pwLen)
+{
+ if (!hasKey(keyName)) {
+ BOOST_THROW_EXCEPTION(Error("Key `" + keyName.toUri() + "` does not exist"));
+ }
+ return doExportKey(keyName, pw, pwLen);
+}
+
+void
+BackEnd::importKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, const char* pw, size_t pwLen)
+{
+ if (hasKey(keyName)) {
+ BOOST_THROW_EXCEPTION(Error("Key `" + keyName.toUri() + "` already exists"));
+ }
+ doImportKey(keyName, pkcs8, pkcs8Len, pw, pwLen);
+}
+
+void
+BackEnd::setKeyName(KeyHandle& keyHandle, const Name& identity, const KeyParams& params)
+{
+ name::Component keyId;
+ switch (params.getKeyIdType()) {
+ case KeyIdType::USER_SPECIFIED:
+ keyId = params.getKeyId();
+ break;
+ case KeyIdType::SHA256: {
+ using namespace transform;
+
+ OBufferStream os;
+ bufferSource(*keyHandle.derivePublicKey()) >> digestFilter() >> streamSink(os);
+ keyId = name::Component(os.buf());
+ break;
+ }
+ case KeyIdType::RANDOM: {
+ BOOST_ASSERT(!params.getKeyId().empty());
+ keyId = params.getKeyId();
+ break;
+ }
+ default: {
+ BOOST_ASSERT(false);
+ }
+ }
+
+ keyHandle.setKeyName(v2::constructKeyName(identity, keyId));
+}
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
diff --git a/src/security/tpm/back-end.hpp b/src/security/tpm/back-end.hpp
new file mode 100644
index 0000000..749b53d
--- /dev/null
+++ b/src/security/tpm/back-end.hpp
@@ -0,0 +1,182 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TPM_BACK_END_HPP
+#define NDN_SECURITY_TPM_BACK_END_HPP
+
+#include "../../common.hpp"
+#include "../../name.hpp"
+#include "../../encoding/buffer.hpp"
+#include "../key-params.hpp"
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+class KeyHandle;
+
+/**
+ * @brief Abstraction of Tpm back-end.
+ *
+ * This class provides KeyHandle to the front-end and other TPM management operations.
+ */
+class BackEnd : noncopyable
+{
+public:
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+public:
+ virtual
+ ~BackEnd();
+
+public: // key management
+ /**
+ * @return True if a key with name @p keyName exists in TPM.
+ */
+ bool
+ hasKey(const Name& keyName) const;
+
+ /**
+ * @return The handle of a key with name @p keyName, or nullptr if the key does not exist.
+ *
+ * Calling getKeyHandle multiple times with the same keyName will return different KeyHandle
+ * objects that all refer to the same key.
+ */
+ unique_ptr<KeyHandle>
+ getKeyHandle(const Name& keyName) const;
+
+ /**
+ * @brief Create key for @p identity according to @p params.
+ *
+ * The key name is set in the returned KeyHandle.
+ *
+ * @return The handle of the created key.
+ * @throws Tpm::Error if @p params is invalid
+ * @throws Error if the key cannot be created.
+ */
+ unique_ptr<KeyHandle>
+ createKey(const Name& identity, const KeyParams& params);
+
+ /**
+ * @brief Delete a key with name @p keyName.
+ *
+ * Continuing to use existing KeyHandles on a deleted key results in undefined behavior.
+ *
+ * @throws Error if the deletion fails.
+ */
+ void
+ deleteKey(const Name& keyName);
+
+ /**
+ * @return A private key with name @p keyName in encrypted PKCS #8 format using password @p pw
+ * @throws Error if the key does not exist
+ * @throws Error if the key cannot be exported, e.g., insufficient privilege
+ */
+ ConstBufferPtr
+ exportKey(const Name& keyName, const char* pw, size_t pwLen);
+
+ /**
+ * @brief Import a private key in encrypted PKCS #8 format
+ *
+ * @param keyName The name of imported private key
+ * @param pkcs8 Pointer to the key in encrypted PKCS #8 format
+ * @param pkcs8Len The size of the key in encrypted PKCS #8 format
+ * @param pw The password to decrypt the private key
+ * @param pwLen The length of the password
+ * @throws Error if import fails.
+ */
+ void
+ importKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, const char* pw, size_t pwLen);
+
+protected: // static helper method
+ /**
+ * @brief Set the key name in @p keyHandle according to @p identity and @p params
+ */
+ static void
+ setKeyName(KeyHandle& keyHandle, const Name& identity, const KeyParams& params);
+
+private: // pure virtual methods
+ /**
+ * @return True if a key with name @p keyName exists in TPM.
+ */
+ virtual bool
+ doHasKey(const Name& keyName) const = 0;
+
+ /**
+ * @return The handle of a key with name @p keyName, or nullptr if the key does not exist
+ */
+ virtual unique_ptr<KeyHandle>
+ doGetKeyHandle(const Name& keyName) const = 0;
+
+ /**
+ * @brief Create key for @p identityName according to @p params.
+ *
+ * The created key is named as: /<identityName>/[keyId]/KEY
+ * The key name is set in the returned KeyHandle.
+ *
+ * @return The handle of the created key.
+ * @throws Error when key cannot be created.
+ */
+ virtual unique_ptr<KeyHandle>
+ doCreateKey(const Name& identity, const KeyParams& params) = 0;
+
+ /**
+ * @brief Delete a key with name @p keyName.
+ *
+ * @throws Error if the deletion fails.
+ */
+ virtual void
+ doDeleteKey(const Name& keyName) = 0;
+
+ /**
+ * @return A private key with name @p keyName in encrypted PKCS #8 format using password @p pw
+ * @throws Error if the key cannot be exported, e.g., insufficient privilege
+ */
+ virtual ConstBufferPtr
+ doExportKey(const Name& keyName, const char* pw, size_t pwLen) = 0;
+
+ /**
+ * @brief Import a private key in encrypted PKCS #8 format using @p password
+ *
+ * @param keyName The name of imported private key
+ * @param pkcs8 Pointer to the key in PKCS #8 format
+ * @param pkcs8Len The size of the key in PKCS #8 format
+ * @param pw The password to decrypt the private key
+ * @param pwLen The length of the password
+ * @throws Error if import fails.
+ */
+ virtual void
+ doImportKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, const char* pw, size_t pwLen) = 0;
+};
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_TPM_BACK_END_HPP
diff --git a/src/security/tpm/helper-osx.hpp b/src/security/tpm/helper-osx.hpp
new file mode 100644
index 0000000..2e7d827
--- /dev/null
+++ b/src/security/tpm/helper-osx.hpp
@@ -0,0 +1,154 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TPM_HELPER_OSX_HPP
+#define NDN_SECURITY_TPM_HELPER_OSX_HPP
+
+#include "../../common.hpp"
+
+#ifndef NDN_CXX_HAVE_OSX_SECURITY
+#error "This file should not be included ..."
+#endif
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+/**
+ * @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();
+ }
+
+public: // Access
+ const T&
+ get() const
+ {
+ return m_typeRef;
+ }
+
+ T&
+ get()
+ {
+ return m_typeRef;
+ }
+
+ bool
+ operator==(const std::nullptr_t&)
+ {
+ return m_typeRef == nullptr;
+ }
+
+ bool
+ operator!=(const std::nullptr_t&)
+ {
+ return m_typeRef != nullptr;
+ }
+
+ ///////////////////
+ // Miscellaneous //
+
+ void
+ retain(const T& typeRef)
+ {
+ if (typeRef != nullptr) {
+ CFRetain(typeRef);
+ }
+ release();
+ m_typeRef = typeRef;
+ }
+
+ void
+ retain()
+ {
+ T typeRef = m_typeRef;
+ m_typeRef = nullptr;
+ retain(typeRef);
+ }
+
+ void
+ release()
+ {
+ if (m_typeRef != nullptr) {
+ CFRelease(m_typeRef);
+ m_typeRef = nullptr;
+ }
+ };
+
+private:
+ T m_typeRef;
+};
+
+typedef CFReleaser<SecKeyRef> KeyRefOsx;
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_TPM_HELPER_OSX_HPP
diff --git a/src/security/tpm/key-handle-mem.cpp b/src/security/tpm/key-handle-mem.cpp
new file mode 100644
index 0000000..00f5b21
--- /dev/null
+++ b/src/security/tpm/key-handle-mem.cpp
@@ -0,0 +1,69 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 "key-handle-mem.hpp"
+#include "../../encoding/buffer-stream.hpp"
+#include "../transform.hpp"
+#include "../transform/private-key.hpp"
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+using transform::PrivateKey;
+
+KeyHandleMem::KeyHandleMem(shared_ptr<PrivateKey> key)
+ : m_key(key)
+{
+ BOOST_ASSERT(key != nullptr);
+}
+
+ConstBufferPtr
+KeyHandleMem::doSign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const
+{
+ switch (digestAlgorithm) {
+ case DigestAlgorithm::SHA256: {
+ using namespace transform;
+
+ OBufferStream sigOs;
+ bufferSource(buf, size) >> signerFilter(digestAlgorithm, *m_key) >> streamSink(sigOs);
+ return sigOs.buf();
+ }
+ default:
+ return nullptr;
+ }
+}
+
+ConstBufferPtr
+KeyHandleMem::doDecrypt(const uint8_t* cipherText, size_t cipherTextLen) const
+{
+ return m_key->decrypt(cipherText, cipherTextLen);
+}
+
+ConstBufferPtr
+KeyHandleMem::doDerivePublicKey() const
+{
+ return m_key->derivePublicKey();
+}
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
diff --git a/src/security/tpm/key-handle-mem.hpp b/src/security/tpm/key-handle-mem.hpp
new file mode 100644
index 0000000..006c4ec
--- /dev/null
+++ b/src/security/tpm/key-handle-mem.hpp
@@ -0,0 +1,63 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TPM_KEY_HANDLE_MEM_HPP
+#define NDN_SECURITY_TPM_KEY_HANDLE_MEM_HPP
+
+#include "key-handle.hpp"
+
+namespace ndn {
+namespace security {
+
+namespace transform {
+class PrivateKey;
+} // namespace transform
+
+namespace tpm {
+
+/**
+ * @brief A TPM key handle that keeps the private key in memory
+ */
+class KeyHandleMem : public KeyHandle
+{
+public:
+ explicit
+ KeyHandleMem(shared_ptr<transform::PrivateKey> key);
+
+private:
+ ConstBufferPtr
+ doSign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const final;
+
+ ConstBufferPtr
+ doDecrypt(const uint8_t* cipherText, size_t cipherTextLen) const final;
+
+ ConstBufferPtr
+ doDerivePublicKey() const final;
+
+private:
+ shared_ptr<transform::PrivateKey> m_key;
+};
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_TPM_KEY_HANDLE_MEM_HPP
diff --git a/src/security/tpm/key-handle-osx.cpp b/src/security/tpm/key-handle-osx.cpp
new file mode 100644
index 0000000..518a673
--- /dev/null
+++ b/src/security/tpm/key-handle-osx.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 "key-handle-osx.hpp"
+#include "back-end-osx.hpp"
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+KeyHandleOsx::KeyHandleOsx(const BackEndOsx& impl, const KeyRefOsx& key)
+ : m_impl(impl)
+ , m_key(key)
+{
+ if (m_key.get() == 0)
+ BOOST_THROW_EXCEPTION(Error("key is not set"));
+}
+
+ConstBufferPtr
+KeyHandleOsx::doSign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const
+{
+ return m_impl.sign(m_key, digestAlgorithm, buf, size);
+}
+
+ConstBufferPtr
+KeyHandleOsx::doDecrypt(const uint8_t* cipherText, size_t cipherTextLen) const
+{
+ return m_impl.decrypt(m_key, cipherText, cipherTextLen);
+}
+
+ConstBufferPtr
+KeyHandleOsx::doDerivePublicKey() const
+{
+ return m_impl.derivePublicKey(m_key);
+}
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
diff --git a/src/security/tpm/key-handle-osx.hpp b/src/security/tpm/key-handle-osx.hpp
new file mode 100644
index 0000000..4337f0d
--- /dev/null
+++ b/src/security/tpm/key-handle-osx.hpp
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TPM_KEY_HANDLE_OSX_HPP
+#define NDN_SECURITY_TPM_KEY_HANDLE_OSX_HPP
+
+#include "key-handle.hpp"
+#include "helper-osx.hpp"
+
+#ifndef NDN_CXX_HAVE_OSX_SECURITY
+#error "This file should not be compiled ..."
+#endif
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+class BackEndOsx;
+
+/**
+ * @brief Abstraction of TPM key handle used by the TPM based on OS X Keychain Service.
+ */
+class KeyHandleOsx : public KeyHandle
+{
+public:
+ class Error : public KeyHandle::Error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : KeyHandle::Error(what)
+ {
+ }
+ };
+
+public:
+ KeyHandleOsx(const BackEndOsx& impl, const KeyRefOsx& key);
+
+private:
+ ConstBufferPtr
+ doSign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const final;
+
+ ConstBufferPtr
+ doDecrypt(const uint8_t* cipherText, size_t cipherTextLen) const final;
+
+ ConstBufferPtr
+ doDerivePublicKey() const final;
+
+private:
+ const BackEndOsx& m_impl;
+ KeyRefOsx m_key;
+};
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_TPM_KEY_HANDLE_OSX_HPP
diff --git a/src/security/tpm/key-handle.cpp b/src/security/tpm/key-handle.cpp
new file mode 100644
index 0000000..70553b4
--- /dev/null
+++ b/src/security/tpm/key-handle.cpp
@@ -0,0 +1,62 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 "key-handle.hpp"
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+KeyHandle::~KeyHandle() = default;
+
+ConstBufferPtr
+KeyHandle::sign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const
+{
+ return doSign(digestAlgorithm, buf, size);
+}
+
+ConstBufferPtr
+KeyHandle::decrypt(const uint8_t* cipherText, size_t cipherTextLen) const
+{
+ return doDecrypt(cipherText, cipherTextLen);
+}
+
+ConstBufferPtr
+KeyHandle::derivePublicKey() const
+{
+ return doDerivePublicKey();
+}
+
+void
+KeyHandle::setKeyName(const Name& keyName)
+{
+ m_keyName = keyName;
+}
+
+Name
+KeyHandle::getKeyName() const
+{
+ return m_keyName;
+}
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
diff --git a/src/security/tpm/key-handle.hpp b/src/security/tpm/key-handle.hpp
new file mode 100644
index 0000000..d6faf4d
--- /dev/null
+++ b/src/security/tpm/key-handle.hpp
@@ -0,0 +1,97 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TPM_KEY_HANDLE_HPP
+#define NDN_SECURITY_TPM_KEY_HANDLE_HPP
+
+#include "../../common.hpp"
+#include "../../name.hpp"
+#include "../security-common.hpp"
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+/**
+ * @brief Abstraction of TPM key handle.
+ *
+ * Handle provides an interface to perform crypto operations with a key in TPM.
+ */
+class KeyHandle : noncopyable
+{
+public:
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+public:
+ virtual
+ ~KeyHandle();
+
+ /**
+ * @return a digital signature created on @p buf using this key with @p digestAlgorithm.
+ */
+ ConstBufferPtr
+ sign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const;
+
+ /**
+ * @return plain text content decrypted from @p cipherText using this key.
+ */
+ ConstBufferPtr
+ decrypt(const uint8_t* cipherText, size_t cipherTextLen) const;
+
+ /**
+ * @return the PCKS#8 encoded public key bits derived from this key.
+ */
+ ConstBufferPtr
+ derivePublicKey() const;
+
+ void
+ setKeyName(const Name& keyName);
+
+ Name
+ getKeyName() const;
+
+private:
+ virtual ConstBufferPtr
+ doSign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const = 0;
+
+ virtual ConstBufferPtr
+ doDecrypt(const uint8_t* cipherText, size_t cipherTextLen) const = 0;
+
+ virtual ConstBufferPtr
+ doDerivePublicKey() const = 0;
+
+private:
+ Name m_keyName;
+};
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_TPM_KEY_HANDLE_HPP
diff --git a/src/security/tpm/tpm.cpp b/src/security/tpm/tpm.cpp
new file mode 100644
index 0000000..234c48d
--- /dev/null
+++ b/src/security/tpm/tpm.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 "tpm.hpp"
+#include "back-end.hpp"
+#include "../../encoding/buffer-stream.hpp"
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+Tpm::Tpm(const std::string& scheme, const std::string& location, unique_ptr<BackEnd> backEnd)
+ : m_scheme(scheme)
+ , m_location(location)
+ , m_backEnd(std::move(backEnd))
+{
+}
+
+Tpm::~Tpm() = default;
+
+std::string
+Tpm::getTpmLocator() const
+{
+ return m_scheme + ":" + m_location;
+}
+
+bool
+Tpm::hasKey(const Name& keyName) const
+{
+ return m_backEnd->hasKey(keyName);
+}
+
+Name
+Tpm::createKey(const Name& identityName, const KeyParams& params)
+{
+ switch (params.getKeyType()) {
+ case KeyType::RSA:
+ case KeyType::EC: {
+ unique_ptr<KeyHandle> keyHandle = m_backEnd->createKey(identityName, params);
+ Name keyName = keyHandle->getKeyName();
+ m_keys[keyName] = std::move(keyHandle);
+ return keyName;
+ }
+ default: {
+ BOOST_THROW_EXCEPTION(Error("Fail to create a key pair: Unsupported key type"));
+ }
+ }
+}
+
+void
+Tpm::deleteKey(const Name& keyName)
+{
+ auto it = m_keys.find(keyName);
+ if (it != m_keys.end())
+ m_keys.erase(it);
+
+ m_backEnd->deleteKey(keyName);
+}
+
+ConstBufferPtr
+Tpm::getPublicKey(const Name& keyName) const
+{
+ const KeyHandle* key = findKey(keyName);
+
+ if (key == nullptr)
+ return nullptr;
+ else
+ return key->derivePublicKey();
+}
+
+ConstBufferPtr
+Tpm::sign(const uint8_t* buf, size_t size, const Name& keyName, DigestAlgorithm digestAlgorithm) const
+{
+ const KeyHandle* key = findKey(keyName);
+
+ if (key == nullptr)
+ return nullptr;
+ else
+ return key->sign(digestAlgorithm, buf, size);
+}
+
+ConstBufferPtr
+Tpm::decrypt(const uint8_t* buf, size_t size, const Name& keyName) const
+{
+ const KeyHandle* key = findKey(keyName);
+
+ if (key == nullptr)
+ return nullptr;
+ else
+ return key->decrypt(buf, size);
+}
+
+ConstBufferPtr
+Tpm::exportPrivateKey(const Name& keyName, const char* pw, size_t pwLen)
+{
+ return m_backEnd->exportKey(keyName, pw, pwLen);
+}
+
+bool
+Tpm::importPrivateKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, const char* pw, size_t pwLen)
+{
+ try {
+ m_backEnd->importKey(keyName, pkcs8, pkcs8Len, pw, pwLen);
+ }
+ catch (const BackEnd::Error&) {
+ return false;
+ }
+ return true;
+}
+
+const KeyHandle*
+Tpm::findKey(const Name& keyName) const
+{
+ auto it = m_keys.find(keyName);
+
+ if (it != m_keys.end())
+ return it->second.get();
+
+ unique_ptr<KeyHandle> handle = m_backEnd->getKeyHandle(keyName);
+
+ if (handle != nullptr) {
+ KeyHandle* key = handle.get();
+ m_keys[keyName] = std::move(handle);
+ return key;
+ }
+
+ return nullptr;
+}
+
+} // namespace tpm
+} // namespace security
+} // namespace ndn
diff --git a/src/security/tpm/tpm.hpp b/src/security/tpm/tpm.hpp
new file mode 100644
index 0000000..01b22ae
--- /dev/null
+++ b/src/security/tpm/tpm.hpp
@@ -0,0 +1,207 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TPM_TPM_HPP
+#define NDN_SECURITY_TPM_TPM_HPP
+
+#include "../../common.hpp"
+#include "../security-common.hpp"
+#include "../../name.hpp"
+#include "../key-params.hpp"
+#include "key-handle.hpp"
+#include <unordered_map>
+
+namespace ndn {
+namespace security {
+namespace tpm {
+
+class BackEnd;
+
+/**
+ * @brief represents the front-end of TPM
+ *
+ * The TPM (Trusted Platform Module) stores the private portion of a user's cryptography keys.
+ * The format and location of stored information is indicated by the TpmLocator.
+ * The TPM is designed to work with a PIB (Public Information Base) which stores public keys and
+ * related information such as certificate.
+ *
+ * The TPM also provides functionalities of crypto transformation, such as signing and decryption.
+ *
+ * A TPM consists of a unified front-end interface and a back-end implementation. The front-end
+ * cache the handles of private keys which is provided by the back-end implementation.
+ *
+ * @throw tpm::BackEnd::Error when underlying implementation has non-semantic error.
+ * @throw Tpm::Error when there is an semantic error.
+ */
+class Tpm : noncopyable
+{
+public:
+ friend class KeyChain;
+
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+public:
+ ~Tpm();
+
+ std::string
+ getTpmLocator() const;
+
+ /**
+ * @brief Check if a private key exist
+ *
+ * @param keyName The key name
+ * @return true if the key exists
+ */
+ bool
+ hasKey(const Name& keyName) const;
+
+ /**
+ * @return The public portion of an asymmetric key with name @p name
+ * or nullptr if the key does not exist
+ *
+ * The public key is in PKCS#8 format
+ */
+ ConstBufferPtr
+ getPublicKey(const Name& keyName) const;
+
+ /**
+ * @brief Sign blob using key with name @p keyName with digest @p digestAlgorithm.
+ *
+ * @return The signature, or nullptr if the key does not exist
+ */
+ ConstBufferPtr
+ sign(const uint8_t* buf, size_t size, const Name& keyName, DigestAlgorithm digestAlgorithm) const;
+
+ /**
+ * @brief Decrypt blob using key with name @p keyName.
+ *
+ * @return The signature, or nullptr if the key does not exist
+ */
+ ConstBufferPtr
+ decrypt(const uint8_t* buf, size_t size, const Name& keyName) const;
+
+NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ /*
+ * @brief Create a new TPM instance with the specified @p location
+ *
+ * @param scheme The scheme for the TPM
+ * @param location The location for the TPM
+ * @param impl The back-end implementation
+ */
+ Tpm(const std::string& scheme, const std::string& location, unique_ptr<BackEnd> impl);
+
+ BackEnd*
+ getBackEnd()
+ {
+ return m_backEnd.get();
+ }
+
+ /**
+ * @brief Create key for @p identityName according to @p params.
+ *
+ * The created key is named as: /<identityName>/[keyId]/KEY
+ *
+ * @return the key name
+ * @throws Tpm::Error if the key has already existed or the params is invalid
+ */
+ Name
+ createKey(const Name& identityName, const KeyParams& params);
+
+ /**
+ * @brief Delete a key pair with name @p keyName.
+ */
+ void
+ deleteKey(const Name& keyName);
+
+ /**
+ * @brief Export a private key
+ *
+ * This method will export the private key in encrypted PKCS #8 format if the key exists.
+ *
+ * @param keyName The private key name
+ * @param pw The password to encrypt the private key
+ * @param pwLen The length of the password
+ * @return The encoded private key wrapper or an empty block if the key cannot be exported.
+ */
+ ConstBufferPtr
+ exportPrivateKey(const Name& keyName, const char* pw, size_t pwLen);
+
+ /**
+ * @brief Import a private key
+ *
+ * @param keyName The private key name
+ * @param pkcs8 The private key wrapper
+ * @param pkcs8Len The length of the private key wrapper
+ * @param pw The password to encrypt the private key
+ * @param pwLen The length of the password
+ * @return false if importing fails
+ */
+ bool
+ importPrivateKey(const Name& keyName,
+ const uint8_t* pkcs8, size_t pkcs8Len,
+ const char* pw, size_t pwLen);
+
+ /**
+ * @brief Clear the key cache
+ *
+ * An empty cache can force Tpm to do key lookup in back-end.
+ */
+ void
+ clearKeyCache()
+ {
+ m_keys.clear();
+ }
+
+private:
+
+ /**
+ * @brief Internal KeyHandle lookup
+ *
+ * @return A pointer to the handle of key @p keyName if it exists, otherwise nullptr.
+ */
+ const KeyHandle*
+ findKey(const Name& keyName) const;
+
+private:
+ std::string m_scheme;
+ std::string m_location;
+
+ mutable std::unordered_map<Name, unique_ptr<KeyHandle>> m_keys;
+
+ unique_ptr<BackEnd> m_backEnd;
+};
+
+} // namespace tpm
+
+using tpm::Tpm;
+
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_TPM_TPM_HPP
diff --git a/tests/unit-tests/security/tpm/back-end-wrapper-file.hpp b/tests/unit-tests/security/tpm/back-end-wrapper-file.hpp
new file mode 100644
index 0000000..3e403ce
--- /dev/null
+++ b/tests/unit-tests/security/tpm/back-end-wrapper-file.hpp
@@ -0,0 +1,72 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TESTS_SECURITY_TPM_BACK_END_WRAPPER_FILE_HPP
+#define NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_FILE_HPP
+
+#include "security/tpm/back-end-file.hpp"
+#include <boost/filesystem.hpp>
+
+namespace ndn {
+namespace security {
+namespace tpm {
+namespace tests {
+
+/**
+ * @brief A wrapper of tpm::BackEndFile for unit test template.
+ */
+class BackEndWrapperFile
+{
+public:
+ BackEndWrapperFile()
+ : m_tmpPath(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "TpmFileTest")
+ , m_impl(new BackEndFile(m_tmpPath.string()))
+ {
+ }
+
+ ~BackEndWrapperFile()
+ {
+ boost::filesystem::remove_all(m_tmpPath);
+ }
+
+ BackEnd&
+ getTpm()
+ {
+ return *m_impl;
+ }
+
+ std::string
+ getScheme()
+ {
+ return "tpm-file";
+ }
+
+private:
+ boost::filesystem::path m_tmpPath;
+ unique_ptr<BackEnd> m_impl;
+};
+
+} // namespace tests
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_FILE_HPP
diff --git a/tests/unit-tests/security/tpm/back-end-wrapper-mem.hpp b/tests/unit-tests/security/tpm/back-end-wrapper-mem.hpp
new file mode 100644
index 0000000..ea10295
--- /dev/null
+++ b/tests/unit-tests/security/tpm/back-end-wrapper-mem.hpp
@@ -0,0 +1,64 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TESTS_SECURITY_TPM_BACK_END_WRAPPER_MEM_HPP
+#define NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_MEM_HPP
+
+#include "security/tpm/back-end-mem.hpp"
+
+namespace ndn {
+namespace security {
+namespace tpm {
+namespace tests {
+
+/**
+ * @brief A wrapper of tpm::BackEndMem for unit test template.
+ */
+class BackEndWrapperMem
+{
+public:
+ BackEndWrapperMem()
+ {
+ m_impl = unique_ptr<BackEnd>(new BackEndMem);
+ }
+
+ BackEnd&
+ getTpm()
+ {
+ return *m_impl;
+ }
+
+ std::string
+ getScheme()
+ {
+ return "tpm-memory";
+ }
+
+private:
+ unique_ptr<BackEnd> m_impl;
+};
+
+} // namespace tests
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_MEM_HPP
diff --git a/tests/unit-tests/security/tpm/back-end-wrapper-osx.hpp b/tests/unit-tests/security/tpm/back-end-wrapper-osx.hpp
new file mode 100644
index 0000000..d02b717
--- /dev/null
+++ b/tests/unit-tests/security/tpm/back-end-wrapper-osx.hpp
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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_TESTS_SECURITY_TPM_BACK_END_WRAPPER_OSX_HPP
+#define NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_OSX_HPP
+
+#include "security/tpm/back-end-osx.hpp"
+#include "security/tpm/key-handle-osx.hpp"
+#include <Availability.h>
+
+namespace ndn {
+namespace security {
+namespace tpm {
+namespace tests {
+
+/**
+ * @brief A wrapper of tpm::BackEndOsx for unit test template.
+ */
+class BackEndWrapperOsx
+{
+public:
+ BackEndWrapperOsx()
+ {
+ std::string oldHOME;
+ if (std::getenv("OLD_HOME"))
+ oldHOME = std::getenv("OLD_HOME");
+
+ if (std::getenv("HOME"))
+ m_HOME = std::getenv("HOME");
+
+ if (!oldHOME.empty())
+ setenv("HOME", oldHOME.c_str(), 1);
+ else
+ unsetenv("HOME");
+
+ m_impl = unique_ptr<BackEnd>(new BackEndOsx);
+ }
+
+ ~BackEndWrapperOsx()
+ {
+ if (!m_HOME.empty())
+ setenv("HOME", m_HOME.c_str(), 1);
+ else
+ unsetenv("HOME");
+ }
+
+ BackEnd&
+ getTpm()
+ {
+ return *m_impl;
+ }
+
+ std::string
+ getScheme()
+ {
+ return "tpm-osxkeychain";
+ }
+
+private:
+ std::string m_HOME;
+ unique_ptr<BackEnd> m_impl;
+};
+
+} // namespace tests
+} // namespace tpm
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_OSX_HPP
diff --git a/tests/unit-tests/security/tpm/back-end.t.cpp b/tests/unit-tests/security/tpm/back-end.t.cpp
new file mode 100644
index 0000000..01b9e6c
--- /dev/null
+++ b/tests/unit-tests/security/tpm/back-end.t.cpp
@@ -0,0 +1,268 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 "security/tpm/back-end.hpp"
+#include "security/tpm/back-end-mem.hpp"
+#include "security/tpm/key-handle.hpp"
+#include "security/tpm/tpm.hpp"
+#include "security/transform.hpp"
+#include "security/transform/public-key.hpp"
+#include "security/transform/private-key.hpp"
+#include "encoding/buffer-stream.hpp"
+#include "security/pib/key.hpp"
+
+#include "back-end-wrapper-file.hpp"
+#include "back-end-wrapper-mem.hpp"
+#ifdef NDN_CXX_HAVE_OSX_SECURITY
+#include "back-end-wrapper-osx.hpp"
+#endif // NDN_CXX_HAVE_OSX_SECURITY
+#include "boost-test.hpp"
+
+#include <boost/mpl/list.hpp>
+#include <set>
+
+namespace ndn {
+namespace security {
+namespace tpm {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(Tpm)
+BOOST_AUTO_TEST_SUITE(TestBackEnd)
+
+using tpm::Tpm;
+
+typedef boost::mpl::list<
+#ifdef NDN_CXX_HAVE_OSX_SECURITY
+ BackEndWrapperOsx,
+#endif // NDN_CXX_HAVE_OSX_SECURITY
+ BackEndWrapperMem,
+ BackEndWrapperFile
+ > TestBackEnds;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(KeyManagement, T, TestBackEnds)
+{
+ T wrapper;
+ BackEnd& tpm = wrapper.getTpm();
+
+ Name identity("/Test/KeyName");
+ name::Component keyId("1");
+ Name keyName = v2::constructKeyName(identity, keyId);
+
+ // key should not exist
+ BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
+ BOOST_CHECK(tpm.getKeyHandle(keyName) == nullptr);
+
+ // create key, should exist
+ BOOST_CHECK(tpm.createKey(identity, RsaKeyParams(keyId)) != nullptr);
+ BOOST_CHECK(tpm.hasKey(keyName));
+ BOOST_CHECK(tpm.getKeyHandle(keyName) != nullptr);
+
+ // create a key with the same name, should throw error
+ BOOST_CHECK_THROW(tpm.createKey(identity, RsaKeyParams(keyId)), Tpm::Error);
+
+ // delete key, should not exist
+ tpm.deleteKey(keyName);
+ BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
+ BOOST_CHECK(tpm.getKeyHandle(keyName) == nullptr);
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(RsaSigning, T, TestBackEnds)
+{
+ T wrapper;
+ BackEnd& tpm = wrapper.getTpm();
+
+ // create an rsa key
+ Name identity("/Test/KeyName");
+
+ unique_ptr<KeyHandle> key = tpm.createKey(identity, RsaKeyParams());
+ Name keyName = key->getKeyName();
+
+ const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+ Block sigBlock(tlv::SignatureValue, key->sign(DigestAlgorithm::SHA256, content, sizeof(content)));
+
+ transform::PublicKey pubKey;
+ ConstBufferPtr pubKeyBits = key->derivePublicKey();
+ pubKey.loadPkcs8(pubKeyBits->buf(), pubKeyBits->size());
+
+ bool result;
+ {
+ using namespace transform;
+ bufferSource(content, sizeof(content)) >> verifierFilter(DigestAlgorithm::SHA256, pubKey,
+ sigBlock.value(), sigBlock.value_size())
+ >> boolSink(result);
+ }
+ BOOST_CHECK_EQUAL(result, true);
+
+ tpm.deleteKey(keyName);
+ BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(RsaDecryption, T, TestBackEnds)
+{
+ T wrapper;
+ BackEnd& tpm = wrapper.getTpm();
+
+ // create an rsa key
+ Name identity("/Test/KeyName");
+
+ unique_ptr<KeyHandle> key = tpm.createKey(identity, RsaKeyParams());
+ Name keyName = key->getKeyName();
+
+ const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+
+ transform::PublicKey pubKey;
+ ConstBufferPtr pubKeyBits = key->derivePublicKey();
+ pubKey.loadPkcs8(pubKeyBits->buf(), pubKeyBits->size());
+
+ ConstBufferPtr cipherText = pubKey.encrypt(content, sizeof(content));
+
+ ConstBufferPtr plainText = key->decrypt(cipherText->buf(), cipherText->size());
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(content, content + sizeof(content),
+ plainText->begin(), plainText->end());
+
+ tpm.deleteKey(keyName);
+ BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(EcdsaSigning, T, TestBackEnds)
+{
+ T wrapper;
+ BackEnd& tpm = wrapper.getTpm();
+
+ // create an ecdsa key
+ Name identity("/Test/Ecdsa/KeyName");
+
+ unique_ptr<KeyHandle> key = tpm.createKey(identity, EcdsaKeyParams());
+ Name ecdsaKeyName = key->getKeyName();
+
+ const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+ Block sigBlock(tlv::SignatureValue, key->sign(DigestAlgorithm::SHA256, content, sizeof(content)));
+
+ transform::PublicKey pubKey;
+ ConstBufferPtr pubKeyBits = key->derivePublicKey();
+ pubKey.loadPkcs8(pubKeyBits->buf(), pubKeyBits->size());
+
+ bool result;
+ {
+ using namespace transform;
+ bufferSource(content, sizeof(content)) >> verifierFilter(DigestAlgorithm::SHA256, pubKey,
+ sigBlock.value(), sigBlock.value_size())
+ >> boolSink(result);
+ }
+ BOOST_CHECK_EQUAL(result, true);
+
+ tpm.deleteKey(ecdsaKeyName);
+ BOOST_CHECK_EQUAL(tpm.hasKey(ecdsaKeyName), false);
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(ImportExport, T, TestBackEnds)
+{
+ std::string privateKeyPkcs1 =
+ "MIIEpAIBAAKCAQEAw0WM1/WhAxyLtEqsiAJgWDZWuzkYpeYVdeeZcqRZzzfRgBQT\n"
+ "sNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobws3iigohnM9yTK+KKiayPhIAm/+5H\n"
+ "GT6SgFJhYhqo1/upWdueojil6RP4/AgavHhopxlAVbk6G9VdVnlQcQ5Zv0OcGi73\n"
+ "c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9gZwIL5PuE9BiO6I39cL9z7EK1SfZh\n"
+ "OWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA9rH58ynaAix0tcR/nBMRLUX+e3rU\n"
+ "RHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0ywIDAQABAoIBADQkckOIl4IZMUTn\n"
+ "W8LFv6xOdkJwMKC8G6bsPRFbyY+HvC2TLt7epSvfS+f4AcYWaOPcDu2E49vt2sNr\n"
+ "cASly8hgwiRRAB3dHH9vcsboiTo8bi2RFvMqvjv9w3tK2yMxVDtmZamzrrnaV3YV\n"
+ "Q+5nyKo2F/PMDjQ4eUAKDOzjhBuKHsZBTFnA1MFNI+UKj5X4Yp64DFmKlxTX/U2b\n"
+ "wzVywo5hzx2Uhw51jmoLls4YUvMJXD0wW5ZtYRuPogXvXb/of9ef/20/wU11WFKg\n"
+ "Xb4gfR8zUXaXS1sXcnVm3+24vIs9dApUwykuoyjOqxWqcHRec2QT2FxVGkFEraze\n"
+ "CPa4rMECgYEA5Y8CywomIcTgerFGFCeMHJr8nQGqY2V/owFb3k9maczPnC9p4a9R\n"
+ "c5szLxA9FMYFxurQZMBWSEG2JS1HR2mnjigx8UKjYML/A+rvvjZOMe4M6Sy2ggh4\n"
+ "SkLZKpWTzjTe07ByM/j5v/SjNZhWAG7sw4/LmPGRQkwJv+KZhGojuOkCgYEA2cOF\n"
+ "T6cJRv6kvzTz9S0COZOVm+euJh/BXp7oAsAmbNfOpckPMzqHXy8/wpdKl6AAcB57\n"
+ "OuztlNfV1D7qvbz7JuRlYwQ0cEfBgbZPcz1p18HHDXhwn57ZPb8G33Yh9Omg0HNA\n"
+ "Imb4LsVuSqxA6NwSj7cpRekgTedrhLFPJ+Ydb5MCgYEAsM3Q7OjILcIg0t6uht9e\n"
+ "vrlwTsz1mtCV2co2I6crzdj9HeI2vqf1KAElDt6G7PUHhglcr/yjd8uEqmWRPKNX\n"
+ "ddnnfVZB10jYeP/93pac6z/Zmc3iU4yKeUe7U10ZFf0KkiiYDQd59CpLef/2XScS\n"
+ "HB0oRofnxRQjfjLc4muNT+ECgYEAlcDk06MOOTly+F8lCc1bA1dgAmgwFd2usDBd\n"
+ "Y07a3e0HGnGLN3Kfl7C5i0tZq64HvxLnMd2vgLVxQlXGPpdQrC1TH+XLXg+qnlZO\n"
+ "ivSH7i0/gx75bHvj75eH1XK65V8pDVDEoSPottllAIs21CxLw3N1ObOZWJm2EfmR\n"
+ "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n"
+ "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n"
+ "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n";
+
+ T wrapper;
+ BackEnd& tpm = wrapper.getTpm();
+
+ Name keyName("/Test/KeyName/KEY/1");
+
+ tpm.deleteKey(keyName);
+ BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
+
+ transform::PrivateKey sKey;
+ BOOST_REQUIRE_NO_THROW(sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(privateKeyPkcs1.c_str()),
+ privateKeyPkcs1.size()));
+
+ std::string password("password");
+
+ OBufferStream os;
+ sKey.savePkcs8(os, password.c_str(), password.size());
+ ConstBufferPtr privateKeyBuffer = os.buf();
+
+ BOOST_REQUIRE_NO_THROW(tpm.importKey(keyName,
+ privateKeyBuffer->buf(), privateKeyBuffer->size(),
+ password.c_str(), password.size()));
+ BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true);
+
+ ConstBufferPtr exportedKey = tpm.exportKey(keyName, password.c_str(), password.size());
+ BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true);
+
+ transform::PrivateKey sKey2;
+ sKey2.loadPkcs8(exportedKey->buf(), exportedKey->size(), password.c_str(), password.size());
+ OBufferStream os2;
+ sKey.savePkcs1Base64(os2);
+ ConstBufferPtr pkcs1Buffer = os2.buf();
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(privateKeyPkcs1.begin(), privateKeyPkcs1.end(),
+ pkcs1Buffer->begin(), pkcs1Buffer->end());
+
+ tpm.deleteKey(keyName);
+ BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
+}
+
+BOOST_AUTO_TEST_CASE(RandomKeyId)
+{
+ BackEndWrapperMem wrapper;
+ BackEnd& tpm = wrapper.getTpm();
+ Name identity("/Test/KeyName");
+
+ std::set<Name> keyNames;
+ for (int i = 0; i < 100; i++) {
+ auto key = tpm.createKey(identity, RsaKeyParams());
+ Name keyName = key->getKeyName();
+ tpm.deleteKey(keyName);
+ BOOST_CHECK(keyNames.insert(keyName).second);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestBackEnd
+BOOST_AUTO_TEST_SUITE_END() // Tpm
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace tpm
+} // namespace security
+} // namespace ndn