Add functionality of endorsement
diff --git a/disable/endorse-sql-table-model.cpp b/disable/endorse-sql-table-model.cpp
new file mode 100644
index 0000000..ea45f47
--- /dev/null
+++ b/disable/endorse-sql-table-model.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "endorse-sql-table-model.h"
+
+#ifndef Q_MOC_RUN
+#include "logging.h"
+#endif
+
+
+INIT_LOGGER("EndorseSqlTableModel");
+
+EndorseSqlTableModel::EndorseSqlTableModel(QObject * parent, QSqlDatabase db)
+  : QSqlTableModel(parent, db)
+{}
+  
+EndorseSqlTableModel::~EndorseSqlTableModel()
+{}
+
+Qt::ItemFlags 
+EndorseSqlTableModel::flags ( const QModelIndex & index )
+{
+  if(index.column() == 3)
+    {
+      _LOG_DEBUG("index: row: " << index.row() << " " << index.column() << " check!");
+      return Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsUserCheckable;
+    }
+  else
+    {
+      _LOG_DEBUG("index: row: " << index.row() << " " << index.column() << " no-check!");
+      return  QSqlTableModel::flags(index);
+    }
+}
+
+bool 
+EndorseSqlTableModel::setData ( const QModelIndex & index, const QVariant & value, int role)
+{
+  bool success = true;
+ 
+  if (index.column() == 3)
+    {
+      _LOG_DEBUG("setData: " << role);
+      if(role == Qt::CheckStateRole)
+	{
+	  QString val = (value==Qt::Checked)?"1":"0";
+	  return QSqlTableModel::setData(index, val, role);
+	}
+      
+      return true;
+    }
+  else
+    {
+      return QSqlTableModel::setData(index, value, role);
+    }
+}
+
+QVariant 
+EndorseSqlTableModel::data ( const QModelIndex & index, int role) const
+{
+  QVariant value = QSqlTableModel::data(index, role);
+  // if (index.column() == 3 && role == Qt::CheckStateRole)
+  if (index.column() == 3)
+    {
+      if(role == Qt::CheckStateRole)
+	{
+	  bool aBool = ((value.toInt() != 0) ? 1 : 0);
+	  if (aBool)
+	    return Qt::Checked;
+	  else
+	    return Qt::Unchecked;
+	}
+      if(role == Qt::DisplayRole)
+	  return QVariant();
+
+      return value;
+    }
+  else
+    {
+      return value;
+    }
+}
diff --git a/disable/endorse-sql-table-model.h b/disable/endorse-sql-table-model.h
new file mode 100644
index 0000000..dab58c3
--- /dev/null
+++ b/disable/endorse-sql-table-model.h
@@ -0,0 +1,34 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef LINKNDN_ENDORSE_SQL_TABLE_MODEL_H
+#define LINKNDN_ENDORSE_SQL_TABLE_MODEL_H
+
+#include <QtSql/QSqlTableModel>
+
+class EndorseSqlTableModel : public QSqlTableModel
+{
+public:
+  EndorseSqlTableModel(QObject * parent = 0, QSqlDatabase db = QSqlDatabase());
+  
+  virtual
+  ~EndorseSqlTableModel();
+
+  Qt::ItemFlags 
+  flags ( const QModelIndex & index );
+
+  bool 
+  setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );
+
+  QVariant 
+  data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
+};
+
+#endif
diff --git a/src/addcontactpanel.cpp b/src/addcontactpanel.cpp
index b1cec57..8ce77c8 100644
--- a/src/addcontactpanel.cpp
+++ b/src/addcontactpanel.cpp
@@ -12,6 +12,9 @@
 #include "ui_addcontactpanel.h"
 
 #ifndef Q_MOC_RUN
+#include <cryptopp/base64.h>
+// #include <ndn.cxx/helpers/der/der.h>
+#include <ndn.cxx/helpers/der/visitor/simple-visitor.h>
 #include "logging.h"
 #endif
 
@@ -31,6 +34,7 @@
   
   qRegisterMetaType<ndn::Name>("NdnName");
   qRegisterMetaType<EndorseCertificate>("EndorseCertificate");
+  qRegisterMetaType<ndn::Data>("NdnData");
 
   connect(ui->cancelButton, SIGNAL(clicked()),
           this, SLOT(onCancelClicked()));
@@ -42,6 +46,16 @@
           this, SLOT(selfEndorseCertificateFetched(const EndorseCertificate&)));
   connect(&*m_contactManager, SIGNAL(contactFetchFailed(const ndn::Name&)),
           this, SLOT(selfEndorseCertificateFetchFailed(const ndn::Name&)));
+  connect(&*m_contactManager, SIGNAL(collectEndorseFetched(const ndn::Data&)),
+          this, SLOT(onCollectEndorseFetched(const ndn::Data&)));
+  connect(&*m_contactManager, SIGNAL(collectEndorseFetchFailed(const ndn::Name&)),
+          this, SLOT(onCollectEndorseFetchFailed(const ndn::Name&)));
+  connect(&*m_contactManager, SIGNAL(contactKeyFetched(const EndorseCertificate&)),
+          this, SLOT(onContactKeyFetched(const EndorseCertificate&)));
+  connect(&*m_contactManager, SIGNAL(contactKeyFetchFailed(const ndn::Name&)),
+          this, SLOT(onContactKeyFetchFailed(const ndn::Name&)));
+
+
 }
 
 AddContactPanel::~AddContactPanel()
@@ -57,13 +71,54 @@
 void
 AddContactPanel::onSearchClicked()
 {
+  m_currentEndorseCertificateReady = false;
+  m_currentCollectEndorseReady = false;
   ui->infoView->clear();
   for(int i = ui->infoView->rowCount() - 1; i >= 0 ; i--)
     ui->infoView->removeRow(i);
   QString inputIdentity = ui->contactInput->text();
   m_searchIdentity = Name(inputIdentity.toUtf8().constData());
 
-  m_contactManager->fetchSelfEndorseCertificate(m_searchIdentity);
+  if(Qt::Checked == ui->fetchBox->checkState())
+    {
+      m_contactManager->fetchSelfEndorseCertificate(m_searchIdentity);
+      m_contactManager->fetchCollectEndorse(m_searchIdentity);
+    }
+  else
+    {
+      if(isCorrectName(m_searchIdentity))
+        m_contactManager->fetchKey(m_searchIdentity);
+      else
+        {
+          m_warningDialog->setMsg("Wrong key certificate name!");
+          m_warningDialog->show();
+        }
+    }
+}
+
+bool
+AddContactPanel::isCorrectName(const Name& name)
+{
+  string key("KEY");
+  string idCert("ID-CERT");
+
+  if(name.get(-1).toUri() != idCert)
+    return false;
+  
+  int keyIndex = -1;
+  for(int i = 0; i < name.size(); i++)
+    {
+      if(name.get(i).toUri() == key)
+        {
+          keyIndex = i;
+          break;
+        }
+    }
+  
+  if(keyIndex < 0)
+    return false;
+  else
+    return true;
 }
 
 void
@@ -79,20 +134,10 @@
 AddContactPanel::selfEndorseCertificateFetched(const EndorseCertificate& endorseCertificate)
 {
   m_currentEndorseCertificate = Ptr<EndorseCertificate>(new EndorseCertificate(endorseCertificate));
-  const Profile& profile = endorseCertificate.getProfileData()->getProfile();
-  ui->infoView->setColumnCount(3);
-  Profile::const_iterator it = profile.begin();
-  int rowCount = 0;
-  for(; it != profile.end(); it++)
-  {
-    ui->infoView->insertRow(rowCount);  
-    QTableWidgetItem *type = new QTableWidgetItem(QString::fromUtf8(it->first.c_str()));
-    ui->infoView->setItem(rowCount, 0, type);
-    string valueString(it->second.buf(), it->second.size());
-    QTableWidgetItem *value = new QTableWidgetItem(QString::fromUtf8(valueString.c_str()));
-    ui->infoView->setItem(rowCount, 1, value);
-    rowCount++;
-  }
+  m_currentEndorseCertificateReady = true;
+
+  if(m_currentCollectEndorseReady == true)
+    displayContactInfo();
 }
 
 void
@@ -102,6 +147,145 @@
   m_warningDialog->show();
 }
 
