security: Add interface to request different key id generation

The option for key id include timestamp, random, and user-specified
value.

This commit only adds the interface, the support to honor the interface
will be implemented later.

Change-Id: I476381ff0fc56cd7906392cb7482b7458e386781
Refs: #2948
diff --git a/src/security/key-params.cpp b/src/security/key-params.cpp
index 7ee2e1e..792efe1 100644
--- a/src/security/key-params.cpp
+++ b/src/security/key-params.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2014 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -23,37 +23,50 @@
 
 namespace ndn {
 
-static const uint32_t RSA_KEY_SIZES[] = {2048, 1024};
+static const uint32_t MIN_RSA_KEY_SIZE = 1024;
+static const uint32_t DEFAULT_RSA_KEY_SIZE = 2048;
 static const uint32_t ECDSA_KEY_SIZES[] = {256, 384};
-static const uint32_t AES_KEY_SIZES[] = {64, 128, 256};
+static const uint32_t AES_KEY_SIZES[] = {128, 192, 256};
+
+KeyParams::~KeyParams() = default;
+
+KeyParams::KeyParams(KeyType keyType, KeyIdType keyIdType)
+  : m_keyType(keyType)
+  , m_keyIdType(keyIdType)
+{
+  BOOST_ASSERT(keyIdType != KeyIdType::USER_SPECIFIED);
+}
+
+KeyParams::KeyParams(KeyType keyType, const name::Component& keyId)
+  : m_keyType(keyType)
+  , m_keyIdType(KeyIdType::USER_SPECIFIED)
+  , m_keyId(keyId)
+{
+  BOOST_ASSERT(!keyId.empty());
+}
 
 uint32_t
 RsaKeyParamsInfo::checkKeySize(uint32_t size)
 {
-  for (size_t i = 0; i < (sizeof(RSA_KEY_SIZES) / sizeof(uint32_t)); i++)
-    {
-      if (RSA_KEY_SIZES[i] == size)
-        return size;
-    }
-  return getDefaultSize();
+  if (size < MIN_RSA_KEY_SIZE)
+    BOOST_THROW_EXCEPTION(KeyParams::Error("Unsupported key size"));
+  return size;
 }
 
 uint32_t
 RsaKeyParamsInfo::getDefaultSize()
 {
-  return RSA_KEY_SIZES[0];
+  return DEFAULT_RSA_KEY_SIZE;
 }
 
 uint32_t
 EcdsaKeyParamsInfo::checkKeySize(uint32_t size)
 {
-
-  for (size_t i = 0; i < (sizeof(ECDSA_KEY_SIZES) / sizeof(uint32_t)); i++)
-    {
-      if (ECDSA_KEY_SIZES[i] == size)
-        return size;
-    }
-  return getDefaultSize();
+  for (size_t i = 0; i < (sizeof(ECDSA_KEY_SIZES) / sizeof(ECDSA_KEY_SIZES[0])); i++) {
+    if (ECDSA_KEY_SIZES[i] == size)
+      return size;
+  }
+  BOOST_THROW_EXCEPTION(KeyParams::Error("Unsupported key size"));
 }
 
 uint32_t
@@ -66,12 +79,11 @@
 uint32_t
 AesKeyParamsInfo::checkKeySize(uint32_t size)
 {
-  for (size_t i = 0; i < (sizeof(AES_KEY_SIZES) / sizeof(uint32_t)); i++)
-    {
-      if (AES_KEY_SIZES[i] == size)
-        return size;
-    }
-  return getDefaultSize();
+  for (size_t i = 0; i < (sizeof(AES_KEY_SIZES) / sizeof(AES_KEY_SIZES[0])); i++) {
+    if (AES_KEY_SIZES[i] == size)
+      return size;
+  }
+  BOOST_THROW_EXCEPTION(KeyParams::Error("Unsupported key size"));
 }
 
 uint32_t
diff --git a/src/security/key-params.hpp b/src/security/key-params.hpp
index 9769270..8f28a3e 100644
--- a/src/security/key-params.hpp
+++ b/src/security/key-params.hpp
@@ -23,6 +23,7 @@
 #define NDN_SECURITY_KEY_PARAMS_HPP
 
 #include "../common.hpp"
+#include "../name-component.hpp"
 #include "security-common.hpp"
 
 namespace ndn {
@@ -46,9 +47,7 @@
   };
 
   virtual
-  ~KeyParams()
-  {
-  }
+  ~KeyParams();
 
   KeyType
   getKeyType() const
@@ -56,15 +55,48 @@
     return m_keyType;
   }
 
