ccnx: Added verifier and a few small changes
Change-Id: Idbdc0597bd9afb3cfa7c7bbc05175ca8aa1c6b1b
diff --git a/ccnx/ccnx-key.cc b/ccnx/ccnx-key.cc
index 19dc84d..c3fdf10 100644
--- a/ccnx/ccnx-key.cc
+++ b/ccnx/ccnx-key.cc
@@ -58,8 +58,8 @@
TiXmlElement *root = doc.RootElement();
for (TiXmlElement *child = root->FirstChildElement(); child; child = child->NextSiblingElement())
{
- const char *elemName = child->Value();
- const char *text = child->GetText();
+ string elemName = child->Value();
+ string text = child->GetText();
if (elemName == "Name")
{
m_meta.realworldID = text;
@@ -70,7 +70,7 @@
}
else if (elemName == "Valid_to")
{
- m_meta.validTo = boost::lexical_cast<time_t>(std::string(text));
+ m_meta.validTo = boost::lexical_cast<time_t>(text);
}
else if (elemName == "Valid_from")
{
@@ -109,7 +109,7 @@
return EXPIRED;
}
- return VALID;
+ return WITHIN_VALID_TIME_SPAN;
}
} // Ccnx
diff --git a/ccnx/ccnx-key.h b/ccnx/ccnx-key.h
index 695afda..3d14afc 100644
--- a/ccnx/ccnx-key.h
+++ b/ccnx/ccnx-key.h
@@ -36,7 +36,7 @@
enum VALIDITY
{
NOT_YET_VALID,
- VALID,
+ WITHIN_VALID_TIME_SPAN,
EXPIRED,
OTHER
};
diff --git a/ccnx/ccnx-pco.cpp b/ccnx/ccnx-pco.cpp
index 591f1d3..4ca46c7 100644
--- a/ccnx/ccnx-pco.cpp
+++ b/ccnx/ccnx-pco.cpp
@@ -37,22 +37,25 @@
}
-ParsedContentObject::ParsedContentObject(const unsigned char *data, size_t len, bool verified)
+ParsedContentObject::ParsedContentObject(const unsigned char *data, size_t len, bool integrityChecked, bool verified)
: m_comps(NULL)
+ , m_integrityChecked(integrityChecked)
, m_verified(verified)
{
init(data, len);
}
-ParsedContentObject::ParsedContentObject(const Bytes &bytes, bool verified)
+ParsedContentObject::ParsedContentObject(const Bytes &bytes, bool integrityChecked, bool verified)
: m_comps(NULL)
+ , m_integrityChecked(integrityChecked)
, m_verified(verified)
{
init(head(bytes), bytes.size());
}
-ParsedContentObject::ParsedContentObject(const ParsedContentObject &other, bool verified)
+ParsedContentObject::ParsedContentObject(const ParsedContentObject &other, bool integrityChecked, bool verified)
: m_comps(NULL)
+ , m_integrityChecked(integrityChecked)
, m_verified(verified)
{
init(head(other.m_bytes), other.m_bytes.size());
@@ -100,4 +103,36 @@
return Name(head(m_bytes), m_comps);
}
+Name
+ParsedContentObject::keyName() const
+{
+ CcnxCharbufPtr ptr = boost::make_shared<CcnxCharbuf>();
+ ccn_charbuf_append(ptr->getBuf(), head(m_bytes) + m_pco.offset[CCN_PCO_B_KeyName_Name], m_pco.offset[CCN_PCO_E_KeyName_Name] - m_pco.offset[CCN_PCO_B_KeyName_Name]);
+
+ return Name(*ptr);
+
+}
+
+HashPtr
+ParsedContentObject::publisherPublicKeyDigest() const
+{
+ const unsigned char *buf = NULL;
+ size_t size = 0;
+ ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest, head(m_bytes), m_pco.offset[CCN_PCO_B_PublisherPublicKeyDigest], m_pco.offset[CCN_PCO_E_PublisherPublicKeyDigest], &buf, &size);
+
+ return boost::make_shared<Hash>(buf, size);
+}
+
+ParsedContentObject::Type
+ParsedContentObject::type() const
+{
+ switch (m_pco.type)
+ {
+ case CCN_CONTENT_DATA: return DATA;
+ case CCN_CONTENT_KEY: return KEY;
+ default: break;
+ }
+ return OTHER;
+}
+
}
diff --git a/ccnx/ccnx-pco.h b/ccnx/ccnx-pco.h
index 28b039d..d75a7ea 100644
--- a/ccnx/ccnx-pco.h
+++ b/ccnx/ccnx-pco.h
@@ -25,18 +25,28 @@
#include "ccnx-wrapper.h"
#include "ccnx-common.h"
#include "ccnx-name.h"
+#include "hash-helper.h"
namespace Ccnx {
struct MisformedContentObjectException : virtual boost::exception, virtual std::exception { };
+class Key;
+typedef boost::shared_ptr<Key> KeyPtr;
+
class ParsedContentObject
{
public:
- ParsedContentObject(const unsigned char *data, size_t len, bool verified = false);
- ParsedContentObject(const unsigned char *data, const ccn_parsed_ContentObject &pco, bool verified = false);
- ParsedContentObject(const Bytes &bytes, bool verified = false);
- ParsedContentObject(const ParsedContentObject &other, bool verified = false);
+ enum Type
+ {
+ DATA,
+ KEY,
+ OTHER
+ };
+ ParsedContentObject(const unsigned char *data, size_t len, bool integrityChecked = false, bool verified = false);
+ ParsedContentObject(const unsigned char *data, const ccn_parsed_ContentObject &pco, bool integrityChecked = false, bool verified = false);
+ ParsedContentObject(const Bytes &bytes, bool integrityChecked = false, bool verified = false);
+ ParsedContentObject(const ParsedContentObject &other, bool integrityChecked = false, bool verified = false);
virtual ~ParsedContentObject();
Bytes
@@ -48,6 +58,15 @@
Name
name() const;
+ Name
+ keyName() const;
+
+ HashPtr
+ publisherPublicKeyDigest() const;
+
+ Type
+ type() const;
+
inline const Bytes &
buf () const;
@@ -57,6 +76,12 @@
void
setVerified(bool verified) { m_verified = verified; }
+ bool
+ integrityChecked() const { return m_integrityChecked; }
+
+ void
+ setIntegrityChecked(bool checked) { m_integrityChecked = checked; }
+
const unsigned char *
msg() const { return head(m_bytes); }
@@ -72,6 +97,7 @@
ccn_indexbuf *m_comps;
Bytes m_bytes;
bool m_verified;
+ bool m_integrityChecked;
};
const Bytes &
diff --git a/ccnx/ccnx-verifier.cpp b/ccnx/ccnx-verifier.cpp
new file mode 100644
index 0000000..e2832ac
--- /dev/null
+++ b/ccnx/ccnx-verifier.cpp
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ccnx-verifier.h"
+
+namespace Ccnx {
+
+static const size_t ROOT_KEY_DIGEST_LEN = 32; // SHA-256
+static const unsigned char ROOT_KEY_DIGEST[ROOT_KEY_DIGEST_LEN] = {0xa7, 0xd9, 0x8b, 0x81, 0xde, 0x13, 0xfc,
+0x56, 0xc5, 0xa6, 0x92, 0xb4, 0x44, 0x93, 0x6e, 0x56, 0x70, 0x9d, 0x52, 0x6f, 0x70,
+0xed, 0x39, 0xef, 0xb5, 0xe2, 0x3, 0x29, 0xa5, 0x53, 0x3e, 0x68};
+
+Verifier::Verifier(CcnxWrapper *ccnx)
+ : m_ccnx(ccnx)
+ , m_rootKeyDigest(ROOT_KEY_DIGEST, ROOT_KEY_DIGEST_LEN)
+{
+}
+
+Verifier::~Verifier()
+{
+}
+
+bool
+Verifier::verify(const PcoPtr &pco)
+{
+ if (pco->integrityChecked())
+ {
+ return false;
+ }
+
+ HashPtr publisherPublicKeyDigest = pco->publisherPublicKeyDigest();
+ KeyCache::iterator it = m_keyCache.find(*publisherPublicKeyDigest);
+ if (it != m_keyCache.end())
+ {
+ KeyPtr key = it->second;
+ if (key->validity() == Key::WITHIN_VALID_TIME_SPAN)
+ {
+ // integrity checked, and the key is trustworthy
+ pco->setVerified(true);
+ return true;
+ }
+ else
+ {
+ // delete the invalid key cache
+ m_keyCache.erase(it);
+ }
+ }
+
+ // keyName is the name specified in key locator, i.e. without version and segment
+ Name keyName = pco->keyName();
+ int keyNameSize = keyName.size();
+
+ // for keys, we have to make sure key name is strictly prefix of the content name
+ if (pco->type() == ParsedContentObject::KEY)
+ {
+ Name contentName = pco->name();
+ if (keyNameSize >= contentName.size() || contentName.getPartialName(0, keyNameSize) != keyName)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // for now, user can assign any data using his key
+ }
+
+ Name metaName = keyName.getPartialName(0, keyNameSize - 1) + Name("/info") + keyName.getPartialName(keyNameSize - 1);
+
+ Selectors selectors;
+
+ selectors.childSelector(Selectors::RIGHT)
+ .interestLifetime(1.0);
+
+ PcoPtr keyObject = m_ccnx->get(keyName, selectors);
+ PcoPtr metaObject = m_ccnx->get(metaName, selectors);
+ if (!keyObject || !metaObject || !keyObject->integrityChecked() || !metaObject->integrityChecked())
+ {
+ return false;
+ }
+
+ HashPtr publisherKeyHashInKeyObject = keyObject->publisherPublicKeyDigest();
+ HashPtr publisherKeyHashInMetaObject = metaObject->publisherPublicKeyDigest();
+
+ // make sure key and meta are signed using the same key
+ if (publisherKeyHashInKeyObject->IsZero() || ! (*publisherKeyHashInKeyObject == *publisherKeyHashInMetaObject))
+ {
+ return false;
+ }
+
+ KeyPtr key = boost::make_shared<Key>(keyObject, metaObject);
+ if (key->validity() != Key::WITHIN_VALID_TIME_SPAN)
+ {
+ return false;
+ }
+
+ // check pco is actually signed by this key (maybe redundant)
+ if (! (*pco->publisherPublicKeyDigest() == key->hash()))
+ {
+ return false;
+ }
+
+ // now we only need to make sure the keyObject is trustworthy
+ if (key->hash() == m_rootKeyDigest)
+ {
+ // the key is the root key
+ // do nothing now
+ }
+ else
+ {
+ // can not verify key
+ if (!verify(keyObject))
+ {
+ return false;
+ }
+ }
+
+ // ok, keyObject verified, because metaObject is signed by the same parent key and integrity checked
+ // so metaObject is also verified
+ m_keyCache.insert(std::make_pair(key->hash(), key));
+
+ pco->setVerified(true);
+ return true;
+}
+
+} // Ccnx
diff --git a/ccnx/ccnx-verifier.h b/ccnx/ccnx-verifier.h
new file mode 100644
index 0000000..2ee6def
--- /dev/null
+++ b/ccnx/ccnx-verifier.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef CCNX_VERIFIER_H
+#define CCNX_VERIFIER_H
+
+#include "ccnx-common.h"
+#include "ccnx-wrapper.h"
+#include "ccnx-name.h"
+#include "ccnx-key.h"
+#include "ccnx-pco.h"
+#include <map>
+
+namespace Ccnx {
+
+class CcnxWrapper;
+
+// not thread-safe, don't want to add a mutex for KeyCache
+// which increases the possibility of dead-locking
+// ccnx-wrapper would take care of thread-safety issue
+class Verifier
+{
+public:
+ Verifier(CcnxWrapper *ccnx);
+ ~Verifier();
+
+ bool verify(const PcoPtr &pco);
+
+private:
+
+private:
+ CcnxWrapper *m_ccnx;
+ Hash m_rootKeyDigest;
+ typedef std::map<Hash, KeyPtr> KeyCache;
+ KeyCache m_keyCache;
+};
+
+} // Ccnx
+
+#endif // CCNX_VERIFIER_H
diff --git a/ccnx/ccnx-wrapper.cpp b/ccnx/ccnx-wrapper.cpp
index cc87710..58cebcd 100644
--- a/ccnx/ccnx-wrapper.cpp
+++ b/ccnx/ccnx-wrapper.cpp
@@ -455,7 +455,7 @@
tuple<Closure *, ExecutorPtr, Selectors> *realData = reinterpret_cast< tuple<Closure*, ExecutorPtr, Selectors>* > (selfp->data);
tie (cp, executor, selectors) = *realData;
- bool verified = false;
+ bool checked = false;
switch (kind)
{
@@ -468,7 +468,7 @@
return CCN_UPCALL_RESULT_OK;
case CCN_UPCALL_CONTENT:
- verified = true;
+ checked = true;
_LOG_TRACE (">> incomingData content upcall: " << Name (info->content_ccnb, info->content_comps));
break;
@@ -495,7 +495,7 @@
return CCN_UPCALL_RESULT_OK;
}
- PcoPtr pco = make_shared<ParsedContentObject> (info->content_ccnb, info->pco->offset[CCN_PCO_E], verified);
+ PcoPtr pco = make_shared<ParsedContentObject> (info->content_ccnb, info->pco->offset[CCN_PCO_E], checked);
// this will be run in executor
executor->execute (bind (&Closure::runDataCallback, cp, pco->name (), pco));
@@ -684,11 +684,11 @@
}
bool
-CcnxWrapper::verifyPco(PcoPtr &pco)
+CcnxWrapper::checkPcoIntegrity(PcoPtr &pco)
{
- bool verified = (ccn_verify_content(m_handle, pco->msg(), (ccn_parsed_ContentObject *)pco->pco()) == 0);
- pco->setVerified(verified);
- return verified;
+ bool checked = (ccn_verify_content(m_handle, pco->msg(), (ccn_parsed_ContentObject *)pco->pco()) == 0);
+ pco->setIntegrityChecked(checked);
+ return checked;
}
// This is needed just for get function implementation
diff --git a/ccnx/ccnx-wrapper.h b/ccnx/ccnx-wrapper.h
index 418dde5..f3438c9 100644
--- a/ccnx/ccnx-wrapper.h
+++ b/ccnx/ccnx-wrapper.h
@@ -93,7 +93,7 @@
putToCcnd (const Bytes &contentObject);
bool
- verifyPco(PcoPtr &pco);
+ checkPcoIntegrity(PcoPtr &pco);
PcoPtr
get (const Name &interest, const Selectors &selector = Selectors(), double maxWait = 4.0/*seconds*/);
diff --git a/src/fetcher.cc b/src/fetcher.cc
index d59f457..44ab9fc 100644
--- a/src/fetcher.cc
+++ b/src/fetcher.cc
@@ -132,8 +132,8 @@
if (m_forwardingHint == Name ())
{
- // check whether data is verified in this case; if verified invoke callback
- if (data->verified())
+ // check whether data integrity is checked in this case
+ if (data->integrityChecked())
{
if (!m_segmentCallback.empty ())
{
@@ -149,12 +149,12 @@
}
else
{
- // in this case we don't care whether "data" is verified, in fact, we expect it is unverified
+ // in this case we don't care whether "data" is verified, in fact, we expect it is unverified
try {
PcoPtr pco = make_shared<ParsedContentObject> (*data->contentPtr ());
// we need to verify this pco and apply callback only when verified
- if (m_ccnx->verifyPco(pco))
+ if (m_ccnx->checkPcoIntegrity(pco))
{
if (!m_segmentCallback.empty ())
{
diff --git a/src/hash-helper.h b/src/hash-helper.h
index d289bb1..64a625e 100644
--- a/src/hash-helper.h
+++ b/src/hash-helper.h
@@ -41,8 +41,8 @@
static HashPtr Origin;
Hash ()
- : m_length(0)
- , m_buf(0)
+ : m_buf(0)
+ , m_length(0)
{
}
diff --git a/test/test-ccnx-wrapper.cc b/test/test-ccnx-wrapper.cc
index 5389702..2089bc2 100644
--- a/test/test-ccnx-wrapper.cc
+++ b/test/test-ccnx-wrapper.cc
@@ -68,7 +68,7 @@
PcoPtr npco = make_shared<ParsedContentObject> (*(pco->contentPtr()));
g_dataCallback_counter ++;
BOOST_CHECK(npco);
- BOOST_CHECK(c1->verifyPco(npco));
+ BOOST_CHECK(c1->checkPcoIntegrity(npco));
}
void