blob: 36a0705ceedc3be672017826bef610f56c326562 [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 Yu76dd8002013-12-24 11:16:32 +080035using namespace std;
Yingdi Yu348f5ea2014-03-01 14:47:25 -080036namespace fs = boost::filesystem;
Yingdi Yu9236c432013-10-18 11:29:25 -070037
Yingdi Yu348f5ea2014-03-01 14:47:25 -080038INIT_LOGGER("chronos.ContactManager");
Yingdi Yuec3d9a32013-10-18 18:35:09 -070039
Yingdi Yufa4ce792014-02-06 18:09:22 -080040namespace chronos{
Yingdi Yu4685b1b2013-10-18 17:05:02 -070041
Yingdi Yu348f5ea2014-03-01 14:47:25 -080042static const uint8_t DNS_RP_SEPARATOR[2] = {0xF0, 0x2E}; // %F0.
43
Yingdi Yufa4ce792014-02-06 18:09:22 -080044ContactManager::ContactManager(shared_ptr<Face> face,
45 QObject* parent)
46 : QObject(parent)
Yingdi Yufa4ce792014-02-06 18:09:22 -080047 , m_face(face)
Yingdi Yu348f5ea2014-03-01 14:47:25 -080048 , m_dnsListenerId(0)
Yingdi Yufa4ce792014-02-06 18:09:22 -080049{
Yingdi Yu76dd8002013-12-24 11:16:32 +080050 initializeSecurity();
Yingdi Yu9236c432013-10-18 11:29:25 -070051}
52
53ContactManager::~ContactManager()
Yingdi Yu6eabbd72013-12-27 08:44:12 +080054{}
Yingdi Yu9236c432013-10-18 11:29:25 -070055
Yingdi Yu348f5ea2014-03-01 14:47:25 -080056// private methods
Yingdi Yu06f572b2014-03-11 15:46:10 -070057shared_ptr<IdentityCertificate>
58ContactManager::loadTrustAnchor()
59{
60 shared_ptr<IdentityCertificate> anchor;
61
62 QFile anchorFile(":/security/anchor.cert");
63
64 if (!anchorFile.open(QIODevice::ReadOnly))
65 {
66 emit warning(QString("Cannot load trust anchor!"));
67
68 return anchor;
69 }
70
71 qint64 fileSize = anchorFile.size();
72 char* buf = new char[fileSize];
73 anchorFile.read(buf, fileSize);
74
75 try
76 {
77 using namespace CryptoPP;
78
79 OBufferStream os;
80 StringSource(reinterpret_cast<const uint8_t*>(buf), fileSize, true, new Base64Decoder(new FileSink(os)));
81 anchor = make_shared<IdentityCertificate>();
82 anchor->wireDecode(Block(os.buf()));
83 }
84 catch(CryptoPP::Exception& e)
85 {
86 emit warning(QString("Cannot load trust anchor!"));
87 }
88 catch(IdentityCertificate::Error& e)
89 {
90 emit warning(QString("Cannot load trust anchor!"));
91 }
92 catch(Block::Error& e)
93 {
94 emit warning(QString("Cannot load trust anchor!"));
95 }
96
97 delete [] buf;
98
99 return anchor;
100}
101
Yingdi Yu76dd8002013-12-24 11:16:32 +0800102void
103ContactManager::initializeSecurity()
104{
Yingdi Yu06f572b2014-03-11 15:46:10 -0700105 shared_ptr<IdentityCertificate> anchor = loadTrustAnchor();
Yingdi Yufa4ce792014-02-06 18:09:22 -0800106
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800107 shared_ptr<ValidatorRegex> validator = make_shared<ValidatorRegex>(m_face);
108 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><ENDORSED>",
109 "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
110 "==", "\\1", "\\1\\2", true));
111 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><><ENDORSEE>",
112 "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
113 "==", "\\1", "\\1\\2", true));
114 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><PROFILE>",
115 "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
116 "==", "\\1", "\\1\\2", true));
117 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<PROFILE-CERT>]*)<PROFILE-CERT>",
118 "^([^<KEY>]*)<KEY>(<>*<ksk-.*>)<ID-CERT>$",
119 "==", "\\1", "\\1\\2", true));
120 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>",
121 "^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>$",
122 ">", "\\1\\2", "\\1", true));
123 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>",
124 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
125 "==", "\\1", "\\1\\2", true));
126 validator->addDataVerificationRule(make_shared<SecRuleRelative>("^(<>*)$",
127 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
128 ">", "\\1", "\\1\\2", true));
129 validator->addTrustAnchor(anchor);
130 m_validator = validator;
Yingdi Yu76dd8002013-12-24 11:16:32 +0800131}
132
133void
Yingdi Yufa4ce792014-02-06 18:09:22 -0800134ContactManager::fetchCollectEndorse(const Name& identity)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800135{
136 Name interestName = identity;
137 interestName.append("DNS").append("ENDORSED");
138
Yingdi Yu76dd8002013-12-24 11:16:32 +0800139 Interest interest(interestName);
Yingdi Yua7876722014-03-25 14:46:55 -0700140 interest.setInterestLifetime(time::milliseconds(1000));
Yingdi Yufa4ce792014-02-06 18:09:22 -0800141 interest.setMustBeFresh(true);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800142
Yingdi Yufa4ce792014-02-06 18:09:22 -0800143 OnDataValidated onValidated = bind(&ContactManager::onDnsCollectEndorseValidated, this, _1, identity);
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700144 OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsCollectEndorseValidationFailed, this, _1, _2, identity);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800145 TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsCollectEndorseTimeoutNotify, this, _1, identity);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800146
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800147 sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
Yingdi Yub2e747d2013-11-05 23:06:43 -0800148}
149
150void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800151ContactManager::fetchEndorseCertificateInternal(const Name& identity, int certIndex)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800152{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800153 shared_ptr<EndorseCollection> endorseCollection = m_bufferedContacts[identity].m_endorseCollection;
154
155 if(certIndex >= endorseCollection->endorsement_size())
156 prepareEndorseInfo(identity);
157
158 Name interestName(endorseCollection->endorsement(certIndex).certname());
159
Yingdi Yu76dd8002013-12-24 11:16:32 +0800160 Interest interest(interestName);
Yingdi Yua7876722014-03-25 14:46:55 -0700161 interest.setInterestLifetime(time::milliseconds(1000));
Yingdi Yufa4ce792014-02-06 18:09:22 -0800162 interest.setMustBeFresh(true);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800163
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800164 m_face->expressInterest(interest,
165 bind(&ContactManager::onEndorseCertificateInternal,
166 this, _1, _2, identity, certIndex,
167 endorseCollection->endorsement(certIndex).hash()),
168 bind(&ContactManager::onEndorseCertificateInternalTimeout,
169 this, _1, identity, certIndex));
Yingdi Yu76dd8002013-12-24 11:16:32 +0800170}
171
Yingdi Yu76dd8002013-12-24 11:16:32 +0800172void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800173ContactManager::prepareEndorseInfo(const Name& identity)
Yingdi Yu76dd8002013-12-24 11:16:32 +0800174{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800175 // _LOG_DEBUG("prepareEndorseInfo");
176 const Profile& profile = m_bufferedContacts[identity].m_selfEndorseCert->getProfile();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800177
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800178 shared_ptr<EndorseInfo> endorseInfo = make_shared<EndorseInfo>();
179 m_bufferedContacts[identity].m_endorseInfo = endorseInfo;
180
181 Profile::const_iterator pIt = profile.begin();
182 Profile::const_iterator pEnd = profile.end();
183
184 map<string, int> endorseCount;
185 for(; pIt != pEnd; pIt++)
186 {
187 // _LOG_DEBUG("prepareEndorseInfo: profile[" << pIt->first << "]: " << pIt->second);
188 endorseCount[pIt->first] = 0;
189 }
190
191 int endorseCertCount = 0;
192
193 vector<shared_ptr<EndorseCertificate> >::const_iterator cIt = m_bufferedContacts[identity].m_endorseCertList.begin();
194 vector<shared_ptr<EndorseCertificate> >::const_iterator cEnd = m_bufferedContacts[identity].m_endorseCertList.end();
195
196 for(; cIt != cEnd; cIt++, endorseCertCount++)
197 {
198 shared_ptr<Contact> contact = getContact((*cIt)->getSigner().getPrefix(-1));
199 if(!static_cast<bool>(contact))
200 continue;
201
202 if(!contact->isIntroducer()
203 || !contact->canBeTrustedFor(profile.getIdentityName()))
204 continue;
205
206 if(!Validator::verifySignature(**cIt, contact->getPublicKey()))
207 continue;
208
209 const Profile& tmpProfile = (*cIt)->getProfile();
210 if(tmpProfile != profile)
211 continue;
212
213 const vector<string>& endorseList = (*cIt)->getEndorseList();
214 vector<string>::const_iterator eIt = endorseList.begin();
215 for(; eIt != endorseList.end(); eIt++)
216 endorseCount[*eIt] += 1;
217 }
218
219 pIt = profile.begin();
220 pEnd = profile.end();
221 for(; pIt != pEnd; pIt++)
222 {
223 EndorseInfo::Endorsement* endorsement = endorseInfo->add_endorsement();
224 endorsement->set_type(pIt->first);
225 endorsement->set_value(pIt->second);
226 stringstream ss;
227 ss << endorseCount[pIt->first] << "/" << endorseCertCount;
228 endorsement->set_endorse(ss.str());
229 }
230
231 emit contactEndorseInfoReady (*endorseInfo);
232}
233
234void
235ContactManager::onDnsSelfEndorseCertValidated(const shared_ptr<const Data>& data,
236 const Name& identity)
237{
238 try
239 {
240 Data plainData;
241 plainData.wireDecode(data->getContent().blockFromValue());
242 shared_ptr<EndorseCertificate> selfEndorseCertificate = make_shared<EndorseCertificate>(boost::cref(plainData));
243 if(Validator::verifySignature(plainData, selfEndorseCertificate->getPublicKeyInfo()))
244 {
245 m_bufferedContacts[identity].m_selfEndorseCert = selfEndorseCertificate;
246 fetchCollectEndorse(identity);
247 }
248 else
249 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
250 }
251 catch(Block::Error& e)
252 {
253 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
254 }
255 catch(Data::Error& e)
256 {
257 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
258 }
259 catch(EndorseCertificate::Error& e)
260 {
261 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
262 }
263}
264
265void
266ContactManager::onDnsSelfEndorseCertValidationFailed(const shared_ptr<const Data>& data,
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700267 const string& failInfo,
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800268 const Name& identity)
269{
270 // If we cannot validate the Self-Endorse-Certificate, we may retry or fetch id-cert,
271 // but let's stay with failure for now.
272 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
273}
274
275void
276ContactManager::onDnsSelfEndorseCertTimeoutNotify(const Interest& interest,
277 const Name& identity)
278{
279 // If we cannot validate the Self-Endorse-Certificate, we may retry or fetch id-cert,
280 // but let's stay with failure for now.
281 emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
282}
283
284void
285ContactManager::onDnsCollectEndorseValidated(const shared_ptr<const Data>& data,
286 const Name& identity)
287{
288 shared_ptr<EndorseCollection> endorseCollection = make_shared<EndorseCollection>();
289 if(!endorseCollection->ParseFromArray(data->getContent().value(), data->getContent().value_size()))
290 {
291 m_bufferedContacts[identity].m_endorseCollection = endorseCollection;
292 fetchEndorseCertificateInternal(identity, 0);
293 }
294 else
295 prepareEndorseInfo(identity);
296}
297
298void
299ContactManager::onDnsCollectEndorseValidationFailed(const shared_ptr<const Data>& data,
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700300 const string& failInfo,
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800301 const Name& identity)
302{
303 prepareEndorseInfo(identity);
304}
305
306void
307ContactManager::onDnsCollectEndorseTimeoutNotify(const Interest& interest,
308 const Name& identity)
309{
310 // _LOG_DEBUG("onDnsCollectEndorseTimeoutNotify: " << interest.getName());
311 prepareEndorseInfo(identity);
312}
313
314void
315ContactManager::onEndorseCertificateInternal(const Interest& interest,
316 Data& data,
317 const Name& identity,
318 int certIndex,
319 string hash)
320{
321 stringstream ss;
322 {
323 using namespace CryptoPP;
324
325 SHA256 hash;
326 StringSource(data.wireEncode().wire(), data.wireEncode().size(), true,
327 new HashFilter(hash, new FileSink(ss)));
328 }
329
330 if(ss.str() == hash)
331 {
332 shared_ptr<EndorseCertificate> endorseCertificate = make_shared<EndorseCertificate>(boost::cref(data));
333 m_bufferedContacts[identity].m_endorseCertList.push_back(endorseCertificate);
334 }
335
336 fetchEndorseCertificateInternal(identity, certIndex+1);
337}
338
339void
340ContactManager::onEndorseCertificateInternalTimeout(const Interest& interest,
341 const Name& identity,
342 int certIndex)
343{
344 fetchEndorseCertificateInternal(identity, certIndex+1);
345}
346
347void
348ContactManager::collectEndorsement()
349{
350 {
351 boost::recursive_mutex::scoped_lock lock(m_collectCountMutex);
352 m_collectCount = m_contactList.size();
353
354 ContactList::iterator it = m_contactList.begin();
355 ContactList::iterator end = m_contactList.end();
356
357 for(; it != end ; it++)
358 {
359 Name interestName = (*it)->getNameSpace();
360 interestName.append("DNS").append(m_identity.wireEncode()).append("ENDORSEE");
361
362 Interest interest(interestName);
Yingdi Yua7876722014-03-25 14:46:55 -0700363 interest.setInterestLifetime(time::milliseconds(1000));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800364
365 OnDataValidated onValidated = bind(&ContactManager::onDnsEndorseeValidated, this, _1);
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700366 OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsEndorseeValidationFailed, this, _1, _2);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800367 TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsEndorseeTimeoutNotify, this, _1);
368
369 sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
370 }
Yingdi Yu76dd8002013-12-24 11:16:32 +0800371 }
372}
373
374void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800375ContactManager::onDnsEndorseeValidated(const shared_ptr<const Data>& data)
Yingdi Yuae8217c2013-11-09 00:03:26 -0800376{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800377 Data endorseData;
378 endorseData.wireDecode(data->getContent().blockFromValue());
Yingdi Yu76dd8002013-12-24 11:16:32 +0800379
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800380 EndorseCertificate endorseCertificate(endorseData);
381 m_contactStorage->updateCollectEndorse(endorseCertificate);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800382
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800383 decreaseCollectStatus();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800384}
Yingdi Yuae8217c2013-11-09 00:03:26 -0800385
386void
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700387ContactManager::onDnsEndorseeValidationFailed(const shared_ptr<const Data>& data, const string& failInfo)
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700388{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800389 decreaseCollectStatus();
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700390}
391
Yingdi Yub2e747d2013-11-05 23:06:43 -0800392void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800393ContactManager::onDnsEndorseeTimeoutNotify(const Interest& interest)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800394{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800395 decreaseCollectStatus();
Yingdi Yub2e747d2013-11-05 23:06:43 -0800396}
397
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800398void
399ContactManager::decreaseCollectStatus()
Yingdi Yub2e747d2013-11-05 23:06:43 -0800400{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800401 int count;
402 {
403 boost::recursive_mutex::scoped_lock lock(m_collectCountMutex);
404 m_collectCount--;
405 count = m_collectCount;
406 }
Yingdi Yub2e747d2013-11-05 23:06:43 -0800407
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800408 if(count == 0)
409 publishCollectEndorsedDataInDNS();
410}
Yingdi Yub2e747d2013-11-05 23:06:43 -0800411
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800412void
413ContactManager::publishCollectEndorsedDataInDNS()
414{
415 Name dnsName = m_identity;
416 dnsName.append("DNS").append("ENDORSED").appendVersion();
Yingdi Yub2e747d2013-11-05 23:06:43 -0800417
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800418 Data data;
419 data.setName(dnsName);
420
421 EndorseCollection endorseCollection;
422 m_contactStorage->getCollectEndorse(endorseCollection);
423
424 OBufferStream os;
425 endorseCollection.SerializeToOstream(&os);
426
427 data.setContent(os.buf());
428 m_keyChain.signByIdentity(data, m_identity);
429
430 m_contactStorage->updateDnsOthersEndorse(data);
431 m_face->put(data);
432}
433
434void
435ContactManager::onIdentityCertValidated(const shared_ptr<const Data>& data)
436{
437 shared_ptr<IdentityCertificate> cert = make_shared<IdentityCertificate>(boost::cref(*data));
438 m_bufferedIdCerts[cert->getName()] = cert;
439 decreaseIdCertCount();
440}
441
442void
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700443ContactManager::onIdentityCertValidationFailed(const shared_ptr<const Data>& data, const string& failInfo)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800444{
445 _LOG_DEBUG("ContactManager::onIdentityCertValidationFailed " << data->getName());
446 decreaseIdCertCount();
447}
448
449void
450ContactManager::onIdentityCertTimeoutNotify(const Interest& interest)
451{
452 _LOG_DEBUG("ContactManager::onIdentityCertTimeoutNotify: " << interest.getName());
453 decreaseIdCertCount();
454}
455
456void
457ContactManager::decreaseIdCertCount()
458{
459 int count;
460 {
461 boost::recursive_mutex::scoped_lock lock(m_idCertCountMutex);
462 m_idCertCount--;
463 count = m_idCertCount;
464 }
465
466 if(count == 0)
467 {
468 QStringList certNameList;
469 QStringList nameList;
470
471 BufferedIdCerts::const_iterator it = m_bufferedIdCerts.begin();
472 BufferedIdCerts::const_iterator end = m_bufferedIdCerts.end();
473 for(; it != end; it++)
474 {
475 certNameList << QString::fromStdString(it->second->getName().toUri());
476 Profile profile(*(it->second));
477 nameList << QString::fromStdString(profile.get("name"));
478 }
479
480 emit idCertNameListReady(certNameList);
481 emit nameListReady(nameList);
482 }
Yingdi Yub2e747d2013-11-05 23:06:43 -0800483}
484
Yingdi Yu76dd8002013-12-24 11:16:32 +0800485shared_ptr<EndorseCertificate>
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800486ContactManager::getSignedSelfEndorseCertificate(const Profile& profile)
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700487{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800488 Name certificateName = m_keyChain.getDefaultCertificateNameForIdentity(m_identity);
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700489
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800490 shared_ptr<IdentityCertificate> signingCert = m_keyChain.getCertificate(certificateName);
Yingdi Yu72781e52013-11-06 23:00:21 -0800491
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700492 vector<string> endorseList;
493 Profile::const_iterator it = profile.begin();
494 for(; it != profile.end(); it++)
495 endorseList.push_back(it->first);
496
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800497 shared_ptr<EndorseCertificate> selfEndorseCertificate =
498 shared_ptr<EndorseCertificate>(new EndorseCertificate(*signingCert, profile, endorseList));
499
500 m_keyChain.sign(*selfEndorseCertificate, certificateName);
501
502 return selfEndorseCertificate;
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700503}
504
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700505void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800506ContactManager::publishSelfEndorseCertificateInDNS(const EndorseCertificate& selfEndorseCertificate)
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700507{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800508 Name dnsName = m_identity;
Yingdi Yufa4ce792014-02-06 18:09:22 -0800509 dnsName.append("DNS").append("PROFILE").appendVersion();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800510
511 Data data;
Yingdi Yu76dd8002013-12-24 11:16:32 +0800512 data.setName(dnsName);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800513 data.setContent(selfEndorseCertificate.wireEncode());
Yingdi Yua7876722014-03-25 14:46:55 -0700514 data.setFreshnessPeriod(time::milliseconds(1000));
Yingdi Yu76dd8002013-12-24 11:16:32 +0800515
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800516 m_keyChain.signByIdentity(data, m_identity);
517
518 m_contactStorage->updateDnsSelfProfileData(data);
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800519 m_face->put(data);
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700520}
521
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800522shared_ptr<EndorseCertificate>
523ContactManager::generateEndorseCertificate(const Name& identity)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800524{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800525 shared_ptr<Contact> contact = getContact(identity);
526 if(!static_cast<bool>(contact))
527 return shared_ptr<EndorseCertificate>();
Yingdi Yub2e747d2013-11-05 23:06:43 -0800528
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800529 Name signerKeyName = m_keyChain.getDefaultKeyNameForIdentity(m_identity);
530
531 vector<string> endorseList;
532 m_contactStorage->getEndorseList(identity, endorseList);
533
534 shared_ptr<EndorseCertificate> cert =
535 shared_ptr<EndorseCertificate>(new EndorseCertificate(contact->getPublicKeyName(),
536 contact->getPublicKey(),
537 contact->getNotBefore(),
538 contact->getNotAfter(),
539 signerKeyName,
540 contact->getProfile(),
541 endorseList));
542 m_keyChain.signByIdentity(*cert, m_identity);
543 return cert;
544
545}
546
547void
548ContactManager::publishEndorseCertificateInDNS(const EndorseCertificate& endorseCertificate)
549{
Yingdi Yufa4ce792014-02-06 18:09:22 -0800550 Name endorsee = endorseCertificate.getPublicKeyName().getPrefix(-1);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800551 Name dnsName = m_identity;
552 dnsName.append("DNS")
553 .append(endorsee.wireEncode())
554 .append("ENDORSEE")
555 .appendVersion();
Yingdi Yub2e747d2013-11-05 23:06:43 -0800556
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800557 Data data;
Yingdi Yu76dd8002013-12-24 11:16:32 +0800558 data.setName(dnsName);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800559 data.setContent(endorseCertificate.wireEncode());
Yingdi Yub2e747d2013-11-05 23:06:43 -0800560
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800561 m_keyChain.signByIdentity(data, m_identity);
562
563 m_contactStorage->updateDnsEndorseOthers(data, dnsName.get(-3).toEscapedString());
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800564 m_face->put(data);
Yingdi Yub2e747d2013-11-05 23:06:43 -0800565}
566
567void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800568ContactManager::sendInterest(const Interest& interest,
569 const OnDataValidated& onValidated,
570 const OnDataValidationFailed& onValidationFailed,
571 const TimeoutNotify& timeoutNotify,
572 int retry /* = 1 */)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800573{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800574 m_face->expressInterest(interest,
575 bind(&ContactManager::onTargetData,
576 this, _1, _2, onValidated, onValidationFailed),
577 bind(&ContactManager::onTargetTimeout,
578 this, _1, retry, onValidated, onValidationFailed, timeoutNotify));
579}
Yingdi Yu76dd8002013-12-24 11:16:32 +0800580
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800581void
582ContactManager::onTargetData(const Interest& interest,
583 const Data& data,
584 const OnDataValidated& onValidated,
585 const OnDataValidationFailed& onValidationFailed)
586{
587 // _LOG_DEBUG("On receiving data: " << data.getName());
588 m_validator->validate(data, onValidated, onValidationFailed);
589}
Yingdi Yub2e747d2013-11-05 23:06:43 -0800590
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800591void
592ContactManager::onTargetTimeout(const Interest& interest,
593 int retry,
594 const OnDataValidated& onValidated,
595 const OnDataValidationFailed& onValidationFailed,
596 const TimeoutNotify& timeoutNotify)
597{
598 // _LOG_DEBUG("On interest timeout: " << interest.getName());
599 if(retry > 0)
600 sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, retry-1);
601 else
602 timeoutNotify(interest);
603}
604
605void
606ContactManager::onDnsInterest(const Name& prefix, const Interest& interest)
607{
608 const Name& interestName = interest.getName();
609 shared_ptr<Data> data;
610
611 if(interestName.size() <= prefix.size())
612 return;
613
614 if(interestName.size() == (prefix.size()+1))
Yingdi Yub2e747d2013-11-05 23:06:43 -0800615 {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800616 data = m_contactStorage->getDnsData("N/A", interestName.get(prefix.size()).toEscapedString());
617 if(static_cast<bool>(data))
618 m_face->put(*data);
619 return;
Yingdi Yub2e747d2013-11-05 23:06:43 -0800620 }
Yingdi Yub2e747d2013-11-05 23:06:43 -0800621
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800622 if(interestName.size() == (prefix.size()+2))
623 {
624 data = m_contactStorage->getDnsData(interestName.get(prefix.size()).toEscapedString(),
625 interestName.get(prefix.size()+1).toEscapedString());
626 if(static_cast<bool>(data))
627 m_face->put(*data);
628 return;
629 }
630}
Yingdi Yub2e747d2013-11-05 23:06:43 -0800631
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800632void
633ContactManager::onDnsRegisterFailed(const Name& prefix, const string& failInfo)
634{
635 emit warning(QString(failInfo.c_str()));
636}
637
638
639// public slots
640void
641ContactManager::onIdentityUpdated(const QString& identity)
642{
643 m_identity = Name(identity.toStdString());
644
645 m_contactStorage = make_shared<ContactStorage>(m_identity);
646
647 if(m_dnsListenerId)
648 m_face->unsetInterestFilter(m_dnsListenerId);
649
650 Name dnsPrefix;
651 dnsPrefix.append(m_identity).append("DNS");
652 m_dnsListenerId = m_face->setInterestFilter(dnsPrefix,
653 bind(&ContactManager::onDnsInterest, this, _1, _2),
654 bind(&ContactManager::onDnsRegisterFailed, this, _1, _2));
655
656 m_contactList.clear();
657 m_contactStorage->getAllContacts(m_contactList);
658
659 m_bufferedContacts.clear();
660
661 collectEndorsement();
Yingdi Yub2e747d2013-11-05 23:06:43 -0800662}
663
Yingdi Yuae8217c2013-11-09 00:03:26 -0800664void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800665ContactManager::onFetchContactInfo(const QString& identity)
Yingdi Yuae8217c2013-11-09 00:03:26 -0800666{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800667 // try to fetch self-endorse-certificate via DNS PROFILE first.
668 Name identityName(identity.toStdString());
669 Name interestName;
670 interestName.append(identityName).append("DNS").append("PROFILE");
Yingdi Yu76dd8002013-12-24 11:16:32 +0800671
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800672 // _LOG_DEBUG("onFetchContactInfo " << identity.toStdString() << " profile: " << interestName);
673
674 Interest interest(interestName);
Yingdi Yua7876722014-03-25 14:46:55 -0700675 interest.setInterestLifetime(time::milliseconds(1000));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800676 interest.setMustBeFresh(true);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800677
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800678 OnDataValidated onValidated = bind(&ContactManager::onDnsSelfEndorseCertValidated, this, _1, identityName);
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700679 OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsSelfEndorseCertValidationFailed, this, _1, _2, identityName);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800680 TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsSelfEndorseCertTimeoutNotify, this, _1, identityName);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800681
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800682 sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
683}
Yingdi Yu76dd8002013-12-24 11:16:32 +0800684
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800685void
686ContactManager::onAddFetchedContact(const QString& identity)
687{
688 // _LOG_DEBUG("onAddFetchedContact");
689
690 Name identityName(identity.toStdString());
691
692 BufferedContacts::const_iterator it = m_bufferedContacts.find(identityName);
693 if(it != m_bufferedContacts.end())
694 {
695 Contact contact(*(it->second.m_selfEndorseCert));
696 // _LOG_DEBUG("onAddFetchedContact: contact ready");
697 try
698 {
699 m_contactStorage->addContact(contact);
700 m_bufferedContacts.erase(identityName);
701
702 m_contactList.clear();
703 m_contactStorage->getAllContacts(m_contactList);
704
705 onWaitForContactList();
706 }
707 catch(ContactStorage::Error& e)
708 {
709 emit warning(QString::fromStdString(e.what()));
710 }
711 }
712 else
713 {
714 emit warning(QString("Failure: no information of %1").arg(identity));
715 }
716}
717
718void
719ContactManager::onUpdateProfile()
720{
721 // Get current profile;
722 shared_ptr<Profile> newProfile = m_contactStorage->getSelfProfile();
723 if(!static_cast<bool>(newProfile))
Yingdi Yuae8217c2013-11-09 00:03:26 -0800724 return;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800725
726 _LOG_DEBUG("ContactManager::onUpdateProfile: getProfile");
727
728 shared_ptr<EndorseCertificate> newEndorseCertificate = getSignedSelfEndorseCertificate(*newProfile);
729
730 m_contactStorage->addSelfEndorseCertificate(*newEndorseCertificate);
731
732 publishSelfEndorseCertificateInDNS(*newEndorseCertificate);
733}
734
735void
736ContactManager::onRefreshBrowseContact()
737{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800738 std::vector<std::string> bufferedIdCertNames;
739 try
740 {
741 using namespace boost::asio::ip;
742 tcp::iostream request_stream;
743 request_stream.expires_from_now(boost::posix_time::milliseconds(5000));
744 request_stream.connect("ndncert.named-data.net","80");
745 if(!request_stream)
746 {
747 emit warning(QString::fromStdString("Fail to fetch certificate directory! #1"));
748 return;
749 }
750
751 request_stream << "GET /cert/list/ HTTP/1.0\r\n";
752 request_stream << "Host: ndncert.named-data.net\r\n\r\n";
753 request_stream.flush();
754
755 string line1;
756 std::getline(request_stream,line1);
757 if (!request_stream)
758 {
759 emit warning(QString::fromStdString("Fail to fetch certificate directory! #2"));
760 return;
761 }
762
763 std::stringstream response_stream(line1);
764 std::string http_version;
765 response_stream >> http_version;
766 unsigned int status_code;
767 response_stream >> status_code;
768 std::string status_message;
769 std::getline(response_stream,status_message);
770
771 if (!response_stream||http_version.substr(0,5)!="HTTP/")
772 {
773 emit warning(QString::fromStdString("Fail to fetch certificate directory! #3"));
774 return;
775 }
776 if (status_code!=200)
777 {
778 emit warning(QString::fromStdString("Fail to fetch certificate directory! #4"));
779 return;
780 }
781 vector<string> headers;
782 std::string header;
783 while (std::getline(request_stream, header) && header != "\r")
784 headers.push_back(header);
785
786 std::istreambuf_iterator<char> stream_iter (request_stream);
787 std::istreambuf_iterator<char> end_of_stream;
788
789 typedef boost::tokenizer< boost::escaped_list_separator<char>, std::istreambuf_iterator<char> > tokenizer_t;
790 tokenizer_t certItems (stream_iter, end_of_stream,boost::escaped_list_separator<char>('\\', '\n', '"'));
791
792 for (tokenizer_t::iterator it = certItems.begin(); it != certItems.end (); it++)
793 if (!it->empty())
794 bufferedIdCertNames.push_back(*it);
795 }
796 catch(std::exception &e)
797 {
798 emit warning(QString::fromStdString("Fail to fetch certificate directory! #N"));
799 }
800
801 {
802 boost::recursive_mutex::scoped_lock lock(m_idCertCountMutex);
803 m_idCertCount = bufferedIdCertNames.size();
Yingdi Yuae8217c2013-11-09 00:03:26 -0800804 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800805 m_bufferedIdCerts.clear();
806
807 std::vector<std::string>::const_iterator it = bufferedIdCertNames.begin();
808 std::vector<std::string>::const_iterator end = bufferedIdCertNames.end();
809 for(; it != end; it++)
810 {
811 Name certName(*it);
812
813 Interest interest(certName);
Yingdi Yua7876722014-03-25 14:46:55 -0700814 interest.setInterestLifetime(time::milliseconds(1000));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800815 interest.setMustBeFresh(true);
816
817 OnDataValidated onValidated = bind(&ContactManager::onIdentityCertValidated, this, _1);
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700818 OnDataValidationFailed onValidationFailed = bind(&ContactManager::onIdentityCertValidationFailed, this, _1, _2);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800819 TimeoutNotify timeoutNotify = bind(&ContactManager::onIdentityCertTimeoutNotify, this, _1);
820
821 sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
822 }
823
Yingdi Yuae8217c2013-11-09 00:03:26 -0800824}
825
Yingdi Yu72232692013-11-12 17:50:21 -0800826void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800827ContactManager::onFetchIdCert(const QString& qCertName)
Yingdi Yu72232692013-11-12 17:50:21 -0800828{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800829 Name certName(qCertName.toStdString());
830 if(m_bufferedIdCerts.find(certName) != m_bufferedIdCerts.end())
831 {
832 emit idCertReady(*m_bufferedIdCerts[certName]);
833 }
Yingdi Yu72232692013-11-12 17:50:21 -0800834}
Yingdi Yuae8217c2013-11-09 00:03:26 -0800835
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800836void
837ContactManager::onAddFetchedContactIdCert(const QString& qCertName)
838{
839 Name certName(qCertName.toStdString());
840 Name identity = IdentityCertificate::certificateNameToPublicKeyName(certName).getPrefix(-1);
841
842 BufferedIdCerts::const_iterator it = m_bufferedIdCerts.find(certName);
843 if(it != m_bufferedIdCerts.end())
844 {
845 Contact contact(*it->second);
846 try
847 {
848 m_contactStorage->addContact(contact);
849 m_bufferedIdCerts.erase(certName);
850
851 m_contactList.clear();
852 m_contactStorage->getAllContacts(m_contactList);
853
854 onWaitForContactList();
855 }
856 catch(ContactStorage::Error& e)
857 {
858 emit warning(QString::fromStdString(e.what()));
859 }
860 }
861 else
862 emit warning(QString("Failure: no information of %1").arg(QString::fromStdString(identity.toUri())));
863}
864
865void
866ContactManager::onWaitForContactList()
867{
868 ContactList::const_iterator it = m_contactList.begin();
869 ContactList::const_iterator end = m_contactList.end();
870
871 QStringList aliasList;
872 QStringList idList;
873 for(; it != end; it++)
874 {
875 aliasList << QString((*it)->getAlias().c_str());
876 idList << QString((*it)->getNameSpace().toUri().c_str());
877 }
878
879 emit contactAliasListReady(aliasList);
880 emit contactIdListReady(idList);
881}
882
883void
884ContactManager::onWaitForContactInfo(const QString& identity)
885{
886 ContactList::const_iterator it = m_contactList.begin();
887 ContactList::const_iterator end = m_contactList.end();
888
889 for(; it != end; it++)
890 if((*it)->getNameSpace().toUri() == identity.toStdString())
891 emit contactInfoReady(QString((*it)->getNameSpace().toUri().c_str()),
892 QString((*it)->getName().c_str()),
893 QString((*it)->getInstitution().c_str()),
894 (*it)->isIntroducer());
895}
896
897void
898ContactManager::onRemoveContact(const QString& identity)
899{
900 m_contactStorage->removeContact(Name(identity.toStdString()));
901 m_contactList.clear();
902 m_contactStorage->getAllContacts(m_contactList);
903
904 onWaitForContactList();
905}
906
907void
908ContactManager::onUpdateAlias(const QString& identity, const QString& alias)
909{
910 m_contactStorage->updateAlias(Name(identity.toStdString()), alias.toStdString());
911 m_contactList.clear();
912 m_contactStorage->getAllContacts(m_contactList);
913
914 onWaitForContactList();
915}
916
917void
918ContactManager::onUpdateIsIntroducer(const QString& identity, bool isIntroducer)
919{
920 m_contactStorage->updateIsIntroducer(Name(identity.toStdString()), isIntroducer);
921}
922
923void
924ContactManager::onUpdateEndorseCertificate(const QString& identity)
925{
926 Name identityName(identity.toStdString());
927 shared_ptr<EndorseCertificate> newEndorseCertificate = generateEndorseCertificate(identityName);
928
929 if(!static_cast<bool>(newEndorseCertificate))
930 return;
931
932 m_contactStorage->addEndorseCertificate(*newEndorseCertificate, identityName);
933
934 publishEndorseCertificateInDNS(*newEndorseCertificate);
935}
936
937} // namespace chronos
Yingdi Yufa4ce792014-02-06 18:09:22 -0800938
Yingdi Yu4685b1b2013-10-18 17:05:02 -0700939
940#if WAF
941#include "contact-manager.moc"
942#include "contact-manager.cpp.moc"
943#endif