security: Adding supports to signed interest

refs: #1161

Change-Id: I042381b171d44417f296397d872cd639935a89e9
diff --git a/src/encoding/block.cpp b/src/encoding/block.cpp
index f881c8e..bad73a2 100644
--- a/src/encoding/block.cpp
+++ b/src/encoding/block.cpp
@@ -245,4 +245,27 @@
   Tlv::readVarNumber(m_value_begin, m_value_end);
 }
 
+Block
+Block::blockFromValue() const
+{
+  if (value_size()==0)
+    throw Error("Underlying value buffer is empty");
+  
+  Buffer::const_iterator begin = value_begin(),
+    end = value_end();
+
+  Buffer::const_iterator element_begin = begin;
+      
+  uint32_t type = Tlv::readType(begin, end);
+  uint64_t length = Tlv::readVarNumber(begin, end);
+
+  if (end-begin != length)
+    throw Tlv::Error("TLV length mismatches buffer length");
+      
+  return Block(m_buffer,
+               type,
+               element_begin, end,
+               begin, end);
+}
+
 } // namespace ndn
diff --git a/src/encoding/block.hpp b/src/encoding/block.hpp
index a764dd1..9c2777d 100644
--- a/src/encoding/block.hpp
+++ b/src/encoding/block.hpp
@@ -184,6 +184,9 @@
   inline size_t
   value_size() const;
 
+  Block
+  blockFromValue() const;
+
 protected:
   ConstBufferPtr m_buffer;
 
diff --git a/src/security/key-chain.hpp b/src/security/key-chain.hpp
index 21898e6..778732b 100644
--- a/src/security/key-chain.hpp
+++ b/src/security/key-chain.hpp
@@ -12,6 +12,7 @@
 #include "identity-certificate.hpp"
 #include "public-key.hpp"
 #include "signature-sha256-with-rsa.hpp"
+#include "../interest.hpp"
 
 //PublicInfo
 #include "sec-public-info-sqlite3.hpp"
