Add ProfileData
diff --git a/src/endorse-certificate.cpp b/src/endorse-certificate.cpp
index a565ebc..c6d338a 100644
--- a/src/endorse-certificate.cpp
+++ b/src/endorse-certificate.cpp
@@ -10,6 +10,8 @@
 
 #include "endorse-certificate.h"
 #include "exception.h"
+#include <ndn.cxx/helpers/der/der.h>
+#include <ndn.cxx/helpers/der/visitor/simple-visitor.h>
 #include <ndn.cxx/security/certificate/certificate-subdescrpt.h>
 
 
@@ -17,29 +19,143 @@
 using namespace ndn;
 using namespace ndn::security;
 
-EndorseExtension::EndorseExtension(const Blob & value)
-  : CertificateExtension("1.3.6.1.5.32.2", true, value)
+ProfileExtension::ProfileExtension(const ProfileData & profileData)
+  : CertificateExtension("1.3.6.1.5.32.2.1", true, *profileData.encodeToWire())
 {}
 
+ProfileExtension::ProfileExtension(const ProfileExtension& profileExtension)
+  : CertificateExtension("1.3.6.1.5.32.2.1", true, profileExtension.m_extnValue)
+{}
+
+ProfileExtension::ProfileExtension(const CertificateExtension& extension)
+  : CertificateExtension(extension.getOID(), extension.getCritical(), extension.getValue())
+{
+  if(m_extnID != OID("1.3.6.1.5.32.2.1"))
+    throw LnException("Wrong ProfileExtension Number!");
+}
+
+Ptr<ProfileData>
+ProfileExtension::getProfileData()
+{
+  boost::iostreams::stream
+    <boost::iostreams::array_source> is (m_extnValue.buf (), m_extnValue.size ());
+  return Ptr<ProfileData>(new ProfileData(*Data::decodeFromWire(is)));
+}
+
+EndorseExtension::EndorseExtension(const vector<string>& endorsedList)
+  : CertificateExtension("1.3.6.1.5.32.2.2", true, *EndorseExtension::prepareValue(endorsedList))
+{}
+
+EndorseExtension::EndorseExtension(const EndorseExtension& endorseExtension)
+  : CertificateExtension("1.3.6.1.5.32.2.2", true, endorseExtension.m_extnValue)
+{}
+
+EndorseExtension::EndorseExtension(const CertificateExtension& extension)
+  : CertificateExtension(extension.getOID(), extension.getCritical(), extension.getValue())
+{
+  if(m_extnID != OID("1.3.6.1.5.32.2.2"))
+    throw LnException("Wrong EndorseExtension Number!");
+}
+
+vector<string>
+EndorseExtension::getEndorsedList()
+{
+  vector<string> endorsedList;
+
+  boost::iostreams::stream
+    <boost::iostreams::array_source> is (m_extnValue.buf(), m_extnValue.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++)
+      endorsedList.push_back(boost::any_cast<string>(children[i]->accept(simpleVisitor)));
+
+  return endorsedList;
+}
+
+Ptr<Blob>
+EndorseExtension::prepareValue(const vector<string>& endorsedList)
+{
+  Ptr<der::DerSequence> root = Ptr<der::DerSequence>::Create();
+  
+  vector<string>::const_iterator it = endorsedList.begin();
+  for(; it != endorsedList.end(); it++)
+    {
+      Ptr<der::DerPrintableString> entry = Ptr<der::DerPrintableString>(new der::DerPrintableString(*it));
+      root->addChild(entry);
+    }
+  
+  blob_stream blobStream;
+  OutputIterator & start = reinterpret_cast<OutputIterator &> (blobStream);
+  root->encode(start);
+
+  return blobStream.buf ();
+}
+
 EndorseCertificate::EndorseCertificate(const IdentityCertificate& kskCertificate,
-				       const Name& signer,
-				       const Time& notBefore,
-				       const Time& notAfter)
+                                       const Time& notBefore,
+                                       const Time& notAfter,
+                                       Ptr<ProfileData> profileData,
+                                       const vector<string>& endorseList)
   : Certificate()
   , m_keyName(kskCertificate.getPublicKeyName())
-  , m_signer(signer)
+  , m_signer(kskCertificate.getPublicKeyName())
+  , m_profileData(profileData)
+  , 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());
+  setName(dataName);
+
   setNotBefore(notBefore);
   setNotAfter(notAfter);
   addSubjectDescription(CertificateSubDescrypt("2.5.4.41", m_keyName.toUri()));
   setPublicKeyInfo(kskCertificate.getPublicKeyInfo());
