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()