@@ -35,8 +36,8 @@
 template<class Info, class Tpm>
 class KeyChainImpl : public Info, public Tpm
 {
+  typedef typename Info::Error InfoError;
 public:
-  // struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
   
   /**
    * Create an identity by creating a pair of Key-Signing-Key (KSK) for this identity and a self-signed certificate of the KSK.
@@ -53,7 +54,7 @@
 
       ptr_lib::shared_ptr<IdentityCertificate> selfCert = selfSign(keyName); 
   
-      Info::addCertificateAsDefault(*selfCert);
+      Info::addCertificateAsIdentityDefault(*selfCert);
 
       return keyName;
     }
@@ -110,7 +111,7 @@
     
     ptr_lib::shared_ptr<PublicKey> pubKey = Info::getPublicKey(keyName);
     if (!pubKey)
-      throw std::runtime_error("Requested public key [" + keyName.toUri() + "] doesn't exist");
+      throw InfoError("Requested public key [" + keyName.toUri() + "] doesn't exist");
     
     ptr_lib::shared_ptr<IdentityCertificate> certificate =
       createIdentityCertificate(certificatePrefix,
@@ -167,11 +168,25 @@
         Info::refreshDefaultCertificate();
 
         if(!Info::defaultCertificate())
-          throw std::runtime_error("Default IdentityCertificate cannot be determined");
+          throw InfoError("Default IdentityCertificate cannot be determined");
       }
 
     sign(data, *Info::defaultCertificate());
   }
+
+  void
+  sign(Interest &interest)
+  {
+    if (!Info::defaultCertificate())
+      {
+        Info::refreshDefaultCertificate();
+
+        if(!Info::defaultCertificate())
+          throw InfoError("Default IdentityCertificate cannot be determined");
+      }
+
+    sign(interest, *Info::defaultCertificate());
+  }
   
   /**
    * Wire encode the Data object, sign it and set its signature.
@@ -183,7 +198,7 @@
   {
     ptr_lib::shared_ptr<IdentityCertificate> cert = Info::getCertificate(certificateName);
     if (!cert)
-      throw std::runtime_error("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
+      throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
 
     SignatureSha256WithRsa signature;
     signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
@@ -194,7 +209,27 @@
   }
 
   void
-  sign(Data& data, const IdentityCertificate& certificate)
+  sign(Interest &interest, const Name &certificateName)
+  {
+    ptr_lib::shared_ptr<IdentityCertificate> cert = Info::getCertificate(certificateName);
+    if(!static_cast<bool>(cert))
+      throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
+
+    SignatureSha256WithRsa signature;
+    signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
+
+    Name interestName = interest.getName().append(Name::Component::fromNumber(getNow())).append(signature.getInfo());
+
+    signature.setValue(Tpm::signInTpm(interestName.wireEncode().value(), 
+                                      interestName.wireEncode().value_size(), 
+                                      cert->getPublicKeyName(),
+                                      DIGEST_ALGORITHM_SHA256));
+    
+    interest.getName().append(signature.getValue());
+  }
+
+  void
+  sign(Data &data, const IdentityCertificate& certificate)
   {
     SignatureSha256WithRsa signature;
     signature.setKeyLocator(certificate.getName().getPrefix(-1));
@@ -203,6 +238,23 @@
     // For temporary usage, we support RSA + SHA256 only, but will support more.
     signDataInTpm(data, certificate.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
   }
+
+  void
+  sign(Interest &interest, const IdentityCertificate& certificate)
+  {
+    SignatureSha256WithRsa signature;
+    signature.setKeyLocator(certificate.getName().getPrefix(-1)); // implicit conversion should take care
+
+    Name &interestName = interest.getName();
+    interestName.append(Name::Component::fromNumber(getNow())).append(signature.getInfo());
+
+    signature.setValue(Tpm::signInTpm(interestName.wireEncode().value(), 
+                                      interestName.wireEncode().value_size(), 
+                                      certificate.getPublicKeyName(), 
+                                      DIGEST_ALGORITHM_SHA256));
+    
+    interestName.append(signature.getValue());
+  }
   
   /**
    * Sign the byte array using a certificate name and return a Signature object.
@@ -215,8 +267,8 @@
   sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
   {
     ptr_lib::shared_ptr<IdentityCertificate> cert = Info::getCertificate(certificateName);
-    if (!cert)
-      throw std::runtime_error("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
+    if (!static_cast<bool>(cert))
+      throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
 
     SignatureSha256WithRsa signature;
     signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
@@ -232,7 +284,7 @@
    * @param identityName The identity name for the key to use for signing.  If omitted, infer the signing identity from the data packet name.
    */
   void 
-  signByIdentity(Data& data, const Name& identityName = Name())
+  signByIdentity(Data& data, const Name& identityName)
   {
     Name signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
 
@@ -242,6 +294,18 @@
     sign(data, signingCertificateName);
   }
 
+  void 
+  signByIdentity(Interest& interest, const Name& identityName)
+  {
+    Name signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
+
+    if (signingCertificateName.getComponentCount() == 0)
+      throw std::runtime_error("No qualified certificate name found!");
+
+    sign(interest, signingCertificateName);
+  }
+
+
   /**
    * Sign the byte array using an identity name and return a Signature object.
    * @param buffer The byte array to be signed.
@@ -269,7 +333,7 @@
   selfSign(const Name& keyName)
   {
     if(keyName.empty())
-      throw std::runtime_error("Incorrect key name: " + keyName.toUri());
+      throw InfoError("Incorrect key name: " + keyName.toUri());
 
     ptr_lib::shared_ptr<IdentityCertificate> certificate = ptr_lib::make_shared<IdentityCertificate>();
     
@@ -278,7 +342,7 @@
     
     ptr_lib::shared_ptr<PublicKey> pubKey = Info::getPublicKey(keyName);
     if (!pubKey)
-      throw std::runtime_error("Requested public key [" + keyName.toUri() + "] doesn't exist");
+      throw InfoError("Requested public key [" + keyName.toUri() + "] doesn't exist");
   
     certificate->setName(certificateName);
     certificate->setNotBefore(getNow());
@@ -341,7 +405,7 @@
     }
     
     if (i >= certificatePrefix.size())
-      throw std::runtime_error("Identity Certificate Prefix does not have a KEY component");
+      throw InfoError("Identity Certificate Prefix does not have a KEY component");
 
     result.append(certificatePrefix.getSubName(0, i));
     result.append(certificatePrefix.getSubName(i + 1, certificatePrefix.size()-i-1));
diff --git a/src/security/sec-policy-no-verify.cpp b/src/security/sec-policy-no-verify.cpp
index 1dce9d2..3a45756 100644
--- a/src/security/sec-policy-no-verify.cpp
+++ b/src/security/sec-policy-no-verify.cpp
@@ -18,7 +18,7 @@
     
 ptr_lib::shared_ptr<ValidationRequest>
 SecPolicyNoVerify::checkVerificationPolicy
-  (const ptr_lib::shared_ptr<Data>& data, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed)
+  (const ptr_lib::shared_ptr<const Data>& data, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed)
 { 
   onVerified(); 
   return ptr_lib::shared_ptr<ValidationRequest>();
@@ -26,7 +26,7 @@
 
 ptr_lib::shared_ptr<ValidationRequest>
 SecPolicyNoVerify::checkVerificationPolicy
-  (const ptr_lib::shared_ptr<Interest>& interest, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed)
+  (const ptr_lib::shared_ptr<const Interest>& interest, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed)
 { 
   onVerified(); 
   return ptr_lib::shared_ptr<ValidationRequest>();
diff --git a/src/security/sec-policy-no-verify.hpp b/src/security/sec-policy-no-verify.hpp
index 4b3e15a..59dd615 100644
--- a/src/security/sec-policy-no-verify.hpp
+++ b/src/security/sec-policy-no-verify.hpp
@@ -33,7 +33,7 @@
    */
   virtual ptr_lib::shared_ptr<ValidationRequest>
   checkVerificationPolicy
-    (const ptr_lib::shared_ptr<Data>& data, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed);
+    (const ptr_lib::shared_ptr<const Data>& data, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed);
 
   /**
    * Check whether the received interest packet complies with the verification policy, and get the indication of the next verification step.
@@ -47,7 +47,7 @@
    */
   virtual ptr_lib::shared_ptr<ValidationRequest>
   checkVerificationPolicy
-    (const ptr_lib::shared_ptr<Interest>& interest, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed);
+    (const ptr_lib::shared_ptr<const Interest>& interest, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed);
 };
 
 }