-protected:
-  explicit
-  KeyParams(KeyType keyType)
-    : m_keyType(keyType)
+  KeyIdType
+  getKeyIdType() const
   {
+    return m_keyIdType;
   }
 
+  void
+  setKeyId(const name::Component& keyId)
+  {
+    m_keyId = keyId;
+  }
+
+  const name::Component&
+  getKeyId() const
+  {
+    return m_keyId;
+  }
+
+protected:
+  /**
+   * @brief Create a key generation parameter
+   *
+   * @param keyType Type of the created key
+   * @param keyIdType The method how the key id should be generated; must not be
+                      KeyIdType::USER_SPECIFIED
+   */
+  KeyParams(KeyType keyType, KeyIdType keyIdType);
+
+  /**
+   * @brief Create a key generation parameter
+   *
+   * @param keyType Type of the created key
+   * @param keyId The user-specified key id. The keyIdType will be set to KeyIdType::USER_SPECIFIED.
+   *              keyId MUST NOT be the empty component.
+   * @post getKeyIdType() == KeyIdType::USER_SPECIFIED
+   */
+  KeyParams(KeyType keyType, const name::Component& keyId);
+
 private:
   KeyType m_keyType;
+  KeyIdType m_keyIdType;
+  name::Component m_keyId;
 };
 
 
@@ -78,7 +110,11 @@
     return KeyType::RSA;
   }
 
-  /// @brief check if size is qualified, otherwise return the default key size.
+  /**
+   * @brief check if @p size is qualified.
+   *
+   * @throw KeyParams::Error if the key size is not supported.
+   */
   static uint32_t
   checkKeySize(uint32_t size);
 
@@ -96,7 +132,11 @@
     return KeyType::EC;
   }
 
-  /// @brief check if size is qualified, otherwise return the default key size.
+  /**
+   * @brief check if @p size is qualified.
+   *
+   * @throw KeyParams::Error if the key size is not supported.
+   */
   static uint32_t
   checkKeySize(uint32_t size);
 
@@ -110,25 +150,27 @@
 class SimplePublicKeyParams : public KeyParams
 {
 public:
+  /// @brief Create key parameter with user specified @p keyId.
   explicit
-  SimplePublicKeyParams(uint32_t size = KeyParamsInfo::getDefaultSize())
-    : KeyParams(KeyParamsInfo::getType())
+  SimplePublicKeyParams(const name::Component& keyId,
+                        uint32_t size = KeyParamsInfo::getDefaultSize())
+    : KeyParams(KeyParamsInfo::getType(), keyId)
   {
     setKeySize(size);
   }
 
+  /**
+   * @brief Create key parameter with auto-created keyId.
+   *
+   * This method is used only if user does not want to maintain the uniqueness of key name.
+   * By default, an 8-byte random number will be used as the key Id.
+   */
   explicit
-  SimplePublicKeyParams(const SimplePublicKeyParams& params)
-    : KeyParams(params)
-    , m_size(params.m_size)
+  SimplePublicKeyParams(uint32_t size = KeyParamsInfo::getDefaultSize(),
+                        KeyIdType keyIdType = KeyIdType::RANDOM)
+    : KeyParams(KeyParamsInfo::getType(), keyIdType)
   {
-  }
-
-  explicit
-  SimplePublicKeyParams(const KeyParams& params)
-    : KeyParams(params.getKeyType())
-  {
-    BOOST_THROW_EXCEPTION(KeyParams::Error("Incorrect key parameters (incompatible key type)"));
+    setKeySize(size);
   }
 
   uint32_t
@@ -171,7 +213,11 @@
     return KeyType::AES;
   }
 
-  /// @brief check if size is qualified, otherwise return the default key size.
+  /**
+   * @brief check if @p size is qualified.
+   *
+   * @return KeyParams::Error if the key size is not supported.
+   */
   static uint32_t
   checkKeySize(uint32_t size);
 
