security: Add helpers for Command Interest

refs: #1238

Change-Id: I5a42f888b83bcc6dc51ea02045e438a4905ed145
diff --git a/src/helper/command-interest-validator.cpp b/src/helper/command-interest-validator.cpp
new file mode 100644
index 0000000..396ee8f
--- /dev/null
+++ b/src/helper/command-interest-validator.cpp
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "command-interest-validator.hpp"
+
+namespace ndn
+{
+const ssize_t CommandInterestValidator::POS_SIG_VALUE  = -1;
+const ssize_t CommandInterestValidator::POS_SIG_INFO   = -2;
+const ssize_t CommandInterestValidator::POS_RANDOM_VAL = -3;
+const ssize_t CommandInterestValidator::POS_TIMESTAMP  = -4;
+const int64_t CommandInterestValidator::GRACE_INTERVAL = 3000;
+
+void
+CommandInterestValidator::checkPolicy (const Interest& interest, 
+					      int stepCount, 
+					      const OnInterestValidated &onValidated, 
+					      const OnInterestValidationFailed &onValidationFailed,
+					      std::vector<shared_ptr<ValidationRequest> > &nextSteps)
+{
+  try{
+    Name interestName  = interest.getName();
+
+    Signature signature(interestName.get(POS_SIG_INFO).blockFromValue(), 
+			interestName.get(POS_SIG_VALUE).blockFromValue());
+    
+    SignatureSha256WithRsa sig(signature);
+    const Name & keyLocatorName = sig.getKeyLocator().getName();
+    Name keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocatorName);
+
+    //Check if command is in the trusted scope
+    bool inScope = false;
+    std::list<SecRuleSpecific>::iterator scopeIt = m_trustScopeForInterest.begin();
+    for(; scopeIt != m_trustScopeForInterest.end(); scopeIt++)
+      {
+	if(scopeIt->satisfy(interestName, keyName))
+	  {
+	    inScope = true;
+	    break;
+	  }
+      }
+    if(inScope == false)
+      {
+	onValidationFailed(interest.shared_from_this());
+	return;
+      }
+
+    //Check if timestamp is valid
+    uint64_t timestamp = interestName.get(POS_TIMESTAMP).toNumber();
+    uint64_t current = static_cast<uint64_t>(time::now()/1000000);
+    std::map<Name, uint64_t>::const_iterator timestampIt = m_lastTimestamp.find(keyName);
+    if(timestampIt == m_lastTimestamp.end())
+      {
+	if(timestamp > (current + m_graceInterval) || (timestamp + m_graceInterval) < current)
+	  {
+	    onValidationFailed(interest.shared_from_this());
+	    return;
+	  }
+      }
+    else if(m_lastTimestamp[keyName] >= timestamp)
+      {
+	onValidationFailed(interest.shared_from_this());
+	return;
+      }
+    
+    //Check if signature can be verified
+    Name signedName = interestName.getPrefix(-1);
+    Buffer signedBlob = Buffer(signedName.wireEncode().value(), signedName.wireEncode().value_size()); //These two lines could be optimized
+    if(!Validator::verifySignature(signedBlob.buf(), signedBlob.size(), sig, m_trustAnchorsForInterest[keyName]))
+      {
+	onValidationFailed(interest.shared_from_this());
+	return;
+      }
+
+    m_lastTimestamp[keyName] = timestamp;
+    onValidated(interest.shared_from_this());
+    return;
+
+  }catch(...){
+    onValidationFailed(interest.shared_from_this());
+  }
+}
+
+}//ndn