+  addExtension(ProfileExtension(*m_profileData));
+  addExtension(EndorseExtension(m_endorseList));
+  
+  encode();
+}
+
+EndorseCertificate::EndorseCertificate(const EndorseCertificate& endorseCertificate,
+                                       const Name& signer,
+                                       const Time& notBefore,
+                                       const Time& notAfter,
+                                       const vector<string>& endorseList)
+  : Certificate()
+  , m_keyName(endorseCertificate.m_keyName)
+  , m_signer(signer)
+  , m_profileData(endorseCertificate.m_profileData)
+  , 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());
+  setName(dataName);
+  
+  setNotBefore(notBefore);
+  setNotAfter(notAfter);
+  addSubjectDescription(CertificateSubDescrypt("2.5.4.41", m_keyName.toUri()));
+  setPublicKeyInfo(endorseCertificate.getPublicKeyInfo());
+  addExtension(ProfileExtension(*m_profileData));
+  addExtension(EndorseExtension(m_endorseList));
+
+  encode();
 }
 
 EndorseCertificate::EndorseCertificate(const EndorseCertificate& endorseCertificate)
   : Certificate(endorseCertificate)
   , m_keyName(endorseCertificate.m_keyName)
   , m_signer(endorseCertificate.m_signer)
-  , m_profileList(endorseCertificate.m_profileList)
+  , m_profileData(endorseCertificate.m_profileData)
+  , m_endorseList(endorseCertificate.m_endorseList)
 {}
 
 EndorseCertificate::EndorseCertificate(const Data& data)
@@ -64,14 +180,21 @@
   m_keyName = dataName.getSubName(0, profileIndex);
   m_signer = dataName.getSubName(profileIndex + 1, dataName.size() - profileIndex - 2);
 
-  OID profileExtenstionOID("1.3.6.1.5.32.2");
+  OID profileExtensionOID("1.3.6.1.5.32.2.1");
+  OID endorseExtensionOID("1.3.6.1.5.32.2.2");
+
   ExtensionList::iterator it = m_extnList.begin();
   for(; it != m_extnList.end(); it++)
     {
-      if(profileExtenstionOID == it->getOID())
+      if(profileExtensionOID == it->getOID())
 	{
-	  Ptr<Blob> valueBlob = Ptr<Blob>(new Blob(it->getValue().buf(), it->getValue().size()));
-	  m_profileList.push_back(ProfileData(*(Data::decodeFromWire(valueBlob))));
+          ProfileExtension profileExtension(*it);
+	  m_profileData = profileExtension.getProfileData();
 	}
+      if(endorseExtensionOID == it->getOID())
+        {
+          EndorseExtension endorseExtension(*it);
+          m_endorseList = endorseExtension.getEndorsedList();
+        }
     }
 }
diff --git a/src/endorse-certificate.h b/src/endorse-certificate.h
index 28202da..c4d160d 100644
--- a/src/endorse-certificate.h
+++ b/src/endorse-certificate.h
@@ -8,8 +8,8 @@
  * Author: Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
-#ifndef LINKEDN_ENDORSE_CERTIFICATE_H
-#define LINKEDN_ENDORSE_CERTIFICATE_H
+#ifndef LINKNDN_ENDORSE_CERTIFICATE_H
+#define LINKNDN_ENDORSE_CERTIFICATE_H
 
 #include <vector>
 #include <ndn.cxx/data.h>
@@ -18,22 +18,54 @@
 
 #include "profile-data.h"
 
