security: New generalized signing API in KeyChain

A new API in KeyChain introduces a general interface to sign interest
and data packets and supply necessary signing information, such as
signing identity name, signing key name, or signing certificate name.
In addition, the supplied signing information can include additional
information that signer wants to include in the SignatureInfo of the
signed packet.

Old sign methods `KeyChain::sign(Packet, Name)`, `KeyChain::sign(uint8_t*, size_t, Name)`,
`KeyChain::signByIdentity(Packet, Name)`, `KeyChain::signByIdentity(uint8_t*, size_t, Name)`,
`KeyChain::signWithSha256(Data)`, and `KeyChain::signWithSha256(Interest)`
are now deprecated and will be removed in the next release.

Change-Id: I086e6c6522f70bcb7799e7dfc4cc4b2f8a3816a0
Refs: #2871, #1705
diff --git a/src/face.hpp b/src/face.hpp
index 47e841e..a42a95f 100644
--- a/src/face.hpp
+++ b/src/face.hpp
@@ -41,12 +41,16 @@
 namespace ndn {
 
 class Transport;
-class KeyChain;
 
 class PendingInterestId;
 class RegisteredPrefixId;
 class InterestFilterId;
 
+namespace security {
+class KeyChain;
+}
+using security::KeyChain;
+
 namespace nfd {
 class Controller;
 }
diff --git a/src/management/nfd-controller.cpp b/src/management/nfd-controller.cpp
index c5d06d4..5f2f133 100644
--- a/src/management/nfd-controller.cpp
+++ b/src/management/nfd-controller.cpp
@@ -51,10 +51,12 @@
     m_keyChain.sign(interest);
     break;
   case CommandOptions::SIGNING_PARAMS_IDENTITY:
-    m_keyChain.signByIdentity(interest, options.getSigningIdentity());
+    m_keyChain.sign(interest, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID,
+                                                    options.getSigningIdentity()));
     break;
   case CommandOptions::SIGNING_PARAMS_CERTIFICATE:
-    m_keyChain.sign(interest, options.getSigningCertificate());
+    m_keyChain.sign(interest, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_CERT,
+                                                    options.getSigningCertificate()));
     break;
   default:
     BOOST_ASSERT(false);
