blob: f7559651b1fdcd33af6753e87201a4674ff73f05 [file] [log] [blame]
/* -*- 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>
*/
#if __clang__
#pragma clang diagnostic ignored "-Wtautological-compare"
#endif
#include "contact-manager.h"
#ifndef Q_MOC_RUN
#include <ndn-cpp-dev/face.hpp>
#include <ndn-cpp-dev/security/signature-sha256-with-rsa.hpp>
#ifndef WITH_SECURITY
#include <ndn-cpp-dev/security/validator-null.hpp>
#else
#include <ndn-cpp-dev/security/validator-regex.hpp>
#include <cryptopp/base64.h>
#include <ndn-cpp-dev/security/sec-rule-relative.hpp>
#endif
#include "endorse-collection.pb.h"
#include "logging.h"
#endif
using namespace ndn;
using namespace std;
INIT_LOGGER("ContactManager");
namespace chronos{
ContactManager::ContactManager(shared_ptr<Face> face,
QObject* parent)
: QObject(parent)
, m_contactStorage(new ContactStorage())
, m_dnsStorage(new DnsStorage())
, m_face(face)
{
initializeSecurity();
}
ContactManager::~ContactManager()
{}
void
ContactManager::initializeSecurity()
{
#ifndef WITH_SECURITY
m_keyChain = make_shared<KeyChain>();
m_validator = make_shared<ValidatorNull>();
#else
shared_ptr<SecPolicySimple> policy = make_shared<SecPolicySimple>();
m_verifier = make_shared<Verifier>(policy);
m_verifier->setFace(m_face);
policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><ENDORSED>",
"^([^<KEY>]*)<KEY>(<>*)[<ksk-.*><dsk-.*>]<ID-CERT>$",
"==", "\\1", "\\1\\2", true));
policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><PROFILE>",
"^([^<KEY>]*)<KEY>(<>*)[<ksk-.*><dsk-.*>]<ID-CERT>$",
"==", "\\1", "\\1\\2", true));
policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^([^<PROFILE-CERT>]*)<PROFILE-CERT>",
"^([^<KEY>]*)<KEY>(<>*<ksk-.*>)<ID-CERT>$",
"==", "\\1", "\\1\\2", true));
policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>",
"^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>$",
">", "\\1\\2", "\\1", true));
policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>",
"^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
"==", "\\1", "\\1\\2", true));
policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^(<>*)$",
"^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
">", "\\1", "\\1\\2", true));
policy->addSigningPolicyRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><PROFILE>",
"^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>",
"==", "\\1", "\\1\\2", true));
const string TrustAnchor("BIICqgOyEIWlKzDI2xX2hdq5Azheu9IVyewcV4uM7ylfh67Y8MIxF3tDCTx5JgEn\
HYMuCaYQm6XuaXTlVfDdWff/K7Xebq8IgGxjNBeU9eMf7Gy9iIMrRAOdBG0dBHmo\
67biGs8F+P1oh1FwKu/FN1AE9vh8HSOJ94PWmjO+6PvITFIXuI3QbcCz8rhvbsfb\
5X/DmfbJ8n8c4X3nVxrBm6fd4z8kOFOvvhgJImvqsow69Uy+38m8gJrmrcWMoPBJ\
WsNLcEriZCt/Dlg7EqqVrIn6ukylKCvVrxA9vm/cEB74J/N+T0JyMRDnTLm17gpq\
Gd75rhj+bLmpOMOBT7Nb27wUKq8gcXzeAADy+p1uZG4A+p1LRVkA+vVrc2stMTM4\
MzMyNTcyMAD6vUlELUNFUlQA+q39PgurHgAAAaID4gKF5vjua9EIr3/Fn8k1AdSc\
nEryjVDW3ikvYoSwjK7egTkAArq1BSc+C6sdAAHiAery+p1uZG4A+p1LRVkA+vVr\
c2stMTM4MzMyNTcyMAD6vUlELUNFUlQAAAAAAAGaFr0wggFjMCIYDzIwMTMxMTAx\
MTcxMTIyWhgPMjAxNDExMDExNzExMjJaMBkwFwYDVQQpExBORE4gVGVzdGJlZCBS\
b290MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA06x+elwzWCHa4I3b\
yrYCMAIVxQpRVLuOXp0h+BS+5GNgMVPi7+40o4zSJG+kiU8CIH1mtj8RQAzBX9hF\
I5VAyOC8nS8D8YOfBwt2yRDZPgt1E5PpyYUBiDYuq/zmJDL8xjxAlxrMzVOqD/uj\
/vkkcBM/T1t9Q6p1CpRyq+GMRbV4EAHvH7MFb6bDrH9t8DHEg7NPUCaSQBrd7PvL\
72P+QdiNH9zs/EiVzAkeMG4iniSXLuYM3z0gMqqcyUUUr6r1F9IBmDO+Kp97nZh8\
VCL+cnIEwyzAFAupQH5GoXUWGiee8oKWwH2vGHX7u6sWZsCp15NMSG3OC4jUIZOE\
iVUF1QIBEQAA");
string decoded;
CryptoPP::StringSource ss(reinterpret_cast<const unsigned char *>(TrustAnchor.c_str()),
TrustAnchor.size(),
true,
new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded)));
Data data;
data.wireDecode(Block(reinterpret_cast<const uint8_t*>(decoded.c_str()), decoded.size()));
shared_ptr<IdentityCertificate> anchor = make_shared<IdentityCertificate>(data);
policy->addTrustAnchor(anchor);
#endif
}
void
ContactManager::fetchSelfEndorseCertificate(const ndn::Name& identity)
{
Name interestName = identity;
interestName.append("DNS").append("PROFILE");
Interest interest(interestName);
interest.setMustBeFresh(true);
OnDataValidated onValidated = bind(&ContactManager::onDnsSelfEndorseCertValidated, this, _1, identity);
OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsSelfEndorseCertValidationFailed, this, _1, identity);
TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsSelfEndorseCertTimeoutNotify, this, identity);
sendInterest(interest, onValidated, onValidationFailed, timeoutNotify);
}
void
ContactManager::onDnsSelfEndorseCertValidated(const shared_ptr<const Data>& data,
const Name& identity)
{
try{
Data plainData;
plainData.wireDecode(data->getContent().blockFromValue());
EndorseCertificate selfEndorseCertificate(plainData);
if(Validator::verifySignature(plainData, plainData.getSignature(), selfEndorseCertificate.getPublicKeyInfo()))
emit contactFetched(selfEndorseCertificate);
else
emit contactFetchFailed(identity);
}catch(...){
emit contactFetchFailed (identity);
}
}
void
ContactManager::fetchCollectEndorse(const Name& identity)
{
Name interestName = identity;
interestName.append("DNS").append("ENDORSED");
Interest interest(interestName);
interest.setInterestLifetime(1000);
interest.setMustBeFresh(true);
OnDataValidated onValidated = bind(&ContactManager::onDnsCollectEndorseValidated, this, _1, identity);
OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsCollectEndorseValidationFailed, this, _1, identity);
TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsCollectEndorseTimeoutNotify, this, identity);
sendInterest(interest, onValidated, onValidationFailed, timeoutNotify);
}
void
ContactManager::fetchKey(const Name& certName)
{
Name interestName = certName;
Interest interest(interestName);
interest.setInterestLifetime(1000);
interest.setMustBeFresh(true);
OnDataValidated onValidated = bind(&ContactManager::onKeyValidated, this, _1, certName);
OnDataValidationFailed onValidationFailed = bind(&ContactManager::onKeyValidationFailed, this, _1, certName);
TimeoutNotify timeoutNotify = bind(&ContactManager::onKeyTimeoutNotify, this, certName);
sendInterest(interest, onValidated, onValidationFailed, timeoutNotify);
}
void
ContactManager::onKeyValidated(const shared_ptr<const Data>& data, const Name& identity)
{
IdentityCertificate identityCertificate(*data);
Profile profile(identityCertificate);
try{
EndorseCertificate endorseCertificate(identityCertificate, profile);
m_keyChain->sign(endorseCertificate);
emit contactKeyFetched (endorseCertificate);
}catch(...){
return;
}
}
void
ContactManager::fetchIdCertificate(const Name& certName)
{
Name interestName = certName;
Interest interest(interestName);
interest.setInterestLifetime(1000);
interest.setMustBeFresh(true);
OnDataValidated onValidated = bind(&ContactManager::onIdCertValidated, this, _1, certName);
OnDataValidationFailed onValidationFailed = bind(&ContactManager::onIdCertValidationFailed, this, _1, certName);
TimeoutNotify timeoutNotify = bind(&ContactManager::onIdCertTimeoutNotify, this, certName);
sendInterest(interest, onValidated, onValidationFailed, timeoutNotify);
}
void
ContactManager::updateProfileData(const Name& identity)
{
// Get current profile;
shared_ptr<Profile> newProfile = m_contactStorage->getSelfProfile(identity);
if(!static_cast<bool>(newProfile))
return;
shared_ptr<EndorseCertificate> newEndorseCertificate = getSignedSelfEndorseCertificate(identity, *newProfile);
if(!static_cast<bool>(newEndorseCertificate))
return;
m_contactStorage->addSelfEndorseCertificate(*newEndorseCertificate, identity);
publishSelfEndorseCertificateInDNS(*newEndorseCertificate);
}
void
ContactManager::updateEndorseCertificate(const ndn::Name& identity, const ndn::Name& signerIdentity)
{
shared_ptr<EndorseCertificate> newEndorseCertificate = generateEndorseCertificate(identity, signerIdentity);
if(!static_cast<bool>(newEndorseCertificate))
return;
m_contactStorage->addEndorseCertificate(*newEndorseCertificate, identity);
publishEndorseCertificateInDNS(*newEndorseCertificate, signerIdentity);
}
shared_ptr<EndorseCertificate>
ContactManager::generateEndorseCertificate(const Name& identity, const Name& signerIdentity)
{
shared_ptr<ContactItem> contact = getContact(identity);
if(!static_cast<bool>(contact))
return shared_ptr<EndorseCertificate>();
Name signerKeyName = m_keyChain->getDefaultKeyNameForIdentity(signerIdentity);
vector<string> endorseList;
m_contactStorage->getEndorseList(identity, endorseList);
try{
shared_ptr<EndorseCertificate> cert = make_shared<EndorseCertificate>(contact->getSelfEndorseCertificate(), signerKeyName, endorseList);
m_keyChain->signByIdentity(*cert, signerIdentity);
return cert;
}catch(...){
return shared_ptr<EndorseCertificate>();
}
}
shared_ptr<EndorseCertificate>
ContactManager::getSignedSelfEndorseCertificate(const Name& identity,
const Profile& profile)
{
Name certificateName = m_keyChain->getDefaultCertificateNameForIdentity(identity);
if(0 == certificateName.size())
return shared_ptr<EndorseCertificate>();
Name signingKeyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
shared_ptr<IdentityCertificate> kskCert;
if(signingKeyName.get(-1).toEscapedString().substr(0,4) == "dsk-")
{
shared_ptr<IdentityCertificate> signingCert = m_keyChain->getCertificate(certificateName);
if(!static_cast<bool>(signingCert))
return shared_ptr<EndorseCertificate>();
try{
SignatureSha256WithRsa dskCertSig(signingCert->getSignature());
Name keyName = IdentityCertificate::certificateNameToPublicKeyName(dskCertSig.getKeyLocator().getName());
Name kskCertName = m_keyChain->getDefaultCertificateNameForKey(keyName);
kskCert = m_keyChain->getCertificate(kskCertName);
}catch(...){
return shared_ptr<EndorseCertificate>();
}
}
else
kskCert = m_keyChain->getCertificate(certificateName);
if(!static_cast<bool>(kskCert))
return shared_ptr<EndorseCertificate>();
vector<string> endorseList;
Profile::const_iterator it = profile.begin();
for(; it != profile.end(); it++)
endorseList.push_back(it->first);
try{
shared_ptr<EndorseCertificate> selfEndorseCertificate = make_shared<EndorseCertificate>(*kskCert, profile, endorseList);
m_keyChain->sign(*selfEndorseCertificate, kskCert->getName());
return selfEndorseCertificate;
}catch(...){
return shared_ptr<EndorseCertificate>();
}
}
void
ContactManager::publishSelfEndorseCertificateInDNS(const EndorseCertificate& selfEndorseCertificate)
{
Data data;
Name identity = selfEndorseCertificate.getPublicKeyName().getPrefix(-1);
Name dnsName = identity;
dnsName.append("DNS").append("PROFILE").appendVersion();
data.setName(dnsName);
data.setContent(selfEndorseCertificate.wireEncode());
m_keyChain->signByIdentity(data, identity);
m_dnsStorage->updateDnsSelfProfileData(data, identity);
m_face->put(data);
}
void
ContactManager::publishEndorseCertificateInDNS(const EndorseCertificate& endorseCertificate, const Name& signerIdentity)
{
Data data;
Name endorsee = endorseCertificate.getPublicKeyName().getPrefix(-1);
Name dnsName = signerIdentity;
dnsName.append("DNS").append(endorsee.wireEncode()).append("ENDORSEE").appendVersion();
data.setName(dnsName);
data.setContent(endorseCertificate.wireEncode());
m_keyChain->signByIdentity(data, signerIdentity);
m_dnsStorage->updateDnsEndorseOthers(data, signerIdentity, endorsee);
m_face->put(data);
}
void
ContactManager::publishCollectEndorsedDataInDNS(const Name& identity)
{
Data data;
Name dnsName = identity;
dnsName.append("DNS").append("ENDORSED").appendVersion();
data.setName(dnsName);
vector<Buffer> collectEndorseList;
m_contactStorage->getCollectEndorseList(identity, collectEndorseList);
Chronos::EndorseCollection endorseCollection;
vector<Buffer>::const_iterator it = collectEndorseList.begin();
for(; it != collectEndorseList.end(); it++)
{
string entryStr(reinterpret_cast<const char*>(it->buf()), it->size());
endorseCollection.add_endorsement()->set_blob(entryStr);
}
string encoded;
endorseCollection.SerializeToString(&encoded);
data.setContent(reinterpret_cast<const uint8_t*>(encoded.c_str()), encoded.size());
m_keyChain->signByIdentity(data, identity);
m_dnsStorage->updateDnsOthersEndorse(data, identity);
m_face->put(data);
}
void
ContactManager::addContact(const IdentityCertificate& identityCertificate, const Profile& profile)
{
try{
EndorseCertificate endorseCertificate(identityCertificate, profile);
m_keyChain->signByIdentity(endorseCertificate, m_defaultIdentity);
ContactItem contactItem(endorseCertificate);
m_contactStorage->addContact(contactItem);
emit contactAdded(contactItem.getNameSpace());
}catch(std::runtime_error& e){
emit warning(e.what());
_LOG_ERROR("Exception: " << e.what());
return;
}
}
void
ContactManager::removeContact(const Name& contactNameSpace)
{
shared_ptr<ContactItem> contact = getContact(contactNameSpace);
if(!static_cast<bool>(contact))
return;
m_contactStorage->removeContact(contactNameSpace);
emit contactRemoved(contact->getPublicKeyName());
}
}//chronos
#if WAF
#include "contact-manager.moc"
#include "contact-manager.cpp.moc"
#endif