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