diff --git a/src/security/key-chain.cpp b/src/security/key-chain.cpp
index f4ea723..2950a50 100644
--- a/src/security/key-chain.cpp
+++ b/src/security/key-chain.cpp
@@ -35,9 +35,15 @@
 #include "sec-tpm-file.hpp"
 
 namespace ndn {
+namespace security {
 
 // Use a GUID as a magic number of KeyChain::DEFAULT_PREFIX identifier
 const Name KeyChain::DEFAULT_PREFIX("/723821fd-f534-44b3-80d9-44bf5f58bbbb");
+const Name KeyChain::DIGEST_SHA256_IDENTITY("/localhost/identity/digest-sha256");
+
+// Note: cannot use default constructor, as it depends on static variables which may or may not be
+// initialized at this point
+const SigningInfo KeyChain::DEFAULT_SIGNING_INFO(SigningInfo::SIGNER_TYPE_NULL, Name(), SignatureInfo());
 
 const RsaKeyParams KeyChain::DEFAULT_KEY_PARAMS;
 
@@ -439,41 +445,125 @@
   return certificate;
 }
 
+std::tuple<Name, SignatureInfo>
+KeyChain::prepareSignatureInfo(const SigningInfo& params)
+{
+  SignatureInfo sigInfo = params.getSignatureInfo();
+
+  shared_ptr<IdentityCertificate> signingCert;
+
+  switch (params.getSignerType()) {
+  case SigningInfo::SIGNER_TYPE_NULL:
+    {
+      if (m_pib->getDefaultCertificate() == nullptr)
+        setDefaultCertificateInternal();
+
+      signingCert = m_pib->getDefaultCertificate();
+      break;
+    }
+  case SigningInfo::SIGNER_TYPE_ID:
+    {
+      Name signingCertName;
+      try {
+        signingCertName = m_pib->getDefaultCertificateNameForIdentity(params.getSignerName());
+      }
+      catch (SecPublicInfo::Error&) {
+        signingCertName = createIdentity(params.getSignerName());
+      }
+
+      signingCert = m_pib->getCertificate(signingCertName);
+
+      break;
+    }
+  case SigningInfo::SIGNER_TYPE_KEY:
+    {
+      Name signingCertName;
+      try {
+        signingCertName = m_pib->getDefaultCertificateNameForKey(params.getSignerName());
+      }
+      catch (SecPublicInfo::Error&) {
+        throw Error("signing certificate does not exist");
+      }
+
+      signingCert = m_pib->getCertificate(signingCertName);
+
+      break;
+    }
+  case SigningInfo::SIGNER_TYPE_CERT:
+    {
+      signingCert = m_pib->getCertificate(params.getSignerName());
+      if (signingCert == nullptr)
+        throw Error("signing certificate does not exist");
+
+      break;
+    }
+  case SigningInfo::SIGNER_TYPE_SHA256:
+    {
+      sigInfo.setSignatureType(tlv::DigestSha256);
+      return std::make_tuple(DIGEST_SHA256_IDENTITY, sigInfo);
+    }
+  default:
+    throw Error("Unrecognized signer type");
+  }
+
+  sigInfo.setSignatureType(getSignatureType(signingCert->getPublicKeyInfo().getKeyType(),
+                                            params.getDigestAlgorithm()));
+  sigInfo.setKeyLocator(KeyLocator(signingCert->getName().getPrefix(-1)));
+
+  return std::make_tuple(signingCert->getPublicKeyName(), sigInfo);
+}
+
+void
+KeyChain::sign(Data& data, const SigningInfo& params)
+{
+  signImpl(data, params);
+}
+
+void
+KeyChain::sign(Interest& interest, const SigningInfo& params)
+{
+  signImpl(interest, params);
+}
+
+Block
+KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params)
+{
+  Name keyName;
+  SignatureInfo sigInfo;
+  std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
+  return pureSign(buffer, bufferLength, keyName, DIGEST_ALGORITHM_SHA256);
+}
+
 Signature
 KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
 {
   shared_ptr<IdentityCertificate> certificate = m_pib->getCertificate(certificateName);
 
-  KeyLocator keyLocator(certificate->getName().getPrefix(-1));
-  shared_ptr<Signature> sig =
-    determineSignatureWithPublicKey(keyLocator, certificate->getPublicKeyInfo().getKeyType());
+  if (certificate == nullptr)
+    throw SecPublicInfo::Error("certificate does not exist");
 
-  if (!static_cast<bool>(sig))
-    throw SecTpm::Error("unknown key type");
-
+  Signature sig;
 
   // For temporary usage, we support SHA256 only, but will support more.
-  sig->setValue(m_tpm->signInTpm(buffer, bufferLength,
-                                 certificate->getPublicKeyName(),
-                                 DIGEST_ALGORITHM_SHA256));
+  sig.setValue(m_tpm->signInTpm(buffer, bufferLength,
+                                certificate->getPublicKeyName(),
+                                DIGEST_ALGORITHM_SHA256));
 
-  return *sig;
+  return sig;
 }
 
 shared_ptr<IdentityCertificate>
 KeyChain::selfSign(const Name& keyName)
 {
   shared_ptr<PublicKey> pubKey;
-  try
-    {
-      pubKey = m_pib->getPublicKey(keyName); // may throw an exception.
-    }
-  catch (SecPublicInfo::Error& e)
-    {
-      return shared_ptr<IdentityCertificate>();
-    }
+  try {
+    pubKey = m_pib->getPublicKey(keyName); // may throw an exception.
+  }
+  catch (SecPublicInfo::Error&) {
+    return shared_ptr<IdentityCertificate>();
+  }
 
-  shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
+  auto certificate = make_shared<IdentityCertificate>();
 
   Name certificateName = keyName.getPrefix(-1);
   certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
@@ -486,6 +576,8 @@
                                                                    keyName.toUri()));
   certificate->encode();
 
+  certificate->setSignature(Signature(SignatureInfo()));
+
   selfSign(*certificate);
   return certificate;
 }
@@ -493,19 +585,16 @@
 void
 KeyChain::selfSign(IdentityCertificate& cert)
 {
-  Name keyName = IdentityCertificate::certificateNameToPublicKeyName(cert.getName());
+  Name keyName = cert.getPublicKeyName();
   if (!m_tpm->doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
     throw SecTpm::Error("Private key does not exist");
 
+  SignatureInfo sigInfo(cert.getSignature().getInfo());
+  sigInfo.setKeyLocator(KeyLocator(cert.getName().getPrefix(-1)));
+  sigInfo.setSignatureType(getSignatureType(cert.getPublicKeyInfo().getKeyType(),
+                                            DIGEST_ALGORITHM_SHA256));
 
-  KeyLocator keyLocator(cert.getName().getPrefix(-1));
-  shared_ptr<Signature> sig =
-    determineSignatureWithPublicKey(keyLocator, cert.getPublicKeyInfo().getKeyType());
-
-  if (!static_cast<bool>(sig))
-    throw SecTpm::Error("unknown key type");
-
-  signPacketWrapper(cert, *sig, keyName, DIGEST_ALGORITHM_SHA256);
+  signPacketWrapper(cert, Signature(sigInfo), keyName, DIGEST_ALGORITHM_SHA256);
 }
 
 shared_ptr<SecuredBag>
@@ -568,33 +657,6 @@
   m_pib->addCertificateAsIdentityDefault(securedBag.getCertificate());
 }
 