+void
+AddContactPanel::onContactKeyFetched(const EndorseCertificate& endorseCertificate)
+{
+  m_currentEndorseCertificate = Ptr<EndorseCertificate>(new EndorseCertificate(endorseCertificate));
+
+  const Blob& keyBlob = endorseCertificate.getPublicKeyInfo().getKeyBlob();
+  string encoded;
+  CryptoPP::StringSource ss(reinterpret_cast<const unsigned char *>(keyBlob.buf()), keyBlob.size(), true,
+                            new CryptoPP::Base64Encoder(new CryptoPP::StringSink(encoded), true, 64));
+  
+  ui->infoView->setColumnCount(1);  
+  ui->infoView->insertRow(0);  
+  QTableWidgetItem *keyBits = new QTableWidgetItem(QString::fromUtf8(encoded.c_str()));
+  ui->infoView->setItem(0, 0, keyBits);
+}
+
+void
+AddContactPanel::onContactKeyFetchFailed(const Name& identity)
+{
+  m_warningDialog->setMsg("Cannot fetch contact ksk certificate");
+  m_warningDialog->show();
+}
+
+void
+AddContactPanel::onCollectEndorseFetched(const Data& data)
+{
+  m_currentCollectEndorse = Ptr<Data>(new Data(data));
+  m_currentCollectEndorseReady = true;
+
+  if(m_currentEndorseCertificateReady == true)
+    displayContactInfo();
+}
+
+void
+AddContactPanel::onCollectEndorseFetchFailed(const Name& identity)
+{
+  m_currentCollectEndorse = NULL;
+  m_currentCollectEndorseReady = true;
+  
+  if(m_currentEndorseCertificateReady == true)
+    displayContactInfo();
+}
+
+void
+AddContactPanel::displayContactInfo()
+{
+  _LOG_TRACE("displayContactInfo");
+  const Profile& profile = m_currentEndorseCertificate->getProfileData()->getProfile();
+  const Blob& profileBlob = m_currentEndorseCertificate->getProfileData()->content();
+
+  map<string, int> endorseCount;
+
+  if(m_currentCollectEndorse != NULL)
+    {
+      _LOG_DEBUG("CollectEndorse fetched");
+      boost::iostreams::stream
+        <boost::iostreams::array_source> is (m_currentCollectEndorse->content().buf(), m_currentCollectEndorse->content().size());
+  
+      Ptr<der::DerSequence> root = DynamicCast<der::DerSequence>(der::DerNode::parse(reinterpret_cast<InputIterator &>(is)));
+      const der::DerNodePtrList & children = root->getChildren();
+      der::SimpleVisitor simpleVisitor;
+      
+      for(int i = 0; i < children.size(); i++)
+        {
+          Ptr<Blob> dataBlob = boost::any_cast<Ptr<Blob> >(children[i]->accept(simpleVisitor));
+          Ptr<Data> data = Data::decodeFromWire(dataBlob);
+          Ptr<EndorseCertificate> endorseCert = Ptr<EndorseCertificate>(new EndorseCertificate(*data));
+          _LOG_DEBUG("endorseCert name: " << endorseCert->getName().toUri());
+          
+          Name signerKeyName = endorseCert->getSigner();
+          Name signerName = signerKeyName.getPrefix(signerKeyName.size()-1);
+          
+          Ptr<ContactItem> contact = m_contactManager->getContact(signerName);
+          if(contact == NULL)
+            continue;
+          _LOG_DEBUG("get contact: " << signerName.toUri());
+
+          if(!contact->isIntroducer() || !contact->canBeTrustedFor(m_currentEndorseCertificate->getProfileData()->getIdentityName()))
+            continue;
+          _LOG_DEBUG("contact can be trusted");
+          
+          if(!security::PolicyManager::verifySignature(*data, contact->getSelfEndorseCertificate().getPublicKeyInfo()))
+            continue;
+
+          const Blob& tmpProfileBlob = endorseCert->getProfileData()->content();
+          if(profileBlob != tmpProfileBlob)
+            continue;
+
+           _LOG_DEBUG("Profile equal");
+
+          const vector<string>& endorseList = endorseCert->getEndorseList();
+          vector<string>::const_iterator it = endorseList.begin();
+          for(; it != endorseList.end(); it++)
+            {
+              _LOG_DEBUG("Entry: " << *it);
+              endorseCount[*it] += 1;
+            }
+        }
+    }
+
+  // map<string, int>::iterator tmp_it = endorseCount.begin();
+  // for(; tmp_it != endorseCount.end(); tmp_it++)
+  //   {
+  //     _LOG_DEBUG("Entry: " << tmp_it->first << " " << tmp_it->second);
+  //   }
+  
+  ui->infoView->setColumnCount(3);
+  Profile::const_iterator it = profile.begin();
+  int rowCount = 0;
+  
+  QTableWidgetItem *typeHeader = new QTableWidgetItem(QString::fromUtf8("Type"));
+  ui->infoView->setHorizontalHeaderItem(0, typeHeader);
+  QTableWidgetItem *valueHeader = new QTableWidgetItem(QString::fromUtf8("Value"));
+  ui->infoView->setHorizontalHeaderItem(1, valueHeader);
+  QTableWidgetItem *endorseHeader = new QTableWidgetItem(QString::fromUtf8("Endorse"));
+  ui->infoView->setHorizontalHeaderItem(2, endorseHeader);
+  
+  for(; it != profile.end(); it++)
+  {
+    ui->infoView->insertRow(rowCount);  
+    QTableWidgetItem *type = new QTableWidgetItem(QString::fromUtf8(it->first.c_str()));
+    ui->infoView->setItem(rowCount, 0, type);
+    
+    string valueString(it->second.buf(), it->second.size());
+    QTableWidgetItem *value = new QTableWidgetItem(QString::fromUtf8(valueString.c_str()));
+    ui->infoView->setItem(rowCount, 1, value);
+    
+    map<string, int>::iterator map_it = endorseCount.find(it->first);
+    QTableWidgetItem *endorse = NULL;
+    if(map_it == endorseCount.end())
+      endorse = new QTableWidgetItem(QString::number(0));
+    else
+      endorse = new QTableWidgetItem(QString::number(map_it->second));
+    ui->infoView->setItem(rowCount, 2, endorse);
+
+    rowCount++;
+  }
+}
+
 #if WAF
 #include "addcontactpanel.moc"
 #include "addcontactpanel.cpp.moc"
diff --git a/src/addcontactpanel.h b/src/addcontactpanel.h
index 1536464..3437e54 100644
--- a/src/addcontactpanel.h
+++ b/src/addcontactpanel.h
@@ -29,6 +29,8 @@
 
 Q_DECLARE_METATYPE(EndorseCertificate)
 
+Q_DECLARE_METATYPE(ndn::Data)
+
 class AddContactPanel : public QDialog
 {
   Q_OBJECT
@@ -39,6 +41,13 @@
 
   ~AddContactPanel();
 
+private:
+  void
+  displayContactInfo();
+
+  bool
+  isCorrectName(const ndn::Name& name);
+
 private slots:
   void
   onCancelClicked();
@@ -55,6 +64,18 @@
   void
   selfEndorseCertificateFetchFailed(const ndn::Name& identity);
 
+  void
+  onContactKeyFetched(const EndorseCertificate& endorseCertificate);
+
+  void
+  onContactKeyFetchFailed(const ndn::Name& identity);
+
+  void
+  onCollectEndorseFetched(const ndn::Data& data);
+
+  void
+  onCollectEndorseFetchFailed(const ndn::Name& identity);
+
 signals:
   void
   newContactAdded();
@@ -65,6 +86,9 @@
   ndn::Ptr<ContactManager> m_contactManager;
   WarningDialog* m_warningDialog;
   ndn::Ptr<EndorseCertificate> m_currentEndorseCertificate;
+  ndn::Ptr<ndn::Data> m_currentCollectEndorse;
+  bool m_currentEndorseCertificateReady;
+  bool m_currentCollectEndorseReady;
 };
 
 #endif // ADDCONTACTPANEL_H
diff --git a/src/addcontactpanel.ui b/src/addcontactpanel.ui
index 7974593..1955964 100644
--- a/src/addcontactpanel.ui
+++ b/src/addcontactpanel.ui
@@ -22,7 +22,7 @@
      <height>481</height>
     </rect>
    </property>
-   <layout class="QVBoxLayout" name="addContactPanelLayout" stretch="1,25,1">
+   <layout class="QVBoxLayout" name="addContactPanelLayout" stretch="1,25,0,1">
     <property name="spacing">
      <number>10</number>
     </property>
@@ -67,6 +67,16 @@
      </widget>
     </item>
     <item>
+     <widget class="QCheckBox" name="fetchBox">
+      <property name="text">
+       <string>Fetch profile</string>
+      </property>
+      <property name="checkable">
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+    <item>
      <layout class="QHBoxLayout" name="buttonLayout">
       <item>
        <widget class="QPushButton" name="cancelButton">
diff --git a/src/contact-item.cpp b/src/contact-item.cpp
index eb342d6..839988c 100644
--- a/src/contact-item.cpp
+++ b/src/contact-item.cpp
@@ -28,34 +28,34 @@
   , m_isIntroducer(isIntroducer)
 {
   Name endorsedkeyName = selfEndorseCertificate.getPublicKeyName();
-  Ptr<const signature::Sha256WithRsa> endorseSig = boost::dynamic_pointer_cast<const signature::Sha256WithRsa>(selfEndorseCertificate.getSignature());
-  const Name& signingKeyName = endorseSig->getKeyLocator().getKeyName();
+  // Ptr<const signature::Sha256WithRsa> endorseSig = boost::dynamic_pointer_cast<const signature::Sha256WithRsa>(selfEndorseCertificate.getSignature());
+  // const Name& signingKeyName = endorseSig->getKeyLocator().getKeyName();
   
-  int i = 0;
-  int j = -1;
-  string keyString("KEY");
-  string idString("ID-CERT");
-  for(; i < signingKeyName.size(); i++)
-    {
-      if(keyString == signingKeyName.get(i).toUri())
-        j = i;
-      if(idString == signingKeyName.get(i).toUri())
-        break;
-    }
+  // int i = 0;
+  // int j = -1;
+  // string keyString("KEY");
+  // string idString("ID-CERT");
+  // for(; i < signingKeyName.size(); i++)
+  //   {
+  //     if(keyString == signingKeyName.get(i).toUri())
+  //       j = i;
+  //     if(idString == signingKeyName.get(i).toUri())
+  //       break;
+  //   }
 
-  if(i >= signingKeyName.size() || j < 0)
-    throw LnException("Wrong name!");
+  // if(i >= signingKeyName.size() || j < 0)
+  //   throw LnException("Wrong name!");
 
-  Name subName = signingKeyName.getSubName(0, j);
-  subName.append(signingKeyName.getSubName(j+1, i-j-1));
+  // Name subName = signingKeyName.getSubName(0, j);
+  // subName.append(signingKeyName.getSubName(j+1, i-j-1));
 
 
 
-  // _LOG_DEBUG("endorsedkeyName " << endorsedkeyName.toUri());
-  // _LOG_DEBUG("subKeyName " << subName.toUri());
+  // // _LOG_DEBUG("endorsedkeyName " << endorsedkeyName.toUri());
+  // // _LOG_DEBUG("subKeyName " << subName.toUri());
 
-  if(endorsedkeyName != subName)
-    throw LnException("not a self-claimed");
+  // if(endorsedkeyName != subName)
+  //   throw LnException("not a self-claimed");
 
   m_namespace = endorsedkeyName.getSubName(0, endorsedkeyName.size() - 1);
   m_alias = alias.empty() ? m_namespace.toUri() : alias;
diff --git a/src/contact-item.h b/src/contact-item.h
index fcf24a1..9ab478b 100644
--- a/src/contact-item.h
+++ b/src/contact-item.h
@@ -58,6 +58,10 @@
   isIntroducer() const
   { return m_isIntroducer; }
 
+  inline void
+  setIsIntroducer(bool isIntroducer) 
+  { m_isIntroducer = isIntroducer; }
+
   void
   addTrustScope(const ndn::Name& nameSpace)
   {
diff --git a/src/contact-manager.cpp b/src/contact-manager.cpp
index 2c30921..de3a9ca 100644
--- a/src/contact-manager.cpp
+++ b/src/contact-manager.cpp
@@ -19,6 +19,7 @@
 #include <ndn.cxx/security/policy/identity-policy-rule.h>
 #include <ndn.cxx/security/cache/ttl-certificate-cache.h>
 #include <ndn.cxx/security/encryption/basic-encryption-manager.h>
+#include <ndn.cxx/helpers/der/der.h>
 #include <fstream>
 #include "logging.h"
 #endif
@@ -54,6 +55,9 @@
   Ptr<EncryptionManager> encryptionManager = Ptr<EncryptionManager>(new BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
   Ptr<Keychain> keychain = Ptr<Keychain>(new Keychain(identityManager, policyManager, encryptionManager));
 
+  policyManager->addVerificationPolicyRule(Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<DNS>]*)<DNS><ENDORSED>",
+                                                                                          "^([^<KEY>]*)<KEY>(<>*)[<ksk-.*><dsk-.*>]<ID-CERT>$",
+                                                                                          "==", "\\1", "\\1\\2", true)));
   policyManager->addVerificationPolicyRule(Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<DNS>]*)<DNS><PROFILE>",
                                                                                           "^([^<KEY>]*)<KEY>(<>*)[<ksk-.*><dsk-.*>]<ID-CERT>$",
                                                                                           "==", "\\1", "\\1\\2", true)));
@@ -116,6 +120,99 @@
 }
 
 void
