blob: f89e0231b4697166fd1018d10efb7ff105ed7eb1 [file] [log] [blame]
Yingdi Yu9236c432013-10-18 11:29:25 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Yingdi Yu
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Yingdi Yu <yingdi@cs.ucla.edu>
9 */
10
Yingdi Yuf8f572d2014-01-13 11:19:47 -080011#if __clang__
Yingdi Yuf8f572d2014-01-13 11:19:47 -080012#pragma clang diagnostic ignored "-Wtautological-compare"
Yingdi Yuf8f572d2014-01-13 11:19:47 -080013#endif
14
Yingdi Yu9236c432013-10-18 11:29:25 -070015#include "contact-manager.h"
Yingdi Yu348f5ea2014-03-01 14:47:25 -080016#include <QStringList>
Yingdi Yu06f572b2014-03-11 15:46:10 -070017#include <QFile>
Yingdi Yu9236c432013-10-18 11:29:25 -070018
Yingdi Yu4685b1b2013-10-18 17:05:02 -070019#ifndef Q_MOC_RUN
Yingdi Yu348f5ea2014-03-01 14:47:25 -080020#include <ndn-cpp-dev/util/crypto.hpp>
21#include <ndn-cpp-dev/util/io.hpp>
22#include <ndn-cpp-dev/security/sec-rule-relative.hpp>
Yingdi Yufa4ce792014-02-06 18:09:22 -080023#include <ndn-cpp-dev/security/validator-regex.hpp>
Yingdi Yu72781e52013-11-06 23:00:21 -080024#include <cryptopp/base64.h>
Yingdi Yu348f5ea2014-03-01 14:47:25 -080025#include <cryptopp/files.h>
26#include <cryptopp/sha.h>
Yingdi Yu06f572b2014-03-11 15:46:10 -070027#include <cryptopp/filters.h>
Yingdi Yu348f5ea2014-03-01 14:47:25 -080028#include <boost/asio.hpp>
29#include <boost/tokenizer.hpp>
30#include <boost/filesystem.hpp>
Yingdi Yuec3d9a32013-10-18 18:35:09 -070031#include "logging.h"
Yingdi Yu4685b1b2013-10-18 17:05:02 -070032#endif
Yingdi Yu9236c432013-10-18 11:29:25 -070033
34using namespace ndn;
Yingdi Yu348f5ea2014-03-01 14:47:25 -080035namespace fs = boost::filesystem;
Yingdi Yu9236c432013-10-18 11:29:25 -070036
Yingdi Yu348f5ea2014-03-01 14:47:25 -080037INIT_LOGGER("chronos.ContactManager");
Yingdi Yuec3d9a32013-10-18 18:35:09 -070038
Yingdi Yufa4ce792014-02-06 18:09:22 -080039namespace chronos{
Yingdi Yu4685b1b2013-10-18 17:05:02 -070040
Yingdi Yu17032f82014-03-25 15:48:23 -070041using ndn::shared_ptr;
42
Yingdi Yu348f5ea2014-03-01 14:47:25 -080043static const uint8_t DNS_RP_SEPARATOR[2] = {0xF0, 0x2E}; // %F0.
44
Yingdi Yufa4ce792014-02-06 18:09:22 -080045ContactManager::ContactManager(shared_ptr<Face> face,
46 QObject* parent)
47 : QObject(parent)
Yingdi Yufa4ce792014-02-06 18:09:22 -080048 , m_face(face)
Yingdi Yu348f5ea2014-03-01 14:47:25 -080049 , m_dnsListenerId(0)
Yingdi Yufa4ce792014-02-06 18:09:22 -080050{
Yingdi Yu76dd8002013-12-24 11:16:32 +080051 initializeSecurity();
Yingdi Yu9236c432013-10-18 11:29:25 -070052}
53
54ContactManager::~ContactManager()
Yingdi Yu6eabbd72013-12-27 08:44:12 +080055{}
Yingdi Yu9236c432013-10-18 11:29:25 -070056
Yingdi Yu348f5ea2014-03-01 14:47:25 -080057// private methods
Yingdi Yu06f572b2014-03-11 15:46:10 -070058shared_ptr<IdentityCertificate>
59ContactManager::loadTrustAnchor()
60{
61 shared_ptr<IdentityCertificate> anchor;
62
63 QFile anchorFile(":/security/anchor.cert");
64
65 if (!anchorFile.open(QIODevice::ReadOnly))
66 {
67 emit warning(QString("Cannot load trust anchor!"));
68
69 return anchor;
70 }
71
72 qint64 fileSize = anchorFile.size();
73 char* buf = new char[fileSize];
74 anchorFile.read(buf, fileSize);
75
76 try
77 {
78 using namespace CryptoPP;
79
80 OBufferStream os;
81 StringSource(reinterpret_cast<const uint8_t*>(buf), fileSize, true, new Base64Decoder(new FileSink(os)));
82 anchor = make_shared<IdentityCertificate>();
83 anchor->wireDecode(Block(os.buf()));
84 }
85 catch(CryptoPP::Exception& e)
86 {
87 emit warning(QString("Cannot load trust anchor!"));
88 }
89 catch(IdentityCertificate::Error& e)
90 {
91 emit warning(QString("Cannot load trust anchor!"));
92 }
93 catch(Block::Error& e)
94 {
95 emit warning(QString("Cannot load trust anchor!"));
96 }
97
98 delete [] buf;
99
100 return anchor;
101}
102
Yingdi Yu76dd8002013-12-24 11:16:32 +0800103void
104ContactManager::initializeSecurity()
105{
Yingdi Yu06f572b2014-03-11 15:46:10 -0700106 shared_ptr<IdentityCertificate> anchor = loadTrustAnchor();
Yingdi Yufa4ce792014-02-06 18:09:22 -0800107
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800108 shared_ptr<ValidatorRegex> validator = make_shared<ValidatorRegex>(m_face);
109 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><ENDORSED>",
110 "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
111 "==", "\\1", "\\1\\2", true));
112 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><><ENDORSEE>",
113 "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
114 "==", "\\1", "\\1\\2", true));
115 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><PROFILE>",
116 "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
117 "==", "\\1", "\\1\\2", true));
118 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<PROFILE-CERT>]*)<PROFILE-CERT>",
119 "^([^<KEY>]*)<KEY>(<>*<ksk-.*>)<ID-CERT>$",
120 "==", "\\1", "\\1\\2", true));
121 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>",
122 "^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>$",
123 ">", "\\1\\2", "\\1", true));
124 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>",
125 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
126 "==", "\\1", "\\1\\2", true));
127 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^(<>*)$",
128 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
129 ">", "\\1", "\\1\\2", true));
130 validator->addTrustAnchor(anchor);
131 m_validator = validator;
Yingdi Yu76dd8002013-12-24 11:16:32 +0800132}
133
134void
Yingdi Yufa4ce792014-02-06 18:09:22 -0800135ContactManager::fetchCollectEndorse(const Name& identity)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800136{
137 Name interestName = identity;
138 interestName.append("DNS").append("ENDORSED");
139
Yingdi Yu76dd8002013-12-24 11:16:32 +0800140 Interest interest(interestName);
Yingdi Yua7876722014-03-25 14:46:55 -0700141 interest.setInterestLifetime(time::milliseconds(1000));
Yingdi Yufa4ce792014-02-06 18:09:22 -0800142 interest.setMustBeFresh(true);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800143
Yingdi Yufa4ce792014-02-06 18:09:22 -0800144 OnDataValidated onValidated = bind(&ContactManager::onDnsCollectEndorseValidated, this, _1, identity);
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700145 OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsCollectEndorseValidationFailed, this, _1, _2, identity);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800146 TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsCollectEndorseTimeoutNotify, this, _1, identity);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800147
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800148 sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
Yingdi Yub2e747d2013-11-05 23:06:43 -0800149}
150
151void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800152ContactManager::fetchEndorseCertificateInternal(const Name& identity, int certIndex)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800153{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800154 shared_ptr<EndorseCollection> endorseCollection = m_bufferedContacts[identity].m_endorseCollection;
155
156 if(certIndex >= endorseCollection->endorsement_size())
157 prepareEndorseInfo(identity);
158
159 Name interestName(endorseCollection->endorsement(certIndex).certname());
160
Yingdi Yu76dd8002013-12-24 11:16:32 +0800161 Interest interest(interestName);
Yingdi Yua7876722014-03-25 14:46:55 -0700162 interest.setInterestLifetime(time::milliseconds(1000));
Yingdi Yufa4ce792014-02-06 18:09:22 -0800163 interest.setMustBeFresh(true);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800164
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800165 m_face->expressInterest(interest,
166 bind(&ContactManager::onEndorseCertificateInternal,
167 this, _1, _2, identity, certIndex,
168 endorseCollection->endorsement(certIndex).hash()),
169 bind(&ContactManager::onEndorseCertificateInternalTimeout,
170 this, _1, identity, certIndex));
Yingdi Yu76dd8002013-12-24 11:16:32 +0800171}
172
Yingdi Yu76dd8002013-12-24 11:16:32 +0800173void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800174ContactManager::prepareEndorseInfo(const Name& identity)
Yingdi Yu76dd8002013-12-24 11:16:32 +0800175{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800176 // _LOG_DEBUG("prepareEndorseInfo");
177 const Profile& profile = m_bufferedContacts[identity].m_selfEndorseCert->getProfile();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800178
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800179 shared_ptr<EndorseInfo> endorseInfo = make_shared<EndorseInfo>();
180 m_bufferedContacts[identity].m_endorseInfo = endorseInfo;
181
182 Profile::const_iterator pIt = profile.begin();
183 Profile::const_iterator pEnd = profile.end();
184
Yingdi Yu17032f82014-03-25 15:48:23 -0700185 std::map<std::string, int> endorseCount;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800186 for(; pIt != pEnd; pIt++)
187 {
188 // _LOG_DEBUG("prepareEndorseInfo: profile[" << pIt->first << "]: " << pIt->second);
189 endorseCount[pIt->first] = 0;
190 }
191
192 int endorseCertCount = 0;
193
Yingdi Yu17032f82014-03-25 15:48:23 -0700194 std::vector<shared_ptr<EndorseCertificate> >::const_iterator cIt = m_bufferedContacts[identity].m_endorseCertList.begin();
195 std::vector<shared_ptr<EndorseCertificate> >::const_iterator cEnd = m_bufferedContacts[identity].m_endorseCertList.end();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800196
197 for(; cIt != cEnd; cIt++, endorseCertCount++)
198 {
199 shared_ptr<Contact> contact = getContact((*cIt)->getSigner().getPrefix(-1));
200 if(!static_cast<bool>(contact))
201 continue;
202
203 if(!contact->isIntroducer()
204 || !contact->canBeTrustedFor(profile.getIdentityName()))
205 continue;
206
207 if(!Validator::verifySignature(**cIt, contact->getPublicKey()))
208 continue;
209
210 const Profile& tmpProfile = (*cIt)->getProfile();
211 if(tmpProfile != profile)
212 continue;
213
Yingdi Yu17032f82014-03-25 15:48:23 -0700214 const std::vector<std::string>& endorseList = (*cIt)->getEndorseList();
215 std::vector<std::string>::const_iterator eIt = endorseList.begin();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800216 for(; eIt != endorseList.end(); eIt++)
217 endorseCount[*eIt] += 1;
218 }
219
220 pIt = profile.begin();
221 pEnd = profile.end();
222 for(; pIt != pEnd; pIt++)
223 {
224 EndorseInfo::Endorsement* endorsement = endorseInfo->add_endorsement();
225 endorsement->set_type(pIt->first);
226 endorsement->set_value(pIt->second);
Yingdi Yu17032f82014-03-25 15:48:23 -0700227 std::stringstream ss;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800228 ss << endorseCount[pIt->first] << "/" << endorseCertCount;
229 endorsement->set_endorse(ss.str());
230 }
231
232 emit contactEndorseInfoReady (*endorseInfo);
233}
234
235void
236ContactManager::onDnsSelfEndorseCertValidated(const shared_ptr<const Data>& data,
237 const Name& identity)
238{
239 try
240 {
241 Data plainData;
242 plainData.wireDecode(data->getContent().blockFromValue());
243 shared_ptr<EndorseCertificate> selfEndorseCertificate = make_shared<EndorseCertificate>(boost::cref(plainData));
244 if(Validator::verifySignature(plainData, selfEndorseCertificate->getPublicKeyInfo()))
245 {
246 m_bufferedContacts[identity].m_selfEndorseCert = selfEndorseCertificate;
247 fetchCollectEndorse(identity);
248 }
249 else
250 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
251 }
252 catch(Block::Error& e)
253 {
254 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
255 }
256 catch(Data::Error& e)
257 {
258 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
259 }
260 catch(EndorseCertificate::Error& e)
261 {
262 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
263 }
264}
265
266void
267ContactManager::onDnsSelfEndorseCertValidationFailed(const shared_ptr<const Data>& data,
Yingdi Yu17032f82014-03-25 15:48:23 -0700268 const std::string& failInfo,
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800269 const Name& identity)
270{
271 // If we cannot validate the Self-Endorse-Certificate, we may retry or fetch id-cert,
272 // but let's stay with failure for now.
273 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
274}
275
276void
277ContactManager::onDnsSelfEndorseCertTimeoutNotify(const Interest& interest,
278 const Name& identity)
279{
280 // If we cannot validate the Self-Endorse-Certificate, we may retry or fetch id-cert,
281 // but let's stay with failure for now.
282 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
283}
284
285void
286ContactManager::onDnsCollectEndorseValidated(const shared_ptr<const Data>& data,
287 const Name& identity)
288{
289 shared_ptr<EndorseCollection> endorseCollection = make_shared<EndorseCollection>();
290 if(!endorseCollection->ParseFromArray(data->getContent().value(), data->getContent().value_size()))
291 {
292 m_bufferedContacts[identity].m_endorseCollection = endorseCollection;
293 fetchEndorseCertificateInternal(identity, 0);
294 }
295 else
296 prepareEndorseInfo(identity);
297}
298
299void
300ContactManager::onDnsCollectEndorseValidationFailed(const shared_ptr<const Data>& data,
Yingdi Yu17032f82014-03-25 15:48:23 -0700301 const std::string& failInfo,
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800302 const Name& identity)
303{
304 prepareEndorseInfo(identity);
305}
306
307void
308ContactManager::onDnsCollectEndorseTimeoutNotify(const Interest& interest,
309 const Name& identity)
310{
311 // _LOG_DEBUG("onDnsCollectEndorseTimeoutNotify: " << interest.getName());
312 prepareEndorseInfo(identity);
313}
314
315void
316ContactManager::onEndorseCertificateInternal(const Interest& interest,
317 Data& data,
318 const Name& identity,
319 int certIndex,
Yingdi Yu17032f82014-03-25 15:48:23 -0700320 std::string hash)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800321{
Yingdi Yu17032f82014-03-25 15:48:23 -0700322 std::stringstream ss;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800323 {
324 using namespace CryptoPP;
325
326 SHA256 hash;
327 StringSource(data.wireEncode().wire(), data.wireEncode().size(), true,
328 new HashFilter(hash, new FileSink(ss)));
329 }
330
331 if(ss.str() == hash)
332 {
333 shared_ptr<EndorseCertificate> endorseCertificate = make_shared<EndorseCertificate>(boost::cref(data));
334 m_bufferedContacts[identity].m_endorseCertList.push_back(endorseCertificate);
335 }
336
337 fetchEndorseCertificateInternal(identity, certIndex+1);
338}
339
340void
341ContactManager::onEndorseCertificateInternalTimeout(const Interest& interest,
342 const Name& identity,
343 int certIndex)
344{
345 fetchEndorseCertificateInternal(identity, certIndex+1);
346}
347
348void
349ContactManager::collectEndorsement()
350{
351 {
352 boost::recursive_mutex::scoped_lock lock(m_collectCountMutex);
353 m_collectCount = m_contactList.size();
354
355 ContactList::iterator it = m_contactList.begin();
356 ContactList::iterator end = m_contactList.end();
357
358 for(; it != end ; it++)
359 {
360 Name interestName = (*it)->getNameSpace();
361 interestName.append("DNS").append(m_identity.wireEncode()).append("ENDORSEE");
362
363 Interest interest(interestName);
Yingdi Yua7876722014-03-25 14:46:55 -0700364 interest.setInterestLifetime(time::milliseconds(1000));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800365
366 OnDataValidated onValidated = bind(&ContactManager::onDnsEndorseeValidated, this, _1);
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700367 OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsEndorseeValidationFailed, this, _1, _2);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800368 TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsEndorseeTimeoutNotify, this, _1);
369
370 sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
371 }
Yingdi Yu76dd8002013-12-24 11:16:32 +0800372 }
373}
374
375void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800376ContactManager::onDnsEndorseeValidated(const shared_ptr<const Data>& data)
Yingdi Yuae8217c2013-11-09 00:03:26 -0800377{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800378 Data endorseData;
379 endorseData.wireDecode(data->getContent().blockFromValue());
Yingdi Yu76dd8002013-12-24 11:16:32 +0800380
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800381 EndorseCertificate endorseCertificate(endorseData);
382 m_contactStorage->updateCollectEndorse(endorseCertificate);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800383
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800384 decreaseCollectStatus();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800385}
Yingdi Yuae8217c2013-11-09 00:03:26 -0800386
387void
Yingdi Yu17032f82014-03-25 15:48:23 -0700388ContactManager::onDnsEndorseeValidationFailed(const shared_ptr<const Data>& data, const std::string& failInfo)
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700389{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800390 decreaseCollectStatus();
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700391}
392
Yingdi Yub2e747d2013-11-05 23:06:43 -0800393void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800394ContactManager::onDnsEndorseeTimeoutNotify(const Interest& interest)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800395{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800396 decreaseCollectStatus();
Yingdi Yub2e747d2013-11-05 23:06:43 -0800397}
398
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800399void
400ContactManager::decreaseCollectStatus()
Yingdi Yub2e747d2013-11-05 23:06:43 -0800401{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800402 int count;
403 {
404 boost::recursive_mutex::scoped_lock lock(m_collectCountMutex);
405 m_collectCount--;
406 count = m_collectCount;
407 }
Yingdi Yub2e747d2013-11-05 23:06:43 -0800408
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800409 if(count == 0)
410 publishCollectEndorsedDataInDNS();
411}
Yingdi Yub2e747d2013-11-05 23:06:43 -0800412
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800413void
414ContactManager::publishCollectEndorsedDataInDNS()
415{
416 Name dnsName = m_identity;
417 dnsName.append("DNS").append("ENDORSED").appendVersion();
Yingdi Yub2e747d2013-11-05 23:06:43 -0800418
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800419 Data data;
420 data.setName(dnsName);
421
422 EndorseCollection endorseCollection;
423 m_contactStorage->getCollectEndorse(endorseCollection);
424
425 OBufferStream os;
426 endorseCollection.SerializeToOstream(&os);
427
428 data.setContent(os.buf());
429 m_keyChain.signByIdentity(data, m_identity);
430
431 m_contactStorage->updateDnsOthersEndorse(data);
432 m_face->put(data);
433}
434
435void
436ContactManager::onIdentityCertValidated(const shared_ptr<const Data>& data)
437{
438 shared_ptr<IdentityCertificate> cert = make_shared<IdentityCertificate>(boost::cref(*data));
439 m_bufferedIdCerts[cert->getName()] = cert;
440 decreaseIdCertCount();
441}
442
443void
Yingdi Yu17032f82014-03-25 15:48:23 -0700444ContactManager::onIdentityCertValidationFailed(const shared_ptr<const Data>& data, const std::string& failInfo)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800445{
446 _LOG_DEBUG("ContactManager::onIdentityCertValidationFailed " << data->getName());
447 decreaseIdCertCount();
448}
449
450void
451ContactManager::onIdentityCertTimeoutNotify(const Interest& interest)
452{
453 _LOG_DEBUG("ContactManager::onIdentityCertTimeoutNotify: " << interest.getName());
454 decreaseIdCertCount();
455}
456
457void
458ContactManager::decreaseIdCertCount()
459{
460 int count;
461 {
462 boost::recursive_mutex::scoped_lock lock(m_idCertCountMutex);
463 m_idCertCount--;
464 count = m_idCertCount;
465 }
466
467 if(count == 0)
468 {
469 QStringList certNameList;
470 QStringList nameList;
471
472 BufferedIdCerts::const_iterator it = m_bufferedIdCerts.begin();
473 BufferedIdCerts::const_iterator end = m_bufferedIdCerts.end();
474 for(; it != end; it++)
475 {
476 certNameList << QString::fromStdString(it->second->getName().toUri());
477 Profile profile(*(it->second));
478 nameList << QString::fromStdString(profile.get("name"));
479 }
480
481 emit idCertNameListReady(certNameList);
482 emit nameListReady(nameList);
483 }
Yingdi Yub2e747d2013-11-05 23:06:43 -0800484}
485
Yingdi Yu76dd8002013-12-24 11:16:32 +0800486shared_ptr<EndorseCertificate>
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800487ContactManager::getSignedSelfEndorseCertificate(const Profile& profile)
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700488{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800489 Name certificateName = m_keyChain.getDefaultCertificateNameForIdentity(m_identity);
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700490
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800491 shared_ptr<IdentityCertificate> signingCert = m_keyChain.getCertificate(certificateName);
Yingdi Yu72781e52013-11-06 23:00:21 -0800492
Yingdi Yu17032f82014-03-25 15:48:23 -0700493 std::vector<std::string> endorseList;
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700494 Profile::const_iterator it = profile.begin();
495 for(; it != profile.end(); it++)
496 endorseList.push_back(it->first);
497
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800498 shared_ptr<EndorseCertificate> selfEndorseCertificate =
499 shared_ptr<EndorseCertificate>(new EndorseCertificate(*signingCert, profile, endorseList));
500
501 m_keyChain.sign(*selfEndorseCertificate, certificateName);
502
503 return selfEndorseCertificate;
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700504}
505
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700506void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800507ContactManager::publishSelfEndorseCertificateInDNS(const EndorseCertificate& selfEndorseCertificate)
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700508{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800509 Name dnsName = m_identity;
Yingdi Yufa4ce792014-02-06 18:09:22 -0800510 dnsName.append("DNS").append("PROFILE").appendVersion();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800511
512 Data data;
Yingdi Yu76dd8002013-12-24 11:16:32 +0800513 data.setName(dnsName);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800514 data.setContent(selfEndorseCertificate.wireEncode());
Yingdi Yua7876722014-03-25 14:46:55 -0700515 data.setFreshnessPeriod(time::milliseconds(1000));
Yingdi Yu76dd8002013-12-24 11:16:32 +0800516
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800517 m_keyChain.signByIdentity(data, m_identity);
518
519 m_contactStorage->updateDnsSelfProfileData(data);
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800520 m_face->put(data);
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700521}
522
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800523shared_ptr<EndorseCertificate>
524ContactManager::generateEndorseCertificate(const Name& identity)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800525{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800526 shared_ptr<Contact> contact = getContact(identity);
527 if(!static_cast<bool>(contact))
528 return shared_ptr<EndorseCertificate>();
Yingdi Yub2e747d2013-11-05 23:06:43 -0800529
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800530 Name signerKeyName = m_keyChain.getDefaultKeyNameForIdentity(m_identity);
531
Yingdi Yu17032f82014-03-25 15:48:23 -0700532 std::vector<std::string> endorseList;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800533 m_contactStorage->getEndorseList(identity, endorseList);
534
535 shared_ptr<EndorseCertificate> cert =
536 shared_ptr<EndorseCertificate>(new EndorseCertificate(contact->getPublicKeyName(),
537 contact->getPublicKey(),
538 contact->getNotBefore(),
539 contact->getNotAfter(),
540 signerKeyName,
541 contact->getProfile(),
542 endorseList));
543 m_keyChain.signByIdentity(*cert, m_identity);
544 return cert;
545
546}
547
548void
549ContactManager::publishEndorseCertificateInDNS(const EndorseCertificate& endorseCertificate)
550{
Yingdi Yufa4ce792014-02-06 18:09:22 -0800551 Name endorsee = endorseCertificate.getPublicKeyName().getPrefix(-1);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800552 Name dnsName = m_identity;
553 dnsName.append("DNS")
554 .append(endorsee.wireEncode())
555 .append("ENDORSEE")
556 .appendVersion();
Yingdi Yub2e747d2013-11-05 23:06:43 -0800557
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800558 Data data;
Yingdi Yu76dd8002013-12-24 11:16:32 +0800559 data.setName(dnsName);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800560 data.setContent(endorseCertificate.wireEncode());
Yingdi Yub2e747d2013-11-05 23:06:43 -0800561
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800562 m_keyChain.signByIdentity(data, m_identity);
563
564 m_contactStorage->updateDnsEndorseOthers(data, dnsName.get(-3).toEscapedString());
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800565 m_face->put(data);
Yingdi Yub2e747d2013-11-05 23:06:43 -0800566}
567
568void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800569ContactManager::sendInterest(const Interest& interest,
570 const OnDataValidated& onValidated,
571 const OnDataValidationFailed& onValidationFailed,
572 const TimeoutNotify& timeoutNotify,
573 int retry /* = 1 */)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800574{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800575 m_face->expressInterest(interest,
576 bind(&ContactManager::onTargetData,
577 this, _1, _2, onValidated, onValidationFailed),
578 bind(&ContactManager::onTargetTimeout,
579 this, _1, retry, onValidated, onValidationFailed, timeoutNotify));
580}
Yingdi Yu76dd8002013-12-24 11:16:32 +0800581
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800582void
583ContactManager::onTargetData(const Interest& interest,
584 const Data& data,
585 const OnDataValidated& onValidated,
586 const OnDataValidationFailed& onValidationFailed)
587{
588 // _LOG_DEBUG("On receiving data: " << data.getName());
589 m_validator->validate(data, onValidated, onValidationFailed);
590}
Yingdi Yub2e747d2013-11-05 23:06:43 -0800591
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800592void
593ContactManager::onTargetTimeout(const Interest& interest,
594 int retry,
595 const OnDataValidated& onValidated,
596 const OnDataValidationFailed& onValidationFailed,
597 const TimeoutNotify& timeoutNotify)
598{
599 // _LOG_DEBUG("On interest timeout: " << interest.getName());
600 if(retry > 0)
601 sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, retry-1);
602 else
603 timeoutNotify(interest);
604}
605
606void
607ContactManager::onDnsInterest(const Name& prefix, const Interest& interest)
608{
609 const Name& interestName = interest.getName();
610 shared_ptr<Data> data;
611
612 if(interestName.size() <= prefix.size())
613 return;
614
615 if(interestName.size() == (prefix.size()+1))
Yingdi Yub2e747d2013-11-05 23:06:43 -0800616 {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800617 data = m_contactStorage->getDnsData("N/A", interestName.get(prefix.size()).toEscapedString());
618 if(static_cast<bool>(data))
619 m_face->put(*data);
620 return;
Yingdi Yub2e747d2013-11-05 23:06:43 -0800621 }
Yingdi Yub2e747d2013-11-05 23:06:43 -0800622
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800623 if(interestName.size() == (prefix.size()+2))
624 {
625 data = m_contactStorage->getDnsData(interestName.get(prefix.size()).toEscapedString(),
626 interestName.get(prefix.size()+1).toEscapedString());
627 if(static_cast<bool>(data))
628 m_face->put(*data);
629 return;
630 }
631}
Yingdi Yub2e747d2013-11-05 23:06:43 -0800632
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800633void
Yingdi Yu17032f82014-03-25 15:48:23 -0700634ContactManager::onDnsRegisterFailed(const Name& prefix, const std::string& failInfo)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800635{
636 emit warning(QString(failInfo.c_str()));
637}
638
639
640// public slots
641void
642ContactManager::onIdentityUpdated(const QString& identity)
643{
644 m_identity = Name(identity.toStdString());
645
646 m_contactStorage = make_shared<ContactStorage>(m_identity);
647
648 if(m_dnsListenerId)
649 m_face->unsetInterestFilter(m_dnsListenerId);
650
651 Name dnsPrefix;
652 dnsPrefix.append(m_identity).append("DNS");
653 m_dnsListenerId = m_face->setInterestFilter(dnsPrefix,
654 bind(&ContactManager::onDnsInterest, this, _1, _2),
655 bind(&ContactManager::onDnsRegisterFailed, this, _1, _2));
656
657 m_contactList.clear();
658 m_contactStorage->getAllContacts(m_contactList);
659
660 m_bufferedContacts.clear();
661
662 collectEndorsement();
Yingdi Yub2e747d2013-11-05 23:06:43 -0800663}
664
Yingdi Yuae8217c2013-11-09 00:03:26 -0800665void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800666ContactManager::onFetchContactInfo(const QString& identity)
Yingdi Yuae8217c2013-11-09 00:03:26 -0800667{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800668 // try to fetch self-endorse-certificate via DNS PROFILE first.
669 Name identityName(identity.toStdString());
670 Name interestName;
671 interestName.append(identityName).append("DNS").append("PROFILE");
Yingdi Yu76dd8002013-12-24 11:16:32 +0800672
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800673 // _LOG_DEBUG("onFetchContactInfo " << identity.toStdString() << " profile: " << interestName);
674
675 Interest interest(interestName);
Yingdi Yua7876722014-03-25 14:46:55 -0700676 interest.setInterestLifetime(time::milliseconds(1000));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800677 interest.setMustBeFresh(true);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800678
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800679 OnDataValidated onValidated = bind(&ContactManager::onDnsSelfEndorseCertValidated, this, _1, identityName);
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700680 OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsSelfEndorseCertValidationFailed, this, _1, _2, identityName);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800681 TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsSelfEndorseCertTimeoutNotify, this, _1, identityName);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800682
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800683 sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
684}
Yingdi Yu76dd8002013-12-24 11:16:32 +0800685
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800686void
687ContactManager::onAddFetchedContact(const QString& identity)
688{
689 // _LOG_DEBUG("onAddFetchedContact");
690
691 Name identityName(identity.toStdString());
692
693 BufferedContacts::const_iterator it = m_bufferedContacts.find(identityName);
694 if(it != m_bufferedContacts.end())
695 {
696 Contact contact(*(it->second.m_selfEndorseCert));
697 // _LOG_DEBUG("onAddFetchedContact: contact ready");
698 try
699 {
700 m_contactStorage->addContact(contact);
701 m_bufferedContacts.erase(identityName);
702
703 m_contactList.clear();
704 m_contactStorage->getAllContacts(m_contactList);
705
706 onWaitForContactList();
707 }
708 catch(ContactStorage::Error& e)
709 {
710 emit warning(QString::fromStdString(e.what()));
711 }
712 }
713 else
714 {
715 emit warning(QString("Failure: no information of %1").arg(identity));
716 }
717}
718
719void
720ContactManager::onUpdateProfile()
721{
722 // Get current profile;
723 shared_ptr<Profile> newProfile = m_contactStorage->getSelfProfile();
724 if(!static_cast<bool>(newProfile))
Yingdi Yuae8217c2013-11-09 00:03:26 -0800725 return;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800726
727 _LOG_DEBUG("ContactManager::onUpdateProfile: getProfile");
728
729 shared_ptr<EndorseCertificate> newEndorseCertificate = getSignedSelfEndorseCertificate(*newProfile);
730
731 m_contactStorage->addSelfEndorseCertificate(*newEndorseCertificate);
732
733 publishSelfEndorseCertificateInDNS(*newEndorseCertificate);
734}
735
736void
737ContactManager::onRefreshBrowseContact()
738{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800739 std::vector<std::string> bufferedIdCertNames;
740 try
741 {
742 using namespace boost::asio::ip;
743 tcp::iostream request_stream;
744 request_stream.expires_from_now(boost::posix_time::milliseconds(5000));
745 request_stream.connect("ndncert.named-data.net","80");
746 if(!request_stream)
747 {
748 emit warning(QString::fromStdString("Fail to fetch certificate directory! #1"));
749 return;
750 }
751
752 request_stream << "GET /cert/list/ HTTP/1.0\r\n";
753 request_stream << "Host: ndncert.named-data.net\r\n\r\n";
754 request_stream.flush();
755
Yingdi Yu17032f82014-03-25 15:48:23 -0700756 std::string line1;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800757 std::getline(request_stream,line1);
758 if (!request_stream)
759 {
760 emit warning(QString::fromStdString("Fail to fetch certificate directory! #2"));
761 return;
762 }
763
764 std::stringstream response_stream(line1);
765 std::string http_version;
766 response_stream >> http_version;
767 unsigned int status_code;
768 response_stream >> status_code;
769 std::string status_message;
770 std::getline(response_stream,status_message);
771
772 if (!response_stream||http_version.substr(0,5)!="HTTP/")
773 {
774 emit warning(QString::fromStdString("Fail to fetch certificate directory! #3"));
775 return;
776 }
777 if (status_code!=200)
778 {
779 emit warning(QString::fromStdString("Fail to fetch certificate directory! #4"));
780 return;
781 }
Yingdi Yu17032f82014-03-25 15:48:23 -0700782 std::vector<std::string> headers;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800783 std::string header;
784 while (std::getline(request_stream, header) && header != "\r")
785 headers.push_back(header);
786
787 std::istreambuf_iterator<char> stream_iter (request_stream);
788 std::istreambuf_iterator<char> end_of_stream;
789
790 typedef boost::tokenizer< boost::escaped_list_separator<char>, std::istreambuf_iterator<char> > tokenizer_t;
791 tokenizer_t certItems (stream_iter, end_of_stream,boost::escaped_list_separator<char>('\\', '\n', '"'));
792
793 for (tokenizer_t::iterator it = certItems.begin(); it != certItems.end (); it++)
794 if (!it->empty())
795 bufferedIdCertNames.push_back(*it);
796 }
797 catch(std::exception &e)
798 {
799 emit warning(QString::fromStdString("Fail to fetch certificate directory! #N"));
800 }
801
802 {
803 boost::recursive_mutex::scoped_lock lock(m_idCertCountMutex);
804 m_idCertCount = bufferedIdCertNames.size();
Yingdi Yuae8217c2013-11-09 00:03:26 -0800805 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800806 m_bufferedIdCerts.clear();
807
808 std::vector<std::string>::const_iterator it = bufferedIdCertNames.begin();
809 std::vector<std::string>::const_iterator end = bufferedIdCertNames.end();
810 for(; it != end; it++)
811 {
812 Name certName(*it);
813
814 Interest interest(certName);
Yingdi Yua7876722014-03-25 14:46:55 -0700815 interest.setInterestLifetime(time::milliseconds(1000));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800816 interest.setMustBeFresh(true);
817
818 OnDataValidated onValidated = bind(&ContactManager::onIdentityCertValidated, this, _1);
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700819 OnDataValidationFailed onValidationFailed = bind(&ContactManager::onIdentityCertValidationFailed, this, _1, _2);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800820 TimeoutNotify timeoutNotify = bind(&ContactManager::onIdentityCertTimeoutNotify, this, _1);
821
822 sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
823 }
824
Yingdi Yuae8217c2013-11-09 00:03:26 -0800825}
826
Yingdi Yu72232692013-11-12 17:50:21 -0800827void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800828ContactManager::onFetchIdCert(const QString& qCertName)
Yingdi Yu72232692013-11-12 17:50:21 -0800829{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800830 Name certName(qCertName.toStdString());
831 if(m_bufferedIdCerts.find(certName) != m_bufferedIdCerts.end())
832 {
833 emit idCertReady(*m_bufferedIdCerts[certName]);
834 }
Yingdi Yu72232692013-11-12 17:50:21 -0800835}
Yingdi Yuae8217c2013-11-09 00:03:26 -0800836
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800837void
838ContactManager::onAddFetchedContactIdCert(const QString& qCertName)
839{
840 Name certName(qCertName.toStdString());
841 Name identity = IdentityCertificate::certificateNameToPublicKeyName(certName).getPrefix(-1);
842
843 BufferedIdCerts::const_iterator it = m_bufferedIdCerts.find(certName);
844 if(it != m_bufferedIdCerts.end())
845 {
846 Contact contact(*it->second);
847 try
848 {
849 m_contactStorage->addContact(contact);
850 m_bufferedIdCerts.erase(certName);
851
852 m_contactList.clear();
853 m_contactStorage->getAllContacts(m_contactList);
854
855 onWaitForContactList();
856 }
857 catch(ContactStorage::Error& e)
858 {
859 emit warning(QString::fromStdString(e.what()));
860 }
861 }
862 else
863 emit warning(QString("Failure: no information of %1").arg(QString::fromStdString(identity.toUri())));
864}
865
866void
867ContactManager::onWaitForContactList()
868{
869 ContactList::const_iterator it = m_contactList.begin();
870 ContactList::const_iterator end = m_contactList.end();
871
872 QStringList aliasList;
873 QStringList idList;
874 for(; it != end; it++)
875 {
876 aliasList << QString((*it)->getAlias().c_str());
877 idList << QString((*it)->getNameSpace().toUri().c_str());
878 }
879
880 emit contactAliasListReady(aliasList);
881 emit contactIdListReady(idList);
882}
883
884void
885ContactManager::onWaitForContactInfo(const QString& identity)
886{
887 ContactList::const_iterator it = m_contactList.begin();
888 ContactList::const_iterator end = m_contactList.end();
889
890 for(; it != end; it++)
891 if((*it)->getNameSpace().toUri() == identity.toStdString())
892 emit contactInfoReady(QString((*it)->getNameSpace().toUri().c_str()),
893 QString((*it)->getName().c_str()),
894 QString((*it)->getInstitution().c_str()),
895 (*it)->isIntroducer());
896}
897
898void
899ContactManager::onRemoveContact(const QString& identity)
900{
901 m_contactStorage->removeContact(Name(identity.toStdString()));
902 m_contactList.clear();
903 m_contactStorage->getAllContacts(m_contactList);
904
905 onWaitForContactList();
906}
907
908void
909ContactManager::onUpdateAlias(const QString& identity, const QString& alias)
910{
911 m_contactStorage->updateAlias(Name(identity.toStdString()), alias.toStdString());
912 m_contactList.clear();
913 m_contactStorage->getAllContacts(m_contactList);
914
915 onWaitForContactList();
916}
917
918void
919ContactManager::onUpdateIsIntroducer(const QString& identity, bool isIntroducer)
920{
921 m_contactStorage->updateIsIntroducer(Name(identity.toStdString()), isIntroducer);
922}
923
924void
925ContactManager::onUpdateEndorseCertificate(const QString& identity)
926{
927 Name identityName(identity.toStdString());
928 shared_ptr<EndorseCertificate> newEndorseCertificate = generateEndorseCertificate(identityName);
929
930 if(!static_cast<bool>(newEndorseCertificate))
931 return;
932
933 m_contactStorage->addEndorseCertificate(*newEndorseCertificate, identityName);
934
935 publishEndorseCertificateInDNS(*newEndorseCertificate);
936}
937
938} // namespace chronos
Yingdi Yufa4ce792014-02-06 18:09:22 -0800939
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700940
941#if WAF
942#include "contact-manager.moc"
943#include "contact-manager.cpp.moc"
944#endif