-shared_ptr<Signature>
-KeyChain::determineSignatureWithPublicKey(const KeyLocator& keyLocator,
-                                          KeyType keyType, DigestAlgorithm digestAlgorithm)
-{
-  switch (keyType)
-    {
-    case KEY_TYPE_RSA:
-      {
-        // For temporary usage, we support SHA256 only, but will support more.
-        if (digestAlgorithm != DIGEST_ALGORITHM_SHA256)
-          return shared_ptr<Signature>();
-
-        return make_shared<SignatureSha256WithRsa>(keyLocator);
-      }
-    case KEY_TYPE_ECDSA:
-      {
-        // For temporary usage, we support SHA256 only, but will support more.
-        if (digestAlgorithm != DIGEST_ALGORITHM_SHA256)
-          return shared_ptr<Signature>();
-
-        return make_shared<SignatureSha256WithEcdsa>(keyLocator);
-      }
-    default:
-      return shared_ptr<Signature>();
-    }
-}
-
 void
 KeyChain::setDefaultCertificateInternal()
 {
@@ -641,9 +703,9 @@
   EncodingBuffer encoder;
   data.wireEncode(encoder, true);
 
-  Block signatureValue = m_tpm->signInTpm(encoder.buf(), encoder.size(),
-                                          keyName, digestAlgorithm);
-  data.wireEncode(encoder, signatureValue);
+  Block sigValue = pureSign(encoder.buf(), encoder.size(), keyName, digestAlgorithm);
+
+  data.wireEncode(encoder, sigValue);
 }
 
 void
@@ -662,15 +724,26 @@
     .append(name::Component::fromNumber(random::generateWord64())) // nonce
     .append(signature.getInfo());                                  // signatureInfo
 
-  Block sigValue = m_tpm->signInTpm(signedName.wireEncode().value(),
-                                    signedName.wireEncode().value_size(),
-                                    keyName,
-                                    digestAlgorithm);
+  Block sigValue = pureSign(signedName.wireEncode().value(),
+                            signedName.wireEncode().value_size(),
+                            keyName,
+                            digestAlgorithm);
+
   sigValue.encode();
   signedName.append(sigValue);                                     // signatureValue
   interest.setName(signedName);
 }
 
+Block
+KeyChain::pureSign(const uint8_t* buf, size_t size,
+                   const Name& keyName, DigestAlgorithm digestAlgorithm) const
+{
+  if (keyName == DIGEST_SHA256_IDENTITY)
+    return Block(tlv::SignatureValue, crypto::sha256(buf, size));
+
+  return m_tpm->signInTpm(buf, size, keyName, digestAlgorithm);
+}
+
 Signature
 KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
 {
@@ -688,7 +761,13 @@
 
   // We either get or create the signing certificate, sign data! (no exception unless fatal error
   // in TPM)
-  return sign(buffer, bufferLength, signingCertificateName);
+  Signature sig;
+
+  // For temporary usage, we support SHA256 only, but will support more.
+  sig.setValue(sign(buffer, bufferLength, SigningInfo(SigningInfo::SIGNER_TYPE_CERT,
+                                                      signingCertificateName)));
+
+  return sig;
 }
 
 void
@@ -754,4 +833,19 @@
     m_tpm->deleteKeyPairInTpm(keyName);
 }
 
+tlv::SignatureTypeValue
+KeyChain::getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm)
+{
+  switch (keyType) {
+    case KEY_TYPE_RSA:
+      return tlv::SignatureSha256WithRsa;
+    case KEY_TYPE_ECDSA:
+      return tlv::SignatureSha256WithEcdsa;
+    default:
+      throw Error("Unsupported key types");
+  }
+
 }
+
+} // namespace security
+} // namespace ndn
diff --git a/src/security/key-chain.hpp b/src/security/key-chain.hpp
index 955733d..7f16cd0 100644
--- a/src/security/key-chain.hpp
+++ b/src/security/key-chain.hpp
@@ -31,6 +31,7 @@
 #include "signature-sha256-with-rsa.hpp"
 #include "signature-sha256-with-ecdsa.hpp"
 #include "digest-sha256.hpp"
+#include "signing-info.hpp"
 
 #include "../interest.hpp"
 #include "../util/crypto.hpp"