+ContactManager::fetchCollectEndorse(const ndn::Name& identity)
+{
+  Name interestName = identity;
+  interestName.append("DNS").append("ENDORSED");
+
+  Ptr<Interest> interestPtr = Ptr<Interest>(new Interest(interestName));
+  interestPtr->setChildSelector(Interest::CHILD_RIGHT);
+  interestPtr->setInterestLifetime(1);
+  Ptr<Closure> closure = Ptr<Closure> (new Closure(boost::bind(&ContactManager::onDnsCollectEndorseVerified, 
+                                                               this,
+                                                               _1,
+                                                               identity),
+						   boost::bind(&ContactManager::onDnsCollectEndorseTimeout,
+                                                               this,
+                                                               _1, 
+                                                               _2,
+                                                               identity,
+                                                               0),
+						   boost::bind(&ContactManager::onDnsCollectEndorseUnverified,
+                                                               this,
+                                                               _1,
+                                                               identity)));
+  m_wrapper->sendInterest(interestPtr, closure);
+}
+
+void
+ContactManager::fetchKey(const ndn::Name& certName)
+{
+  Name interestName = certName;
+  
+  Ptr<Interest> interestPtr = Ptr<Interest>(new Interest(interestName));
+  interestPtr->setChildSelector(Interest::CHILD_RIGHT);
+  Ptr<Closure> closure = Ptr<Closure> (new Closure(boost::bind(&ContactManager::onKeyVerified, 
+                                                               this,
+                                                               _1,
+                                                               certName),
+						   boost::bind(&ContactManager::onKeyTimeout,
+                                                               this,
+                                                               _1, 
+                                                               _2,
+                                                               certName,
+                                                               0),
+						   boost::bind(&ContactManager::onKeyUnverified,
+                                                               this,
+                                                               _1,
+                                                               certName)));
+  m_wrapper->sendInterest(interestPtr, closure);
+}
+
+void
+ContactManager::onDnsCollectEndorseVerified(Ptr<Data> data, const Name& identity)
+{ emit collectEndorseFetched (*data); }
+
+void
+ContactManager::onDnsCollectEndorseTimeout(Ptr<Closure> closure, Ptr<Interest> interest, const Name& identity, int retry)
+{ emit collectEndorseFetchFailed (identity); }
+
+void
+ContactManager::onDnsCollectEndorseUnverified(Ptr<Data> data, const Name& identity)
+{ emit collectEndorseFetchFailed (identity); }
+
+void
+ContactManager::onKeyVerified(Ptr<Data> data, const Name& identity)
+{
+  IdentityCertificate identityCertificate(*data);
+  Name keyName = identityCertificate.getPublicKeyName();
+  Profile profile(keyName.getPrefix(keyName.size()-1), 
+                  keyName.get(-2).toUri(),
+                  keyName.getPrefix(keyName.size()-2).toUri());
+  
+  Ptr<ProfileData> profileData = Ptr<ProfileData>(new ProfileData(keyName.getPrefix(keyName.size()-1),
+                                                                  profile));
+  
+  Ptr<IdentityManager> identityManager = m_keychain->getIdentityManager();
+  Name certificateName = identityManager->getDefaultCertificateName ();
+  identityManager->signByCertificate(*profileData, certificateName);
+
+  EndorseCertificate endorseCertificate(identityCertificate, profileData);
+
+  identityManager->signByCertificate(endorseCertificate, certificateName);
+
+  emit contactKeyFetched (endorseCertificate); 
+}
+
+void
+ContactManager::onKeyUnverified(Ptr<Data> data, const Name& identity)
+{ emit contactKeyFetchFailed (identity); }
+
+void
+ContactManager::onKeyTimeout(Ptr<Closure> closure, Ptr<Interest> interest, const Name& identity, int retry)
+{ emit contactKeyFetchFailed(identity); }
+
+void
 ContactManager::updateProfileData(const Name& identity)
 {
   _LOG_DEBUG("updateProfileData: " << identity.toUri());
@@ -159,6 +256,46 @@
     }
 }
 
+void
+ContactManager::updateEndorseCertificate(const ndn::Name& identity, const ndn::Name& signerIdentity)
+{
+  Ptr<Blob> oldEndorseCertificateBlob = m_contactStorage->getEndorseCertificate(identity);
+  Ptr<EndorseCertificate> newEndorseCertificate = generateEndorseCertificate(identity, signerIdentity);
+  if(NULL != oldEndorseCertificateBlob)
+    {
+      Ptr<Data> plainData = Data::decodeFromWire(oldEndorseCertificateBlob);
+      EndorseCertificate oldEndorseCertificate(*plainData);
+      const Blob& oldEndorseContent = oldEndorseCertificate.content();
+      const Blob& newEndorseContent = newEndorseCertificate->content();
+      if(oldEndorseContent == newEndorseContent)
+        return;
+    }
+  else
+    {
+      if(NULL == newEndorseCertificate)
+        return;
+    }
+  m_contactStorage->addEndorseCertificate(newEndorseCertificate, identity);
+  publishEndorseCertificateInDNS(newEndorseCertificate, signerIdentity);
+}
+
+Ptr<EndorseCertificate> 
+ContactManager::generateEndorseCertificate(const Name& identity, const Name& signerIdentity)
+{
+  Ptr<ContactItem> contact = getContact(identity);
+
+  Ptr<IdentityManager> identityManager = m_keychain->getIdentityManager();
+  Name signerKeyName = identityManager->getDefaultKeyNameForIdentity(signerIdentity);
+  Name signerCertName = identityManager->getDefaultCertificateNameByIdentity(signerIdentity);
+
+  vector<string> endorseList = m_contactStorage->getEndorseList(identity);
+
+  Ptr<EndorseCertificate> cert = Ptr<EndorseCertificate>(new EndorseCertificate(contact->getSelfEndorseCertificate(), signerKeyName, endorseList)); 
+  identityManager->signByCertificate(*cert, signerCertName);
+
+  return cert;
+}
+
 vector<Ptr<ContactItem> >
 ContactManager::getContactItemList()
 { return m_contactStorage->getAllContacts(); }
@@ -207,8 +344,6 @@
     endorseList.push_back(it->first);
   
   Ptr<EndorseCertificate> selfEndorseCertificate = Ptr<EndorseCertificate>(new EndorseCertificate(*kskCert,
-                                                                                                  kskCert->getNotBefore(),
-                                                                                                  kskCert->getNotAfter(),
                                                                                                   profileData,
                                                                                                   endorseList));
   identityManager->signByCertificate(*selfEndorseCertificate, kskCert->getName());
@@ -249,24 +384,7 @@
 
 void
 ContactManager::onDnsSelfEndorseCertificateTimeout(Ptr<Closure> closure, Ptr<Interest> interest, const Name& identity, int retry)
-{
-  if(retry > 0)
-    {
-      Ptr<Closure> newClosure = Ptr<Closure>(new Closure(closure->m_dataCallback,
-                                                         boost::bind(&ContactManager::onDnsSelfEndorseCertificateTimeout, 
-                                                                     this, 
-                                                                     _1, 
-                                                                     _2, 
-                                                                     identity,
-                                                                     retry - 1),
-                                                         closure->m_unverifiedCallback,
-                                                         closure->m_stepCount)
-                                             );
-      m_wrapper->sendInterest(interest, newClosure);
-    }
-  else
-    emit contactFetchFailed(identity);
-}
+{ emit contactFetchFailed(identity); }
 
 void
 ContactManager::publishSelfEndorseCertificateInDNS(Ptr<EndorseCertificate> selfEndorseCertificate)
@@ -300,6 +418,71 @@
   m_wrapper->putToNdnd(*dnsBlob);
 }
 
+void
+ContactManager::publishEndorseCertificateInDNS(Ptr<EndorseCertificate> endorseCertificate, const Name& signerIdentity)
+{
+  Ptr<Data> data = Ptr<Data>::Create();
+
+  Name keyName = endorseCertificate->getPublicKeyName();
+  Name endorsee = keyName.getSubName(0, keyName.size()-1);
+
+
+  Name dnsName = signerIdentity;
+  dnsName.append("DNS").append(endorsee).append("ENDORSEE").appendVersion();
+  
+  data->setName(dnsName);
+  Ptr<Blob> blob = endorseCertificate->encodeToWire();
+
+  Content content(blob->buf(), blob->size());
+  data->setContent(content);
+
+  Name signCertName = m_keychain->getIdentityManager()->getDefaultCertificateNameByIdentity(signerIdentity);
+  m_keychain->getIdentityManager()->signByCertificate(*data, signCertName);
+
+  m_dnsStorage->updateDnsEndorseOthers(*data, signerIdentity, endorsee);
+  
+  Ptr<Blob> dnsBlob = data->encodeToWire();
+
+  m_wrapper->putToNdnd(*dnsBlob);
+}
+
+void
+ContactManager::publishEndorsedDataInDns(const Name& identity)
+{
+  Ptr<Data> data = Ptr<Data>::Create();
+
+  Name dnsName = identity;
+  dnsName.append("DNS").append("ENDORSED").appendVersion();
+  data->setName(dnsName);
+  
+  Ptr<vector<Blob> > collectEndorseList = m_contactStorage->getCollectEndorseList(identity);
+
+  Ptr<der::DerSequence> root = Ptr<der::DerSequence>::Create();
+
+  vector<Blob>::const_iterator it = collectEndorseList->begin();
+  for(; it != collectEndorseList->end(); it++)
+    {
+      Ptr<der::DerOctetString> entry = Ptr<der::DerOctetString>(new der::DerOctetString(*it));
+      root->addChild(entry);
+    }
+  
+  blob_stream blobStream;
+  OutputIterator & start = reinterpret_cast<OutputIterator &> (blobStream);
+  root->encode(start);
+
+  Content content(blobStream.buf()->buf(), blobStream.buf()->size());
+  data->setContent(content);
+  
+  Name signCertName = m_keychain->getIdentityManager()->getDefaultCertificateNameByIdentity(identity);
+  m_keychain->getIdentityManager()->signByCertificate(*data, signCertName);
+
+  m_dnsStorage->updateDnsOthersEndorse(*data, identity);
+  
+  Ptr<Blob> dnsBlob = data->encodeToWire();
+
+  m_wrapper->putToNdnd(*dnsBlob);
+}
+
 
 #if WAF
 #include "contact-manager.moc"
diff --git a/src/contact-manager.h b/src/contact-manager.h
index 465a1cc..b8498cc 100644
--- a/src/contact-manager.h
+++ b/src/contact-manager.h
@@ -37,8 +37,17 @@
   fetchSelfEndorseCertificate(const ndn::Name& identity);
 
   void
+  fetchKey(const ndn::Name& identity);
+
+  void
+  fetchCollectEndorse(const ndn::Name& identity);
+
+  void
   updateProfileData(const ndn::Name& identity);
 
+  void
+  updateEndorseCertificate(const ndn::Name& identity, const ndn::Name& signerIdentity);
+
   std::vector<ndn::Ptr<ContactItem> >
   getContactItemList();
 
@@ -61,6 +70,9 @@
   getWrapper()
   { return m_wrapper; }
 
+  void
+  publishEndorsedDataInDns(const ndn::Name& identity);
+
 private:
   void
   setKeychain();
@@ -68,9 +80,15 @@
   ndn::Ptr<EndorseCertificate>
   getSignedSelfEndorseCertificate(const ndn::Name& identity, const Profile& profile);
 
+  ndn::Ptr<EndorseCertificate> 
+  generateEndorseCertificate(const ndn::Name& identity, const ndn::Name& signerIdentity);
+
   void
   publishSelfEndorseCertificateInDNS(ndn::Ptr<EndorseCertificate> selfEndorseCertificate);
 
+  void
+  publishEndorseCertificateInDNS(ndn::Ptr<EndorseCertificate> endorseCertificate, const ndn::Name& signerIdentity);
+
   void 
   onDnsSelfEndorseCertificateVerified(ndn::Ptr<ndn::Data> selfEndorseCertificate, const ndn::Name& identity);
 
