security: Export/Import Identity from/into KeyChain
Change-Id: I757f51f1408cf08b9fb1b1927834889fd29c0231
diff --git a/src/encoding/tlv-security.hpp b/src/encoding/tlv-security.hpp
new file mode 100644
index 0000000..1a522ce
--- /dev/null
+++ b/src/encoding/tlv-security.hpp
@@ -0,0 +1,29 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef NDN_TLV_SECURITY_HPP
+#define NDN_TLV_SECURITY_HPP
+
+#include "tlv.hpp"
+
+namespace ndn {
+namespace tlv {
+namespace security {
+
+enum {
+ IdentityPackage = 128,
+ KeyPackage = 129,
+ CertificatePackage = 130
+};
+
+} // namespace security
+} // namespace tlv
+} // namespace ndn
+
+#endif // NDN_TLV_SECURITY_HPP
diff --git a/src/security/key-chain.hpp b/src/security/key-chain.hpp
index d9d475d..981dfce 100644
--- a/src/security/key-chain.hpp
+++ b/src/security/key-chain.hpp
@@ -13,6 +13,7 @@
#include "public-key.hpp"
#include "signature-sha256-with-rsa.hpp"
#include "../interest.hpp"
+#include "../encoding/tlv-security.hpp"
//PublicInfo
#include "sec-public-info-sqlite3.hpp"
@@ -59,7 +60,7 @@
if(certName.empty())
{
- ptr_lib::shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
+ shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
Info::addCertificateAsIdentityDefault(*selfCert);
certName = selfCert->getName();
}
@@ -105,7 +106,7 @@
* @param notAfter The notAfter vallue in validity field of the generated certificate.
* @return The name of generated identity certificate.
*/
- ptr_lib::shared_ptr<IdentityCertificate>
+ shared_ptr<IdentityCertificate>
createIdentityCertificate
(const Name& certificatePrefix,
const Name& signerCertificateName,
@@ -114,11 +115,11 @@
{
Name keyName = getKeyNameFromCertificatePrefix(certificatePrefix);
- ptr_lib::shared_ptr<PublicKey> pubKey = Info::getPublicKey(keyName);
+ shared_ptr<PublicKey> pubKey = Info::getPublicKey(keyName);
if (!pubKey)
throw InfoError("Requested public key [" + keyName.toUri() + "] doesn't exist");
- ptr_lib::shared_ptr<IdentityCertificate> certificate =
+ shared_ptr<IdentityCertificate> certificate =
createIdentityCertificate(certificatePrefix,
*pubKey,
signerCertificateName,
@@ -139,7 +140,7 @@
* @param notAfter The notAfter vallue in validity field of the generated certificate.
* @return The generated identity certificate.
*/
- ptr_lib::shared_ptr<IdentityCertificate>
+ shared_ptr<IdentityCertificate>
createIdentityCertificate
(const Name& certificatePrefix,
const PublicKey& publicKey,
@@ -147,7 +148,7 @@
const MillisecondsSince1970& notBefore,
const MillisecondsSince1970& notAfter)
{
- ptr_lib::shared_ptr<IdentityCertificate> certificate (new IdentityCertificate());
+ shared_ptr<IdentityCertificate> certificate (new IdentityCertificate());
Name keyName = getKeyNameFromCertificatePrefix(certificatePrefix);
Name certificateName = certificatePrefix;
@@ -243,7 +244,7 @@
Signature
sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
{
- ptr_lib::shared_ptr<IdentityCertificate> cert = Info::getCertificate(certificateName);
+ shared_ptr<IdentityCertificate> cert = Info::getCertificate(certificateName);
if (!static_cast<bool>(cert))
throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
@@ -306,18 +307,18 @@
* @param keyName The name of the public key.
* @return The generated certificate.
*/
- ptr_lib::shared_ptr<IdentityCertificate>
+ shared_ptr<IdentityCertificate>
selfSign(const Name& keyName)
{
if(keyName.empty())
throw InfoError("Incorrect key name: " + keyName.toUri());
- ptr_lib::shared_ptr<IdentityCertificate> certificate = ptr_lib::make_shared<IdentityCertificate>();
+ shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
Name certificateName = keyName.getPrefix(-1);
certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
- ptr_lib::shared_ptr<PublicKey> pubKey = Info::getPublicKey(keyName);
+ shared_ptr<PublicKey> pubKey = Info::getPublicKey(keyName);
if (!pubKey)
throw InfoError("Requested public key [" + keyName.toUri() + "] doesn't exist");
@@ -366,7 +367,7 @@
}
void
- deleteIdentity (const Name &identity)
+ deleteIdentity (const Name& identity)
{
if(Info::getDefaultIdentity() == identity)
return;
@@ -382,6 +383,71 @@
Tpm::deleteKeyPairInTpm(*it);
}
+ Block
+ exportIdentity(const Name& identity, bool inTerminal = true, std::string passwordStr = "")
+ {
+ if (!Info::doesIdentityExist(identity))
+ throw InfoError("Identity does not exist!");
+
+ Name keyName = Info::getDefaultKeyNameForIdentity(identity);
+
+ if(keyName.empty())
+ throw InfoError("Default key does not exist!");
+
+ ConstBufferPtr pkcs8 = Tpm::exportPrivateKeyPkcs8FromTpm(keyName, inTerminal, passwordStr);
+ Block wireKey(tlv::security::KeyPackage, pkcs8);
+
+ Name certName = Info::getDefaultCertificateNameForKey(keyName);
+
+ if(certName.empty())
+ {
+ shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
+ Info::addCertificateAsIdentityDefault(*selfCert);
+ certName = selfCert->getName();
+ }
+
+ shared_ptr<IdentityCertificate> cert = Info::getCertificate(certName);
+ Block wireCert(tlv::security::CertificatePackage, cert->wireEncode());
+
+ Block wire(tlv::security::IdentityPackage);
+ wire.push_back(wireCert);
+ wire.push_back(wireKey);
+
+ return wire;
+ }
+
+ void
+ importIdentity(const Block& block, bool inTerminal = true, std::string passwordStr = "")
+ {
+ block.parse();
+
+ Data data;
+ data.wireDecode(block.get(tlv::security::CertificatePackage).blockFromValue());
+ shared_ptr<IdentityCertificate> cert = make_shared<IdentityCertificate>(data);
+
+ Name keyName = IdentityCertificate::certificateNameToPublicKeyName(cert->getName());
+ Name identity = keyName.getPrefix(-1);
+
+ // Add identity
+ if (Info::doesIdentityExist(identity))
+ deleteIdentity(identity);
+ Info::addIdentity(identity);
+
+ // Add key
+ Block wireKey = block.get(tlv::security::KeyPackage);
+ if (Tpm::doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
+ deleteKey(keyName);
+ Tpm::importPrivateKeyPkcs8IntoTpm(keyName, wireKey.value(), wireKey.value_size(), inTerminal, passwordStr);
+ shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
+ Info::addPublicKey(keyName, KEY_TYPE_RSA, *pubKey); // HACK! We should set key type according to the pkcs8 info.
+ Info::setDefaultKeyNameForIdentity(keyName);
+
+ // Add cert
+ if (Info::doesCertificateExist(cert->getName()))
+ deleteCertificate(cert->getName());
+ Info::addCertificateAsIdentityDefault(*cert);
+ }
+
private:
@@ -428,7 +494,7 @@
Tpm::generateKeyPairInTpm(keyName.toUri(), keyType, keySize);
- ptr_lib::shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
+ shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
Info::addPublicKey(keyName, keyType, *pubKey);
return keyName;
diff --git a/src/security/sec-tpm-file.cpp b/src/security/sec-tpm-file.cpp
index 47cf83b..78d7ef7 100644
--- a/src/security/sec-tpm-file.cpp
+++ b/src/security/sec-tpm-file.cpp
@@ -22,12 +22,15 @@
#include <cryptopp/sha.h>
#include <cryptopp/pssr.h>
#include <cryptopp/modes.h>
+#include <cryptopp/pwdbased.h>
+#include <cryptopp/sha.h>
+#include <cryptopp/des.h>
#include <sys/types.h>
#include <sys/stat.h>
-using namespace CryptoPP;
-using namespace ndn;
+#include <algorithm>
+
using namespace std;
namespace ndn
@@ -45,6 +48,35 @@
boost::filesystem::create_directories (m_keystorePath);
}
+ boost::filesystem::path
+ nameTransform(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 = nameTransform(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;
};
@@ -64,8 +96,7 @@
if(doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
throw Error("private key exists");
- string keyFileName = nameTransform(keyURI, "");
- maintainMapping(keyURI, keyFileName);
+ string keyFileName = m_impl->maintainMapping(keyURI);
try{
switch(keyType){
@@ -104,8 +135,8 @@
void
SecTpmFile::deleteKeyPairInTpm(const Name &keyName)
{
- boost::filesystem::path publicKeyPath(nameTransform(keyName.toUri(), ".pub"));
- boost::filesystem::path privateKeyPath(nameTransform(keyName.toUri(), ".pri"));
+ boost::filesystem::path publicKeyPath(m_impl->nameTransform(keyName.toUri(), ".pub"));
+ boost::filesystem::path privateKeyPath(m_impl->nameTransform(keyName.toUri(), ".pri"));
if(boost::filesystem::exists(publicKeyPath))
boost::filesystem::remove(publicKeyPath);
@@ -114,23 +145,61 @@
boost::filesystem::remove(privateKeyPath);
}
-ptr_lib::shared_ptr<PublicKey>
+shared_ptr<PublicKey>
SecTpmFile::getPublicKeyFromTpm(const Name & keyName)
{
string keyURI = keyName.toUri();
if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
- throw Error("public key doesn't exists");
+ return shared_ptr<PublicKey>();
- string publicKeyFileName = nameTransform(keyURI, ".pub");
- std::ostringstream os;
+ ostringstream os;
try{
- FileSource(publicKeyFileName.c_str(), true, new Base64Decoder(new FileSink(os)));
+ using namespace CryptoPP;
+ FileSource(m_impl->nameTransform(keyURI, ".pub").string().c_str(), true, new Base64Decoder(new FileSink(os)));
}catch(const CryptoPP::Exception& e){
- throw Error(e.what());
+ return shared_ptr<PublicKey>();
}
- return ptr_lib::make_shared<PublicKey>(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
+ return make_shared<PublicKey>(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
+}
+
+ConstBufferPtr
+SecTpmFile::exportPrivateKeyPkcs1FromTpm(const Name& keyName)
+{
+ OBufferStream privateKeyOs;
+ CryptoPP::FileSource(m_impl->nameTransform(keyName.toUri(), ".pri").string().c_str(), true,
+ new CryptoPP::Base64Decoder(new CryptoPP::FileSink(privateKeyOs)));
+
+ return privateKeyOs.buf();
+}
+
+bool
+SecTpmFile::importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+ try{
+ string keyFileName = m_impl->maintainMapping(keyName.toUri());
+ keyFileName.append(".pri");
+ CryptoPP::StringSource(buf, size, true,
+ new CryptoPP::Base64Encoder(new CryptoPP::FileSink(keyFileName.c_str())));
+ return true;
+ }catch(...){
+ return false;
+ }
+}
+
+bool
+SecTpmFile::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+ try{
+ string keyFileName = m_impl->maintainMapping(keyName.toUri());
+ keyFileName.append(".pub");
+ CryptoPP::StringSource(buf, size, true,
+ new CryptoPP::Base64Encoder(new CryptoPP::FileSink(keyFileName.c_str())));
+ return true;
+ }catch(...){
+ return false;
+ }
}
Block
@@ -147,8 +216,7 @@
//Read private key
ByteQueue bytes;
- string privateKeyFileName = nameTransform(keyURI, ".pri");
- FileSource file(privateKeyFileName.c_str(), true, new Base64Decoder);
+ FileSource file(m_impl->nameTransform(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
file.TransferTo(bytes);
bytes.MessageEnd();
RSA::PrivateKey privateKey;
@@ -189,8 +257,7 @@
//Read private key
ByteQueue bytes;
- string privateKeyFileName = nameTransform(keyURI, ".pri");
- FileSource file(privateKeyFileName.c_str(), true, new Base64Decoder);
+ FileSource file(m_impl->nameTransform(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
file.TransferTo(bytes);
bytes.MessageEnd();
RSA::PrivateKey privateKey;
@@ -214,7 +281,7 @@
// try{
// string keyBits;
- // string symKeyFileName = nameTransform(keyURI, ".key");
+ // string symKeyFileName = m_impl->nameTransform(keyURI, ".key");
// FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
// using CryptoPP::AES;
@@ -251,8 +318,7 @@
//Read private key
ByteQueue bytes;
- string publicKeyFileName = nameTransform(keyURI, ".pub");
- FileSource file(publicKeyFileName.c_str(), true, new Base64Decoder);
+ FileSource file(m_impl->nameTransform(keyURI, ".pub").string().c_str(), true, new Base64Decoder);
file.TransferTo(bytes);
bytes.MessageEnd();
RSA::PublicKey publicKey;
@@ -276,7 +342,7 @@
// try{
// string keyBits;
- // string symKeyFileName = nameTransform(keyURI, ".key");
+ // string symKeyFileName = m_impl->nameTransform(keyURI, ".key");
// FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
// using CryptoPP::AES;
@@ -305,8 +371,7 @@
if(doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
throw Error("symmetric key exists");
- string keyFileName = nameTransform(keyURI, "");
- maintainMapping(keyURI, keyFileName);
+ string keyFileName = m_impl->maintainMapping(keyURI);
string symKeyFileName = keyFileName + ".key";
try{
@@ -338,27 +403,21 @@
string keyURI = keyName.toUri();
if (keyClass == KEY_CLASS_PUBLIC)
{
- string publicKeyName = SecTpmFile::nameTransform(keyURI, ".pub");
- fstream fin(publicKeyName.c_str(),ios::in);
- if (fin)
+ if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".pub")))
return true;
else
return false;
}
if (keyClass == KEY_CLASS_PRIVATE)
{
- string privateKeyName = SecTpmFile::nameTransform(keyURI, ".pri");
- fstream fin(privateKeyName.c_str(),ios::in);
- if (fin)
+ if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".pri")))
return true;
else
return false;
}
if (keyClass == KEY_CLASS_SYMMETRIC)
{
- string symmetricKeyName = SecTpmFile::nameTransform(keyURI, ".key");
- fstream fin(symmetricKeyName.c_str(),ios::in);
- if (fin)
+ if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".key")))
return true;
else
return false;
@@ -366,38 +425,6 @@
return false;
}
-std::string SecTpmFile::nameTransform(const string &keyName, const string &extension)
-{
- std::string digest;
- CryptoPP::SHA256 hash;
- CryptoPP::StringSource foo(keyName, true,
- new CryptoPP::HashFilter(hash,
- new CryptoPP::Base64Encoder (new CryptoPP::StringSink(digest))
- )
- );
- boost::algorithm::trim(digest);
- for (std::string::iterator ch = digest.begin(); ch != digest.end(); ch++)
- {
- if (*ch == '/')
- {
- *ch = '%';
- }
- }
-
- return (m_impl->m_keystorePath / (digest + extension)).string();
-}
-
-void
-SecTpmFile::maintainMapping(string str1, string str2)
-{
- std::ofstream outfile;
- string dirFile = (m_impl->m_keystorePath / "mapping.txt").string();
-
- outfile.open(dirFile.c_str(), std::ios_base::app);
- outfile << str1 << ' ' << str2 << '\n';
- outfile.close();
-}
-
bool
SecTpmFile::generateRandomBlock(uint8_t* res, size_t size)
{
diff --git a/src/security/sec-tpm-file.hpp b/src/security/sec-tpm-file.hpp
index 7a92ec1..f1e6fa8 100644
--- a/src/security/sec-tpm-file.hpp
+++ b/src/security/sec-tpm-file.hpp
@@ -106,15 +106,22 @@
virtual bool
doesKeyExistInTpm(const Name& keyName, KeyClass keyClass);
- std::string
- nameTransform(const std::string &keyName, const std::string &extension);
virtual bool
generateRandomBlock(uint8_t* res, size_t size);
-private:
- void
- maintainMapping(std::string str1, std::string str2);
+protected:
+ /******************************
+ * From TrustedPlatformModule *
+ ******************************/
+ virtual ConstBufferPtr
+ exportPrivateKeyPkcs1FromTpm(const Name& keyName);
+
+ virtual bool
+ importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size);
+ virtual bool
+ importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size);
+
private:
class Impl;
shared_ptr<Impl> m_impl;
diff --git a/src/security/sec-tpm-memory.cpp b/src/security/sec-tpm-memory.cpp
index a115d48..231a195 100644
--- a/src/security/sec-tpm-memory.cpp
+++ b/src/security/sec-tpm-memory.cpp
@@ -76,6 +76,24 @@
throw Error("SecTpmMemory::deleteKeyPairInTpm not implemented");
}
+ConstBufferPtr
+SecTpmMemory::exportPrivateKeyPkcs1FromTpm(const Name& keyName)
+{
+ throw Error("SecTpmMemory::exportPrivateKeyPkcs1FromTpm is not implemented");
+}
+
+bool
+SecTpmMemory::importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+ throw Error("SecTpmMemory::importPrivateKeyPkcs1IntoTpm is not implemented");
+}
+
+bool
+SecTpmMemory::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+ throw Error("SecTpmMemory::importPublicKeyPkcs1IntoTpm is not implemented");
+}
+
ptr_lib::shared_ptr<PublicKey>
SecTpmMemory::getPublicKeyFromTpm(const Name& keyName)
{
diff --git a/src/security/sec-tpm-memory.hpp b/src/security/sec-tpm-memory.hpp
index 69f5052..b24246b 100644
--- a/src/security/sec-tpm-memory.hpp
+++ b/src/security/sec-tpm-memory.hpp
@@ -29,24 +29,10 @@
virtual
~SecTpmMemory();
- /**
- * Set the public and private key for the keyName.
- * @param keyName The key name.
- * @param publicKeyDer The public key DER byte array.
- * @param publicKeyDerLength The length of publicKeyDer.
- * @param privateKeyDer The private key DER byte array.
- * @param privateKeyDerLength The length of privateKeyDer.
- */
- void setKeyPairForKeyName(const Name& keyName,
- uint8_t *publicKeyDer, size_t publicKeyDerLength,
- uint8_t *privateKeyDer, size_t privateKeyDerLength);
-
- /**
- * Generate a pair of asymmetric keys.
- * @param keyName The name of the key pair.
- * @param keyType The type of the key pair, e.g. KEY_TYPE_RSA.
- * @param keySize The size of the key pair.
- */
+ /******************************
+ * From TrustedPlatformModule *
+ ******************************/
+
virtual void
generateKeyPairInTpm(const Name& keyName, KeyType keyType, int keySize);
@@ -108,16 +94,41 @@
generateSymmetricKeyInTpm(const Name& keyName, KeyType keyType, int keySize);
virtual bool
+ doesKeyExistInTpm(const Name& keyName, KeyClass keyClass);
+
+ virtual bool
generateRandomBlock(uint8_t* res, size_t size);
+ /******************************
+ * SecTpmMemory specific *
+ ******************************/
+
/**
- * Check if a particular key exists.
- * @param keyName The name of the key.
- * @param keyClass The class of the key, e.g. KEY_CLASS_PUBLIC, KEY_CLASS_PRIVATE, or KEY_CLASS_SYMMETRIC.
- * @return True if the key exists, otherwise false.
+ * @brief Set the public and private key for the keyName.
+ *
+ * @param keyName The key name.
+ * @param publicKeyDer The public key DER byte array.
+ * @param publicKeyDerLength The length of publicKeyDer.
+ * @param privateKeyDer The private key DER byte array.
+ * @param privateKeyDerLength The length of privateKeyDer.
*/
+ void setKeyPairForKeyName(const Name& keyName,
+ uint8_t *publicKeyDer, size_t publicKeyDerLength,
+ uint8_t *privateKeyDer, size_t privateKeyDerLength);
+
+protected:
+ /******************************
+ * From TrustedPlatformModule *
+ ******************************/
+ virtual ConstBufferPtr
+ exportPrivateKeyPkcs1FromTpm(const Name& keyName);
+
virtual bool
- doesKeyExistInTpm(const Name& keyName, KeyClass keyClass);
+ importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size);
+
+ virtual bool
+ importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size);
+
private:
class RsaPrivateKey;
diff --git a/src/security/sec-tpm-osx.cpp b/src/security/sec-tpm-osx.cpp
index 3f14f43..d85636d 100644
--- a/src/security/sec-tpm-osx.cpp
+++ b/src/security/sec-tpm-osx.cpp
@@ -11,6 +11,8 @@
#include "security/public-key.hpp"
#include "util/logging.hpp"
+#include <cryptopp/files.h>
+#include <cryptopp/asn.h>
#include <pwd.h>
#include <unistd.h>
@@ -92,9 +94,6 @@
long
getDigestSize(DigestAlgorithm digestAlgo);
- bool
- getPassWord(string& password, string target);
-
///////////////////////////////////////////////
// everything here is public, including data //
///////////////////////////////////////////////
@@ -115,7 +114,7 @@
string keyChainName("ndnroot.keychain");
cerr << "No Default KeyChain! Create " << keyChainName << ":" << endl;
string password;
- while(!m_impl->getPassWord(password, keyChainName))
+ while(!getPassWord(password, keyChainName))
{
cerr << "Password mismatch!" << endl;
}
@@ -226,25 +225,17 @@
void
SecTpmOsx::deleteKeyPairInTpm(const Name &keyName)
{
- string keyNameUri = keyName.toUri();
-
CFStringRef keyLabel = CFStringCreateWithCString(NULL,
- keyNameUri.c_str(),
+ keyName.toUri().c_str(),
kCFStringEncodingUTF8);
-
- CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
- 5,
- &kCFTypeDictionaryKeyCallBacks,
- NULL);
- CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
- CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
- CFDictionaryAddValue(attrDict, kSecMatchLimit, kSecMatchLimitAll);
+ CFMutableDictionaryRef searchDict =
+ CFDictionaryCreateMutable(NULL, 5, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- OSStatus res = SecItemDelete((CFDictionaryRef) attrDict);
-
- if(res != errSecSuccess)
- _LOG_DEBUG("Fail to find the key!");
+ CFDictionaryAddValue(searchDict, kSecClass, kSecClassKey);
+ CFDictionaryAddValue(searchDict, kSecAttrLabel, keyLabel);
+ CFDictionaryAddValue(searchDict, kSecMatchLimit, kSecMatchLimitAll);
+ SecItemDelete(searchDict);
}
void
@@ -293,7 +284,181 @@
NULL,
&exportedKey);
- return ptr_lib::make_shared<PublicKey>(CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
+ shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
+ CFRelease(exportedKey);
+ return key;
+}
+
+ConstBufferPtr
+SecTpmOsx::exportPrivateKeyPkcs1FromTpm(const Name& keyName)
+{
+ using namespace CryptoPP;
+
+ SecKeychainItemRef privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
+ CFDataRef exportedKey;
+ OSStatus res = SecItemExport(privateKey,
+ kSecFormatOpenSSL,
+ 0,
+ NULL,
+ &exportedKey);
+
+ if(res != errSecSuccess)
+ {
+ return shared_ptr<Buffer>();
+ }
+
+ OBufferStream pkcs1Os;
+ FileSink sink(pkcs1Os);
+
+ uint32_t version = 0;
+ OID algorithm("1.2.840.113549.1.1.1");
+ 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);
+ DEREncodeNull(privateKeyAlgorithm);
+ }
+ privateKeyAlgorithm.MessageEnd();
+ DEREncodeOctetString(privateKeyInfo, CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
+ }
+ privateKeyInfo.MessageEnd();
+
+ CFRelease(exportedKey);
+ return pkcs1Os.buf();
+}
+
+bool
+SecTpmOsx::importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+ using namespace CryptoPP;
+
+ StringSource privateKeySource(buf, size, true);
+ uint32_t tmpNum;
+ OID tmpOID;
+ SecByteBlock rawKeyBits;
+ // PrivateKeyInfo ::= SEQUENCE {
+ // INTEGER,
+ // SEQUENCE,
+ // OCTECT STRING}
+ BERSequenceDecoder privateKeyInfo(privateKeySource);
+ {
+ BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
+ BERSequenceDecoder sequenceDecoder(privateKeyInfo);
+ {
+ tmpOID.decode(sequenceDecoder);
+ BERDecodeNull(sequenceDecoder);
+ }
+ BERDecodeOctetString(privateKeyInfo, rawKeyBits);
+ }
+ privateKeyInfo.MessageEnd();
+
+ CFDataRef importedKey = CFDataCreateWithBytesNoCopy(NULL,
+ 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;
+ SecAccessRef access;
+ CFStringRef keyLabel = CFStringCreateWithCString(NULL,
+ keyName.toUri().c_str(),
+ kCFStringEncodingUTF8);
+ SecAccessCreate(keyLabel, NULL, &access);
+ keyParams.accessRef = access;
+ CFArrayRef outItems;
+
+ OSStatus res = SecKeychainItemImport (importedKey,
+ NULL,
+ &externalFormat,
+ &externalType,
+ 0,
+ &keyParams,
+ m_impl->m_keyChainRef,
+ &outItems);
+
+ if(res != errSecSuccess)
+ {
+ return false;
+ }
+
+ SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 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 = (void *)keyUri.c_str();
+ attrList.count++;
+ }
+
+ res = SecKeychainItemModifyAttributesAndData(privateKey,
+ &attrList,
+ 0,
+ NULL);
+
+ if(res != errSecSuccess)
+ {
+ return false;
+ }
+
+ CFRelease(importedKey);
+ return true;
+}
+
+bool
+SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+ CFDataRef importedKey = CFDataCreateWithBytesNoCopy(NULL,
+ buf,
+ size,
+ kCFAllocatorNull);
+
+ SecExternalFormat externalFormat = kSecFormatOpenSSL;
+ SecExternalItemType externalType = kSecItemTypePublicKey;
+ CFArrayRef outItems;
+
+ OSStatus res = SecItemImport (importedKey,
+ NULL,
+ &externalFormat,
+ &externalType,
+ 0,
+ NULL,
+ m_impl->m_keyChainRef,
+ &outItems);
+
+ if(res != errSecSuccess)
+ return false;
+
+ SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 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 = (void *)keyUri.c_str();
+ attrList.count++;
+ }
+
+ res = SecKeychainItemModifyAttributesAndData(publicKey,
+ &attrList,
+ 0,
+ NULL);
+
+ CFRelease(importedKey);
+ return true;
}
Block
@@ -549,17 +714,17 @@
NULL);
CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
- CFDictionaryAddValue(attrDict, kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
+ // CFDictionaryAddValue(attrDict, kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
SecKeychainItemRef itemRef;
OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
- if(res == errSecItemNotFound)
- return false;
- else
+ if(res == errSecSuccess)
return true;
+ else
+ return false;
}
@@ -688,40 +853,5 @@
return -1;
}
}
-
-bool
-SecTpmOsx::Impl::getPassWord(string& password, string target)
-{
- int result = false;
-
- string prompt1 = "Password for " + target + ":";
- string prompt2 = "Confirm password for " + target + ":";
- char* pw0 = NULL;
-
- pw0 = getpass(prompt1.c_str());
- if(!pw0)
- return false;
- string password1 = pw0;
- memset(pw0, 0, strlen(pw0));
-
- pw0 = getpass(prompt2.c_str());
- if(!pw0)
- {
- char* pw1 = const_cast<char*>(password1.c_str());
- memset(pw1, 0, password1.size());
- return false;
- }
-
- if(!password1.compare(pw0))
- {
- result = true;
- password.swap(password1);
- }
-
- char* pw1 = const_cast<char*>(password1.c_str());
- memset(pw1, 0, password1.size());
- memset(pw0, 0, strlen(pw0));
- return result;
-}
}// ndn
diff --git a/src/security/sec-tpm-osx.hpp b/src/security/sec-tpm-osx.hpp
index c4a4972..251df24 100644
--- a/src/security/sec-tpm-osx.hpp
+++ b/src/security/sec-tpm-osx.hpp
@@ -107,18 +107,20 @@
bool
setACL(const Name& keyName, KeyClass keyClass, int acl, const std::string& appPath);
- // /**
- // * verify data (test only)
- // * @param keyName the name of key
- // * @param pData the data to be verified
- // * @param pSig the signature associated with the data
- // * @param digestAlgo digest algorithm
- // * @return true if signature can be verified, otherwise false
- // */
- // bool
- // verifyData(const Name & keyName, const Blob & pData, const Blob & pSig, DigestAlgorithm digestAlgo = DIGEST_ALGORITHM_SHA256);
+protected:
+ /******************************
+ * From TrustedPlatformModule *
+ ******************************/
+ virtual ConstBufferPtr
+ exportPrivateKeyPkcs1FromTpm(const Name& keyName);
- private:
+ virtual bool
+ importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size);
+
+ virtual bool
+ importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size);
+
+private:
class Impl;
shared_ptr<Impl> m_impl;
};
diff --git a/src/security/sec-tpm.cpp b/src/security/sec-tpm.cpp
new file mode 100644
index 0000000..13b04a8
--- /dev/null
+++ b/src/security/sec-tpm.cpp
@@ -0,0 +1,287 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "sec-tpm.hpp"
+
+#include <cryptopp/rsa.h>
+#include <cryptopp/files.h>
+#include <cryptopp/base64.h>
+#include <cryptopp/hex.h>
+#include <cryptopp/osrng.h>
+#include <cryptopp/sha.h>
+#include <cryptopp/pssr.h>
+#include <cryptopp/modes.h>
+#include <cryptopp/pwdbased.h>
+#include <cryptopp/sha.h>
+#include <cryptopp/des.h>
+
+using namespace std;
+
+namespace ndn {
+
+ConstBufferPtr
+SecTpm::exportPrivateKeyPkcs8FromTpm(const Name& keyName, bool inTerminal, const string& passwordStr)
+{
+ uint8_t salt[8] = {0};
+ uint8_t iv[8] = {0};
+
+ try{
+ using namespace CryptoPP;
+
+ // check password
+ string password;
+ if(passwordStr.empty())
+ if(!inTerminal)
+ return shared_ptr<Buffer>();
+ else
+ {
+ int count = 0;
+ while(!getPassWord(password, keyName.toUri()))
+ {
+ cerr << "Password mismatch!" << endl;
+ count++;
+ if(count > 3)
+ return shared_ptr<Buffer>();
+ }
+ }
+ else
+ password = passwordStr;
+
+ // derive key
+ if(!generateRandomBlock(salt, 8))
+ return shared_ptr<Buffer>();
+
+ if(!generateRandomBlock(iv, 8))
+ return shared_ptr<Buffer>();
+
+ 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;
+
+ keyGenerator.DeriveKey(derived, derivedLen,
+ purpose,
+ reinterpret_cast<const byte*>(password.c_str()), password.size(),
+ salt, 8,
+ iterationCount);
+
+ memset(const_cast<char*>(password.c_str()), 0, password.size());
+
+ //encrypt
+ CBC_Mode< DES_EDE3 >::Encryption e;
+ e.SetKeyWithIV(derived, derivedLen, iv);
+
+ string encrypted;
+ OBufferStream encryptedOs;
+ ConstBufferPtr pkcs1PrivateKey = exportPrivateKeyPkcs1FromTpm(keyName);
+ StringSource stringSource(pkcs1PrivateKey->buf(), pkcs1PrivateKey->size(), true,
+ new StreamTransformationFilter(e, new FileSink(encryptedOs)));
+
+ //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;
+ 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(...){
+ return shared_ptr<Buffer>();
+ }
+}
+
+bool
+SecTpm::importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size, bool inTerminal, const string& passwordStr)
+{
+ try{
+ using namespace CryptoPP;
+
+ OID pbes2Id;
+ OID pbkdf2Id;
+ SecByteBlock saltBlock;
+ uint32_t iterationCount;
+ OID pbes2encsId;
+ SecByteBlock ivBlock;
+ SecByteBlock encryptedDataBlock;
+
+ //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();
+
+
+ PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
+ size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
+ byte derived[24] = {0};
+ byte purpose = 0;
+
+ string password;
+ if(passwordStr.empty())
+ if(inTerminal)
+ {
+ char* pw = getpass("Password for the private key: ");
+ if (!pw)
+ return false;
+ password = pw;
+ memset(pw, 0, strlen(pw));
+ }
+ else
+ return false;
+ else
+ password = passwordStr;
+
+ keyGenerator.DeriveKey(derived, derivedLen,
+ purpose,
+ reinterpret_cast<const byte*>(password.c_str()), password.size(),
+ saltBlock.BytePtr(), saltBlock.size(),
+ iterationCount);
+
+ memset(const_cast<char*>(password.c_str()), 0, password.size());
+
+ //decrypt
+ CBC_Mode< DES_EDE3 >::Decryption d;
+ d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr());
+
+ OBufferStream privateKeyOs;
+ StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true,
+ new StreamTransformationFilter(d, new FileSink(privateKeyOs)));
+
+ if(!importPrivateKeyPkcs1IntoTpm(keyName, privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()))
+ return false;
+
+ //derive public key
+ RSA::PrivateKey privateKey;
+ privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
+
+ RSAFunction publicKey(privateKey);
+
+ OBufferStream publicKeyOs;
+ FileSink publicKeySink(publicKeyOs);
+ publicKey.DEREncode(publicKeySink);
+ publicKeySink.MessageEnd();
+
+ if(!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size()))
+ return false;
+
+ return true;
+ }catch(std::runtime_error& e){
+ cerr << e.what() << endl;
+ return false;
+ }
+}
+
+
+}//ndn
diff --git a/src/security/sec-tpm.hpp b/src/security/sec-tpm.hpp
index 9c15ad7..dcdea95 100644
--- a/src/security/sec-tpm.hpp
+++ b/src/security/sec-tpm.hpp
@@ -104,16 +104,115 @@
doesKeyExistInTpm(const Name& keyName, KeyClass keyClass) = 0;
/**
- * @brief Generate a random number.
+ * @brief Generate a random block.
*
- * @param res The pointer to the generated number.
- * @param size The random number size.
+ * @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 Export a private key in PKCS#8 format.
+ *
+ * @param keyName The private key name.
+ * @param password The password to encrypt the private key.
+ * @param inTerminal If password is not supplied, get it via terminal if inTerminal is true, otherwise fail.
+ * @return The private key info (in PKCS8 format) if exist, otherwise a NULL pointer.
+ */
+ ConstBufferPtr
+ exportPrivateKeyPkcs8FromTpm(const Name& keyName, bool inTerminal, const std::string& password);
+
+ /**
+ * @brief Import a private key in PKCS#8 format.
+ *
+ * Also recover the public key and installed it in TPM.
+ *
+ * @param keyName The private key name.
+ * @param key The encoded private key info.
+ * @param password The password to encrypt the private key.
+ * @param inTerminal If password is not supplied, get it via terminal if inTerminal is true, otherwise fail.
+ * @return False if import fails.
+ */
+ bool
+ importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size, bool inTerminal, const std::string& password);
+
+protected:
+ /**
+ * @brief Export a private key in PKCS#1 format.
+ *
+ * @param keyName The private key name.
+ * @return The private key info (in PKCS#1 format) if exist, otherwise a NULL pointer.
+ */
+ virtual ConstBufferPtr
+ exportPrivateKeyPkcs1FromTpm(const Name& keyName) = 0;
+
+ /**
+ * @brief Import a private key in PKCS#1 format.
+ *
+ * @param keyName The private key name.
+ * @param key The encoded private key info.
+ * @return False if import fails.
+ */
+ virtual bool
+ importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size) = 0;
+
+ /**
+ * @brief Import a public key in PKCS#1 format.
+ *
+ * @param keyName The public key name.
+ * @param key The encoded public key info.
+ * @return False if import fails.
+ */
+ virtual bool
+ importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size) = 0;
+
+
+ /**
+ * @brief Get password.
+ *
+ * @param password On return, the password.
+ * @param prompt Prompt for password, i.e., "Password for key:"
+ * @return true if password has been obtained.
+ */
+ inline virtual bool
+ getPassWord(std::string& password, const std::string& prompt);
};
+bool
+SecTpm::getPassWord(std::string& password, const std::string& prompt)
+{
+ int result = false;
+
+ char* pw0 = NULL;
+
+ pw0 = getpass(prompt.c_str());
+ if(!pw0)
+ return false;
+ std::string password1 = pw0;
+ memset(pw0, 0, strlen(pw0));
+
+ pw0 = getpass("Confirm:");
+ if(!pw0)
+ {
+ char* pw1 = const_cast<char*>(password1.c_str());
+ memset(pw1, 0, password1.size());
+ return false;
+ }
+
+ if(!password1.compare(pw0))
+ {
+ result = true;
+ password.swap(password1);
+ }
+
+ char* pw1 = const_cast<char*>(password1.c_str());
+ memset(pw1, 0, password1.size());
+ memset(pw0, 0, strlen(pw0));
+ return result;
+}
+
}
#endif
diff --git a/src/security/validator-regex.cpp b/src/security/validator-regex.cpp
index 1b9dcb9..b85bad2 100644
--- a/src/security/validator-regex.cpp
+++ b/src/security/validator-regex.cpp
@@ -62,7 +62,7 @@
}
else
{
- _LOG_DEBUG("Wrong Invalidity: " << e.what());
+ _LOG_DEBUG("Wrong Invalidity:");
onValidationFailed(data);
return;
}
diff --git a/src/security/validator.cpp b/src/security/validator.cpp
index a44c333..6eec2d0 100644
--- a/src/security/validator.cpp
+++ b/src/security/validator.cpp
@@ -122,7 +122,7 @@
}
default:
{
- _LOG_DEBUG("verifySignature: Unknown signature type: " << sig.getType());
+ _LOG_DEBUG("verifySignature: Unknown signature type: " << data.getSignature().getType());
return false;
}
}
diff --git a/tests/security/test-keychain.cpp b/tests/security/test-keychain.cpp
new file mode 100644
index 0000000..985ef82
--- /dev/null
+++ b/tests/security/test-keychain.cpp
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi0@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#include <boost/test/unit_test.hpp>
+
+#include "security/key-chain.hpp"
+#include "util/time.hpp"
+
+using namespace std;
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(TestKeyChain)
+
+BOOST_AUTO_TEST_CASE (ExportIdentity)
+{
+ KeyChainImpl<SecPublicInfoSqlite3, SecTpmFile> keyChain;
+
+ Name identity(string("/TestKeyChain/ExportIdentity/") + boost::lexical_cast<std::string>(time::now()));
+ keyChain.createIdentity(identity);
+
+ Block exported = keyChain.exportIdentity(identity, true, "1234");
+
+ Name keyName = keyChain.getDefaultKeyNameForIdentity(identity);
+ Name certName = keyChain.getDefaultCertificateNameForKey(keyName);
+
+ keyChain.deleteIdentity(identity);
+
+ BOOST_REQUIRE(keyChain.doesIdentityExist(identity) == false);
+ BOOST_REQUIRE(keyChain.doesPublicKeyExist(keyName) == false);
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+ BOOST_REQUIRE(keyChain.doesCertificateExist(certName) == false);
+
+ keyChain.importIdentity(exported, true, "1234");
+
+ BOOST_REQUIRE(keyChain.doesIdentityExist(identity));
+ BOOST_REQUIRE(keyChain.doesPublicKeyExist(keyName));
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE));
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC));
+ BOOST_REQUIRE(keyChain.doesCertificateExist(certName));
+
+ keyChain.deleteIdentity(identity);
+
+ BOOST_REQUIRE(keyChain.doesIdentityExist(identity) == false);
+ BOOST_REQUIRE(keyChain.doesPublicKeyExist(keyName) == false);
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(keyChain.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+ BOOST_REQUIRE(keyChain.doesCertificateExist(certName) == false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
diff --git a/tests/security/test-sec-tpm-file.cpp b/tests/security/test-sec-tpm-file.cpp
index 55bc983..04adf1f 100644
--- a/tests/security/test-sec-tpm-file.cpp
+++ b/tests/security/test-sec-tpm-file.cpp
@@ -12,6 +12,7 @@
#include "security/key-chain.hpp"
#include <cryptopp/rsa.h>
+#include <cryptopp/hex.h>
using namespace std;
namespace ndn {
@@ -85,6 +86,85 @@
BOOST_CHECK_CLOSE(dev / 256, 0.001, 100);
}
+
+BOOST_AUTO_TEST_CASE (ImportExportKey)
+{
+ using namespace CryptoPP;
+
+ string imported(
+"3082050E304006092A864886F70D01050D3033301B06092A864886F70D01050C300E0408209CF0B1B4C856A802020800301406082A864886F70D0307040884B1229D80690211048204C8DA62C11E1CCFC43F318D0C03DA4B11350122B18F23645C454F41BB46C7F8EED4F95041A9130B33E989AF338951A286B55FB9A707AF1C5B2E1FAE7CD66D6D556CBFD90640BDA0D7904DD8D89CF15AB24F1A652AB76E16411B78E8A9AAEEB6EE06FA793B2B4A3EE4B9B5DFB3FC3D38076145915A11CEC8FD2EAB70F51A0DA8B88B73B4DD5BAFB933ABCD92FFBA7843083CCE6B7A6BD9A51094EFF93DC93A19B4982F5FF8696FDF07B76366B6408EC18F4EA218A4F6B5EA85A5AF3B082D0E3AE74665BDD9FC7DE87A7A54EB038AB2E9196365F8481F1CC601EB866D554B4FBCDABECD35CBE404F3CB313E9799D111AD955C42629FB1A01E6138EFF15E6DE7D2BF8754868157DAC72EE5125221D502DCF0B8E8FF5CA87B601357785E7C95CBFC369B31D747ADACFB95E614507A5622ACAA3541B4FE02AEEC2DD588D3D7860A50C78EF460C39E250851140155052F18419F37D551FC3F5224764A17A2C47F9CEDC63780E3AF48C421D682FD3A68A2E12EB28737DB0F785137FC01282D0D82220E2D147E4E2D261046D3C5842B55C1C2F6BA51727AF57C502242F397ACEC341F2C6C6E739E629A144602C9994C88B4F8B4F7150C087C143D9FEC23A686E5E46A5541A071869089BECC05B186FC3D8F95668A671D7088462D61423BAEB73B41CDA5B69E22D6EE3A64BB523B1522F2433BA8AD98A7500EB5C5859469F45C15E91AC1DA9D9473B3C2B37C38D038F99122E157166B89C1EA941A683A73C3F7C0762E79E9C1E28A306042D8683C26995F7AA1B5CC1B985BB0A9DEE6471E9BCEF977A2BE84BD90CE3025FA76B8B546725D85C37543B69604D3F0822DBA3067E9CF9BF2F0DC676E0D718C963C71DBD7A278BAF2A2FFA65BDB8E60FCDD0D0BA841E37284FB6174047D1EC974730A77A7E808C5F27BF1FF0818AD7B0596C538ECFF2068BD5EED5E90102918E2F224EBFFDB2C8366A5C819A00BF6DDF823BD861331F4BF2323ECA284B90C96AB6C7CDBB200163AEA8FD9EC18BA5ACAA8B8B4BDA532A04AD179D402F09E69F5CE0A179EBEF9A99E8B0C5BC8A9C3CA71C820508E33C79A98B9C31F856F53D1369AD7D9C668BC9160D6C7F3612842BDCDB42F5AE6860E93B2B203CAE26C93A7640640D403BC107DDA031CAD54DC63FFF73861D25DE26B9147C328B3940F2CFB44E82112DD6FA514CB8FD5DD6E6FF4D4EFF430B06AC970D8D75F5BD6A015558ED8D82C5121115DC3657BE88356348C0F8B8EADFD5506C0C046984BB1F12F3EEFD32FED4C8684ABD252BF3CA56092D4A752CF51E13755568C3BF25CFCA0F7AF9279CA593305C27645022DD2DD0F7FFCAC92EDEF04B9DCAE7FD55E2C69C76CF061F1ECD724850FCA574543954105B9A3824B849DDD75DEB57B382054AAB4A1FE467D235FB77C220730ED7D9B79A575831395AAE0C4C0B0D3E7EC17511C3DE9A86AD1C68BFF861FA0151020E43A1C6B4F4D6273D586B1D291AEF45DF454463F39BACA2FF07AA5E24A7EA850189F8C39BA8E88FEB21C1647EF910898B02492C49599111D3558F05A4CFD0FDBF33E802798FF2C437FCD65AAC1024FB29D08DCD7DB7E08279C3EB4B64E58747096641D1886145EC9E5ADDC8BBC81BE0DC77C3F3A017311050B921B5506F13AF30BA04AFAA210F0359E710C01319DE7BFF165A3615E8DDFC6E3FC167BA39B332B42E5207CA4934EABDAE2D057FA661DEB3EBC1A4AFD4F3E014918EC");
+
+ string decoded;
+ StringSource source(imported, true, new HexDecoder(new StringSink(decoded))); // StringSource
+
+ SecTpmFile tpm;
+
+ Name keyName("/TestSecTpmFile/ImportKey/ksk-" + boost::lexical_cast<string>(time::now()));
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+
+ BOOST_REQUIRE_NO_THROW(tpm.importPrivateKeyPkcs8IntoTpm(keyName, reinterpret_cast<const uint8_t*>(decoded.c_str()), decoded.size(), true, "1234"));
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+
+ shared_ptr<PublicKey> pubkeyPtr = tpm.getPublicKeyFromTpm(keyName);
+
+ const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+ Block sigBlock = tpm.signInTpm(content, sizeof(content), keyName, DIGEST_ALGORITHM_SHA256);
+
+ {
+ using namespace CryptoPP;
+
+ RSA::PublicKey publicKey;
+ ByteQueue queue;
+ queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+ publicKey.Load(queue);
+
+ RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+ bool result = verifier.VerifyMessage(content, sizeof(content),
+ sigBlock.value(), sigBlock.value_size());
+
+ BOOST_REQUIRE_EQUAL(result, true);
+ }
+
+ ConstBufferPtr exported = tpm.exportPrivateKeyPkcs8FromTpm(keyName, true, "5678");
+
+ tpm.deleteKeyPairInTpm(keyName);
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+
+ BOOST_REQUIRE(tpm.importPrivateKeyPkcs8IntoTpm(keyName, exported->buf(), exported->size(), true, "5678"));
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+
+ const uint8_t content2[] = {0x05, 0x06, 0x07, 0x08};
+ Block sigBlock2 = tpm.signInTpm(content2, sizeof(content2), keyName, DIGEST_ALGORITHM_SHA256);
+
+ {
+ using namespace CryptoPP;
+
+ RSA::PublicKey publicKey;
+ ByteQueue queue;
+ queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+ publicKey.Load(queue);
+
+ RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+ bool result = verifier.VerifyMessage(content2, sizeof(content2),
+ sigBlock2.value(), sigBlock2.value_size());
+
+ BOOST_REQUIRE_EQUAL(result, true);
+ }
+
+ tpm.deleteKeyPairInTpm(keyName);
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace ndn
diff --git a/tests/security/test-sec-tpm-osx.cpp b/tests/security/test-sec-tpm-osx.cpp
index a0a3bb9..f801018 100644
--- a/tests/security/test-sec-tpm-osx.cpp
+++ b/tests/security/test-sec-tpm-osx.cpp
@@ -85,6 +85,57 @@
BOOST_CHECK_CLOSE(dev / 256, 0.001, 100);
}
+
+BOOST_AUTO_TEST_CASE (ExportImportKey)
+{
+ using namespace CryptoPP;
+
+ SecTpmOsx tpm;
+
+ Name keyName("/TestSecTpmFile/ExportImportKey/ksk-" + boost::lexical_cast<string>(time::now()));
+
+ BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, KEY_TYPE_RSA, 2048));
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+
+ ConstBufferPtr exported = tpm.exportPrivateKeyPkcs8FromTpm(keyName, true, "1234");
+ shared_ptr<PublicKey> pubkeyPtr = tpm.getPublicKeyFromTpm(keyName);
+
+ tpm.deleteKeyPairInTpm(keyName);
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+
+ BOOST_REQUIRE(tpm.importPrivateKeyPkcs8IntoTpm(keyName, exported->buf(), exported->size(), true, "1234"));
+
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == true);
+ BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == true);
+
+ const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
+ Block sigBlock = tpm.signInTpm(content, sizeof(content), keyName, DIGEST_ALGORITHM_SHA256);
+
+ {
+ using namespace CryptoPP;
+
+ RSA::PublicKey publicKey;
+ ByteQueue queue;
+ queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
+ publicKey.Load(queue);
+
+ RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+ bool result = verifier.VerifyMessage(content, sizeof(content),
+ sigBlock.value(), sigBlock.value_size());
+
+ BOOST_REQUIRE_EQUAL(result, true);
+ }
+
+ tpm.deleteKeyPairInTpm(keyName);
+ // This is some problem related to Mac OS Key chain, and we will fix it later.
+ // BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
+ // BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace ndn