security: add HMAC support in KeyChain and SigningInfo

Refs: #3075
Change-Id: Ia1f557ca7c83f4df7f9f87bbe1b4fc214940dcd8
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);