@@ -80,6 +98,26 @@
   void
   onDnsSelfEndorseCertificateTimeout(ndn::Ptr<ndn::Closure> closure, ndn::Ptr<ndn::Interest> interest, const ndn::Name& identity, int retry);
 
+  void
+  onKeyVerified(ndn::Ptr<ndn::Data> data, const ndn::Name& identity);
+
+  void
+  onKeyUnverified(ndn::Ptr<ndn::Data> data, const ndn::Name& identity);
+
+  void
+  onKeyTimeout(ndn::Ptr<ndn::Closure> closure, ndn::Ptr<ndn::Interest> interest, const ndn::Name& identity, int retry);
+
+  void
+  onDnsCollectEndorseVerified(ndn::Ptr<ndn::Data> data, const ndn::Name& identity);
+
+  void
+  onDnsCollectEndorseTimeout(ndn::Ptr<ndn::Closure> closure, ndn::Ptr<ndn::Interest> interest, const ndn::Name& identity, int retry);
+
+  void
+  onDnsCollectEndorseUnverified(ndn::Ptr<ndn::Data> data, const ndn::Name& identity);
+
+  
+
 signals:
   void 
   contactFetched(const EndorseCertificate& endorseCertificate);
@@ -87,6 +125,18 @@
   void
   contactFetchFailed(const ndn::Name& identity);
 
+  void
+  contactKeyFetched(const EndorseCertificate& endorseCertificate);
+
+  void
+  contactKeyFetchFailed(const ndn::Name& identity);
+
+  void 
+  collectEndorseFetched(const ndn::Data& data);
+
+  void
+  collectEndorseFetchFailed(const ndn::Name& identity);
+
 private slots:
   
   
diff --git a/src/contact-storage.cpp b/src/contact-storage.cpp
index 073eaa1..903f210 100644
--- a/src/contact-storage.cpp
+++ b/src/contact-storage.cpp
@@ -56,19 +56,58 @@
       PRIMARY KEY (contact_namespace)                                \n \
   );                                                                 \n \
                                                                      \
-CREATE INDEX contact_index ON TrustedContact(contact_namespace);     \n \
+CREATE INDEX contact_index ON Contact(contact_namespace);            \n \
 ";
 
 const string INIT_TS_TABLE = "\
 CREATE TABLE IF NOT EXISTS                                           \n \
   TrustScope(                                                        \n \
+      id                INTEGER PRIMARY KEY AUTOINCREMENT,           \n \
       contact_namespace BLOB NOT NULL,                               \n \
-      trust_scope       BLOB NOT NULL,                               \n \
-                                                                     \
-      PRIMARY KEY (contact_namespace, trust_scope)                   \n \
+      trust_scope       BLOB NOT NULL                                \n \
   );                                                                 \n \
                                                                      \
-CREATE INDEX ts_index ON TrustedContact(contact_namespace);          \n \
+CREATE INDEX ts_index ON TrustScope(contact_namespace);              \n \
+";
+
+const string INIT_CP_TABLE = "\
+CREATE TABLE IF NOT EXISTS                                           \n \
+  ContactProfile(                                                    \n \
+      profile_identity  BLOB NOT NULL,                               \n \
+      profile_type      BLOB NOT NULL,                               \n \
+      profile_value     BLOB NOT NULL,                               \n \
+      endorse           INTEGER NOT NULL,                            \n \
+                                                                     \
+      PRIMARY KEY (profile_identity, profile_type)                   \n \
+  );                                                                 \n \
+                                                                     \
+CREATE INDEX cp_index ON ContactProfile(profile_identity);           \n \
+";
+
+const string INIT_PE_TABLE = "\
+CREATE TABLE IF NOT EXISTS                                           \n \
+  ProfileEndorse(                                                    \n \
+      identity          BLOB NOT NULL UNIQUE,                        \n \
+      endorse_data      BLOB NOT NULL,                               \n \
+                                                                     \
+      PRIMARY KEY (identity)                                         \n \
+  );                                                                 \n \
+                                                                     \
+CREATE INDEX pe_index ON ProfileEndorse(identity);                   \n \
+";
+
+const string INIT_CE_TABLE = "\
+CREATE TABLE IF NOT EXISTS                                           \n \
+  CollectEndorse(                                                    \n \
+      endorsee          BLOB NOT NULL,                               \n \
+      endorser          BLOB NOT NULL,                               \n \
+      endorse_name      BLOB NOT NULL,                               \n \
+      endorse_data      BLOB NOT NULL,                               \n \
+                                                                     \
+      PRIMARY KEY (endorsee, endorser)                               \n \
+  );                                                                 \n \
+                                                                     \
+CREATE INDEX ce_index ON CollectEndorse(endorsee);                   \n \
 ";
 
 ContactStorage::ContactStorage()
@@ -116,7 +155,7 @@
     }
 
 
-  // Check if TrustedContact table exists
+  // Check if Contact table exists
   sqlite3_prepare_v2 (m_db, "SELECT name FROM sqlite_master WHERE type='table' And name='Contact'", -1, &stmt, 0);
   res = sqlite3_step (stmt);
 
@@ -133,7 +172,7 @@
         throw LnException("Init \"error\" in Contact");
     }
 
-  // Check if TrustedContact table exists
+  // Check if TrustScope table exists
   sqlite3_prepare_v2 (m_db, "SELECT name FROM sqlite_master WHERE type='table' And name='TrustScope'", -1, &stmt, 0);
   res = sqlite3_step (stmt);
 
@@ -149,6 +188,57 @@
       if (res != SQLITE_OK && errmsg != 0)
         throw LnException("Init \"error\" in TrustScope");
     }
+
+  // Check if ContactProfile table exists
+  sqlite3_prepare_v2 (m_db, "SELECT name FROM sqlite_master WHERE type='table' And name='ContactProfile'", -1, &stmt, 0);
+  res = sqlite3_step (stmt);
+
+  bool cpTableExist = false;
+  if (res == SQLITE_ROW)
+      cpTableExist = true;
+  sqlite3_finalize (stmt);
+
+  if(!cpTableExist)
+    {
+      char *errmsg = 0;
+      res = sqlite3_exec (m_db, INIT_CP_TABLE.c_str (), NULL, NULL, &errmsg);
+      if (res != SQLITE_OK && errmsg != 0)
+        throw LnException("Init \"error\" in ContactProfile");
+    }
+
+  // Check if ProfileEndorse table exists
+  sqlite3_prepare_v2 (m_db, "SELECT name FROM sqlite_master WHERE type='table' And name='ProfileEndorse'", -1, &stmt, 0);
+  res = sqlite3_step (stmt);
+
+  bool peTableExist = false;
+  if (res == SQLITE_ROW)
+      peTableExist = true;
+  sqlite3_finalize (stmt);
+
+  if(!peTableExist)
+    {
+      char *errmsg = 0;
+      res = sqlite3_exec (m_db, INIT_PE_TABLE.c_str (), NULL, NULL, &errmsg);
+      if (res != SQLITE_OK && errmsg != 0)
+        throw LnException("Init \"error\" in ProfileEndorse");
+    }
+
+  // Check if CollectEndorse table exists
+  sqlite3_prepare_v2 (m_db, "SELECT name FROM sqlite_master WHERE type='table' And name='CollectEndorse'", -1, &stmt, 0);
+  res = sqlite3_step (stmt);
+
+  bool ceTableExist = false;
+  if (res == SQLITE_ROW)
+      ceTableExist = true;
+  sqlite3_finalize (stmt);
+
+  if(!ceTableExist)
+    {
+      char *errmsg = 0;
+      res = sqlite3_exec (m_db, INIT_CE_TABLE.c_str (), NULL, NULL, &errmsg);
+      if (res != SQLITE_OK && errmsg != 0)
+        throw LnException("Init \"error\" in CollectEndorse");
+    }
 }
 
 bool
@@ -242,6 +332,24 @@
   // _LOG_DEBUG("res " << res);
   sqlite3_finalize (stmt);
 
+  Ptr<ProfileData> profileData = contact.getSelfEndorseCertificate().getProfileData();
+  const Profile&  profile = profileData->getProfile();
+  Profile::const_iterator it = profile.begin();
+  string identity = contact.getNameSpace().toUri();
+  for(; it != profile.end(); it++)
+    {
+      sqlite3_prepare_v2 (m_db, 
+                          "INSERT INTO ContactProfile (profile_identity, profile_type, profile_value, endorse) values (?, ?, ?, 0)", 
+                          -1, 
+                          &stmt, 
+                          0);
+      sqlite3_bind_text(stmt, 1, identity.c_str(),  identity.size (), SQLITE_TRANSIENT);
+      sqlite3_bind_text(stmt, 2, it->first.c_str(), it->first.size(), SQLITE_TRANSIENT);
+      sqlite3_bind_text(stmt, 3, it->second.buf(), it->second.size(), SQLITE_TRANSIENT);
+      res = sqlite3_step (stmt);
+      sqlite3_finalize (stmt);
+    }
+
   if(isIntroducer)
     {
       const vector<Name>& scopeList = contact.getTrustScopeList();
@@ -264,6 +372,18 @@
     }
 }
 
+void
+ContactStorage::updateIsIntroducer(const ndn::Name& identity, bool isIntroducer)
+{
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "UPDATE Contact SET is_introducer=? WHERE contact_namespace=?", -1, &stmt, 0);
+  sqlite3_bind_int(stmt, 1, (isIntroducer ? 1 : 0));
+  sqlite3_bind_text(stmt, 2, identity.toUri().c_str(),  identity.toUri().size (), SQLITE_TRANSIENT);
+  int res = sqlite3_step (stmt);
+  sqlite3_finalize (stmt);
+  return;
+}
+
 void 
 ContactStorage::updateAlias(const ndn::Name& identity, std::string alias)
 {
@@ -352,7 +472,24 @@
       EndorseCertificate endorseCertificate(*certData);
       int isIntroducer = sqlite3_column_int (stmt, 2);
 
-      return Ptr<ContactItem>(new ContactItem(endorseCertificate, isIntroducer, alias));      
+      sqlite3_finalize (stmt);
+      
+      Ptr<ContactItem> contact = Ptr<ContactItem>(new ContactItem(endorseCertificate, isIntroducer, alias));
+
+      if(contact->isIntroducer())
+        {
+          sqlite3_prepare_v2 (m_db, "SELECT trust_scope FROM TrustScope WHERE contact_namespace=?", -1, &stmt, 0);
+          sqlite3_bind_text(stmt, 1, name.toUri().c_str(), name.toUri().size(), SQLITE_TRANSIENT);
+
+          while( sqlite3_step (stmt) == SQLITE_ROW)
+            {
+              Name scope(string(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0)));
+              contact->addTrustScope(scope);
+            }
+          sqlite3_finalize (stmt);  
+        }
+
+      return contact;      
     } 
   return NULL;
 }
@@ -401,6 +538,8 @@
   sqlite3_bind_text(stmt, 1, newEndorseCertificateBlob->buf(), newEndorseCertificateBlob->size(), SQLITE_TRANSIENT);
   sqlite3_bind_text(stmt, 2, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
   sqlite3_step(stmt);
+  
+  sqlite3_finalize (stmt);
 }
 
 void