@@ -185,26 +231,15 @@
 class SimpleSymmetricKeyParams : public KeyParams
 {
 public:
+  /// @brief Create key parameter with user specified @p keyId.
   explicit
-  SimpleSymmetricKeyParams(uint32_t size = KeyParamsInfo::getDefaultSize())
-    : KeyParams(KeyParamsInfo::getType())
+  SimpleSymmetricKeyParams(const name::Component& keyId,
+                           uint32_t size = KeyParamsInfo::getDefaultSize())
+    : KeyParams(KeyParamsInfo::getType(), keyId)
   {
     setKeySize(size);
   }
 
-  explicit
-  SimpleSymmetricKeyParams(const SimpleSymmetricKeyParams& params)
-    : KeyParams(params)
-    , m_size(params.m_size)
-  {
-  }
-
-  explicit
-  SimpleSymmetricKeyParams(const KeyParams& params)
-  {
-    BOOST_THROW_EXCEPTION(KeyParams::Error("Incorrect key parameters (incompatible key type)"));
-  }
-
   uint32_t
   getKeySize() const
   {
@@ -226,7 +261,6 @@
 
 private:
   uint32_t m_size;
-
 };
 
 typedef SimpleSymmetricKeyParams<AesKeyParamsInfo> AesKeyParams;
diff --git a/src/security/security-common.cpp b/src/security/security-common.cpp
index 0ea60cb..cda5fc5 100644
--- a/src/security/security-common.cpp
+++ b/src/security/security-common.cpp
@@ -25,120 +25,99 @@
 namespace ndn {
 
 std::ostream&
+operator<<(std::ostream& os, KeyIdType keyIdType)
+{
+  switch (keyIdType) {
+    case KeyIdType::USER_SPECIFIED:
+      return os << "USER_SPECIFIED";
+    case KeyIdType::SHA256:
+      return os << "SHA256";
+    case KeyIdType::RANDOM:
+      return os << "RANDOM";
+  }
+  return os << static_cast<int>(keyIdType);
+}
+
+std::ostream&
 operator<<(std::ostream& os, KeyType keyType)
 {
   switch (keyType) {
-  case KeyType::NONE:
-    os << "NONE";
-    break;
-  case KeyType::RSA:
-    os << "RSA";
-    break;
-  case KeyType::EC:
-    os << "EC";
-    break;
-  case KeyType::AES:
-    os << "AES";
-    break;
-  default:
-    os << static_cast<int>(keyType);
-    break;
+    case KeyType::NONE:
+      return os << "NONE";
+    case KeyType::RSA:
+      return os << "RSA";
+    case KeyType::EC:
+      return os << "EC";
+    case KeyType::AES:
+      return os << "AES";
   };
-  return os;
+  return os << static_cast<int>(keyType);
 }
 
 std::ostream&
 operator<<(std::ostream& os, KeyClass keyClass)
 {
   switch (keyClass) {
-  case KeyClass::NONE:
-    os << "NONE";
-    break;
-  case KeyClass::PUBLIC:
-    os << "PUBLIC";
-    break;
-  case KeyClass::PRIVATE:
-    os << "PRIVATE";
-    break;
-  case KeyClass::SYMMETRIC:
-    os << "SYMMETRIC";
-    break;
-  default:
-    os << static_cast<int>(keyClass);
-    break;
+    case KeyClass::NONE:
+      return os << "NONE";
+    case KeyClass::PUBLIC:
+      return os << "PUBLIC";
+    case KeyClass::PRIVATE:
+      return os << "PRIVATE";
+    case KeyClass::SYMMETRIC:
+      return os << "SYMMETRIC";
   };
-  return os;
+  return os << static_cast<int>(keyClass);
 }
 
 std::ostream&
 operator<<(std::ostream& os, DigestAlgorithm algorithm)
 {
   switch (algorithm) {
-  case DigestAlgorithm::NONE:
-    os << "NONE";
-    break;
-  case DigestAlgorithm::SHA256:
-    os << "SHA256";
-    break;
-  default:
-    os << static_cast<int>(algorithm);
-    break;
+    case DigestAlgorithm::NONE:
+      return os << "NONE";
+    case DigestAlgorithm::SHA256:
+      return os << "SHA256";
   };
-  return os;
+  return os << static_cast<int>(algorithm);
 }
 
 std::ostream&
 operator<<(std::ostream& os, BlockCipherAlgorithm algorithm)
 {
   switch (algorithm) {
-  case BlockCipherAlgorithm::NONE:
-    os << "NONE";
-    break;
-  case BlockCipherAlgorithm::AES_CBC:
-    os << "AES_CBC";
-    break;
-  default:
-    os << static_cast<int>(algorithm);
-    break;
+    case BlockCipherAlgorithm::NONE:
+      return os << "NONE";
+    case BlockCipherAlgorithm::AES_CBC:
+      return os << "AES_CBC";
   };
-  return os;
+  return os << static_cast<int>(algorithm);
 }
 
 std::ostream&
 operator<<(std::ostream& os, CipherOperator op)
 {
   switch (op) {
-  case CipherOperator::DECRYPT:
-    os << "DECRYPT";
-    break;
-  case CipherOperator::ENCRYPT:
-    os << "ENCRYPT";
-    break;
-  default:
-    os << static_cast<int>(op);
-    break;
+    case CipherOperator::DECRYPT:
+      return os << "DECRYPT";
+    case CipherOperator::ENCRYPT:
+      return os << "ENCRYPT";
   };
-  return os;
+  return os << static_cast<int>(op);
 }
 
 std::ostream&
 operator<<(std::ostream& os, AclType aclType)
 {
   switch (aclType) {
-  case AclType::NONE:
-    os << "NONE";
-    break;
-  case AclType::PUBLIC:
-    os << "PUBLIC";
-    break;
-  case AclType::PRIVATE:
-    os << "PRIVATE";
-    break;
-  default:
-    os << static_cast<int>(aclType);
-    break;
+    case AclType::NONE:
+      return os << "NONE";
+    case AclType::PUBLIC:
+      return os << "PUBLIC";
+    case AclType::PRIVATE:
+      return os << "PRIVATE";
   };
-  return os;
+  return os << static_cast<int>(aclType);
 }
 
 } // namespace ndn
diff --git a/src/security/security-common.hpp b/src/security/security-common.hpp
index bd709f5..ef9a42b 100644
--- a/src/security/security-common.hpp
+++ b/src/security/security-common.hpp
@@ -47,6 +47,33 @@
 
 } // namespace signed_interest
 
