security: add HMAC support in KeyChain and SigningInfo
Refs: #3075
Change-Id: Ia1f557ca7c83f4df7f9f87bbe1b4fc214940dcd8
diff --git a/ndn-cxx/security/signing-info.cpp b/ndn-cxx/security/signing-info.cpp
index f4ef2c5..14d9312 100644
--- a/ndn-cxx/security/signing-info.cpp
+++ b/ndn-cxx/security/signing-info.cpp
@@ -21,6 +21,12 @@
#include "ndn-cxx/security/signing-info.hpp"
+#include "ndn-cxx/encoding/buffer-stream.hpp"
+#include "ndn-cxx/security/transform/base64-decode.hpp"
+#include "ndn-cxx/security/transform/buffer-source.hpp"
+#include "ndn-cxx/security/transform/digest-filter.hpp"
+#include "ndn-cxx/security/transform/stream-sink.hpp"
+
namespace ndn {
namespace security {
@@ -45,6 +51,13 @@
return digestSha256Identity;
}
+const Name&
+SigningInfo::getHmacIdentity()
+{
+ static Name hmacIdentity("/localhost/identity/hmac");
+ return hmacIdentity;
+}
+
SigningInfo::SigningInfo(SignerType signerType,
const Name& signerName,
const SignatureInfo& signatureInfo)
@@ -53,11 +66,7 @@
, m_digestAlgorithm(DigestAlgorithm::SHA256)
, m_info(signatureInfo)
{
- BOOST_ASSERT(signerType == SIGNER_TYPE_NULL ||
- signerType == SIGNER_TYPE_ID ||
- signerType == SIGNER_TYPE_KEY ||
- signerType == SIGNER_TYPE_CERT ||
- signerType == SIGNER_TYPE_SHA256);
+ BOOST_ASSERT(signerType >= SIGNER_TYPE_NULL && signerType <= SIGNER_TYPE_HMAC);
}
SigningInfo::SigningInfo(const Identity& identity)
@@ -101,6 +110,10 @@
else if (scheme == "cert") {
setSigningCertName(nameArg);
}
+ else if (scheme == "hmac-sha256") {
+ setSigningHmacKey(nameArg);
+ setDigestAlgorithm(DigestAlgorithm::SHA256);
+ }
else {
NDN_THROW(std::invalid_argument("Invalid signing string scheme"));
}
@@ -133,6 +146,25 @@
}
SigningInfo&
+SigningInfo::setSigningHmacKey(const std::string& hmacKey)
+{
+ m_type = SIGNER_TYPE_HMAC;
+
+ OBufferStream os;
+ transform::bufferSource(hmacKey) >>
+ transform::base64Decode(false) >>
+ transform::streamSink(os);
+ m_hmacKey = make_shared<transform::PrivateKey>();
+ m_hmacKey->loadRaw(KeyType::HMAC, os.buf()->data(), os.buf()->size());
+
+ // generate key name
+ m_name = getHmacIdentity();
+ m_name.append(name::Component(m_hmacKey->getKeyDigest(DigestAlgorithm::SHA256)));
+
+ return *this;
+}
+
+SigningInfo&
SigningInfo::setSha256Signing()
{
m_type = SIGNER_TYPE_SHA256;
@@ -179,8 +211,9 @@
return os << "cert:" << si.getSignerName();
case SigningInfo::SIGNER_TYPE_SHA256:
return os << "id:" << SigningInfo::getDigestSha256Identity();
+ case SigningInfo::SIGNER_TYPE_HMAC:
+ return os << "id:" << si.getSignerName();
}
-
NDN_THROW(std::invalid_argument("Unknown signer type"));
return os;
}
diff --git a/ndn-cxx/security/signing-info.hpp b/ndn-cxx/security/signing-info.hpp
index ab60b19..9089429 100644
--- a/ndn-cxx/security/signing-info.hpp
+++ b/ndn-cxx/security/signing-info.hpp
@@ -27,6 +27,7 @@
#include "ndn-cxx/security/pib/identity.hpp"
#include "ndn-cxx/security/pib/key.hpp"
#include "ndn-cxx/security/security-common.hpp"
+#include "ndn-cxx/security/transform/private-key.hpp"
namespace ndn {
namespace security {
@@ -47,21 +48,23 @@
};
enum SignerType {
- /// @brief no signer is specified, use default setting or follow the trust schema
+ /// No signer is specified, use default setting or follow the trust schema.
SIGNER_TYPE_NULL = 0,
- /// @brief signer is an identity, use its default key and default certificate
+ /// Signer is an identity, use its default key and default certificate.
SIGNER_TYPE_ID = 1,
- /// @brief signer is a key, use its default certificate
+ /// Signer is a key, use its default certificate.
SIGNER_TYPE_KEY = 2,
- /// @brief signer is a certificate, use it directly
+ /// Signer is a certificate, use it directly.
SIGNER_TYPE_CERT = 3,
- /// @brief use sha256 digest, no signer needs to be specified
+ /// Use a SHA-256 digest only, no signer needs to be specified.
SIGNER_TYPE_SHA256 = 4,
+ /// Signer is a HMAC key.
+ SIGNER_TYPE_HMAC = 5,
};
public:
/**
- * @brief Constructor
+ * @brief Constructor.
*
* @param signerType The type of signer
* @param signerName The name of signer; interpretation differs per signerType
@@ -75,28 +78,29 @@
const SignatureInfo& signatureInfo = getEmptySignatureInfo());
/**
- * @brief Create a signingInfo using pib identity;
+ * @brief Construct from a PIB identity.
*/
explicit
SigningInfo(const Identity& identity);
/**
- * @brief Create a signingInfo using pib key;
+ * @brief Construct from a PIB key.
*/
explicit
SigningInfo(const Key& key);
/**
- * @brief Construct SigningInfo from its string representation
+ * @brief Construct SigningInfo from its string representation.
*
* @param signingStr The representative signing string for SigningInfo signing method
*
- * Structure of the representative string is as follows:
+ * Syntax of the representative string is as follows:
* - default signing: "" (empty string)
- * - signing with a default certificate of a default key for the identity: `id:/my-identity`
- * - signing with a default certificate of the key: `key:/my-identity/ksk-1`
- * - signing with the certificate: `cert:/my-identity/KEY/ksk-1/ID-CERT/%FD%01`
- * - signing with sha256 digest: `id:/localhost/identity/digest-sha256`
+ * - sign with the default certificate of the default key of an identity: `id:/<my-identity>`
+ * - sign with the default certificate of a specific key: `key:/<my-identity>/ksk-1`
+ * - sign with a specific certificate: `cert:/<my-identity>/KEY/ksk-1/ID-CERT/%FD%01`
+ * - sign with HMAC-SHA-256: `hmac-sha256:<base64-encoded-key>`
+ * - sign with SHA-256 (digest only): `id:/localhost/identity/digest-sha256`
*/
explicit
SigningInfo(const std::string& signingStr);
@@ -123,7 +127,14 @@
setSigningCertName(const Name& certificateName);
/**
- * @brief Set Sha256 as the signing method
+ * @brief Set signer to a base64-encoded HMAC key
+ * @post Change the signerType to SIGNER_TYPE_HMAC
+ */
+ SigningInfo&
+ setSigningHmacKey(const std::string& hmacKey);
+
+ /**
+ * @brief Set SHA-256 as the signing method
* @post Reset signerName, also change the signerType to SIGNER_TYPE_SHA256
*/
SigningInfo&
@@ -184,8 +195,15 @@
return m_key;
}
+ shared_ptr<transform::PrivateKey>
+ getHmacKey() const
+ {
+ BOOST_ASSERT(m_type == SIGNER_TYPE_HMAC);
+ return m_hmacKey;
+ }
+
/**
- * @brief Set the digest algorithm for public key operations
+ * @brief Set the digest algorithm for signing operations
*/
SigningInfo&
setDigestAlgorithm(const DigestAlgorithm& algorithm)
@@ -195,7 +213,7 @@
}
/**
- * @return The digest algorithm for public key operations
+ * @return The digest algorithm for signing operations
*/
DigestAlgorithm
getDigestAlgorithm() const
@@ -231,6 +249,12 @@
static const Name&
getDigestSha256Identity();
+ /**
+ * @brief A localhost identity to indicate that the signature is generated using an HMAC key.
+ */
+ static const Name&
+ getHmacIdentity();
+
private: // non-member operators
// NOTE: the following "hidden friend" operators are available via
// argument-dependent lookup only and must be defined inline.
@@ -255,6 +279,7 @@
Name m_name;
Identity m_identity;
Key m_key;
+ shared_ptr<transform::PrivateKey> m_hmacKey;
DigestAlgorithm m_digestAlgorithm;
SignatureInfo m_info;
};
diff --git a/ndn-cxx/security/tpm/back-end-file.cpp b/ndn-cxx/security/tpm/back-end-file.cpp
index 22783ae..8aa98c6 100644
--- a/ndn-cxx/security/tpm/back-end-file.cpp
+++ b/ndn-cxx/security/tpm/back-end-file.cpp
@@ -30,11 +30,13 @@
#include <sys/stat.h>
#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
namespace ndn {
namespace security {
namespace tpm {
+namespace fs = boost::filesystem;
using transform::PrivateKey;
class BackEndFile::Impl
@@ -44,42 +46,44 @@
Impl(const std::string& dir)
{
if (!dir.empty()) {
- keystorePath = boost::filesystem::path(dir);
+ m_keystorePath = fs::path(dir);
}
#ifdef NDN_CXX_HAVE_TESTS
else if (std::getenv("TEST_HOME") != nullptr) {
- keystorePath = boost::filesystem::path(std::getenv("TEST_HOME")) / ".ndn";
+ m_keystorePath = fs::path(std::getenv("TEST_HOME")) / ".ndn";
}
#endif // NDN_CXX_HAVE_TESTS
else if (std::getenv("HOME") != nullptr) {
- keystorePath = boost::filesystem::path(std::getenv("HOME")) / ".ndn";
+ m_keystorePath = fs::path(std::getenv("HOME")) / ".ndn";
}
else {
- keystorePath = boost::filesystem::current_path() / ".ndn";
+ m_keystorePath = fs::current_path() / ".ndn";
}
- keystorePath /= "ndnsec-key-file";
- boost::filesystem::create_directories(keystorePath);
+ m_keystorePath /= "ndnsec-key-file";
+ fs::create_directories(m_keystorePath);
}
- boost::filesystem::path
- toFileName(const Name& keyName)
+ fs::path
+ toFileName(const Name& keyName) const
{
- std::stringstream os;
+ std::ostringstream os;
{
using namespace transform;
- bufferSource(keyName.wireEncode().wire(), keyName.wireEncode().size()) >>
- digestFilter(DigestAlgorithm::SHA256) >> hexEncode() >> streamSink(os);
+ bufferSource(keyName.wireEncode().wire(), keyName.wireEncode().size())
+ >> digestFilter(DigestAlgorithm::SHA256)
+ >> hexEncode()
+ >> streamSink(os);
}
- return keystorePath / (os.str() + ".privkey");
+ return m_keystorePath / (os.str() + ".privkey");
}
-public:
- boost::filesystem::path keystorePath;
+private:
+ fs::path m_keystorePath;
};
BackEndFile::BackEndFile(const std::string& location)
- : m_impl(new Impl(location))
+ : m_impl(make_unique<Impl>(location))
{
}
@@ -95,7 +99,7 @@
bool
BackEndFile::doHasKey(const Name& keyName) const
{
- if (!boost::filesystem::exists(m_impl->toFileName(keyName)))
+ if (!fs::exists(m_impl->toFileName(keyName)))
return false;
try {
@@ -119,13 +123,23 @@
unique_ptr<KeyHandle>
BackEndFile::doCreateKey(const Name& identityName, const KeyParams& params)
{
+ switch (params.getKeyType()) {
+ case KeyType::RSA:
+ case KeyType::EC:
+ break;
+ default:
+ NDN_THROW(Error("File-based TPM does not support creating a key of type " +
+ boost::lexical_cast<std::string>(params.getKeyType())));
+ }
+
shared_ptr<PrivateKey> key(transform::generatePrivateKey(params).release());
unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleMem>(key);
- setKeyName(*keyHandle, identityName, params);
+ Name keyName = constructAsymmetricKeyName(*keyHandle, identityName, params);
+ keyHandle->setKeyName(keyName);
try {
- saveKey(keyHandle->getKeyName(), *key);
+ saveKey(keyName, *key);
return keyHandle;
}
catch (const std::runtime_error&) {
@@ -136,14 +150,14 @@
void
BackEndFile::doDeleteKey(const Name& keyName)
{
- boost::filesystem::path keyPath(m_impl->toFileName(keyName));
- if (!boost::filesystem::exists(keyPath))
+ auto keyPath = m_impl->toFileName(keyName);
+ if (!fs::exists(keyPath))
return;
try {
- boost::filesystem::remove(keyPath);
+ fs::remove(keyPath);
}
- catch (const boost::filesystem::filesystem_error&) {
+ catch (const fs::filesystem_error&) {
NDN_THROW_NESTED(Error("Cannot remove key file"));
}
}
@@ -177,6 +191,17 @@
}
}
+void
+BackEndFile::doImportKey(const Name& keyName, shared_ptr<transform::PrivateKey> key)
+{
+ try {
+ saveKey(keyName, *key);
+ }
+ catch (const PrivateKey::Error&) {
+ NDN_THROW_NESTED(Error("Cannot import private key"));
+ }
+}
+
unique_ptr<PrivateKey>
BackEndFile::loadKey(const Name& keyName) const
{
diff --git a/ndn-cxx/security/tpm/back-end-file.hpp b/ndn-cxx/security/tpm/back-end-file.hpp
index 658d12f..97c1935 100644
--- a/ndn-cxx/security/tpm/back-end-file.hpp
+++ b/ndn-cxx/security/tpm/back-end-file.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -74,6 +74,9 @@
void
doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) final;
+ void
+ doImportKey(const Name& keyName, shared_ptr<transform::PrivateKey> key) final;
+
private:
/**
* @brief Load a private key with name @p keyName from the key directory.
diff --git a/ndn-cxx/security/tpm/back-end-mem.cpp b/ndn-cxx/security/tpm/back-end-mem.cpp
index 68e49d9..5c20f71 100644
--- a/ndn-cxx/security/tpm/back-end-mem.cpp
+++ b/ndn-cxx/security/tpm/back-end-mem.cpp
@@ -26,6 +26,8 @@
#include <unordered_map>
+#include <boost/lexical_cast.hpp>
+
namespace ndn {
namespace security {
namespace tpm {
@@ -39,7 +41,7 @@
};
BackEndMem::BackEndMem(const std::string&)
- : m_impl(new Impl)
+ : m_impl(make_unique<Impl>())
{
}
@@ -70,12 +72,29 @@
unique_ptr<KeyHandle>
BackEndMem::doCreateKey(const Name& identityName, const KeyParams& params)
{
+ switch (params.getKeyType()) {
+ case KeyType::RSA:
+ case KeyType::EC:
+ case KeyType::HMAC:
+ break;
+ default:
+ NDN_THROW(Error("Memory-based TPM does not support creating a key of type " +
+ boost::lexical_cast<std::string>(params.getKeyType())));
+ }
+
shared_ptr<PrivateKey> key(transform::generatePrivateKey(params).release());
unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleMem>(key);
- setKeyName(*keyHandle, identityName, params);
+ Name keyName;
+ if (params.getKeyType() == KeyType::HMAC) {
+ keyName = constructHmacKeyName(*key, identityName, params);
+ }
+ else {
+ keyName = constructAsymmetricKeyName(*keyHandle, identityName, params);
+ }
+ keyHandle->setKeyName(keyName);
- m_impl->keys[keyHandle->getKeyName()] = key;
+ m_impl->keys[keyName] = std::move(key);
return keyHandle;
}
@@ -96,14 +115,20 @@
void
BackEndMem::doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
{
+ auto key = make_shared<PrivateKey>();
try {
- auto key = make_shared<PrivateKey>();
key->loadPkcs8(buf, size, pw, pwLen);
- m_impl->keys[keyName] = key;
}
catch (const PrivateKey::Error&) {
NDN_THROW_NESTED(Error("Cannot import private key"));
}
+ doImportKey(keyName, std::move(key));
+}
+
+void
+BackEndMem::doImportKey(const Name& keyName, shared_ptr<transform::PrivateKey> key)
+{
+ m_impl->keys[keyName] = std::move(key);
}
} // namespace tpm
diff --git a/ndn-cxx/security/tpm/back-end-mem.hpp b/ndn-cxx/security/tpm/back-end-mem.hpp
index 5d1dd3e..eb96090 100644
--- a/ndn-cxx/security/tpm/back-end-mem.hpp
+++ b/ndn-cxx/security/tpm/back-end-mem.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -66,6 +66,9 @@
void
doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) final;
+ void
+ doImportKey(const Name& keyName, shared_ptr<transform::PrivateKey> key) final;
+
private:
class Impl;
const unique_ptr<Impl> m_impl;
diff --git a/ndn-cxx/security/tpm/back-end-osx.cpp b/ndn-cxx/security/tpm/back-end-osx.cpp
index 9e28aab..afa7b27 100644
--- a/ndn-cxx/security/tpm/back-end-osx.cpp
+++ b/ndn-cxx/security/tpm/back-end-osx.cpp
@@ -29,6 +29,8 @@
#include <Security/Security.h>
#include <cstring>
+#include <boost/lexical_cast.hpp>
+
namespace ndn {
namespace security {
namespace tpm {
@@ -361,7 +363,8 @@
break;
}
default: {
- NDN_THROW(Tpm::Error("Failed to generate key pair: Unsupported key type"));
+ NDN_THROW(Error("macOS-based TPM does not support creating a key of type " +
+ boost::lexical_cast<std::string>(keyType)));
}
}
CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
@@ -380,11 +383,12 @@
}
unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleOsx>(privateKey.get());
- setKeyName(*keyHandle, identityName, params);
+ Name keyName = constructAsymmetricKeyName(*keyHandle, identityName, params);
+ keyHandle->setKeyName(keyName);
SecKeychainAttribute attrs[1]; // maximum number of attributes
SecKeychainAttributeList attrList = {0, attrs};
- std::string keyUri = keyHandle->getKeyName().toUri();
+ std::string keyUri = keyName.toUri();
{
attrs[attrList.count].tag = kSecKeyPrintName;
attrs[attrList.count].length = keyUri.size();
@@ -497,6 +501,12 @@
SecKeychainItemModifyAttributesAndData(keychainItem, &attrList, 0, nullptr);
}
+void
+BackEndOsx::doImportKey(const Name& keyName, shared_ptr<transform::PrivateKey> key)
+{
+ NDN_THROW(Error("macOS-based TPM does not support importing a transform::PrivateKey"));
+}
+
} // namespace tpm
} // namespace security
} // namespace ndn
diff --git a/ndn-cxx/security/tpm/back-end-osx.hpp b/ndn-cxx/security/tpm/back-end-osx.hpp
index bbbc159..611ae97 100644
--- a/ndn-cxx/security/tpm/back-end-osx.hpp
+++ b/ndn-cxx/security/tpm/back-end-osx.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -98,6 +98,9 @@
void
doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) final;
+ void
+ doImportKey(const Name& keyName, shared_ptr<transform::PrivateKey> key) final;
+
private:
class Impl;
const unique_ptr<Impl> m_impl;
diff --git a/ndn-cxx/security/tpm/back-end.cpp b/ndn-cxx/security/tpm/back-end.cpp
index 8c54a1c..decbc13 100644
--- a/ndn-cxx/security/tpm/back-end.cpp
+++ b/ndn-cxx/security/tpm/back-end.cpp
@@ -25,6 +25,7 @@
#include "ndn-cxx/security/pib/key.hpp"
#include "ndn-cxx/security/transform/buffer-source.hpp"
#include "ndn-cxx/security/transform/digest-filter.hpp"
+#include "ndn-cxx/security/transform/private-key.hpp"
#include "ndn-cxx/security/transform/stream-sink.hpp"
#include "ndn-cxx/encoding/buffer-stream.hpp"
#include "ndn-cxx/util/random.hpp"
@@ -50,6 +51,10 @@
unique_ptr<KeyHandle>
BackEnd::createKey(const Name& identity, const KeyParams& params)
{
+ if (params.getKeyType() == KeyType::HMAC) {
+ return doCreateKey(identity, params);
+ }
+
// key name checking
switch (params.getKeyIdType()) {
case KeyIdType::USER_SPECIFIED: { // keyId is pre-set.
@@ -107,7 +112,17 @@
}
void
-BackEnd::setKeyName(KeyHandle& keyHandle, const Name& identity, const KeyParams& params)
+BackEnd::importKey(const Name& keyName, shared_ptr<transform::PrivateKey> key)
+{
+ if (hasKey(keyName)) {
+ NDN_THROW(Error("Key `" + keyName.toUri() + "` already exists"));
+ }
+ doImportKey(keyName, key);
+}
+
+Name
+BackEnd::constructAsymmetricKeyName(const KeyHandle& keyHandle, const Name& identity,
+ const KeyParams& params)
{
name::Component keyId;
@@ -135,7 +150,14 @@
}
}
- keyHandle.setKeyName(v2::constructKeyName(identity, keyId));
+ return v2::constructKeyName(identity, keyId);
+}
+
+Name
+BackEnd::constructHmacKeyName(const transform::PrivateKey& key, const Name& identity,
+ const KeyParams& params)
+{
+ return Name(identity).append(name::Component(key.getKeyDigest(DigestAlgorithm::SHA256)));
}
bool
diff --git a/ndn-cxx/security/tpm/back-end.hpp b/ndn-cxx/security/tpm/back-end.hpp
index 069bfe1..8309b52 100644
--- a/ndn-cxx/security/tpm/back-end.hpp
+++ b/ndn-cxx/security/tpm/back-end.hpp
@@ -28,6 +28,11 @@
namespace ndn {
namespace security {
+
+namespace transform {
+class PrivateKey;
+} // namespace transform
+
namespace tpm {
class KeyHandle;
@@ -119,6 +124,14 @@
importKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, const char* pw, size_t pwLen);
/**
+ * @brief Import a private key.
+ *
+ * @throw Error The key could not be imported.
+ */
+ void
+ importKey(const Name& keyName, shared_ptr<transform::PrivateKey> key);
+
+ /**
* @brief Check if the TPM is in terminal mode.
*
* The default implementation always returns true.
@@ -162,10 +175,16 @@
protected: // static helper methods
/**
- * @brief Set the key name in @p keyHandle according to @p identity and @p params.
+ * @brief Construct and return the name of a RSA or EC key, based on @p identity and @p params.
*/
- static void
- setKeyName(KeyHandle& keyHandle, const Name& identity, const KeyParams& params);
+ static Name
+ constructAsymmetricKeyName(const KeyHandle& key, const Name& identity, const KeyParams& params);
+
+ /**
+ * @brief Construct and return the name of a HMAC key, based on @p identity and @p params.
+ */
+ static Name
+ constructHmacKeyName(const transform::PrivateKey& key, const Name& identity, const KeyParams& params);
private: // pure virtual methods
virtual bool
@@ -185,6 +204,9 @@
virtual void
doImportKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, const char* pw, size_t pwLen) = 0;
+
+ virtual void
+ doImportKey(const Name& keyName, shared_ptr<transform::PrivateKey> key) = 0;
};
} // namespace tpm
diff --git a/ndn-cxx/security/tpm/key-handle.cpp b/ndn-cxx/security/tpm/key-handle.cpp
index d5cea11..56057a2 100644
--- a/ndn-cxx/security/tpm/key-handle.cpp
+++ b/ndn-cxx/security/tpm/key-handle.cpp
@@ -52,18 +52,6 @@
return doDerivePublicKey();
}
-void
-KeyHandle::setKeyName(const Name& keyName)
-{
- m_keyName = keyName;
-}
-
-Name
-KeyHandle::getKeyName() const
-{
- return m_keyName;
-}
-
} // namespace tpm
} // namespace security
} // namespace ndn
diff --git a/ndn-cxx/security/tpm/key-handle.hpp b/ndn-cxx/security/tpm/key-handle.hpp
index 743dac5..0a4fd8a 100644
--- a/ndn-cxx/security/tpm/key-handle.hpp
+++ b/ndn-cxx/security/tpm/key-handle.hpp
@@ -72,11 +72,17 @@
ConstBufferPtr
derivePublicKey() const;
- void
- setKeyName(const Name& keyName);
-
Name
- getKeyName() const;
+ getKeyName() const
+ {
+ return m_keyName;
+ }
+
+ void
+ setKeyName(const Name& keyName)
+ {
+ m_keyName = keyName;
+ }
private:
virtual ConstBufferPtr
diff --git a/ndn-cxx/security/tpm/tpm.cpp b/ndn-cxx/security/tpm/tpm.cpp
index a4398e5..d325955 100644
--- a/ndn-cxx/security/tpm/tpm.cpp
+++ b/ndn-cxx/security/tpm/tpm.cpp
@@ -53,19 +53,10 @@
Name
Tpm::createKey(const Name& identityName, const KeyParams& params)
{
- switch (params.getKeyType()) {
- case KeyType::RSA:
- case KeyType::EC: {
- unique_ptr<KeyHandle> keyHandle = m_backEnd->createKey(identityName, params);
- Name keyName = keyHandle->getKeyName();
- m_keys[keyName] = std::move(keyHandle);
- return keyName;
- }
- default: {
- NDN_THROW(Error("Failed to create key pair: Unsupported key type " +
- boost::lexical_cast<std::string>(params.getKeyType())));
- }
- }
+ auto keyHandle = m_backEnd->createKey(identityName, params);
+ auto keyName = keyHandle->getKeyName();
+ m_keys[keyName] = std::move(keyHandle);
+ return keyName;
}
void
@@ -160,6 +151,12 @@
m_backEnd->importKey(keyName, pkcs8, pkcs8Len, pw, pwLen);
}
+void
+Tpm::importPrivateKey(const Name& keyName, shared_ptr<transform::PrivateKey> key)
+{
+ m_backEnd->importKey(keyName, std::move(key));
+}
+
const KeyHandle*
Tpm::findKey(const Name& keyName) const
{
diff --git a/ndn-cxx/security/tpm/tpm.hpp b/ndn-cxx/security/tpm/tpm.hpp
index 5fc6636..be31a7e 100644
--- a/ndn-cxx/security/tpm/tpm.hpp
+++ b/ndn-cxx/security/tpm/tpm.hpp
@@ -32,6 +32,10 @@
namespace ndn {
namespace security {
+namespace transform {
+class PrivateKey;
+} // namespace transform
+
namespace v2 {
class KeyChain;
} // namespace v2
@@ -105,8 +109,9 @@
/**
* @brief Verify blob using the key with name @p keyName and using the digest @p digestAlgorithm.
*
- * @return true if the signature is valid; false if the signature is not valid;
- * `boost::logic::indeterminate` if the key does not exist.
+ * @retval true the signature is valid
+ * @retval false the signature is not valid
+ * @retval indeterminate the key does not exist
*/
boost::logic::tribool
verify(const uint8_t* buf, size_t bufLen, const uint8_t* sig, size_t sigLen,
@@ -163,7 +168,9 @@
/**
* @brief Create key for @p identityName according to @p params.
*
- * The created key is named as: /<identityName>/[keyId]/KEY
+ * The created key is named as follows:
+ * - RSA and EC keys: `/<identityName>/KEY/<keyId>`
+ * - HMAC keys: `/<identityName>/<keyDigest>`
*
* @return The key name.
* @throw Tpm::Error the key already exists or @p params is invalid.
@@ -206,6 +213,12 @@
const char* pw, size_t pwLen);
/**
+ * @brief Import a private key.
+ */
+ void
+ importPrivateKey(const Name& keyName, shared_ptr<transform::PrivateKey> key);
+
+ /**
* @brief Clear the key cache.
*
* An empty cache can force Tpm to do key lookup in the back-end.
diff --git a/ndn-cxx/security/transform/private-key.cpp b/ndn-cxx/security/transform/private-key.cpp
index 570c18c..659de11 100644
--- a/ndn-cxx/security/transform/private-key.cpp
+++ b/ndn-cxx/security/transform/private-key.cpp
@@ -23,6 +23,7 @@
#include "ndn-cxx/security/transform/base64-decode.hpp"
#include "ndn-cxx/security/transform/base64-encode.hpp"
#include "ndn-cxx/security/transform/buffer-source.hpp"
+#include "ndn-cxx/security/transform/digest-filter.hpp"
#include "ndn-cxx/security/transform/stream-sink.hpp"
#include "ndn-cxx/security/transform/stream-source.hpp"
#include "ndn-cxx/security/impl/openssl-helper.hpp"
@@ -123,6 +124,32 @@
}
}
+ConstBufferPtr
+PrivateKey::getKeyDigest(DigestAlgorithm algo) const
+{
+ if (getKeyType() != KeyType::HMAC)
+ NDN_THROW(Error("Digest is not supported for key type " +
+ boost::lexical_cast<std::string>(getKeyType())));
+
+ const uint8_t* buf = nullptr;
+ size_t len = 0;
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ buf = EVP_PKEY_get0_hmac(m_impl->key, &len);
+#else
+ const auto* octstr = reinterpret_cast<ASN1_OCTET_STRING*>(EVP_PKEY_get0(m_impl->key));
+ buf = octstr->data;
+ len = octstr->length;
+#endif
+ if (buf == nullptr)
+ NDN_THROW(Error("Failed to obtain raw key pointer"));
+ if (len * 8 != getKeySize())
+ NDN_THROW(Error("Key length mismatch"));
+
+ OBufferStream os;
+ bufferSource(buf, len) >> digestFilter(algo) >> streamSink(os);
+ return os.buf();
+}
+
void
PrivateKey::loadRaw(KeyType type, const uint8_t* buf, size_t size)
{
diff --git a/ndn-cxx/security/transform/private-key.hpp b/ndn-cxx/security/transform/private-key.hpp
index 1e31b8d..85051f3 100644
--- a/ndn-cxx/security/transform/private-key.hpp
+++ b/ndn-cxx/security/transform/private-key.hpp
@@ -77,6 +77,14 @@
getKeySize() const;
/**
+ * @brief Returns a digest of the private key.
+ *
+ * @note Currently supports only HMAC keys.
+ */
+ ConstBufferPtr
+ getKeyDigest(DigestAlgorithm algo) const;
+
+ /**
* @brief Load a raw private key from a buffer @p buf
*
* @note Currently supports only HMAC keys.
diff --git a/ndn-cxx/security/v2/key-chain.cpp b/ndn-cxx/security/v2/key-chain.cpp
index 8043635..05fc2b1 100644
--- a/ndn-cxx/security/v2/key-chain.cpp
+++ b/ndn-cxx/security/v2/key-chain.cpp
@@ -282,6 +282,12 @@
return key;
}
+Name
+KeyChain::createHmacKey(const Name& prefix, const HmacKeyParams& params)
+{
+ return m_tpm->createKey(prefix, params);
+}
+
void
KeyChain::deleteKey(const Identity& identity, const Key& key)
{
@@ -424,6 +430,21 @@
key.addCertificate(cert);
}
+void
+KeyChain::importPrivateKey(const Name& keyName, shared_ptr<transform::PrivateKey> key)
+{
+ if (m_tpm->hasKey(keyName)) {
+ NDN_THROW(Error("Private key `" + keyName.toUri() + "` already exists"));
+ }
+
+ try {
+ m_tpm->importPrivateKey(keyName, std::move(key));
+ }
+ catch (const tpm::BackEnd::Error&) {
+ NDN_THROW_NESTED(Error("Failed to import private key `" + keyName.toUri() + "`"));
+ }
+}
+
// public: signing
void
@@ -578,8 +599,6 @@
KeyChain::prepareSignatureInfo(const SigningInfo& params)
{
SignatureInfo sigInfo = params.getSignatureInfo();
- name::Component keyId;
- Name certificateName;
pib::Identity identity;
pib::Key key;
@@ -590,6 +609,7 @@
}
catch (const Pib::Error&) { // no default identity, use sha256 for signing.
sigInfo.setSignatureType(tlv::DigestSha256);
+ NDN_LOG_TRACE("Prepared signature info: " << sigInfo);
return std::make_tuple(SigningInfo::getDigestSha256Identity(), sigInfo);
}
break;
@@ -612,9 +632,7 @@
if (!key) {
Name identityName = extractIdentityFromKeyName(params.getSignerName());
try {
- identity = m_pib->getIdentity(identityName);
- key = identity.getKey(params.getSignerName());
- identity = Identity(); // we will use the PIB key instance, so reset identity;
+ key = m_pib->getIdentity(identityName).getKey(params.getSignerName());
}
catch (const Pib::Error&) {
NDN_THROW_NESTED(InvalidSigningInfoError("Signing key `" +
@@ -638,19 +656,29 @@
}
case SigningInfo::SIGNER_TYPE_SHA256: {
sigInfo.setSignatureType(tlv::DigestSha256);
+ NDN_LOG_TRACE("Prepared signature info: " << sigInfo);
return std::make_tuple(SigningInfo::getDigestSha256Identity(), sigInfo);
}
+ case SigningInfo::SIGNER_TYPE_HMAC: {
+ const Name& keyName = params.getSignerName();
+ if (!m_tpm->hasKey(keyName)) {
+ m_tpm->importPrivateKey(keyName, params.getHmacKey());
+ }
+ sigInfo.setSignatureType(getSignatureType(KeyType::HMAC, params.getDigestAlgorithm()));
+ sigInfo.setKeyLocator(keyName);
+ NDN_LOG_TRACE("Prepared signature info: " << sigInfo);
+ return std::make_tuple(keyName, sigInfo);
+ }
default: {
NDN_THROW(InvalidSigningInfoError("Unrecognized signer type " +
boost::lexical_cast<std::string>(params.getSignerType())));
}
}
- if (!identity && !key) {
- NDN_THROW(InvalidSigningInfoError("Cannot determine signing parameters"));
- }
-
- if (identity && !key) {
+ if (!key) {
+ if (!identity) {
+ NDN_THROW(InvalidSigningInfoError("Cannot determine signing parameters"));
+ }
try {
key = identity.getDefaultKey();
}
@@ -663,7 +691,7 @@
BOOST_ASSERT(key);
sigInfo.setSignatureType(getSignatureType(key.getKeyType(), params.getDigestAlgorithm()));
- sigInfo.setKeyLocator(KeyLocator(key.getName()));
+ sigInfo.setKeyLocator(key.getName());
NDN_LOG_TRACE("Prepared signature info: " << sigInfo);
return std::make_tuple(key.getName(), sigInfo);
@@ -687,6 +715,8 @@
return tlv::SignatureSha256WithRsa;
case KeyType::EC:
return tlv::SignatureSha256WithEcdsa;
+ case KeyType::HMAC:
+ return tlv::SignatureHmacWithSha256;
default:
NDN_THROW(Error("Unsupported key type " + boost::lexical_cast<std::string>(keyType)));
}
diff --git a/ndn-cxx/security/v2/key-chain.hpp b/ndn-cxx/security/v2/key-chain.hpp
index 298f14a..1021e8b 100644
--- a/ndn-cxx/security/v2/key-chain.hpp
+++ b/ndn-cxx/security/v2/key-chain.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -147,21 +147,34 @@
public: // Key management
/**
- * @brief Create a key for @p identity according to @p params.
+ * @brief Create a new key for @p identity.
*
- * @param identity reference to a valid Identity object
- * @param params The key parameters if a key needs to be created for the identity (default:
- * EC key with random key id)
+ * @param identity Reference to a valid Identity object
+ * @param params Key creation parameters (default: EC key with random key id)
+ * @pre @p identity must be valid.
*
* If @p identity had no default key selected, the created key will be set as the default for
* this identity.
*
* This method will also create a self-signed certificate for the created key.
- * @pre @p identity must be valid.
*/
Key
createKey(const Identity& identity, const KeyParams& params = getDefaultKeyParams());
+ /**
+ * @brief Create a new HMAC key.
+ *
+ * @param prefix Prefix used to construct the key name (default: `/localhost/identity/hmac`);
+ * the full key name will include additional components according to @p params
+ * @param params Key creation parameters
+ * @return A name that can be subsequently used to reference the created key.
+ *
+ * The newly created key will be inserted in the TPM. HMAC keys don't have any PIB entries.
+ */
+ Name
+ createHmacKey(const Name& prefix = SigningInfo::getHmacIdentity(),
+ const HmacKeyParams& params = HmacKeyParams());
+
/**
* @brief Delete a key @p key of @p identity.
*
@@ -304,7 +317,7 @@
exportSafeBag(const Certificate& certificate, const char* pw, size_t pwLen);
/**
- * @brief Import a pair of certificate and its corresponding private key encapsulated in a SafeBag.
+ * @brief Import a certificate and its corresponding private key from a SafeBag.
*
* If the certificate and key are imported properly, the default setting will be updated as if
* a new key and certificate is added into KeyChain.
@@ -321,6 +334,12 @@
void
importSafeBag(const SafeBag& safeBag, const char* pw, size_t pwLen);
+ /**
+ * @brief Import a private key into the TPM.
+ */
+ void
+ importPrivateKey(const Name& keyName, shared_ptr<transform::PrivateKey> key);
+
NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/**
* @brief Derive SignatureTypeValue according to key type and digest algorithm.
@@ -394,19 +413,15 @@
/**
* @brief Generate a self-signed certificate for a public key.
*
- * The self-signed certificate will also be added into PIB
- *
- * @param keyName The name of the public key
- * @return The generated certificate
+ * The self-signed certificate will also be added to the PIB.
*/
Certificate
selfSign(Key& key);
/**
* @brief Prepare a SignatureInfo TLV according to signing information and return the signing
- * key name
+ * key name.
*
- * @param sigInfo The SignatureInfo to prepare.
* @param params The signing parameters.
* @return The signing key name and prepared SignatureInfo.
* @throw InvalidSigningInfoError when the requested signing method cannot be satisfied.
@@ -415,7 +430,7 @@
prepareSignatureInfo(const SigningInfo& params);
/**
- * @brief Generate a SignatureValue block for a buffer @p buf with size @p size using
+ * @brief Generate a SignatureValue block for a buffer @p buf of size @p size using
* a key with name @p keyName and digest algorithm @p digestAlgorithm.
*/
Block
diff --git a/tests/unit/security/signing-info.t.cpp b/tests/unit/security/signing-info.t.cpp
index 816cb52..e32d5b1 100644
--- a/tests/unit/security/signing-info.t.cpp
+++ b/tests/unit/security/signing-info.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -88,6 +88,16 @@
BOOST_CHECK_EQUAL(infoSha.getSignerType(), SigningInfo::SIGNER_TYPE_SHA256);
BOOST_CHECK_EQUAL(infoSha.getSignerName(), SigningInfo::getEmptyName());
BOOST_CHECK_EQUAL(infoSha.getDigestAlgorithm(), DigestAlgorithm::SHA256);
+
+ std::string encodedKey("QjM3NEEyNkE3MTQ5MDQzN0FBMDI0RTRGQURENUI0OTdGRE"
+ "ZGMUE4RUE2RkYxMkY2RkI2NUFGMjcyMEI1OUNDRg==");
+ info.setSigningHmacKey(encodedKey);
+ BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_HMAC);
+ BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256);
+
+ SigningInfo infoHmac(SigningInfo::SIGNER_TYPE_HMAC, info.getSignerName());
+ BOOST_CHECK_EQUAL(infoHmac.getSignerType(), SigningInfo::SIGNER_TYPE_HMAC);
+ BOOST_CHECK_EQUAL(infoHmac.getDigestAlgorithm(), DigestAlgorithm::SHA256);
}
BOOST_AUTO_TEST_CASE(CustomSignatureInfo)
@@ -127,6 +137,12 @@
BOOST_CHECK_EQUAL(infoCert.getSignerName(), "/my-cert");
BOOST_CHECK_EQUAL(infoCert.getDigestAlgorithm(), DigestAlgorithm::SHA256);
+ SigningInfo infoHmac("hmac-sha256:QjM3NEEyNkE3MTQ5MDQzN0FBMDI0RTRGQURENU"
+ "I0OTdGREZGMUE4RUE2RkYxMkY2RkI2NUFGMjcyMEI1OUNDRg==");
+ BOOST_CHECK_EQUAL(infoHmac.getSignerType(), SigningInfo::SIGNER_TYPE_HMAC);
+ BOOST_CHECK_EQUAL(infoHmac.getSignerName().getPrefix(3), SigningInfo::getHmacIdentity());
+ BOOST_CHECK_EQUAL(infoHmac.getDigestAlgorithm(), DigestAlgorithm::SHA256);
+
SigningInfo infoSha("id:/localhost/identity/digest-sha256");
BOOST_CHECK_EQUAL(infoSha.getSignerType(), SigningInfo::SIGNER_TYPE_SHA256);
BOOST_CHECK_EQUAL(infoSha.getSignerName(), SigningInfo::getEmptyName());
@@ -149,6 +165,9 @@
BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(
SigningInfo(SigningInfo::SIGNER_TYPE_SHA256)),
"id:/localhost/identity/digest-sha256");
+ BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(
+ SigningInfo(SigningInfo::SIGNER_TYPE_HMAC, "/localhost/identity/hmac/1234")),
+ "id:/localhost/identity/hmac/1234");
}
BOOST_AUTO_TEST_CASE(Chaining)
diff --git a/tests/unit/security/tpm/back-end.t.cpp b/tests/unit/security/tpm/back-end.t.cpp
index 1ef374b..aee042f 100644
--- a/tests/unit/security/tpm/back-end.t.cpp
+++ b/tests/unit/security/tpm/back-end.t.cpp
@@ -87,6 +87,28 @@
BOOST_CHECK(tpm.getKeyHandle(keyName) == nullptr);
}
+BOOST_AUTO_TEST_CASE(CreateHmacKey)
+{
+ Name identity("/Test/Identity/HMAC");
+
+ BackEndWrapperMem mem;
+ BackEnd& memTpm = mem.getTpm();
+ auto key = memTpm.createKey(identity, HmacKeyParams());
+ BOOST_REQUIRE(key != nullptr);
+ BOOST_CHECK(!key->getKeyName().empty());
+ BOOST_CHECK(memTpm.hasKey(key->getKeyName()));
+
+ BackEndWrapperFile file;
+ BackEnd& fileTpm = file.getTpm();
+ BOOST_CHECK_THROW(fileTpm.createKey(identity, HmacKeyParams()), BackEnd::Error);
+
+#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS
+ BackEndWrapperOsx osx;
+ BackEnd& osxTpm = osx.getTpm();
+ BOOST_CHECK_THROW(osxTpm.createKey(identity, HmacKeyParams()), BackEnd::Error);
+#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS
+}
+
BOOST_AUTO_TEST_CASE_TEMPLATE(RsaSigning, T, TestBackEnds)
{
T wrapper;
diff --git a/tests/unit/security/transform/private-key.t.cpp b/tests/unit/security/transform/private-key.t.cpp
index 79b3599..2317479 100644
--- a/tests/unit/security/transform/private-key.t.cpp
+++ b/tests/unit/security/transform/private-key.t.cpp
@@ -53,6 +53,7 @@
PrivateKey sKey;
BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::NONE);
BOOST_CHECK_EQUAL(sKey.getKeySize(), 0);
+ BOOST_CHECK_THROW(sKey.getKeyDigest(DigestAlgorithm::SHA256), PrivateKey::Error);
BOOST_CHECK_THROW(sKey.derivePublicKey(), PrivateKey::Error);
const uint8_t theAnswer = 42;
BOOST_CHECK_THROW(sKey.decrypt(&theAnswer, sizeof(theAnswer)), PrivateKey::Error);
@@ -62,6 +63,21 @@
BOOST_CHECK_THROW(sKey.savePkcs8(os, passwd.data(), passwd.size()), PrivateKey::Error);
}
+BOOST_AUTO_TEST_CASE(KeyDigest)
+{
+ const Buffer buf(16);
+ PrivateKey sKey;
+ sKey.loadRaw(KeyType::HMAC, buf.data(), buf.size());
+ auto digest = sKey.getKeyDigest(DigestAlgorithm::SHA256);
+
+ const uint8_t expected[] = {
+ 0x37, 0x47, 0x08, 0xff, 0xf7, 0x71, 0x9d, 0xd5, 0x97, 0x9e, 0xc8, 0x75, 0xd5, 0x6c, 0xd2, 0x28,
+ 0x6f, 0x6d, 0x3c, 0xf7, 0xec, 0x31, 0x7a, 0x3b, 0x25, 0x63, 0x2a, 0xab, 0x28, 0xec, 0x37, 0xbb,
+ };
+ BOOST_CHECK_EQUAL_COLLECTIONS(digest->begin(), digest->end(),
+ expected, expected + sizeof(expected));
+}
+
BOOST_AUTO_TEST_CASE(LoadRaw)
{
const Buffer buf(32);
diff --git a/tests/unit/security/v2/key-chain.t.cpp b/tests/unit/security/v2/key-chain.t.cpp
index 8f5844b..17f8569 100644
--- a/tests/unit/security/v2/key-chain.t.cpp
+++ b/tests/unit/security/v2/key-chain.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -22,6 +22,7 @@
#include "ndn-cxx/security/v2/key-chain.hpp"
#include "ndn-cxx/security/signing-helpers.hpp"
#include "ndn-cxx/security/verification-helpers.hpp"
+#include "ndn-cxx/security/transform/private-key.hpp"
#include "tests/boost-test.hpp"
#include "tests/identity-management-fixture.hpp"
@@ -222,12 +223,11 @@
BOOST_CHECK(id);
BOOST_CHECK(m_keyChain.getPib().getIdentities().find(identityName) != m_keyChain.getPib().getIdentities().end());
// The first added identity becomes the default identity
- BOOST_REQUIRE_NO_THROW(m_keyChain.getPib().getDefaultIdentity());
+ BOOST_CHECK_NO_THROW(m_keyChain.getPib().getDefaultIdentity());
// The default key of the added identity must exist
- Key key;
- BOOST_REQUIRE_NO_THROW(key = id.getDefaultKey());
+ Key key = id.getDefaultKey();
// The default certificate of the default key must exist
- BOOST_REQUIRE_NO_THROW(key.getDefaultCertificate());
+ BOOST_CHECK_NO_THROW(key.getDefaultCertificate());
// Delete key
Name key1Name = key.getName();
@@ -242,12 +242,11 @@
// Create another key
m_keyChain.createKey(id);
// The added key becomes the default key.
- BOOST_REQUIRE_NO_THROW(id.getDefaultKey());
Key key2 = id.getDefaultKey();
BOOST_REQUIRE(key2);
BOOST_CHECK_NE(key2.getName(), key1Name);
BOOST_CHECK_EQUAL(id.getKeys().size(), 1);
- BOOST_REQUIRE_NO_THROW(key2.getDefaultCertificate());
+ BOOST_CHECK_NO_THROW(key2.getDefaultCertificate());
// Create the third key
Key key3 = m_keyChain.createKey(id);
@@ -255,7 +254,7 @@
// The added key will not be the default key, because the default key already exists
BOOST_CHECK_EQUAL(id.getDefaultKey().getName(), key2.getName());
BOOST_CHECK_EQUAL(id.getKeys().size(), 2);
- BOOST_REQUIRE_NO_THROW(key3.getDefaultCertificate());
+ BOOST_CHECK_NO_THROW(key3.getDefaultCertificate());
// Delete cert
BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1);
@@ -268,7 +267,7 @@
// Add cert
m_keyChain.addCertificate(key3, key3Cert1);
BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1);
- BOOST_REQUIRE_NO_THROW(key3.getDefaultCertificate());
+ BOOST_CHECK_NO_THROW(key3.getDefaultCertificate());
m_keyChain.addCertificate(key3, key3Cert1); // overwriting the cert should work
BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1);
// Add another cert
@@ -310,7 +309,10 @@
Key key = id.getDefaultKey();
Certificate cert = key.getDefaultCertificate();
- std::list<SigningInfo> signingInfos = {
+ Name hmacKeyName = m_keyChain.createHmacKey();
+ const Tpm& tpm = m_keyChain.getTpm();
+
+ std::vector<SigningInfo> signingInfos = {
SigningInfo(),
SigningInfo(SigningInfo::SIGNER_TYPE_ID, id.getName()),
@@ -329,6 +331,9 @@
signingByCertificate(cert.getName()),
signingByCertificate(cert),
+ SigningInfo(SigningInfo::SIGNER_TYPE_HMAC, hmacKeyName),
+ SigningInfo("hmac-sha256:QjM3NEEyNkE3MTQ5MDQzN0FBMDI0RTRGQURENUI0OTdGREZGMUE4RUE2RkYxMkY2RkI2NUFGMjcyMEI1OUNDRg=="),
+
SigningInfo(SigningInfo::SIGNER_TYPE_SHA256),
signingWithSha256()
};
@@ -356,6 +361,25 @@
BOOST_CHECK(verifyDigest(data, DigestAlgorithm::SHA256));
BOOST_CHECK(verifyDigest(interest, DigestAlgorithm::SHA256));
}
+ else if (signingInfo.getSignerType() == SigningInfo::SIGNER_TYPE_HMAC) {
+ Name keyName = signingInfo.getSignerName();
+ BOOST_CHECK_EQUAL(data.getSignature().getType(), tlv::SignatureHmacWithSha256);
+ BOOST_CHECK_EQUAL(interestSignature.getType(), tlv::SignatureHmacWithSha256);
+
+ BOOST_CHECK(bool(tpm.verify(data.wireEncode().value(),
+ data.wireEncode().value_size() - data.getSignature().getValue().size(),
+ data.getSignature().getValue().value(),
+ data.getSignature().getValue().value_size(),
+ keyName, DigestAlgorithm::SHA256)));
+
+ const Name& interestName = interest.getName();
+ auto nameBlock = interestName.wireEncode();
+ BOOST_CHECK(bool(tpm.verify(nameBlock.value(),
+ nameBlock.value_size() - interestName[signed_interest::POS_SIG_VALUE].size(),
+ interestName[signed_interest::POS_SIG_VALUE].blockFromValue().value(),
+ interestName[signed_interest::POS_SIG_VALUE].blockFromValue().value_size(),
+ keyName, DigestAlgorithm::SHA256)));
+ }
else {
BOOST_CHECK_EQUAL(data.getSignature().getType(), tlv::SignatureSha256WithEcdsa);
BOOST_CHECK_EQUAL(interestSignature.getType(), tlv::SignatureSha256WithEcdsa);
@@ -391,9 +415,21 @@
BOOST_CHECK(id.getName().isPrefixOf(data.getSignature().getKeyLocator().getName()));
}
+BOOST_FIXTURE_TEST_CASE(ImportPrivateKey, IdentityManagementFixture)
+{
+ Name keyName("/test/device2");
+ std::string rawKey("nPSNOHyZKsg2WLqHAs7MXGb0sjQb4zCT");
+ auto key = make_shared<transform::PrivateKey>();
+ key->loadRaw(KeyType::HMAC, reinterpret_cast<const uint8_t*>(rawKey.data()), rawKey.size());
+
+ m_keyChain.importPrivateKey(keyName, key);
+ BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(keyName), true);
+ BOOST_CHECK_THROW(m_keyChain.importPrivateKey(keyName, key), KeyChain::Error);
+}
+
BOOST_FIXTURE_TEST_CASE(ExportImport, IdentityManagementFixture)
{
- Identity id = addIdentity("/TestKeyChain/ExportIdentity/");
+ Identity id = addIdentity("/TestKeyChain/ExportIdentity");
Certificate cert = id.getDefaultKey().getDefaultCertificate();
shared_ptr<SafeBag> exported = m_keyChain.exportSafeBag(cert, "1234", 4);
@@ -412,13 +448,11 @@
BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(cert.getKeyName()), true);
BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 1);
- BOOST_REQUIRE_NO_THROW(m_keyChain.getPib().getIdentity(cert.getIdentity()));
Identity newId = m_keyChain.getPib().getIdentity(cert.getIdentity());
BOOST_CHECK_EQUAL(newId.getKeys().size(), 1);
- BOOST_REQUIRE_NO_THROW(newId.getKey(cert.getKeyName()));
Key newKey = newId.getKey(cert.getKeyName());
BOOST_CHECK_EQUAL(newKey.getCertificates().size(), 1);
- BOOST_REQUIRE_NO_THROW(newKey.getCertificate(cert.getName()));
+ BOOST_CHECK_NO_THROW(newKey.getCertificate(cert.getName()));
m_keyChain.deleteIdentity(newId);
BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 0);