@@ -413,4 +552,142 @@
   sqlite3_bind_text(stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
   sqlite3_bind_text(stmt, 2, newEndorseCertificateBlob->buf(), newEndorseCertificateBlob->size(), SQLITE_TRANSIENT);
   sqlite3_step(stmt);
+
+  sqlite3_finalize (stmt);
+}
+
+Ptr<Blob>
+ContactStorage::getEndorseCertificate(const ndn::Name& identity)
+{
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "SELECT endorse_data FROM ProfileEndorse where identity=?", -1, &stmt, 0);
+  sqlite3_bind_text(stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
+
+  Ptr<Blob> result = NULL;
+  if(sqlite3_step (stmt) == SQLITE_ROW)
+    result = Ptr<Blob>(new Blob(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0)));
+
+  sqlite3_finalize (stmt);
+
+  return result;
+}
+
+void
+ContactStorage::updateEndorseCertificate(ndn::Ptr<EndorseCertificate> endorseCertificate, const ndn::Name& identity)
+{
+  Ptr<Blob> newEndorseCertificateBlob = endorseCertificate->encodeToWire();
+
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "UPDATE ProfileEndorse SET endorse_data=? WHERE identity=?", -1, &stmt, 0);
+  sqlite3_bind_text(stmt, 1, newEndorseCertificateBlob->buf(), newEndorseCertificateBlob->size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 2, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
+  sqlite3_step(stmt);
+
+  sqlite3_finalize (stmt);
+}
+
+void
+ContactStorage::addEndorseCertificate(ndn::Ptr<EndorseCertificate> endorseCertificate, const ndn::Name& identity)
+{
+  Ptr<Blob> newEndorseCertificateBlob = endorseCertificate->encodeToWire();
+
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "INSERT INTO ProfileEndorse (identity, endorse_data) values (?, ?)", -1, &stmt, 0);
+  sqlite3_bind_text(stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 2, newEndorseCertificateBlob->buf(), newEndorseCertificateBlob->size(), SQLITE_TRANSIENT);
+  sqlite3_step(stmt);
+
+  sqlite3_finalize (stmt);
+}
+
+vector<string>
+ContactStorage::getEndorseList(const Name& identity)
+{
+  vector<string> endorseList;
+
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "SELECT profile_type FROM ContactProfile WHERE profile_identity=? AND endorse=1 ORDER BY profile_type", -1, &stmt, 0);
+  sqlite3_bind_text(stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
+
+  while( sqlite3_step (stmt) == SQLITE_ROW)
+    {
+      string profileType(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
+      endorseList.push_back(profileType);      
+    }
+  sqlite3_finalize (stmt);  
+  
+  return endorseList;
+}
+
+void
+ContactStorage::updateCollectEndorse(const EndorseCertificate& endorseCertificate)
+{
+  Name endorserName = endorseCertificate.getSigner();
+  Name keyName = endorseCertificate.getPublicKeyName();
+  Name endorseeName = keyName.getPrefix(keyName.size()-1);
+  Name getCertName = endorseCertificate.getName();
+  Name oldCertName;
+  bool insert = true;
+  bool update = true;
+
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "SELECT endorse_name FROM CollectEndorse WHERE endorser=? AND endorsee=?", -1, &stmt, 0);
+  sqlite3_bind_text(stmt, 1, endorserName.toUri().c_str(), endorserName.toUri().size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 2, endorseeName.toUri().c_str(), endorseeName.toUri().size(), SQLITE_TRANSIENT);
+
+  if(sqlite3_step (stmt) == SQLITE_ROW)
+    {
+      insert = false;
+      oldCertName = Name(string(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0)));
+      if(getCertName == oldCertName)
+        update = false;
+    }
+  sqlite3_finalize (stmt);  
+  
+  if(insert)
+    {
+      sqlite3_prepare_v2 (m_db, "INSERT INTO CollectEndorse (endorser, endorsee, endorse_name, endorse_data) VALUES (?, ?, ?, ?)", -1, &stmt, 0);
+      sqlite3_bind_text(stmt, 1, endorserName.toUri().c_str(), endorserName.toUri().size(), SQLITE_TRANSIENT);
+      sqlite3_bind_text(stmt, 2, endorseeName.toUri().c_str(), endorseeName.toUri().size(), SQLITE_TRANSIENT);
+      sqlite3_bind_text(stmt, 3, getCertName.toUri().c_str(), getCertName.toUri().size(), SQLITE_TRANSIENT);
+      Ptr<Blob> blob = endorseCertificate.encodeToWire();
+      sqlite3_bind_text(stmt, 4, blob->buf(), blob->size(), SQLITE_TRANSIENT);
+      int res = sqlite3_step (stmt);
+      // if(res != SQLITE_OK)
+      //   _LOG_DEBUG("Insert CollectEndorse Failure: " << getCertName.toUri());
+      sqlite3_finalize (stmt); 
+      return;
+    }
+  if(update)
+    {
+      sqlite3_prepare_v2 (m_db, "UPDATE CollectEndorse SET endorse_name=?, endorse_data=? WHERE endorser=? AND endorsee=?", -1, &stmt, 0);
+      sqlite3_bind_text(stmt, 1, getCertName.toUri().c_str(), getCertName.toUri().size(), SQLITE_TRANSIENT);
+      Ptr<Blob> blob = endorseCertificate.encodeToWire();
+      sqlite3_bind_text(stmt, 2, blob->buf(), blob->size(), SQLITE_TRANSIENT);
+      sqlite3_bind_text(stmt, 3, endorserName.toUri().c_str(), endorserName.toUri().size(), SQLITE_TRANSIENT);
+      sqlite3_bind_text(stmt, 4, endorseeName.toUri().c_str(), endorseeName.toUri().size(), SQLITE_TRANSIENT);
+      int res = sqlite3_step (stmt);
+      // if(res != SQLITE_OK)
+      //   _LOG_DEBUG("Insert CollectEndorse Failure: " << getCertName.toUri());
+      sqlite3_finalize (stmt); 
+      return;
+    }
+}
+
+Ptr<vector<Blob> >
+ContactStorage::getCollectEndorseList(const Name& name)
+{
+  Ptr<vector<Blob> > collectEndorseList = Ptr<vector<Blob> >::Create();
+
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "SELECT endorse_data FROM CollectEndorse WHERE endorsee=?", -1, &stmt, 0);
+  sqlite3_bind_text(stmt, 1, name.toUri().c_str(), name.toUri().size(), SQLITE_TRANSIENT);
+
+  while(sqlite3_step (stmt) == SQLITE_ROW)
+    {
+      Blob blob(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
+      collectEndorseList->push_back(blob);
+    }
+
+  return collectEndorseList;
 }
diff --git a/src/contact-storage.h b/src/contact-storage.h
index 882dff5..ee5f032 100644
--- a/src/contact-storage.h
+++ b/src/contact-storage.h
@@ -36,6 +36,9 @@
   void
   addContact(const ContactItem& contactItem);
 
+  void
+  updateIsIntroducer(const ndn::Name& identity, bool isIntroducer);
+
   void 
   updateAlias(const ndn::Name& identity, std::string alias);
 
@@ -48,6 +51,8 @@
   ndn::Ptr<Profile>
   getSelfProfile(const ndn::Name& identity) const;
 
+
+  //SelfEndorse
   ndn::Ptr<ndn::Blob>
   getSelfEndorseCertificate(const ndn::Name& identity);
 
@@ -56,7 +61,30 @@
 
   void
   addSelfEndorseCertificate(ndn::Ptr<EndorseCertificate> endorseCertificate, const ndn::Name& identity);
+
+
+  //ProfileEndorse
+  ndn::Ptr<ndn::Blob>
+  getEndorseCertificate(const ndn::Name& identity);
+
+  void
+  updateEndorseCertificate(ndn::Ptr<EndorseCertificate> endorseCertificate, const ndn::Name& identity);
+
+  void
+  addEndorseCertificate(ndn::Ptr<EndorseCertificate> endorseCertificate, const ndn::Name& identity);
+
+  std::vector<std::string>
+  getEndorseList(const ndn::Name& identity);
+
   
+  //CollectEndorse
+  void
+  updateCollectEndorse(const EndorseCertificate& endorseCertificate);
+
+  ndn::Ptr<std::vector<ndn::Blob> >
+  getCollectEndorseList(const ndn::Name& name);
+  
+
 private:
   bool
   doesSelfEntryExist(const ndn::Name& identity, const std::string& profileType);
diff --git a/src/contactpanel.cpp b/src/contactpanel.cpp
index cc44a37..b22f460 100644
--- a/src/contactpanel.cpp
+++ b/src/contactpanel.cpp
@@ -16,6 +16,9 @@
 #include <QItemSelectionModel>
 #include <QModelIndex>
 #include <QDir>
+#include <QtSql/QSqlRecord>
+#include <QtSql/QSqlField>
+#include <QtSql/QSqlError>
 
 #ifndef Q_MOC_RUN
 #include <ndn.cxx/security/keychain.h>
@@ -71,6 +74,7 @@
   m_defaultIdentity = m_keychain->getDefaultIdentity();
   m_settingDialog->setIdentity(m_defaultIdentity.toUri());
   setInvitationListener();
+  collectEndorsement();
   
   ui->ContactList->setModel(m_contactListModel);
   
@@ -113,6 +117,18 @@
 
   connect(ui->isIntroducer, SIGNAL(stateChanged(int)),
           this, SLOT(isIntroducerChanged(int)));
+
+  connect(ui->addScope, SIGNAL(clicked()),
+          this, SLOT(addScopeClicked()));
+
+  connect(ui->deleteScope, SIGNAL(clicked()),
+          this, SLOT(deleteScopeClicked()));
+
+  connect(ui->saveButton, SIGNAL(clicked()),
+          this, SLOT(saveScopeClicked()));
+
+  connect(ui->endorseButton, SIGNAL(clicked()),
+          this, SLOT(endorseButtonClicked()));
 }
 
 ContactPanel::~ContactPanel()
@@ -121,8 +137,8 @@
   delete m_contactListModel;
   delete m_profileEditor;
   delete m_addContactPanel;
-  if(NULL != m_currentContactTrustScopeListModel)
-    delete m_currentContactTrustScopeListModel;
+  delete m_trustScopeModel;
+  delete m_endorseDataModel;
 
   delete m_menuInvite;
 
@@ -140,6 +156,10 @@
   db.setDatabaseName(path);
   bool ok = db.open();
   _LOG_DEBUG("db opened: " << std::boolalpha << ok );
+
+  m_trustScopeModel = new QSqlTableModel;
+  m_endorseDataModel = new QSqlTableModel;
+  m_endorseComboBoxDelegate = new EndorseComboBoxDelegate;
 }
 
 void 
@@ -204,6 +224,72 @@
 {}
 
 void