diff --git a/src/security/sec-policy-self-verify.cpp b/src/security/sec-policy-self-verify.cpp
index 2793b69..6f7b657 100644
--- a/src/security/sec-policy-self-verify.cpp
+++ b/src/security/sec-policy-self-verify.cpp
@@ -22,7 +22,7 @@
 
 ptr_lib::shared_ptr<ValidationRequest>
 SecPolicySelfVerify::checkVerificationPolicy
-  (const ptr_lib::shared_ptr<Data>& data, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed)
+  (const ptr_lib::shared_ptr<const Data>& data, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed)
 { 
   // Cast to const Data* so that we use the const version of getSignature() and don't reset the default encoding.
   const Sha256WithRsaSignature *signature = dynamic_cast<const Sha256WithRsaSignature*>(((const Data*)data.get())->getSignature());
diff --git a/src/security/sec-policy-self-verify.hpp b/src/security/sec-policy-self-verify.hpp
index 1b17646..1e95d59 100644
--- a/src/security/sec-policy-self-verify.hpp
+++ b/src/security/sec-policy-self-verify.hpp
@@ -48,7 +48,7 @@
    */
   virtual ptr_lib::shared_ptr<ValidationRequest>
   checkVerificationPolicy
-    (const ptr_lib::shared_ptr<Data>& data, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed);
+    (const ptr_lib::shared_ptr<const Data>& data, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed);
 
   /**
    * Check whether the received interest packet complies with the verification policy, and get the indication of the next verification step.
@@ -62,7 +62,7 @@
    */
   virtual ptr_lib::shared_ptr<ValidationRequest>
   checkVerificationPolicy
-    (const ptr_lib::shared_ptr<Interest>& interest, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed);
+    (const ptr_lib::shared_ptr<const Interest>& interest, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed);
 };
 
 }
diff --git a/src/security/sec-policy.hpp b/src/security/sec-policy.hpp
index 0d17e41..5158f61 100644
--- a/src/security/sec-policy.hpp
+++ b/src/security/sec-policy.hpp
@@ -41,7 +41,7 @@
    */
   virtual ptr_lib::shared_ptr<ValidationRequest>
   checkVerificationPolicy