+/**
+ * @brief The type of KeyId component in a key name
+ */
+enum class KeyIdType {
+  /**
+   * @brief User-specified key ID
+   *
+   * It is user's responsibility to assure the uniqueness of the key names.
+   */
+  USER_SPECIFIED = 0,
+  /**
+   * @brief Use the SHA256 hash of the public key as the key id
+   *
+   * This KeyId type guarantees the uniqueness of the key names.
+   */
+  SHA256 = 1,
+  /**
+   * @brief Use a 64-bit random number as the key id
+   *
+   * This KeyId provides roughly uniqueness of the key names.
+   */
+  RANDOM = 2
+};
+
+std::ostream&
+operator<<(std::ostream& os, KeyIdType keyIdType);
+
 enum class KeyType {
   NONE = 0,
   RSA  = 1,
diff --git a/tests/unit-tests/security/key-params.t.cpp b/tests/unit-tests/security/key-params.t.cpp
index a1fefa4..f8efed1 100644
--- a/tests/unit-tests/security/key-params.t.cpp
+++ b/tests/unit-tests/security/key-params.t.cpp
@@ -23,6 +23,8 @@
 
 #include "boost-test.hpp"
 
+#include <boost/lexical_cast.hpp>
+
 namespace ndn {
 namespace tests {
 
@@ -34,14 +36,21 @@
   RsaKeyParams params;
   BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::RSA);
   BOOST_CHECK_EQUAL(params.getKeySize(), 2048);
+  BOOST_CHECK(params.getKeyIdType() == KeyIdType::RANDOM);
 
-  RsaKeyParams params2(1024);
+  RsaKeyParams params2(1024, KeyIdType::SHA256);
   BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::RSA);
   BOOST_CHECK_EQUAL(params2.getKeySize(), 1024);
+  BOOST_CHECK(params2.getKeyIdType() == KeyIdType::SHA256);
 
-  RsaKeyParams params3(3);
-  BOOST_CHECK_EQUAL(params3.getKeyType(), KeyType::RSA);
-  BOOST_CHECK_EQUAL(params3.getKeySize(), 2048);
+  BOOST_CHECK_THROW(RsaKeyParams(3), KeyParams::Error);
+
+  name::Component keyId("keyId");
+  RsaKeyParams params4(keyId);
+  BOOST_CHECK(params4.getKeyType() == KeyType::RSA);
+  BOOST_CHECK_EQUAL(params4.getKeySize(), 2048);
+  BOOST_CHECK(params4.getKeyIdType() == KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params4.getKeyId(), keyId);
 }
 
 BOOST_AUTO_TEST_CASE(Ecdsa)