+ContactPanel::collectEndorsement()
+{
+  m_collectStatus = Ptr<vector<bool> >::Create();
+  m_collectStatus->assign(m_contactList.size(), false);
+  vector<Ptr<ContactItem> >::iterator it = m_contactList.begin();
+  int count = 0;
+  for(; it != m_contactList.end(); it++, count++)
+    {
+      Name interestName = (*it)->getNameSpace();
+      interestName.append("DNS").append(m_defaultIdentity).append("ENDORSEE");
+      Ptr<Interest> interest = Ptr<Interest>(new Interest(interestName));
+      interest->setChildSelector(Interest::CHILD_RIGHT);
+  
+      Ptr<Closure> closure = Ptr<Closure>(new Closure(boost::bind(&ContactPanel::onDnsEndoreeVerified, 
+                                                                  this,
+                                                                  _1,
+                                                                  count),
+                                                      boost::bind(&ContactPanel::onDnsEndoreeTimeout,
+                                                                  this,
+                                                                  _1, 
+                                                                  _2,
+                                                                  count),
+                                                      boost::bind(&ContactPanel::onDnsEndoreeUnverified,
+                                                                  this,
+                                                                  _1,
+                                                                  count)));
+
+      m_handler->sendInterest(interest, closure);
+    }
+}
+
+void
+ContactPanel::onDnsEndoreeVerified(Ptr<Data> data, int count)
+{
+  Ptr<Blob> contentBlob = Ptr<Blob>(new Blob(data->content().buf(), data->content().size()));
+  Ptr<Data> endorseData = Data::decodeFromWire(contentBlob);
+  EndorseCertificate endorseCertificate(*endorseData);
+
+  _LOG_DEBUG("get data: " << endorseCertificate.getName().toUri());
+
+  m_contactManager->getContactStorage()->updateCollectEndorse(endorseCertificate);
+
+  updateCollectStatus(count);
+}
+
+void
+ContactPanel::onDnsEndoreeTimeout(Ptr<Closure> closure, Ptr<Interest> interest, int count)
+{ updateCollectStatus(count); }
+
+void
+ContactPanel::onDnsEndoreeUnverified(Ptr<Data> data, int count)
+{ updateCollectStatus(count); }
+
+void 
+ContactPanel::updateCollectStatus(int count)
+{
+  m_collectStatus->at(count) = true;
+  vector<bool>::const_iterator it = m_collectStatus->begin();
+  for(; it != m_collectStatus->end(); it++)
+    if(*it == false)
+      return;
+
+  m_contactManager->publishEndorsedDataInDns(m_defaultIdentity);
+}
+
+void
 ContactPanel::onInvitationCertVerified(Ptr<Data> data, 
                                        Ptr<ChronosInvitation> invitation)
 {
@@ -322,16 +408,72 @@
     {
       ui->isIntroducer->setChecked(true);
       ui->addScope->setEnabled(true);
-      ui->deleteScope->setEnabled(true);
-      m_currentContactTrustScopeListModel = new QStringListModel;
+      ui->deleteScope->setEnabled(true);     
+      ui->trustScopeList->setEnabled(true);
+
+      string filter("contact_namespace = '");
+      filter.append(m_currentSelectedContact->getNameSpace().toUri()).append("'");
+
+      m_trustScopeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
+      m_trustScopeModel->setTable("TrustScope");
+      m_trustScopeModel->setFilter(filter.c_str());
+      m_trustScopeModel->select();
+      m_trustScopeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
+      m_trustScopeModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Contact"));
+      m_trustScopeModel->setHeaderData(2, Qt::Horizontal, QObject::tr("TrustScope"));
+
+      // _LOG_DEBUG("row count: " << m_trustScopeModel->rowCount());
+
+      ui->trustScopeList->setModel(m_trustScopeModel);
+      ui->trustScopeList->setColumnHidden(0, true);
+      ui->trustScopeList->setColumnHidden(1, true);
+      ui->trustScopeList->show();
     }
   else
     {
       ui->isIntroducer->setChecked(false);
       ui->addScope->setEnabled(false);
       ui->deleteScope->setEnabled(false);
-      delete m_currentContactTrustScopeListModel;
+
+      string filter("contact_namespace = '");
+      filter.append(m_currentSelectedContact->getNameSpace().toUri()).append("'");
+
+      m_trustScopeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
+      m_trustScopeModel->setTable("TrustScope");
+      m_trustScopeModel->setFilter(filter.c_str());
+      m_trustScopeModel->select();
+      m_trustScopeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
+      m_trustScopeModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Contact"));
+      m_trustScopeModel->setHeaderData(2, Qt::Horizontal, QObject::tr("TrustScope"));
+
+      ui->trustScopeList->setModel(m_trustScopeModel);
+      ui->trustScopeList->setColumnHidden(0, true);
+      ui->trustScopeList->setColumnHidden(1, true);
+      ui->trustScopeList->show();
+
+      ui->trustScopeList->setEnabled(false);
     }
+
+  string filter("profile_identity = '");
+  filter.append(m_currentSelectedContact->getNameSpace().toUri()).append("'");
+
+  m_endorseDataModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
+  m_endorseDataModel->setTable("ContactProfile");
+  m_endorseDataModel->setFilter(filter.c_str());
+  m_endorseDataModel->select();
+  
+  m_endorseDataModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Identity"));
+  m_endorseDataModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Type"));
+  m_endorseDataModel->setHeaderData(2, Qt::Horizontal, QObject::tr("Value"));
+  m_endorseDataModel->setHeaderData(3, Qt::Horizontal, QObject::tr("Endorse"));
+
+  ui->endorseList->setModel(m_endorseDataModel);
+  ui->endorseList->setColumnHidden(0, true);
+  ui->endorseList->resizeColumnToContents(1);
+  ui->endorseList->resizeColumnToContents(2);
+  ui->endorseList->setItemDelegateForColumn(3, m_endorseComboBoxDelegate);
+  ui->endorseList->show();
+
 }
 
 void
@@ -349,6 +491,8 @@
                                            this,
                                            _1));
   m_inviteListenPrefix = prefix;
+
+  collectEndorsement();
 }
 
 void
@@ -486,12 +630,93 @@
     {
       ui->addScope->setEnabled(true);
       ui->deleteScope->setEnabled(true);
+      ui->trustScopeList->setEnabled(true);
+      
+      string filter("contact_namespace = '");
+      filter.append(m_currentSelectedContact->getNameSpace().toUri()).append("'");
+      _LOG_DEBUG("filter: " << filter);
+
+      m_trustScopeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
+      m_trustScopeModel->setTable("TrustScope");
+      m_trustScopeModel->setFilter(filter.c_str());
+      m_trustScopeModel->select();
+      m_trustScopeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
+      m_trustScopeModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Contact"));
+      m_trustScopeModel->setHeaderData(2, Qt::Horizontal, QObject::tr("TrustScope"));
+      _LOG_DEBUG("row count: " << m_trustScopeModel->rowCount());
+
+
+      ui->trustScopeList->setModel(m_trustScopeModel);
+      ui->trustScopeList->setColumnHidden(0, true);
+      ui->trustScopeList->setColumnHidden(1, true);
+      ui->trustScopeList->show();
+
+      m_currentSelectedContact->setIsIntroducer(true);
     }
   else
     {
       ui->addScope->setEnabled(false);
       ui->deleteScope->setEnabled(false);
+
+      string filter("contact_namespace = '");
+      filter.append(m_currentSelectedContact->getNameSpace().toUri()).append("'");
+
+      m_trustScopeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
+      m_trustScopeModel->setTable("TrustScope");
+      m_trustScopeModel->setFilter(filter.c_str());
+      m_trustScopeModel->select();
+      m_trustScopeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
+      m_trustScopeModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Contact"));
+      m_trustScopeModel->setHeaderData(2, Qt::Horizontal, QObject::tr("TrustScope"));
+
+      ui->trustScopeList->setModel(m_trustScopeModel);
+      ui->trustScopeList->setColumnHidden(0, true);
+      ui->trustScopeList->setColumnHidden(1, true);
+      ui->trustScopeList->show();
+
+      ui->trustScopeList->setEnabled(false);
+
+      m_currentSelectedContact->setIsIntroducer(false);
     }
+  m_contactManager->getContactStorage()->updateIsIntroducer(m_currentSelectedContact->getNameSpace(), m_currentSelectedContact->isIntroducer());
+}
+
+void
+ContactPanel::addScopeClicked()
+{
+  int rowCount = m_trustScopeModel->rowCount();
+  QSqlRecord record;
+  QSqlField identityField("contact_namespace", QVariant::String);
+  record.append(identityField);
+  record.setValue("contact_namespace", QString(m_currentSelectedContact->getNameSpace().toUri().c_str()));
+  m_trustScopeModel->insertRow(rowCount);
+  m_trustScopeModel->setRecord(rowCount, record);
+}
+
+void
+ContactPanel::deleteScopeClicked()
+{
+  QItemSelectionModel* selectionModel = ui->trustScopeList->selectionModel();
+  QModelIndexList indexList = selectionModel->selectedIndexes();
+
+  int i = indexList.size() - 1;  
+  for(; i >= 0; i--)
+    m_trustScopeModel->removeRow(indexList[i].row());
+    
+  m_trustScopeModel->submitAll();
+}
+
+void
+ContactPanel::saveScopeClicked()
+{
+  m_trustScopeModel->submitAll();
+}
+
+void
+ContactPanel::endorseButtonClicked()
+{
+  m_endorseDataModel->submitAll();
+  m_contactManager->updateEndorseCertificate(m_currentSelectedContact->getNameSpace(), m_defaultIdentity);
 }
 
 #if WAF
diff --git a/src/contactpanel.h b/src/contactpanel.h
index bbe7c52..222bf0b 100644
--- a/src/contactpanel.h
+++ b/src/contactpanel.h
@@ -23,6 +23,7 @@
 #include "invitationdialog.h"
 #include "settingdialog.h"
 #include "chatdialog.h"
+#include "endorse-combobox-delegate.h"
 
 #ifndef Q_MOC_RUN
 #include "contact-manager.h"
@@ -76,6 +77,23 @@
   onInvitationCertVerified(ndn::Ptr<ndn::Data> data,
                            ndn::Ptr<ChronosInvitation> invitation);
 
+  void
+  collectEndorsement();
+
+  void
+  onDnsEndoreeVerified(ndn::Ptr<ndn::Data> data, int count);
+
+  void
+  onDnsEndoreeTimeout(ndn::Ptr<ndn::Closure> closure, 
+                      ndn::Ptr<ndn::Interest> interest, 
+                      int count);
+  
+  void
+  onDnsEndoreeUnverified(ndn::Ptr<ndn::Data> data, int count);
+
+  void 
+  updateCollectStatus(int count);
+
   std::string
   getRandomString();
 
@@ -137,6 +155,20 @@
   void
   isIntroducerChanged(int state);
 
+  void
+  addScopeClicked();
+
+  void
+  deleteScopeClicked();
+
+  void
+  saveScopeClicked();
+
+  void
+  endorseButtonClicked();
+
+  
+
 private:
   Ui::ContactPanel *ui;
   ndn::Ptr<ContactManager> m_contactManager;
@@ -151,6 +183,7 @@
   QAction* m_menuInvite;
   QAction* m_menuAlias;
   std::vector<ndn::Ptr<ContactItem> > m_contactList;
+  ndn::Ptr<std::vector<bool> > m_collectStatus;
 
   ndn::Ptr<PanelPolicyManager> m_panelPolicyManager;
   ndn::Ptr<ndn::security::Keychain> m_keychain;
@@ -163,7 +196,9 @@
   // std::string m_currentSelectedContactAlias;
   // std::string m_currentSelectedContactNamespace;
   ndn::Ptr<ContactItem> m_currentSelectedContact;