+class ProfileExtension : public ndn::security::CertificateExtension
+{
+public:
+  ProfileExtension(const ProfileData& profileData);
+  
+  ProfileExtension(const ProfileExtension& profileExtension);
+
+  ProfileExtension(const CertificateExtension& extension);
+
+  ~ProfileExtension() {}
+
+  ndn::Ptr<ProfileData>
+  getProfileData();
+};
+
 class EndorseExtension : public ndn::security::CertificateExtension
 {
 public:
-  EndorseExtension(const ndn::Blob & value);
+  EndorseExtension(const std::vector<std::string>& endorsedList);
 
-  virtual
+  EndorseExtension(const EndorseExtension& endorseExtension);
+
+  EndorseExtension(const CertificateExtension& extension);
+
   ~EndorseExtension() {}
+
+  std::vector<std::string>
+  getEndorsedList();
+
+private:
+  static ndn::Ptr<ndn::Blob>
+  prepareValue(const std::vector<std::string>& endorsedList);
 };
 
 class EndorseCertificate : public ndn::security::Certificate
 {
 public:
   EndorseCertificate(const ndn::security::IdentityCertificate& kskCertificate,
+                     const ndn::Time& notBefore,
+                     const ndn::Time& notAfter,
+                     ndn::Ptr<ProfileData> profileData,
+                     const std::vector<std::string>& endorseList);
+
+  EndorseCertificate(const EndorseCertificate& endorseCertificate,
                      const ndn::Name& signer,
                      const ndn::Time& notBefore,
-                     const ndn::Time& notAfter);
+                     const ndn::Time& notAfter,
+                     const std::vector<std::string>& endorseList);
 
   EndorseCertificate(const EndorseCertificate& endorseCertificate);
 
@@ -43,32 +75,27 @@
   ~EndorseCertificate()
   {}
 
-  void 
-  addProfile(const ProfileData& profile);
-
-  void
-  encode();
-
   inline const ndn::Name&
   getSigner() const
   { return m_signer; }
 
-  inline const std::vector<ProfileData>&
-  getProfileList() const
-  { return m_profileList; }
+  inline ndn::Ptr<ProfileData>
+  getProfileData() const
+  { return m_profileData; }
 
-  inline ndn::Name
-  getPublicKeyName ()
+  inline const std::vector<std::string>&
+  getEndorseList() const
+  { return m_endorseList; }
+
+  inline virtual ndn::Name
+  getPublicKeyName () const
   { return m_keyName; }
 
-private:
-  void 
-  decode();
-
-private:
+protected:
   ndn::Name m_keyName;
   ndn::Name m_signer;
-  std::vector<ProfileData> m_profileList;
+  ndn::Ptr<ProfileData> m_profileData;
+  std::vector<std::string> m_endorseList;
 };
 
 #endif
diff --git a/src/profile-data.cpp b/src/profile-data.cpp
index f4b6bde..b779adc 100644
--- a/src/profile-data.cpp
+++ b/src/profile-data.cpp
@@ -10,35 +10,51 @@
 
 #include "profile-data.h"
 #include "exception.h"
-
 #include <ndn.cxx/fields/signature-sha256-with-rsa.h>
 
-using namespace std;
 using namespace ndn;
+using namespace std;
 
-ProfileData::ProfileData (const Name& identityName,
-			  const string& profileType,
-			  const Blob& profileValue)
+ProfileData::ProfileData(const Name& identity,
+			 const Profile& profile)
   : Data()
-  , m_identityName(identityName)
-  , m_profileType(profileType)
+  , m_identity(identity)
+  , m_profile(profile)
 {
-  Name tmpName = identityName;
-  setName(tmpName.append(profileType));
-  setContent(Content(profileValue.buf(), profileValue.size()));
+  Name dataName = identity;
+  TimeInterval ti = time::NowUnixTimestamp();
+  ostringstream oss;
+  oss << ti.total_seconds();
+
+  dataName.append("PROFILE").append(oss.str());
+  setName(dataName);
+  Ptr<Blob> profileBlob = profile.toDerBlob();
+  setContent(Content(profileBlob->buf(), profileBlob->size()));
 }
 
-
-ProfileData::ProfileData (const ProfileData& profile)
+ProfileData::ProfileData(const ProfileData& profileData)
   : Data()
-  , m_identityName(profile.m_identityName)
-  , m_profileType(profile.m_profileType)
+  , m_identity(profileData.m_identity)
+  , m_profile(profileData.m_profile)
 {
-  setName(profile.getName());
-  setContent(profile.getContent());
+  Ptr<const signature::Sha256WithRsa> dataSig = boost::dynamic_pointer_cast<const signature::Sha256WithRsa>(profileData.getSignature());
+  Ptr<signature::Sha256WithRsa> newSig = Ptr<signature::Sha256WithRsa>::Create();
+
+  Ptr<SignedBlob> newSignedBlob = NULL;
+  if(profileData.getSignedBlob() != NULL)
+    newSignedBlob = Ptr<SignedBlob>(new SignedBlob(*profileData.getSignedBlob()));
+  
+  newSig->setKeyLocator(dataSig->getKeyLocator());
+  newSig->setPublisherKeyDigest(dataSig->getPublisherKeyDigest());
+  newSig->setSignatureBits(dataSig->getSignatureBits());
+  
+  setName(profileData.getName());
+  setSignature(newSig);
+  setContent(profileData.getContent());
+  setSignedBlob(newSignedBlob);
 }