-    (const ptr_lib::shared_ptr<Data>& data, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed)
+    (const ptr_lib::shared_ptr<const Data>& data, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed)
   {
     onVerifyFailed();
     return ptr_lib::shared_ptr<ValidationRequest>();
@@ -59,7 +59,7 @@
    */
   virtual ptr_lib::shared_ptr<ValidationRequest>
   checkVerificationPolicy
-    (const ptr_lib::shared_ptr<Interest>& interest, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed)
+    (const ptr_lib::shared_ptr<const Interest>& interest, int stepCount, const OnVerified& onVerified, const OnVerifyFailed& onVerifyFailed)
   {
     onVerifyFailed();
     return ptr_lib::shared_ptr<ValidationRequest>();
diff --git a/src/security/sec-public-info-sqlite3.cpp b/src/security/sec-public-info-sqlite3.cpp
index b7f1f7e..fe96f07 100644
--- a/src/security/sec-public-info-sqlite3.cpp
+++ b/src/security/sec-public-info-sqlite3.cpp
@@ -433,32 +433,27 @@
 ptr_lib::shared_ptr<IdentityCertificate> 
 SecPublicInfoSqlite3::getCertificate(const Name &certificateName)
 {
-  if (doesCertificateExist(certificateName)) {
-    sqlite3_stmt *statement;
-
-    sqlite3_prepare_v2(database_, 
-                       "SELECT certificate_data FROM Certificate \
-                        WHERE cert_name=? AND not_before<datetime('now') AND not_after>datetime('now') and valid_flag=1",
-                       -1, &statement, 0);
-          
-    sqlite3_bind_text(statement, 1, certificateName.toUri(), SQLITE_TRANSIENT);
-      
-    int res = sqlite3_step(statement);
-      
-    ptr_lib::shared_ptr<IdentityCertificate> certificate = ptr_lib::make_shared<IdentityCertificate>();
-    if (res == SQLITE_ROW)
-      {
-        certificate->wireDecode(Block((const uint8_t*)sqlite3_column_blob(statement, 0), sqlite3_column_bytes(statement, 0)));
-      }
-    sqlite3_finalize(statement);
-      
-    return certificate;
-  }
-  else {
-    _LOG_DEBUG("Certificate does not exist!");
-    return ptr_lib::shared_ptr<IdentityCertificate>();
-  }
+  sqlite3_stmt *statement;
+  
+  sqlite3_prepare_v2(database_, 
+                     "SELECT certificate_data FROM Certificate WHERE cert_name=?",
+                     -1, &statement, 0);
+  
+  sqlite3_bind_text(statement, 1, certificateName.toUri(), SQLITE_TRANSIENT);
+  
+  int res = sqlite3_step(statement);
+  
+  ptr_lib::shared_ptr<IdentityCertificate> certificate;
+  if (res == SQLITE_ROW)
+    {
+      certificate = ptr_lib::make_shared<IdentityCertificate>();
+      certificate->wireDecode(Block((const uint8_t*)sqlite3_column_blob(statement, 0), sqlite3_column_bytes(statement, 0)));
+    }
+  sqlite3_finalize(statement);
+  
+  return certificate;
 }
+ 
 
 Name 
 SecPublicInfoSqlite3::getDefaultIdentity()
diff --git a/src/security/verifier.cpp b/src/security/verifier.cpp
index cef8997..62f660d 100644
--- a/src/security/verifier.cpp
+++ b/src/security/verifier.cpp
@@ -179,6 +179,48 @@
 }
 
 bool
+Verifier::verifySignature(const Interest &interest, const PublicKey &key)
+{
+  const Name &interestName = interest.getName();
+
+  if(interestName.size() < 3)
+    return false;
+
+  try{
+    const Block &nameBlock = interestName.wireEncode();
+
+    if(nameBlock.getAll().size() != interestName.size()) //HACK!! we should change it when Name::Component is changed to derive from Block.
+      const_cast<Block&>(nameBlock).parse();
+
+    Signature sig((++nameBlock.getAll().rbegin())->blockFromValue(), 
+                  (nameBlock.getAll().rbegin())->blockFromValue());
+
+    switch(sig.getType()){
+    case Signature::Sha256WithRsa:
+      {
+        SignatureSha256WithRsa sigSha256Rsa(sig);
+
+        return verifySignature(nameBlock.value(), 
+                               nameBlock.value_size() - (nameBlock.getAll().rbegin())->size(), 
+                               sigSha256Rsa, key);
+      }
+    default:
+      {
+        _LOG_DEBUG("verifySignature: Unknown signature type: " << sig.getType());
+        return false;
+      }
+    }
+  }catch(Signature::Error &e){
+    _LOG_DEBUG("verifySignature: " << e.what());
+    return false;
+  }catch(Block::Error &e){
+    _LOG_DEBUG("verifySignature: " << e.what());
+    return false;
+  }
+  return false;
+}
+
+bool
 Verifier::verifySignature(const Buffer &data, const Signature &sig, const PublicKey &key)
 {
   try{
@@ -239,8 +281,25 @@
   RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
   result = verifier.VerifyMessage(data.buf(), data.size(),
 				  sig.getValue().value(), sig.getValue().value_size());
+  
+  return result;
+}
 
-  _LOG_DEBUG("Signature verified? " << data.getName().toUri() << " " << boolalpha << result);
+bool
+Verifier::verifySignature(const uint8_t* buf, const size_t size, const SignatureSha256WithRsa &sig, const PublicKey &key)
+{
+  using namespace CryptoPP;
+
+  bool result = false;
+  
+  RSA::PublicKey publicKey;
+  ByteQueue queue;
+
+  queue.Put(reinterpret_cast<const byte*>(key.get().buf()), key.get().size());
+  publicKey.Load(queue);
+
+  RSASS<PKCS1v15, SHA256>::Verifier verifier (publicKey);
+  result = verifier.VerifyMessage(buf, size, sig.getValue().value(), sig.getValue().value_size());
   
   return result;
 }
diff --git a/src/security/verifier.hpp b/src/security/verifier.hpp
index 07c1494..a9bded4 100644
--- a/src/security/verifier.hpp
+++ b/src/security/verifier.hpp
@@ -83,10 +83,13 @@
   /*****************************************
    *      verifySignature method set       *
    *****************************************/
-    static bool
+  static bool
   verifySignature(const Data &data, const Signature &sig, const PublicKey &publicKey);
 
   static bool
+  verifySignature(const Interest &interest, const PublicKey &publicKey);
+
+  static bool
   verifySignature(const Buffer &data, const Signature &sig, const PublicKey &publicKey);
 
   static bool
@@ -94,6 +97,10 @@
 
   static bool
   verifySignature(const Buffer &data, const SignatureSha256WithRsa &sig, const PublicKey &publicKey);
+  
+  static bool
+  verifySignature(const uint8_t* buf, const size_t size, const SignatureSha256WithRsa &sig, const PublicKey &publicKey);
+
 
 public:
   static const ptr_lib::shared_ptr<SecPolicy>     DefaultPolicy;
diff --git a/tests/test-signed-interest.cpp b/tests/test-signed-interest.cpp
new file mode 100644
index 0000000..5c7e684
--- /dev/null
+++ b/tests/test-signed-interest.cpp
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi0@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#include <boost/test/unit_test.hpp>
+
+#include "security/key-chain.hpp"
+#include "security/verifier.hpp"
+#include <iostream>
+
+using namespace std;
+using namespace ndn;
+
+
+BOOST_AUTO_TEST_SUITE(TestSignedInterest)
+
+BOOST_AUTO_TEST_CASE (SignVerify)
+{
+  KeyChainImpl<SecPublicInfoSqlite3, SecTpmFile> keyChain;
+
+  Name identityName("/test");
+  Name keyName = keyChain.createIdentity(identityName);
+
+  Interest interest("/test/interest");
+  keyChain.signByIdentity(interest, identityName);
+  
+  Block interestBlock(interest.wireEncode().wire(), interest.wireEncode().size());
+
+  Interest interest2;
+  interest2.wireDecode(interestBlock);
+  
+  ptr_lib::shared_ptr<PublicKey> publicKey = keyChain.getPublicKeyFromTpm(keyName);
+  bool result = Verifier::verifySignature(interest2, *publicKey);
+  
+  BOOST_REQUIRE_EQUAL(result, true);
+}
+
+BOOST_AUTO_TEST_SUITE_END()