-  QStringListModel* m_currentContactTrustScopeListModel;
+  QSqlTableModel* m_trustScopeModel;
+  QSqlTableModel* m_endorseDataModel;
+  EndorseComboBoxDelegate* m_endorseComboBoxDelegate;
 
 
 };
diff --git a/src/contactpanel.ui b/src/contactpanel.ui
index 08c15a3..44e4250 100644
--- a/src/contactpanel.ui
+++ b/src/contactpanel.ui
@@ -184,7 +184,7 @@
            <rect>
             <x>20</x>
             <y>10</y>
-            <width>351</width>
+            <width>362</width>
             <height>371</height>
            </rect>
           </property>
@@ -197,7 +197,11 @@
             </widget>
            </item>
            <item>
-            <widget class="QListView" name="trustScopeList"/>
+            <widget class="QTableView" name="trustScopeList">
+             <attribute name="horizontalHeaderStretchLastSection">
+              <bool>true</bool>
+             </attribute>
+            </widget>
            </item>
            <item>
             <layout class="QHBoxLayout" name="horizontalLayout_4">
@@ -221,6 +225,16 @@
                </property>
               </widget>
              </item>
+             <item>
+              <widget class="QPushButton" name="saveButton">
+               <property name="text">
+                <string>Save</string>
+               </property>
+               <property name="autoDefault">
+                <bool>false</bool>
+               </property>
+              </widget>
+             </item>
             </layout>
            </item>
           </layout>
@@ -230,7 +244,7 @@
          <attribute name="title">
           <string>Endorse</string>
          </attribute>
-         <widget class="QTableWidget" name="endorseList">
+         <widget class="QTableView" name="endorseList">
           <property name="geometry">
            <rect>
             <x>20</x>
@@ -239,6 +253,9 @@
             <height>331</height>
            </rect>
           </property>
+          <attribute name="horizontalHeaderStretchLastSection">
+           <bool>true</bool>
+          </attribute>
          </widget>
          <widget class="QPushButton" name="endorseButton">
           <property name="geometry">
@@ -252,6 +269,9 @@
           <property name="text">
            <string>Endorse</string>
           </property>
+          <property name="autoDefault">
+           <bool>false</bool>
+          </property>
          </widget>
         </widget>
        </widget>
@@ -268,6 +288,9 @@
         <property name="text">
          <string>Add Contact</string>
         </property>
+        <property name="autoDefault">
+         <bool>false</bool>
+        </property>
        </widget>
       </item>
       <item>
@@ -275,6 +298,9 @@
         <property name="text">
          <string>Setting</string>
         </property>
+        <property name="autoDefault">
+         <bool>false</bool>
+        </property>
        </widget>
       </item>
       <item>
@@ -282,6 +308,9 @@
         <property name="text">
          <string>Edit Profile</string>
         </property>
+        <property name="autoDefault">
+         <bool>false</bool>
+        </property>
        </widget>
       </item>
      </layout>
diff --git a/src/dns-storage.cpp b/src/dns-storage.cpp
index 13a8f25..70d04fe 100644
--- a/src/dns-storage.cpp
+++ b/src/dns-storage.cpp
@@ -122,18 +122,18 @@
 {
   string dnsIdentity = identity.toUri();
   string dnsName = endorsee.toUri();
-  string dnsType("ENORSEE");
+  string dnsType("ENDORSEE");
   Ptr<Blob> dnsValue = data.encodeToWire();
 
   updateDnsData(*dnsValue, dnsIdentity, dnsName, dnsType, data.getName().toUri());
 }
   
 void
-DnsStorage::updateDnsOthersEndorse(const Data& data, const Name& identity, const Name& endorser)
+DnsStorage::updateDnsOthersEndorse(const Data& data, const Name& identity)
 {
   string dnsIdentity = identity.toUri();
-  string dnsName = endorser.toUri();
-  string dnsType("ENORSER");
+  string dnsName("N/A");
+  string dnsType("ENDORSED");
   Ptr<Blob> dnsValue = data.encodeToWire();
 
   updateDnsData(*dnsValue, dnsIdentity, dnsName, dnsType, data.getName().toUri());
diff --git a/src/dns-storage.h b/src/dns-storage.h
index 0e4ccf4..f6c19ce 100644
--- a/src/dns-storage.h
+++ b/src/dns-storage.h
@@ -28,7 +28,7 @@
   updateDnsEndorseOthers(const ndn::Data& data, const ndn::Name& identity, const ndn::Name& endorsee);
   
   void
-  updateDnsOthersEndorse(const ndn::Data& data, const ndn::Name& identity, const ndn::Name& endorser);
+  updateDnsOthersEndorse(const ndn::Data& data, const ndn::Name& identity);
 
   ndn::Ptr<ndn::Data>
   getData(const ndn::Name& name);
diff --git a/src/endorse-certificate.cpp b/src/endorse-certificate.cpp
index 8dd43e0..20e2aff 100644
--- a/src/endorse-certificate.cpp
+++ b/src/endorse-certificate.cpp
@@ -97,9 +97,36 @@
   return blobStream.buf ();
 }
 
+// EndorseCertificate::EndorseCertificate(const IdentityCertificate& kskCertificate)
+//   : Certificate()
+//   , m_keyName(kskCertificate.getPublicKeyName())
+//   , m_signer(kskCertificate.getPublicKeyName())
+// {
+//   Profile profile(m_keyName.getPrefix(m_keyName.size()-1), 
+//                   m_keyName.get(-2).toUri(),
+//                   m_keyName.get(m_keyName.size()-2).toUri());
+  
+//   Ptr<ProfileData> profileData = Ptr<ProfileData>(new ProfileData(m_keyName.getPrefix(m_keyName.size()-1),
+//                                                                   profile));
+
+//   m_profileData = profileData;
+
+//   Name dataName = m_keyName;
+//   dataName.append("PROFILE-CERT").append(m_signer).appendVersion();
+//   setName(dataName);
+
+//   setNotBefore(kskCertificate.getNotBefore());
+//   setNotAfter(kskCertificate.getNotAfter());
+//   addSubjectDescription(CertificateSubDescrypt("2.5.4.41", m_keyName.toUri()));
+//   setPublicKeyInfo(kskCertificate.getPublicKeyInfo());  
+//   addExtension(ProfileExtension(*m_profileData));
+//   addExtension(EndorseExtension(m_endorseList));
+  
+//   encode();
+// }
+
+
 EndorseCertificate::EndorseCertificate(const IdentityCertificate& kskCertificate,
-                                       const Time& notBefore,
-                                       const Time& notAfter,
                                        Ptr<ProfileData> profileData,
                                        const vector<string>& endorseList)
   : Certificate()
@@ -109,14 +136,11 @@
   , m_endorseList(endorseList)
 {
   Name dataName = m_keyName;
-  TimeInterval ti = time::NowUnixTimestamp();
-  ostringstream oss;
-  oss << ti.total_seconds();
-  dataName.append("PROFILE-CERT").append(m_signer).append(oss.str());
+  dataName.append("PROFILE-CERT").append(m_signer).appendVersion();
   setName(dataName);
 
-  setNotBefore(notBefore);
-  setNotAfter(notAfter);
+  setNotBefore(kskCertificate.getNotBefore());
+  setNotAfter(kskCertificate.getNotAfter());
   addSubjectDescription(CertificateSubDescrypt("2.5.4.41", m_keyName.toUri()));
   setPublicKeyInfo(kskCertificate.getPublicKeyInfo());  
   addExtension(ProfileExtension(*m_profileData));
@@ -127,8 +151,6 @@
 
 EndorseCertificate::EndorseCertificate(const EndorseCertificate& endorseCertificate,
                                        const Name& signer,
-                                       const Time& notBefore,
-                                       const Time& notAfter,
                                        const vector<string>& endorseList)
   : Certificate()
   , m_keyName(endorseCertificate.m_keyName)
@@ -137,14 +159,11 @@
   , m_endorseList(endorseList)
 {
   Name dataName = m_keyName;
-  TimeInterval ti = time::NowUnixTimestamp();
-  ostringstream oss;
-  oss << ti.total_seconds();
-  dataName.append("PROFILE-CERT").append(m_signer).append(oss.str());
+  dataName.append("PROFILE-CERT").append(m_signer).appendVersion();
   setName(dataName);
   
-  setNotBefore(notBefore);
-  setNotAfter(notAfter);
+  setNotBefore(endorseCertificate.getNotBefore());
+  setNotAfter(endorseCertificate.getNotAfter());
   addSubjectDescription(CertificateSubDescrypt("2.5.4.41", m_keyName.toUri()));
   setPublicKeyInfo(endorseCertificate.getPublicKeyInfo());
   addExtension(ProfileExtension(*m_profileData));
diff --git a/src/endorse-certificate.h b/src/endorse-certificate.h
index 3b992c4..1b9b897 100644
--- a/src/endorse-certificate.h
+++ b/src/endorse-certificate.h
@@ -57,16 +57,14 @@
 public:
   EndorseCertificate() {}
 
+  // EndorseCertificate(const ndn::security::IdentityCertificate& kskCertificate);
+
   EndorseCertificate(const ndn::security::IdentityCertificate& kskCertificate,
-                     const ndn::Time& notBefore,
-                     const ndn::Time& notAfter,
                      ndn::Ptr<ProfileData> profileData,
-                     const std::vector<std::string>& endorseList);
+                     const std::vector<std::string>& endorseList = std::vector<std::string>());
 
   EndorseCertificate(const EndorseCertificate& endorseCertificate,
                      const ndn::Name& signer,
-                     const ndn::Time& notBefore,
-                     const ndn::Time& notAfter,
                      const std::vector<std::string>& endorseList);
 
   EndorseCertificate(const EndorseCertificate& endorseCertificate);
diff --git a/src/endorse-combobox-delegate.cpp b/src/endorse-combobox-delegate.cpp
new file mode 100644
index 0000000..e909e3d
--- /dev/null
+++ b/src/endorse-combobox-delegate.cpp
@@ -0,0 +1,83 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "endorse-combobox-delegate.h"
+
+#include <QComboBox>
+#include <QApplication>
+
+#ifndef Q_MOC_RUN
+#include "logging.h"
+#include "exception.h"
+#endif
+
+INIT_LOGGER("EndorseComboBoxDelegate");
+
+EndorseComboBoxDelegate::EndorseComboBoxDelegate(QObject *parent)
+ : QItemDelegate(parent)
+{
+  m_items.push_back("Not Endorsed");
+  m_items.push_back("Endorsed");
+}
+ 
+ 
+QWidget*
+EndorseComboBoxDelegate::createEditor(QWidget *parent, 
+			       const QStyleOptionViewItem &/* option */, 
+			       const QModelIndex &/* index */) const
+{
+  QComboBox* editor = new QComboBox(parent);
+  for(unsigned int i = 0; i < m_items.size(); ++i)
+      editor->addItem(m_items[i].c_str());
+  return editor;
+}
+ 
+void 
+EndorseComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+  QComboBox *comboBox = static_cast<QComboBox*>(editor);
+  int value = index.model()->data(index, Qt::EditRole).toUInt();
+  _LOG_DEBUG("value: " << value);
+  comboBox->setCurrentIndex(value);
+}
+ 
+void 
+EndorseComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+  QComboBox *comboBox = static_cast<QComboBox*>(editor);
+  _LOG_DEBUG("currentIndex: " << comboBox->currentIndex());
+  model->setData(index, comboBox->currentIndex(), Qt::EditRole);
+}
+ 
+void 
+EndorseComboBoxDelegate::updateEditorGeometry(QWidget *editor, 
+				       const QStyleOptionViewItem &option, 
+				       const QModelIndex &/* index */) const
+{
+  editor->setGeometry(option.rect);
+}
+ 
+void 
+EndorseComboBoxDelegate::paint(QPainter *painter, 
+			       const QStyleOptionViewItem &option, 
+			       const QModelIndex &index) const
+{
+  QStyleOptionViewItemV4 myOption = option;
+  QString text = m_items[index.model()->data(index, Qt::EditRole).toUInt()].c_str();
+ 
+  myOption.text = text;
+ 
+  QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &myOption, painter);
+}
+
+#if WAF
+#include "endorse-combobox-delegate.moc"
+#include "endorse-combobox-delegate.cpp.moc"
+#endif
diff --git a/src/endorse-combobox-delegate.h b/src/endorse-combobox-delegate.h
new file mode 100644
index 0000000..d0822b3
--- /dev/null
+++ b/src/endorse-combobox-delegate.h
@@ -0,0 +1,47 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef LINKNDN_ENDORSE_COMBOBOX_DELEGATE_H
+#define LINKNDN_ENDORSE_COMBOBOX_DELEGATE_H
+
+#include <QItemDelegate>
+#include <string>
+#include <vector>
+ 
+class EndorseComboBoxDelegate : public QItemDelegate
+{
+  Q_OBJECT
+public:
+  EndorseComboBoxDelegate(QObject *parent = 0);
+
+  // virtual
+  // ~ComboBoxDelegate() {}
+ 
+  QWidget*
+  createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+  void 
+  setEditorData(QWidget *editor, const QModelIndex &index) const;
+  
+  void 
+  setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
+  
+  void
+  updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+  
+  void
+  paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ 
+private:
+  std::vector<std::string> m_items;
+ 
+};
+
+#endif
diff --git a/src/panel-policy-manager.cpp b/src/panel-policy-manager.cpp
index 33717d5..1bbd849 100644
--- a/src/panel-policy-manager.cpp
+++ b/src/panel-policy-manager.cpp
@@ -38,6 +38,11 @@
   m_dskRule = Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<KEY>]*)<KEY><dsk-.*><ID-CERT><>$", 
 							     "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$", 
 							     "==", "\\1", "\\1\\2", true));