- 
-ProfileData::ProfileData (const Data& data)
+
+ProfileData::ProfileData(const Data& data)
   : Data()
 {
   const Name& dataName = data.getName();
@@ -54,12 +70,14 @@
 	}
     }
 
-  if(profileIndex < 0 || profileIndex + 1 >= dataName.size())
+  if(profileIndex < 0)
     throw LnException("No PROFILE component in data name!");
-  
+
+  m_identity = dataName.getSubName(0, profileIndex);
+
   Ptr<const signature::Sha256WithRsa> dataSig = boost::dynamic_pointer_cast<const signature::Sha256WithRsa>(data.getSignature());
   Ptr<signature::Sha256WithRsa> newSig = Ptr<signature::Sha256WithRsa>::Create();
-
+  
   Ptr<SignedBlob> newSignedBlob = NULL;
   if(data.getSignedBlob() != NULL)
     newSignedBlob = Ptr<SignedBlob>(new SignedBlob(*data.getSignedBlob()));
@@ -73,7 +91,5 @@
   setContent(data.getContent());
   setSignedBlob(newSignedBlob);
 
-  m_identityName = dataName.getSubName(0, profileIndex);
-  m_profileType = dataName.get(profileIndex+1).toUri();
+  m_profile = *Profile::fromDerBlob(data.content());
 }
-
diff --git a/src/profile-data.h b/src/profile-data.h
index c70f6fc..4c2ac71 100644
--- a/src/profile-data.h
+++ b/src/profile-data.h
@@ -8,36 +8,35 @@
  * Author: Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
-#ifndef PROFILE_DATA_H
-#define PROFILE_DATA_H
+#ifndef LINKNDN_PROFILE_DATA_H
+#define LINKNDN_PROFILE_DATA_H
 
 #include <ndn.cxx/data.h>
+#include "profile.h"
 
 class ProfileData : public ndn::Data
 {
 public:
-  ProfileData (const ndn::Name& identityName,
-               const std::string& profileType,
-               const ndn::Blob& profileValue);
+  ProfileData(const ndn::Name& identity,
+              const Profile& profile);
 
-  ProfileData (const ProfileData& profile);
+  ProfileData(const ProfileData& profileData);
 
-  ProfileData (const ndn::Data& data);
-  
-  virtual
-  ~ProfileData () {}
+  ProfileData(const ndn::Data& data);
 
-  inline const ndn::Name&
+  ~ProfileData() {}
+
+  inline const ndn::Name& 
   getIdentityName() const
-  { return m_identityName; }
+  { return m_identity; }
 
-  inline const std::string&
-  getProfileType() const
-  { return m_profileType; }
+  inline const Profile&
+  getProfile() const
+  { return m_profile; }
 
 private:
-  ndn::Name m_identityName;
-  std::string m_profileType;
+  ndn::Name m_identity;
+  Profile m_profile;
 };
 
 #endif
