blob: 6bb283a007ab9e7117b93db0a11b857b69eec775 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2013-2016 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received copies of the GNU General Public License and GNU Lesser
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
* <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*/
#include "security/sec-tpm-osx.hpp"
#include "security/v1/cryptopp.hpp"
#include "util/time.hpp"
#include <boost/lexical_cast.hpp>
#include <Availability.h>
#include "boost-test.hpp"
namespace ndn {
namespace security {
namespace tests {
class OsxKeyChainTestFixture
{
public:
OsxKeyChainTestFixture()
{
std::string oldHOME;
if (std::getenv("OLD_HOME"))
oldHOME = std::getenv("OLD_HOME");
if (std::getenv("HOME"))
m_HOME = std::getenv("HOME");
if (!oldHOME.empty())
setenv("HOME", oldHOME.c_str(), 1);
else
unsetenv("HOME");
}
~OsxKeyChainTestFixture()
{
if (!m_HOME.empty())
setenv("HOME", m_HOME.c_str(), 1);
else
unsetenv("HOME");
}
protected:
std::string m_HOME;
};
BOOST_FIXTURE_TEST_SUITE(SecuritySecTpmOsx, OsxKeyChainTestFixture)
BOOST_AUTO_TEST_CASE(Delete)
{
SecTpmOsx tpm;
Name keyName("/TestSecTpmOsx/Delete/ksk-" +
boost::lexical_cast<std::string>(
time::toUnixTimestamp(time::system_clock::now()).count()));
RsaKeyParams params(2048);
BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true);
tpm.deleteKeyPairInTpm(keyName);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false);
}
BOOST_AUTO_TEST_CASE(SignVerify)
{
SecTpmOsx tpm;
Name keyName("/TestSecTpmOsx/SignVerify/ksk-" +
boost::lexical_cast<std::string>(
time::toUnixTimestamp(time::system_clock::now()).count()));
RsaKeyParams params(2048);
BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
Data data("/TestSecTpmOsx/SignVaerify/Data/1");
const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
Block sigBlock;
BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
keyName, DigestAlgorithm::SHA256));
shared_ptr<v1::PublicKey> publicKey;
BOOST_CHECK_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName));
try
{
using namespace CryptoPP;
RSA::PublicKey rsaPublicKey;
ByteQueue queue;
queue.Put(reinterpret_cast<const byte*>(publicKey->get().buf()), publicKey->get().size());
rsaPublicKey.Load(queue);
RSASS<PKCS1v15, SHA256>::Verifier verifier(rsaPublicKey);
bool isVerified = verifier.VerifyMessage(content, sizeof(content),
sigBlock.value(), sigBlock.value_size());
BOOST_CHECK_EQUAL(isVerified, true);
}
catch (CryptoPP::Exception& e)
{
BOOST_CHECK(false);
}
tpm.deleteKeyPairInTpm(keyName);
}
BOOST_AUTO_TEST_CASE(RandomGenerator)
{
SecTpmOsx tpm;
size_t scale = 1000;
size_t size = 256 * scale;
uint8_t* block = new uint8_t[size];
tpm.generateRandomBlock(block, size);
std::map<uint8_t, int> counter;
for (size_t i = 0; i < size; i++)
{
counter[block[i]] += 1;
}
float dev = 0.0;
for (size_t i = 0; i != 255; i++)
{
dev += ((counter[i] - scale) * (counter[i] - scale)) * 1.0 / (scale * scale);
}
BOOST_CHECK_CLOSE(dev / 256, 0.001, 100);
}
BOOST_AUTO_TEST_CASE(ExportImportKey)
{
using namespace CryptoPP;
SecTpmOsx tpm;
Name keyName("/TestSecTpmOsx/ExportImportKey/ksk-" +
boost::lexical_cast<std::string>(
time::toUnixTimestamp(time::system_clock::now()).count()));
RsaKeyParams params(2048);
BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true);
ConstBufferPtr exported;
BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234"));
shared_ptr<v1::PublicKey> publicKey;
BOOST_REQUIRE_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName));
tpm.deleteKeyPairInTpm(keyName);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false);
BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName,
exported->buf(), exported->size(),
"1234"));
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true);
const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
Block sigBlock;
BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
keyName, DigestAlgorithm::SHA256));
try
{
using namespace CryptoPP;
RSA::PublicKey rsaPublicKey;
ByteQueue queue;
queue.Put(reinterpret_cast<const byte*>(publicKey->get().buf()), publicKey->get().size());
rsaPublicKey.Load(queue);
RSASS<PKCS1v15, SHA256>::Verifier verifier(rsaPublicKey);
bool isVerified = verifier.VerifyMessage(content, sizeof(content),
sigBlock.value(), sigBlock.value_size());
BOOST_CHECK_EQUAL(isVerified, true);
}
catch (CryptoPP::Exception& e)
{
BOOST_CHECK(false);
}
tpm.deleteKeyPairInTpm(keyName);
// This is some problem related to Mac OS Key chain.
// On OSX 10.8, we cannot delete imported keys, but there is no such problem on OSX 10.9.
#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9
BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE) == false);
BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC) == false);
#endif
#endif
}
BOOST_AUTO_TEST_CASE(NonExistingKey)
{
using namespace CryptoPP;
SecTpmOsx tpm;
Name keyName("/TestSecTpmOsx/NonExistingKey");
BOOST_REQUIRE_THROW(tpm.getPublicKeyFromTpm(keyName), SecTpmOsx::Error);
const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
BOOST_REQUIRE_THROW(tpm.signInTpm(content, sizeof(content), keyName, DigestAlgorithm::SHA256),
SecTpmOsx::Error);
BOOST_REQUIRE_THROW(tpm.signInTpm(0, 1, keyName, DigestAlgorithm::SHA256),
SecTpmOsx::Error);
}
BOOST_AUTO_TEST_CASE(EcdsaSigning)
{
SecTpmOsx tpm;
Name keyName("/TestSecTpmOsx/EcdsaSigning/ksk-" +
boost::lexical_cast<std::string>(time::toUnixTimestamp(time::system_clock::now())));
EcdsaKeyParams params;
BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
Data data("/TestSecTpmOsx/EcdsaSigning/Data/1");
const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
Block sigBlock;
BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
keyName, DigestAlgorithm::SHA256));
shared_ptr<v1::PublicKey> pubkeyPtr;
BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
try
{
using namespace CryptoPP;
ECDSA<ECP, SHA256>::PublicKey publicKey;
ByteQueue queue;
queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
publicKey.Load(queue);
uint8_t buffer[64];
size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363,
sigBlock.value(), sigBlock.value_size(), DSA_DER);
ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
bool result = verifier.VerifyMessage(content, sizeof(content),
buffer, usedSize);
BOOST_CHECK_EQUAL(result, true);
}
catch (CryptoPP::Exception& e)
{
BOOST_CHECK(false);
}
tpm.deleteKeyPairInTpm(keyName);
}
BOOST_AUTO_TEST_CASE(ExportImportEcdsaKey)
{
using namespace CryptoPP;
SecTpmOsx tpm;
Name keyName("/TestSecTpmOsx/ExportImportEcdsaKey/ksk-" +
boost::lexical_cast<std::string>(
time::toUnixTimestamp(time::system_clock::now()).count()));
EcdsaKeyParams params;
BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true);
ConstBufferPtr exported;
BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234"));
shared_ptr<v1::PublicKey> publicKey;
BOOST_REQUIRE_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName));
tpm.deleteKeyPairInTpm(keyName);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false);
BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName,
exported->buf(), exported->size(),
"1234"));
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true);
BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true);
const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
Block sigBlock;
BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
keyName, DigestAlgorithm::SHA256));
try
{
using namespace CryptoPP;
ECDSA<ECP, SHA256>::PublicKey ecdsaPublicKey;
ByteQueue queue;
queue.Put(reinterpret_cast<const byte*>(publicKey->get().buf()), publicKey->get().size());
ecdsaPublicKey.Load(queue);
uint8_t buffer[64];
size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363,
sigBlock.value(), sigBlock.value_size(),
DSA_DER);
ECDSA<ECP, SHA256>::Verifier verifier(ecdsaPublicKey);
bool isVerified = verifier.VerifyMessage(content, sizeof(content),
buffer, usedSize);
BOOST_CHECK_EQUAL(isVerified, true);
}
catch (CryptoPP::Exception& e)
{
BOOST_CHECK(false);
}
tpm.deleteKeyPairInTpm(keyName);
// This is some problem related to Mac OS Key chain.
// On OSX 10.8, we cannot delete imported keys, but there is no such problem on OSX 10.9.
#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9
BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE) == false);
BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC) == false);
#endif
#endif
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace security
} // namespace ndn