@@ -39,7 +40,11 @@
 
 
 namespace ndn {
+namespace security {
 
+/**
+ * @brief The packet signing interface.
+ */
 class KeyChain : noncopyable
 {
 public:
@@ -54,8 +59,8 @@
   };
 
   /**
-   * This error is thrown when the TPM locator retrieved from PIB is
-   * different from what is supplied to the KeyChain constructor.
+   * @brief Error thrown when the supplied TPM locator to KeyChain constructor does not match
+   *        the locator stored in PIB
    */
   class MismatchError : public Error
   {
@@ -88,19 +93,27 @@
   static void
   registerTpm(std::initializer_list<std::string> aliases);
 
-  /// @brief Get default PIB locator
+  /**
+   * @brief Get default PIB locator
+   */
   static std::string
   getDefaultPibLocator();
 
-  /// @brief Create a PIB according to @p pibLocator
+  /**
+    * @brief Create a PIB according to @p pibLocator
+    */
   static unique_ptr<SecPublicInfo>
   createPib(const std::string& pibLocator);
 
-  /// @brief Get default TPM locator
+  /**
+   * @brief Get default TPM locator
+   */
   static std::string
   getDefaultTpmLocator();
 
-  /// @brief Create a TPM according to @p tpmLocator
+  /**
+    * @brief Create a TPM according to @p tpmLocator
+    */
   static unique_ptr<SecTpm>
   createTpm(const std::string& tpmLocator);
 
@@ -149,12 +162,23 @@
    * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
    * @param keySize The size of the key.
    * @return The generated key name.
+   * @see generateEcdsaKeyPair
    */
   Name
   generateRsaKeyPair(const Name& identityName, bool isKsk = false, uint32_t keySize = 2048);
 
+  /**
+   * @brief Generate a pair of ECDSA keys for the specified identity.
+   *
+   * @param identityName The name of the identity.
+   * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
+   * @param keySize The size of the key.
+   * @return The generated key name.
+   * @see generateRsaKeyPair
+   */
   Name
   generateEcdsaKeyPair(const Name& identityName, bool isKsk = false, uint32_t keySize = 256);
+
   /**
    * @brief Generate a pair of RSA keys for the specified identity and set it as default key for
    *        the identity.
@@ -163,11 +187,22 @@
    * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
    * @param keySize The size of the key.
    * @return The generated key name.
+   * @see generateRsaKeyPair, generateEcdsaKeyPair, generateEcdsaKeyPairAsDefault
    */
   Name
   generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk = false,
                               uint32_t keySize = 2048);
 
+  /**
+   * @brief Generate a pair of ECDSA keys for the specified identity and set it as default key for
+   *        the identity.
+   *
+   * @param identityName The name of the identity.
+   * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
+   * @param keySize The size of the key.
+   * @return The generated key name.
+   * @see generateRsaKeyPair, generateEcdsaKeyPair, generateRsaKeyPairAsDefault
+   */
   Name
   generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize = 256);
 
@@ -220,19 +255,58 @@
     const Name& certPrefix = DEFAULT_PREFIX);
 
   /**
-   * @brief Sign packet with default identity
+   * @brief Sign data according to the supplied signing information
    *
-   * On return, signatureInfo and signatureValue in the packet are set.
-   * If default identity does not exist,
-   * a temporary identity will be created and set as default.
+   * This method uses the supplied signing information @p params to create the SignatureInfo block:
+   * - it selects a private key and its certificate to sign the packet
+   * - sets the KeyLocator field with the certificate name, and
+   * - adds other requested information to the SignatureInfo block).
    *
-   * @param packet The packet to be signed
+   * After that, the method assigns the created SignatureInfo to the data packets, generate a
+   * signature and sets as part of the SignatureValue block.
+   *
+   * @param data The data to sign
+   * @param params The signing parameters.
+   * @throws Error if signing fails.
+   * @see SigningInfo
    */
-  template<typename T>
   void