diff --git a/src/profile.cpp b/src/profile.cpp
new file mode 100644
index 0000000..182fe77
--- /dev/null
+++ b/src/profile.cpp
@@ -0,0 +1,102 @@
+/* -*- 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 "profile.h"
+#include <ndn.cxx/helpers/der/der.h>
+#include <ndn.cxx/helpers/der/visitor/simple-visitor.h>
+
+using namespace std;
+using namespace ndn;
+
+Profile::Profile(const Name& identityName)
+  : m_identityName(identityName)
+{}
+
+Profile::Profile(const Name& identityName,
+		 const string& name,
+		 const string& institution)
+  : m_identityName(identityName)
+{
+  Blob nameBlob (name.c_str(), name.size());
+  Blob institutionBlob (institution.c_str(), institution.size());
+
+  m_entries[string("name")] = nameBlob;
+  m_entries[string("institution")] = institutionBlob;
+}
+
+Profile::Profile(const Profile& profile)
+  : m_identityName(profile.m_identityName)
+  , m_entries(profile.m_entries)
+{}
+
+void
+Profile::setProfileEntry(const string& profileType,
+			 const Blob& profileValue)
+{ m_entries[profileType] = profileValue; }
+
+Ptr<const Blob>
+Profile::getProfileEntry(const string& profileType)
+{
+  if(m_entries.find(profileType) != m_entries.end())
+      return Ptr<Blob>(new Blob(m_entries[profileType].buf(), m_entries[profileType].size()));
+
+  return NULL;
+}
+
+Ptr<Blob>
+Profile::toDerBlob() const
+{
+  Ptr<der::DerSequence> root = Ptr<der::DerSequence>::Create();
+  
+  Ptr<der::DerPrintableString> identityName = Ptr<der::DerPrintableString>(new der::DerPrintableString(m_identityName.toUri()));
+  root->addChild(identityName);
+
+  map<string, Blob>::const_iterator it = m_entries.begin();
+  for(; it != m_entries.end(); it++)
+    {
+      Ptr<der::DerSequence> entry = Ptr<der::DerSequence>::Create();
+      Ptr<der::DerPrintableString> type = Ptr<der::DerPrintableString>(new der::DerPrintableString(it->first));
+      Ptr<der::DerOctetString> value = Ptr<der::DerOctetString>(new der::DerOctetString(it->second));
+      entry->addChild(type);
+      entry->addChild(value);
+      root->addChild(entry);
+    }
+  
+  blob_stream blobStream;
+  OutputIterator & start = reinterpret_cast<OutputIterator &> (blobStream);
+  root->encode(start);
+
+  return blobStream.buf ();
+}
+
+Ptr<Profile>
+Profile::fromDerBlob(const Blob& derBlob)
+{
+  boost::iostreams::stream
+    <boost::iostreams::array_source> is (derBlob.buf(), derBlob.size());
+
+  Ptr<der::DerSequence> root = DynamicCast<der::DerSequence>(der::DerNode::parse(reinterpret_cast<InputIterator &>(is)));
+  
+  const der::DerNodePtrList & children = root->getChildren();
+  der::SimpleVisitor simpleVisitor;
+  string identityName = boost::any_cast<string>(children[0]->accept(simpleVisitor));
+  Ptr<Profile> profile = Ptr<Profile>(new Profile(identityName));
+
+  for(int i = 1; i < children.size(); i++)
+    {
+      Ptr<der::DerSequence> entry = DynamicCast<der::DerSequence>(children[i]);
+      const der::DerNodePtrList & tuple = root->getChildren();
+      string type = boost::any_cast<string>(tuple[0]->accept(simpleVisitor));
+      Ptr<Blob> value = boost::any_cast<Ptr<Blob> >(tuple[1]->accept(simpleVisitor));
+      profile->setProfileEntry(type, *value);
+    }
+
+  return profile;
+}
diff --git a/src/profile.h b/src/profile.h
new file mode 100644
index 0000000..403b600
--- /dev/null
+++ b/src/profile.h
@@ -0,0 +1,75 @@
+/* -*- 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_PROFILE_H
+#define LINKNDN_PROFILE_H
+
+#include <ndn.cxx/common.h>
+#include <ndn.cxx/fields/name.h>
+#include <ndn.cxx/fields/blob.h>
+#include <map>
+#include <string>
+
+class Profile
+{
+public:
+  typedef std::map<std::string, ndn::Blob>::iterator iterator;
+  typedef std::map<std::string, ndn::Blob>::const_iterator const_iterator;
+public:
+  Profile() {}
+
+  Profile(const ndn::Name& identityName);
+
+  Profile(const ndn::Name& identityName,
+          const std::string& name,
+          const std::string& institution);
+  
+  Profile(const Profile& profile);
+  
+  virtual
+  ~Profile() {}
+
+  void
+  setProfileEntry(const std::string& profileType,
+                  const ndn::Blob& profileValue);
+  
+  ndn::Ptr<const ndn::Blob>
+  getProfileEntry(const std::string& profileType);
+
+  inline Profile::iterator
+  begin()
+  { return m_entries.begin(); }
+
+  inline Profile::const_iterator
+  begin() const
+  { return m_entries.begin(); }
+
+  inline Profile::iterator
+  end()
+  { return m_entries.end(); }
+
+  inline Profile::const_iterator
+  end() const
+  { return m_entries.end(); }
+
+  ndn::Ptr<ndn::Blob>
+  toDerBlob() const;
+
+  static ndn::Ptr<Profile>
+  fromDerBlob(const ndn::Blob& derBlob);
+
+protected:
+  ndn::Name m_identityName;
+  std::map<std::string, ndn::Blob> m_entries;
+};
+
+
+
+#endif