security: Support KeyType in SecPublicInfo

Change-Id: I0c56b849cd9d659a8f6fd0a0225104ea62bbccd6
Refs: #1648
diff --git a/src/security/sec-public-info-sqlite3.cpp b/src/security/sec-public-info-sqlite3.cpp
index db0bdd4..a690bef 100644
--- a/src/security/sec-public-info-sqlite3.cpp
+++ b/src/security/sec-public-info-sqlite3.cpp
@@ -268,9 +268,8 @@
 }
 
 void
-SecPublicInfoSqlite3::addPublicKey(const Name& keyName,
-                                   KeyType keyType,
-                                   const PublicKey& publicKeyDer)
+SecPublicInfoSqlite3::addKey(const Name& keyName,
+                             const PublicKey& publicKeyDer)
 {
   if (keyName.empty())
     return;
@@ -292,7 +291,7 @@
 
   sqlite3_bind_text(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
   sqlite3_bind_text(statement, 2, keyId, SQLITE_TRANSIENT);
-  sqlite3_bind_int(statement, 3, (int)keyType);
+  sqlite3_bind_int(statement, 3, publicKeyDer.getKeyType());
   sqlite3_bind_blob(statement, 4,
                     publicKeyDer.get().buf(),
                     publicKeyDer.get().size(),
@@ -340,6 +339,39 @@
     }
 }
 
+KeyType
+SecPublicInfoSqlite3::getPublicKeyType(const Name& keyName)
+{
+  if (keyName.empty())
+    return KEY_TYPE_NULL;
+
+  string keyId = keyName.get(-1).toUri();
+  Name identityName = keyName.getPrefix(-1);
+
+  sqlite3_stmt* statement;
+  sqlite3_prepare_v2(m_database,
+                     "SELECT key_type FROM Key WHERE identity_name=? AND key_identifier=?",
+                     -1, &statement, 0);
+
+  sqlite3_bind_text(statement, 1, identityName.toUri(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(statement, 2, keyId, SQLITE_TRANSIENT);
+
+  int res = sqlite3_step(statement);
+
+  if (res == SQLITE_ROW)
+    {
+      int typeValue = sqlite3_column_int(statement, 0);
+      sqlite3_finalize(statement);
+      return static_cast<KeyType>(typeValue);
+    }
+  else
+    {
+      sqlite3_finalize(statement);
+      return KEY_TYPE_NULL;
+    }
+
+}
+
 bool
 SecPublicInfoSqlite3::doesCertificateExist(const Name& certificateName)
 {
@@ -424,8 +456,7 @@
   Name keyName =
     IdentityCertificate::certificateNameToPublicKeyName(certificate.getName());
 
-  //HACK!!! Assume the key type is RSA, we should check more.
-  addPublicKey(keyName, KEY_TYPE_RSA, certificate.getPublicKeyInfo());
+  addKey(keyName, certificate.getPublicKeyInfo());
 
   if (doesCertificateExist(certificateName))
     return;
diff --git a/src/security/sec-public-info-sqlite3.hpp b/src/security/sec-public-info-sqlite3.hpp
index 7c3b7b1..f66b188 100644
--- a/src/security/sec-public-info-sqlite3.hpp
+++ b/src/security/sec-public-info-sqlite3.hpp
@@ -66,11 +66,14 @@
   doesPublicKeyExist(const Name& keyName);
 
   virtual void
-  addPublicKey(const Name& keyName, KeyType keyType, const PublicKey& publicKeyDer);
+  addKey(const Name& keyName, const PublicKey& publicKeyDer);
 
   virtual shared_ptr<PublicKey>
   getPublicKey(const Name& keyName);
 
+  virtual KeyType
+  getPublicKeyType(const Name& keyName);
+
   virtual bool
   doesCertificateExist(const Name& certificateName);
 
diff --git a/src/security/sec-public-info.hpp b/src/security/sec-public-info.hpp
index 29b8f64..509cd09 100644
--- a/src/security/sec-public-info.hpp
+++ b/src/security/sec-public-info.hpp
@@ -99,12 +99,26 @@
   /**
    * @brief Add a public key to the identity storage.
    *
+   * @deprecated Use addKey instead
+   *
    * @param keyName The name of the public key to be added
    * @param keyType Type of the public key to be added
    * @param publicKey Reference to the PublicKey object
    */
+  void
+  addPublicKey(const Name& keyName, KeyType keyType, const PublicKey& publicKey)
+  {
+    addKey(keyName, publicKey);
+  }
+
+  /**
+   * @brief Add a public key to the identity storage.
+   *
+   * @param keyName The name of the public key to be added
+   * @param publicKey Reference to the PublicKey object
+   */
   virtual void
-  addPublicKey(const Name& keyName, KeyType keyType, const PublicKey& publicKey) = 0;
+  addKey(const Name& keyName, const PublicKey& publicKey) = 0;
 
   /**
    * @brief Get shared pointer to PublicKey object from the identity storage
@@ -116,6 +130,18 @@
   getPublicKey(const Name& keyName) = 0;
 
   /**
+   * @brief Get the type of the queried public key
+   *
+   * @note KeyType is also available from PublicKey instance.
+   *       This method is more efficient if only KeyType is needed.
+   *
+   * @param keyName The name of the requested public key
+   * @return the type of the key. If the queried key does not exist, KEY_TYPE_NULL will be returned
+   */
+  virtual KeyType
+  getPublicKeyType(const Name& keyName) = 0;
+
+  /**
    * @brief Check if the specified certificate already exists
    *
    * @param certificateName The name of the certificate
diff --git a/src/security/security-common.hpp b/src/security/security-common.hpp
index f795863..b6b3119 100644
--- a/src/security/security-common.hpp
+++ b/src/security/security-common.hpp
@@ -38,14 +38,14 @@
 } // namespace signed_interest
 
 enum KeyType {
-  KEY_TYPE_RSA,
-  KEY_TYPE_ECDSA,
+  KEY_TYPE_RSA   = 0,
+  KEY_TYPE_ECDSA = 1,
   // KEY_TYPE_DSA,
-  KEY_TYPE_AES,
+  KEY_TYPE_AES   = 128,
   // KEY_TYPE_DES,
   // KEY_TYPE_RC4,
   // KEY_TYPE_RC2
-  KEY_TYPE_NULL
+  KEY_TYPE_NULL  = 255
 };
 
 enum KeyClass {
diff --git a/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp b/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
index b91fed1..547eac0 100644
--- a/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
+++ b/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
@@ -21,6 +21,8 @@
 
 #include "security/sec-public-info-sqlite3.hpp"
 #include "security/key-chain.hpp"
+#include "security/cryptopp.hpp"
+#include "encoding/buffer-stream.hpp"
 #include "util/time.hpp"
 
 #include "boost-test.hpp"
@@ -30,6 +32,16 @@
 
 BOOST_AUTO_TEST_SUITE(SecurityTestSecPublicInfoSqlite3)
 
+const std::string RSA_DER("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuFoDcNtffwbfFix64fw0\
+hI2tKMkFrc6Ex7yw0YLMK9vGE8lXOyBl/qXabow6RCz+GldmFN6E2Qhm1+AX3Zm5\
+sj3H53/HPtzMefvMQ9X7U+lK8eNMWawpRzvBh4/36VrK/awlkNIVIQ9aXj6q6BVe\
+zL+zWT/WYemLq/8A1/hHWiwCtfOH1xQhGqWHJzeSgwIgOOrzxTbRaCjhAb1u2TeV\
+yx/I9H/DV+AqSHCaYbB92HDcDN0kqwSnUf5H1+osE9MR5DLBLhXdSiULSgxT3Or/\
+y2QgsgUK59WrjhlVMPEiHHRs15NZJbL1uQFXjgScdEarohcY3dilqotineFZCeN8\
+DwIDAQAB");
+const std::string ECDSA_DER("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENZpqkPJDj8uhSpffOiCbvSYMLsGB\
+1Eo/WU6mrexjGvduQXjqwon/eSHFI6EgHZk8L9KfiV5XVtVsk2g5wIpJVg==");
+
 BOOST_AUTO_TEST_CASE(Delete)
 {
   BOOST_REQUIRE_NO_THROW(KeyChain("sqlite3", "file"));
@@ -98,6 +110,52 @@
   BOOST_CHECK_EQUAL(keyChain.doesIdentityExist(identity), false);
 }
 
+BOOST_AUTO_TEST_CASE(KeyTypeRsa)
+{
+  using namespace CryptoPP;
+
+  OBufferStream os;
+  StringSource ss(reinterpret_cast<const uint8_t*>(RSA_DER.c_str()), RSA_DER.size(),
+                  true, new Base64Decoder(new FileSink(os)));
+
+  shared_ptr<PublicKey> rsaKey;
+  BOOST_REQUIRE_NO_THROW(rsaKey = shared_ptr<PublicKey>(new PublicKey(os.buf()->buf(),
+                                                                      os.buf()->size())));
+  Name rsaKeyName("/TestSecPublicInfoSqlite3/KeyType/RSA");
+  SecPublicInfoSqlite3 pib;
+  pib.addPublicKey(rsaKeyName, rsaKey->getKeyType(), *rsaKey);
+
+  BOOST_CHECK_EQUAL(KEY_TYPE_RSA, pib.getPublicKeyType(rsaKeyName));
+}
+
+BOOST_AUTO_TEST_CASE(KeyTypeEcdsa)
+{
+  using namespace CryptoPP;
+
+  OBufferStream os;
+  StringSource ss(reinterpret_cast<const uint8_t*>(ECDSA_DER.c_str()), ECDSA_DER.size(),
+                  true, new Base64Decoder(new FileSink(os)));
+
+  shared_ptr<PublicKey> ecdsaKey;
+  BOOST_REQUIRE_NO_THROW(ecdsaKey = shared_ptr<PublicKey>(new PublicKey(os.buf()->buf(),
+                                                                        os.buf()->size())));
+  Name ecdsaKeyName("/TestSecPublicInfoSqlite3/KeyType/ECDSA");
+  SecPublicInfoSqlite3 pib;
+  pib.addPublicKey(ecdsaKeyName, ecdsaKey->getKeyType(), *ecdsaKey);
+
+  BOOST_CHECK_EQUAL(KEY_TYPE_ECDSA, pib.getPublicKeyType(ecdsaKeyName));
+
+}
+
+BOOST_AUTO_TEST_CASE(KeyTypeNonExist)
+{
+  Name nullKeyName("/TestSecPublicInfoSqlite3/KeyType/Null");
+  SecPublicInfoSqlite3 pib;
+
+  BOOST_CHECK_EQUAL(KEY_TYPE_NULL, pib.getPublicKeyType(nullKeyName));
+
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace ndn