-  sign(T& packet);
+  sign(Data& data, const SigningInfo& params = DEFAULT_SIGNING_INFO);
 
   /**
+   * @brief Sign interest according to the supplied signing information
+   *
+   * This method uses the supplied signing information @p params to create the SignatureInfo block:
+   * - it selects a private key and its certificate to sign the packet
+   * - sets the KeyLocator field with the certificate name, and
+   * - adds other requested information to the SignatureInfo block).
+   *
+   * After that, the method appends the created SignatureInfo to the interest name, generate a
+   * signature and appends it as part of the SignatureValue block to the interest name.
+   *
+   * @param interest The interest to sign
+   * @param params The signing parameters.
+   * @throws Error if signing fails.
+   * @see SigningInfo
+   */
+  void
+  sign(Interest& interest, const SigningInfo& params = DEFAULT_SIGNING_INFO);
+
+  /**
+   * @brief Sign buffer according to the supplied signing information
+   *
+   * @param buffer The buffer to sign
+   * @param bufferLength The buffer size
+   * @param params The signing parameters.
+   * @return a SignatureValue TLV block
+   * @throws Error if signing fails.
+   * @see SigningInfo
+   */
+  Block
+  sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params);
+
+  /**
+   * @deprecated use sign sign(T&, const SigningInfo&)
    * @brief Sign packet with a particular certificate.
    *
    * @param packet The packet to be signed.
@@ -244,6 +318,7 @@
   sign(T& packet, const Name& certificateName);
 
   /**
+   * @deprecated Use sign(const uint8_t*, size_t, const SigningInfo&) instead
    * @brief Sign the byte array using a particular certificate.
    *
    * @param buffer The byte array to be signed.
@@ -256,6 +331,7 @@
   sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName);
 
   /**
+   * @deprecated use sign sign(T&, const SigningInfo&)
    * @brief Sign packet using the default certificate of a particular identity.
    *
    * If there is no default certificate of that identity, this method will create a self-signed
@@ -269,6 +345,7 @@
   signByIdentity(T& packet, const Name& identityName);
 
   /**
+   * @deprecated use sign(const uint8_t*, size_t, const SigningInfo&) instead
    * @brief Sign the byte array using the default certificate of a particular identity.
    *
    * @param buffer The byte array to be signed.
@@ -280,12 +357,14 @@
   signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName);
 
   /**
+   * @deprecated use sign(Data&, SigningInfo(SigningInfo::SIGNER_TYPE_SHA256))
    * @brief Set Sha256 weak signature for @p data
    */
   void
   signWithSha256(Data& data);
 
   /**
+   * @deprecated use sign(Interest&, SigningInfo(SigningInfo::SIGNER_TYPE_SHA256))
    * @brief Set Sha256 weak signature for @p interest
    */
   void
@@ -697,14 +776,26 @@
              bool needReset);
 
   /**
-   * @brief Determine signature type
+   * @brief Prepare a SignatureInfo TLV according to signing information and return the signing key name
    *
-   * An empty pointer will be returned if there is no valid signature.
+   * @param sigInfo The SignatureInfo to prepare.
+   * @param params The signing parameters.
+   * @return The signing key name and prepared SignatureInfo.
+   * @throw Error when the requested signing method cannot be satisfied.
    */
-  shared_ptr<Signature>
-  determineSignatureWithPublicKey(const KeyLocator& keyLocator,
-                                  KeyType keyType,
-                                  DigestAlgorithm digestAlgorithm = DIGEST_ALGORITHM_SHA256);
+  std::tuple<Name, SignatureInfo>
+  prepareSignatureInfo(const SigningInfo& params);
+
+  /**
+   * @brief Internal abstraction of packet signing.
+   *
+   * @param packet The packet to sign
+   * @param params The signing parameters.
+   * @throw Error when the signing fails.
+   */
+  template<typename T>
+  void
+  signImpl(T& packet, const SigningInfo& params);
 
   /**
    * @brief Set default certificate if it is not initialized
@@ -713,16 +804,6 @@
   setDefaultCertificateInternal();
 
   /**
-   * @brief Sign a packet using a pariticular certificate.
-   *
-   * @param packet The packet to be signed.
-   * @param certificate The signing certificate.
-   */
-  template<typename T>
-  void
-  sign(T& packet, const IdentityCertificate& certificate);
-
-  /**
    * @brief Generate a key pair for the specified identity.
    *
    * @param identityName The name of the specified identity.
@@ -760,6 +841,13 @@
   signPacketWrapper(Interest& interest, const Signature& signature,
                     const Name& keyName, DigestAlgorithm digestAlgorithm);
 
+  /**
+   * @brief Generate a SignatureValue block for a buffer @p buf with size @p size using
+   *        a key with name @p keyName and digest algorithm @p digestAlgorithm.
+   */
+  Block
+  pureSign(const uint8_t* buf, size_t size, const Name& keyName, DigestAlgorithm digestAlgorithm) const;
+
   static void
   registerPibImpl(const std::string& canonicalName,
                   std::initializer_list<std::string> aliases, PibCreateFunc createFunc);
@@ -769,10 +857,24 @@
                   std::initializer_list<std::string> aliases, TpmCreateFunc createFunc);
 
 public:
+  static tlv::SignatureTypeValue
+  getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm);
+
+public:
   static const Name DEFAULT_PREFIX;
+  static const SigningInfo DEFAULT_SIGNING_INFO;
+
+  /**
+   * @brief A localhost identity which indicates that signature is generated using SHA-256.
+   * @todo Passing this as identity is not implemented.
+   */
+  static const Name DIGEST_SHA256_IDENTITY;
+
   // RsaKeyParams is set to be default for backward compatibility.
   static const RsaKeyParams DEFAULT_KEY_PARAMS;
 
+  typedef std::map<std::string, Block> SignParams;
+
 private:
   std::unique_ptr<SecPublicInfo> m_pib;
   std::unique_ptr<SecTpm> m_tpm;
@@ -781,60 +883,28 @@
 
 template<typename T>
 void
-KeyChain::sign(T& packet)
+KeyChain::signImpl(T& packet, const SigningInfo& params)
 {
-  if (!static_cast<bool>(m_pib->getDefaultCertificate()))
-    setDefaultCertificateInternal();
+  Name keyName;
+  SignatureInfo sigInfo;
+  std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
 
-  sign(packet, *m_pib->getDefaultCertificate());
+  signPacketWrapper(packet, Signature(sigInfo),
+                    keyName, params.getDigestAlgorithm());
 }
 
 template<typename T>
 void
 KeyChain::sign(T& packet, const Name& certificateName)
 {
-  shared_ptr<IdentityCertificate> certificate = m_pib->getCertificate(certificateName);
-  sign(packet, *certificate);
+  signImpl(packet, SigningInfo(SigningInfo::SIGNER_TYPE_CERT, certificateName));
 }
 
 template<typename T>
 void
 KeyChain::signByIdentity(T& packet, const Name& identityName)
 {
-  Name signingCertificateName;
-  try
-    {
-      signingCertificateName = m_pib->getDefaultCertificateNameForIdentity(identityName);
-    }
-  catch (SecPublicInfo::Error& e)
-    {
-      signingCertificateName = createIdentity(identityName);
-      // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which
-      // is a fatal error.
-    }
-
-  // We either get or create the signing certificate, sign packet! (no exception unless fatal
-  // error in TPM)
-  sign(packet, signingCertificateName);
-}
-
-template<typename T>
-void
-KeyChain::sign(T& packet, const IdentityCertificate& certificate)
-{
-  KeyLocator keyLocator(certificate.getName().getPrefix(-1));
-
-  shared_ptr<Signature> signature =
-    determineSignatureWithPublicKey(keyLocator, certificate.getPublicKeyInfo().getKeyType());
-
-  if (!static_cast<bool>(signature))
-    throw SecPublicInfo::Error("unknown key type!");
-
-  signPacketWrapper(packet, *signature,
-                    certificate.getPublicKeyName(),
-                    DIGEST_ALGORITHM_SHA256);
-
-  return;
+  signImpl(packet, SigningInfo(SigningInfo::SIGNER_TYPE_ID, identityName));
 }
 
 template<class PibType>
@@ -887,6 +957,10 @@
   }                                                           \
 } ndnCxxAuto ## TpmType ## TpmRegistrationVariable
 
+} // namespace security
+
+using security::KeyChain;
+
 } // namespace ndn
 
 #endif // NDN_SECURITY_KEY_CHAIN_HPP