+  
+  m_endorseeRule = Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<DNS>]*)<DNS><>*<ENDORSEE><>$", 
+                                                                  "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$", 
+                                                                  "==", "\\1", "\\1\\2", true));
+  
   m_kskRegex = Ptr<Regex>(new Regex("^([^<KEY>]*)<KEY>(<>*<ksk-.*>)<ID-CERT><>$", "\\1\\2"));
 
   m_keyNameRegex = Ptr<Regex>(new Regex("^([^<KEY>]*)<KEY>(<>*<ksk-.*>)<ID-CERT>$", "\\1\\2"));
@@ -59,12 +64,15 @@
 {
   // if(m_invitationDataRule->matchDataName(data))
   //   return true;
-
   if(m_kskRegex->match(data.getName()))
      return true;
   if(m_dskRule->matchDataName(data))
     return true;
 
+  if(m_endorseeRule->matchDataName(data))
+    return true;
+
+
   return false;
 }
 
@@ -131,6 +139,25 @@
 
       return NULL;	
     }
+
+  _LOG_DEBUG("KEY Locator: " << keyLocatorName.toUri());
+  if(m_endorseeRule->satisfy(*data))
+    {
+      m_keyNameRegex->match(keyLocatorName);
+      Name keyName = m_keyNameRegex->expand();
+      _LOG_DEBUG("data name: " << data->getName());
+      _LOG_DEBUG("keyName: " << keyName.toUri());
+      if(m_trustAnchors.end() != m_trustAnchors.find(keyName))
+        if(verifySignature(*data, m_trustAnchors[keyName]))
+          verifiedCallback(data);
+        else
+          unverifiedCallback(data);
+      else
+        unverifiedCallback(data);
+
+      return NULL;
+    }
+
   _LOG_DEBUG("Unverified!");
 
   unverifiedCallback(data);
diff --git a/src/panel-policy-manager.h b/src/panel-policy-manager.h
index 7ac8b10..640c184 100644
--- a/src/panel-policy-manager.h
+++ b/src/panel-policy-manager.h
@@ -98,6 +98,7 @@
   ndn::Ptr<ndn::security::IdentityPolicyRule> m_invitationDataSigningRule;
   ndn::Ptr<ndn::Regex> m_kskRegex;
   ndn::Ptr<ndn::security::IdentityPolicyRule> m_dskRule;
+  ndn::Ptr<ndn::security::IdentityPolicyRule> m_endorseeRule;
   ndn::Ptr<ndn::Regex> m_keyNameRegex;
   ndn::Ptr<ndn::Regex> m_signingCertificateRegex;
   std::map<ndn::Name, ndn::security::Publickey> m_trustAnchors;
diff --git a/src/profileeditor.cpp b/src/profileeditor.cpp
index db00a6f..d3d2608 100644
--- a/src/profileeditor.cpp
+++ b/src/profileeditor.cpp
@@ -70,7 +70,7 @@
 ProfileEditor::onDeleteClicked()
 {
   QItemSelectionModel* selectionModel = ui->profileTable->selectionModel();
-  QModelIndexList indexList = selectionModel->selectedRows();
+  QModelIndexList indexList = selectionModel->selectedIndexes();
 
   int i = indexList.size() - 1;  
   for(; i >= 0; i--)
diff --git a/waf-tools/cryptopp.py b/waf-tools/cryptopp.py
new file mode 100644
index 0000000..b61c0bf
--- /dev/null
+++ b/waf-tools/cryptopp.py
@@ -0,0 +1,77 @@
+#! /usr/bin/env python
+# encoding: utf-8
+
+'''
+
+When using this tool, the wscript will look like:
+
+	def options(opt):
+	        opt.tool_options('cryptopp', tooldir=["waf-tools"])
+
+	def configure(conf):
+		conf.load('compiler_cxx cryptopp')
+
+	def build(bld):
+		bld(source='main.cpp', target='app', use='CRYPTOPP')
+
+Options are generated, in order to specify the location of cryptopp includes/libraries.
+
+
+'''
+import sys
+import re
+from waflib import Utils,Logs,Errors
+from waflib.Configure import conf
+CRYPTOPP_DIR=['/usr','/usr/local','/opt/local','/sw']
+CRYPTOPP_VERSION_FILE='config.h'
+CRYPTOPP_VERSION_CODE='''
+#include <iostream>
+#include <cryptopp/config.h>
+int main() { std::cout << CRYPTOPP_VERSION; }
+'''
+
+def options(opt):
+	opt.add_option('--cryptopp',type='string',default='',dest='cryptopp_dir',help='''path to where cryptopp is installed, e.g. /opt/local''')
+@conf
+def __cryptopp_get_version_file(self,dir):
+	try:
+		return self.root.find_dir(dir).find_node('%s/%s' % ('include/cryptopp', CRYPTOPP_VERSION_FILE))
+	except:
+		return None
+@conf
+def cryptopp_get_version(self,dir):
+	val=self.check_cxx(fragment=CRYPTOPP_VERSION_CODE,includes=['%s/%s' % (dir, 'include')], execute=True, define_ret = True, mandatory=True)
+	return val
+@conf
+def cryptopp_get_root(self,*k,**kw):
+	root=k and k[0]or kw.get('path',None)
+	# Logs.pprint ('RED', '   %s' %root)
+	if root and self.__cryptopp_get_version_file(root):
+		return root
+	for dir in CRYPTOPP_DIR:
+		if self.__cryptopp_get_version_file(dir):
+			return dir
+	if root:
+		self.fatal('CryptoPP not found in %s'%root)
+	else:
+		self.fatal('CryptoPP not found, please provide a --cryptopp argument (see help)')
+@conf
+def check_cryptopp(self,*k,**kw):
+	if not self.env['CXX']:
+		self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')
+
+	var=kw.get('uselib_store','CRYPTOPP')
+	self.start_msg('Checking CRYPTOPP')
+	root = self.cryptopp_get_root(*k,**kw)
+	self.env.CRYPTOPP_VERSION=self.cryptopp_get_version(root)
+
+	self.env['INCLUDES_%s'%var]= '%s/%s' % (root, "include")
+	self.env['LIB_%s'%var] = "cryptopp"
+	self.env['LIBPATH_%s'%var] = '%s/%s' % (root, "lib")
+
+	self.end_msg(self.env.CRYPTOPP_VERSION)
+	if Logs.verbose:
+		Logs.pprint('CYAN','	CRYPTOPP include : %s'%self.env['INCLUDES_%s'%var])
+		Logs.pprint('CYAN','	CRYPTOPP lib     : %s'%self.env['LIB_%s'%var])
+		Logs.pprint('CYAN','	CRYPTOPP libpath : %s'%self.env['LIBPATH_%s'%var])
+
diff --git a/wscript b/wscript
index 8834f50..98451fa 100644
--- a/wscript
+++ b/wscript
@@ -8,16 +8,18 @@
     opt.load('compiler_c compiler_cxx boost protoc qt4')
 
     opt.load('tinyxml', tooldir=['waf-tools'])
+    opt.load('cryptopp', tooldir=['waf-tools'])
     
 def configure(conf):
-    conf.load("compiler_c compiler_cxx boost protoc qt4 tinyxml")
+    conf.load("compiler_c compiler_cxx boost protoc qt4 tinyxml cryptopp")
 
-    conf.add_supported_cxxflags (cxxflags = ['-O3', '-g'])
+    conf.add_supported_cxxflags (cxxflags = ['-O0', '-g'])
 
     conf.check_tinyxml(path=conf.options.tinyxml_dir)
     conf.check_cfg(package='libndn.cxx', args=['--cflags', '--libs'], uselib_store='NDNCXX', mandatory=True)
     conf.check_cfg(package='sqlite3', args=['--cflags', '--libs'], uselib_store='SQLITE3', mandatory=True)
     conf.check_cfg(package='liblog4cxx', args=['--cflags', '--libs'], uselib_store='LOG4CXX', mandatory=True)
+    conf.check_cfg (package='ChronoSync', args=['ChronoSync >= 0.1', '--cflags', '--libs'], uselib_store='SYNC', mandatory=True)
     conf.define ("HAVE_LOG4CXX", 1)
 
     conf.check_boost(lib='system random thread filesystem')
@@ -30,9 +32,9 @@
         target = "Contacts",
         features = "qt4 cxx cxxprogram",
         defines = "WAF",
-        source = bld.path.ant_glob(['src/*.cpp', 'src/*.ui', 'logging.cc']),
+        source = bld.path.ant_glob(['src/*.cpp', 'src/*.ui', 'logging.cc', 'src/*.proto']),
         includes = ".",
-        use = "QTCORE QTGUI QTSQL SQLITE3 NDNCXX TINYXML BOOST BOOST_FILESYSTEM LOG4CXX",
+        use = "QTCORE QTGUI QTSQL SQLITE3 NDNCXX TINYXML BOOST BOOST_FILESYSTEM LOG4CXX CRYPTOPP SYNC",
         )
 
     cert_publish = bld (