@@ -49,44 +58,59 @@
   EcdsaKeyParams params;
   BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::EC);
   BOOST_CHECK_EQUAL(params.getKeySize(), 256);
+  BOOST_CHECK(params.getKeyIdType() == KeyIdType::RANDOM);
 
-  EcdsaKeyParams params2(384);
+  EcdsaKeyParams params2(384, KeyIdType::SHA256);
   BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::EC);
   BOOST_CHECK_EQUAL(params2.getKeySize(), 384);
+  BOOST_CHECK(params2.getKeyIdType() == KeyIdType::SHA256);
 
-  EcdsaKeyParams params3(3);
-  BOOST_CHECK_EQUAL(params3.getKeyType(), KeyType::EC);
-  BOOST_CHECK_EQUAL(params3.getKeySize(), 256);
+  BOOST_CHECK_THROW(EcdsaKeyParams(3), KeyParams::Error);
+
+  name::Component keyId("keyId");
+  EcdsaKeyParams params4(keyId);
+  BOOST_CHECK(params4.getKeyType() == KeyType::EC);
+  BOOST_CHECK_EQUAL(params4.getKeySize(), 256);
+  BOOST_CHECK(params4.getKeyIdType() == KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params4.getKeyId(), keyId);
 }
 
 BOOST_AUTO_TEST_CASE(Aes)
 {
-  AesKeyParams params;
+  name::Component keyId("keyId");
+  AesKeyParams params(keyId);
   BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::AES);
-  BOOST_CHECK_EQUAL(params.getKeySize(), 64);
+  BOOST_CHECK_EQUAL(params.getKeySize(), 128);
+  BOOST_CHECK_EQUAL(params.getKeyIdType(), KeyIdType::USER_SPECIFIED);
 
-  AesKeyParams params2(128);
-  BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::AES);
-  BOOST_CHECK_EQUAL(params2.getKeySize(), 128);
+  AesKeyParams params2(keyId, 192);
+  BOOST_CHECK(params2.getKeyType() == KeyType::AES);
+  BOOST_CHECK_EQUAL(params2.getKeySize(), 192);
+  BOOST_CHECK(params.getKeyIdType() == KeyIdType::USER_SPECIFIED);
 
-  AesKeyParams params3(256);
+  AesKeyParams params3(keyId, 256);
   BOOST_CHECK_EQUAL(params3.getKeyType(), KeyType::AES);
   BOOST_CHECK_EQUAL(params3.getKeySize(), 256);
+  BOOST_CHECK(params.getKeyIdType() == KeyIdType::USER_SPECIFIED);
 
-  AesKeyParams params4(4);
-  BOOST_CHECK_EQUAL(params4.getKeyType(), KeyType::AES);
-  BOOST_CHECK_EQUAL(params4.getKeySize(), 64);
+  BOOST_CHECK_THROW(AesKeyParams(keyId, 4), KeyParams::Error);
+
+  AesKeyParams params5(keyId);
+  BOOST_CHECK_EQUAL(params5.getKeyType(), KeyType::AES);
+  BOOST_CHECK_EQUAL(params5.getKeySize(), 128);
+  BOOST_CHECK_EQUAL(params5.getKeyIdType(), KeyIdType::USER_SPECIFIED);
+  BOOST_CHECK_EQUAL(params5.getKeyId(), keyId);
 }
 
-BOOST_AUTO_TEST_CASE(Error)
+BOOST_AUTO_TEST_CASE(KeyIdTypeInfo)
 {
-  EcdsaKeyParams params;
-  BOOST_REQUIRE_THROW((RsaKeyParams(params)), KeyParams::Error);
-
-  AesKeyParams params2;
-  BOOST_REQUIRE_THROW((RsaKeyParams(params2)), KeyParams::Error);
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(KeyIdType::USER_SPECIFIED), "USER_SPECIFIED");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(KeyIdType::SHA256), "SHA256");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(KeyIdType::RANDOM), "RANDOM");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(static_cast<KeyIdType>(12345)), "12345");
 }
 
+
 BOOST_AUTO_TEST_SUITE_END() // TestKeyParams
 BOOST_AUTO_TEST_SUITE_END() // Security