diff --git a/src/security/pib.hpp b/src/security/pib.hpp
index fd8d7cb..b307c83 100644
--- a/src/security/pib.hpp
+++ b/src/security/pib.hpp
@@ -25,10 +25,9 @@
 #include "identity-container.hpp"
 
 namespace ndn {
-class KeyChain;
-
 namespace security {
 
+class KeyChain;
 class PibImpl;
 
 /**
diff --git a/src/security/signing-info.cpp b/src/security/signing-info.cpp
new file mode 100644
index 0000000..c231cc5
--- /dev/null
+++ b/src/security/signing-info.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 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 "signing-info.hpp"
+
+namespace ndn {
+namespace security {
+
+const Name SigningInfo::EMPTY_NAME;
+const SignatureInfo SigningInfo::EMPTY_SIGNATURE_INFO;
+
+SigningInfo::SigningInfo(SignerType signerType,
+                         const Name& signerName,
+                         const SignatureInfo& signatureInfo)
+  : m_type(signerType)
+  , m_name(signerName)
+  , m_digestAlgorithm(DIGEST_ALGORITHM_SHA256)
+  , m_info(signatureInfo)
+{
+}
+
+void
+SigningInfo::setSigningIdentity(const Name& identity)
+{
+  m_type = SIGNER_TYPE_ID;
+  m_name = identity;
+}
+void
+SigningInfo::setSigningKeyName(const Name& keyName)
+{
+  m_type = SIGNER_TYPE_KEY;
+  m_name = keyName;
+}
+
+void
+SigningInfo::setSigningCertName(const Name& certificateName)
+{
+  m_type = SIGNER_TYPE_CERT;
+  m_name = certificateName;
+}
+
+void
+SigningInfo::setSha256Signing()
+{
+  m_type = SIGNER_TYPE_SHA256;
+  m_name.clear();
+}
+
+void
+SigningInfo::setSignatureInfo(const SignatureInfo& signatureInfo)
+{
+  m_info = signatureInfo;
+}
+
+} // namespace ndn
+} // namespace security
diff --git a/src/security/signing-info.hpp b/src/security/signing-info.hpp
new file mode 100644
index 0000000..661276f
--- /dev/null
+++ b/src/security/signing-info.hpp
@@ -0,0 +1,172 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 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.
+ */
+
+#ifndef NDN_SECURITY_SIGNING_INFO_HPP
+#define NDN_SECURITY_SIGNING_INFO_HPP
+
+#include "../name.hpp"
+#include "../signature-info.hpp"
+#include "security-common.hpp"
+
+
+namespace ndn {
+namespace security {
+
+/**
+ * @brief Signing parameters passed to KeyChain
+ */
+class SigningInfo
+{
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+  enum SignerType {
+    /// @brief 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_TYPE_ID = 1,
+    /// @brief signer is a key, use its default certificate
+    SIGNER_TYPE_KEY = 2,
+    /// @brief signer is a certificate, use it directly
+    SIGNER_TYPE_CERT = 3,
+    /// @brief use sha256 digest, no signer needs to be specified
+    SIGNER_TYPE_SHA256 = 4
+  };
+
+public:
+  /**
+   * @brief Constructor
+   *
+   * @param signerType The type of signer
+   * @param signerName The name of signer; interpretation differs per signerType
+   * @param signatureInfo A semi-prepared SignatureInfo which contains other information except
+   *                      SignatureType and KeyLocator.  If SignatureType and KeyLocator are
+   *                      specified, they may be overwritten by KeyChain.
+   */
+  explicit
+  SigningInfo(SignerType signerType = SIGNER_TYPE_NULL,
+              const Name& signerName = EMPTY_NAME,
+              const SignatureInfo& signatureInfo = EMPTY_SIGNATURE_INFO);
+
+  /**
+   * @brief Set signer as an identity with name @p identity
+   * @post Change the signerType to SIGNER_TYPE_ID
+   */
+  void
+  setSigningIdentity(const Name& identity);
+
+  /**
+   * @brief Set signer as a key with name @p keyName
+   * @post Change the signerType to SIGNER_TYPE_KEY
+   */
+  void
+  setSigningKeyName(const Name& keyName);
+
+  /**
+   * @brief Set signer as a certificate with name @p certificateName
+   * @post Change the signerType to SIGNER_TYPE_CERT
+   */
+  void
+  setSigningCertName(const Name& certificateName);
+
+  /**
+   * @brief Set Sha256 as the signing method
+   * @post Reset signerName, also change the signerType to SIGNER_TYPE_SHA256
+   */
+  void
+  setSha256Signing();
+
+  /**
+   * @return Type of the signer
+   */
+  SignerType
+  getSignerType() const
+  {
+    return m_type;
+  }
+
+  /**
+   * @return Name of signer; interpretation differs per signerType
+   */
+  const Name&
+  getSignerName() const
+  {
+    return m_name;
+  }
+
+  /**
+   * @brief Set the digest algorithm for public key operations
+   */
+  void
+  setDigestAlgorithm(const DigestAlgorithm& algorithm)
+  {
+    m_digestAlgorithm = algorithm;
+  }
+
+  /**
+   * @return The digest algorithm for public key operations
+   */
+  DigestAlgorithm
+  getDigestAlgorithm() const
+  {
+    return m_digestAlgorithm;
+  }
+
+  /**
+   * @brief Set a semi-prepared SignatureInfo;
+   */
+  void
+  setSignatureInfo(const SignatureInfo& signatureInfo);
+
+  /**
+   * @return Semi-prepared SignatureInfo
+   */
+  const SignatureInfo&
+  getSignatureInfo() const
+  {
+    return m_info;
+  }
+
+public:
+  static const Name EMPTY_NAME;
+  static const SignatureInfo EMPTY_SIGNATURE_INFO;
+
+private:
+  SignerType m_type;
+  Name m_name;
+
+  DigestAlgorithm m_digestAlgorithm;
+
+  SignatureInfo m_info;
+};
+
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_SIGNING_INFO_HPP
diff --git a/src/signature.cpp b/src/signature.cpp
index 723478c..2152dd0 100644
--- a/src/signature.cpp
+++ b/src/signature.cpp
@@ -46,4 +46,13 @@
   m_info = SignatureInfo(info);
 }
 
+void
+Signature::setValue(const Block& value)
+{
+  if (value.type() != tlv::SignatureValue) {
+    throw Error("The supplied block is not SignatureValue");
+  }
+  m_value = value;
+}
+
 } // namespace ndn
diff --git a/src/signature.hpp b/src/signature.hpp
index 9d7749b..5970270 100644
--- a/src/signature.hpp
+++ b/src/signature.hpp
@@ -50,9 +50,7 @@
     Sha256WithEcdsa = tlv::SignatureSha256WithEcdsa
   };
 
-  Signature()
-  {
-  }
+  Signature() = default;
 
   explicit
   Signature(const Block& info, const Block& value = Block());
@@ -65,7 +63,9 @@
     return m_info.getSignatureType() != -1;
   }
 
-  /// @brief Get SignatureInfo in the wire format
+  /**
+   * @brief Get SignatureInfo in the wire format
+   */
   const Block&
   getInfo() const
   {
@@ -80,13 +80,18 @@
   void
   setInfo(const Block& info);
 
-  /// @brief Set SignatureInfo
+  /**
+   * @brief Set SignatureInfo
+   */
   void
   setInfo(const SignatureInfo& info)
   {
     m_info = info;
   }
 
+  /**
+   * @brief Get SignatureValue in the wire format
+   */
   const Block&
   getValue() const
   {
@@ -94,18 +99,26 @@
     return m_value;
   }
 
+  /**
+   * @brief Get SignatureValue from a block
+   *
+   * @throws tlv::Error if supplied block has type different from SignatureValue
+   */
   void
-  setValue(const Block& value)
-  {
-    m_value = value;
-  }
+  setValue(const Block& value);
 
+  /**
+   * @brief Get signature type
+   */
   uint32_t
   getType() const
   {
     return m_info.getSignatureType();
   }
 
+  /**
+   * @brief Check if SignatureInfo block has a KeyLocator
+   */
   bool
   hasKeyLocator() const
   {
@@ -115,7 +128,7 @@
   /**
    * @brief Get KeyLocator
    *
-   * @throws Signature::Error if keyLocator does not exist
+   * @throws Signature::Error if KeyLocator does not exist
    */
   const KeyLocator&
   getKeyLocator() const
@@ -123,7 +136,9 @@
     return m_info.getKeyLocator();
   }
 
-  /// @brief Set KeyLocator
+  /**
+   * @brief Set KeyLocator
+   */
   void
   setKeyLocator(const KeyLocator& keyLocator)
   {
diff --git a/src/util/command-interest-generator.hpp b/src/util/command-interest-generator.hpp
index 651a19b..fb4ed47 100644
--- a/src/util/command-interest-generator.hpp
+++ b/src/util/command-interest-generator.hpp
@@ -71,13 +71,16 @@
   if (certificateName.empty())
     m_keyChain.sign(interest);
   else
-    m_keyChain.sign(interest, certificateName);
+    m_keyChain.sign(interest,
+                    security::SigningInfo(security::SigningInfo::SIGNER_TYPE_CERT,
+                                          certificateName));
 }
 
 inline void
 CommandInterestGenerator::generateWithIdentity(Interest& interest, const Name& identity)
 {
-  m_keyChain.signByIdentity(interest, identity);
+  m_keyChain.sign(interest,
+                  security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, identity));
 }
 
 
diff --git a/src/util/dummy-client-face.cpp b/src/util/dummy-client-face.cpp
index 24348e9..cfa28a5 100644
--- a/src/util/dummy-client-face.cpp
+++ b/src/util/dummy-client-face.cpp
@@ -158,7 +158,7 @@
     data->setContent(resp.wireEncode());
 
     KeyChain keyChain;
-    keyChain.signWithSha256(*data);
+    keyChain.sign(*data, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_SHA256));
 
     this->getIoService().post([this, data] { this->receive(*data); });
   });
diff --git a/src/util/notification-stream.hpp b/src/util/notification-stream.hpp
index 991a885..3b042a5 100644
--- a/src/util/notification-stream.hpp
+++ b/src/util/notification-stream.hpp
@@ -56,9 +56,6 @@
 
 namespace ndn {
 
-class Face;
-class KeyChain;
-
 namespace util {
 
 /** \brief provides a publisher of Notification Stream