IBR-DTN  1.0.0
KeyExchanger.cpp
Go to the documentation of this file.
1 /*
2  * KeyExchanger.cpp
3  *
4  * Copyright (C) 2014 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  * Thomas Schrader <schrader.thomas@gmail.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22 
23 #include "config.h"
26 
27 #include "core/BundleCore.h"
28 #include "core/EventDispatcher.h"
29 #include <ibrdtn/utils/Clock.h>
30 
31 #include <ibrcommon/data/File.h>
32 #include <ibrcommon/Logger.h>
33 #include <ibrcommon/ssl/HMacStream.h>
34 
36 #include <ibrdtn/utils/Random.h>
37 
43 
44 #ifdef HAVE_OPENSSL_JPAKE_H
46 #endif
47 
48 #include <cstring>
49 #include <time.h>
50 #include <iomanip>
51 #include <iostream>
52 #include <memory>
53 #include <sstream>
54 #include <stdlib.h>
55 
56 namespace dtn
57 {
58  namespace security
59  {
60  const std::string KeyExchanger::TAG = "KeyExchanger";
61 
63  : _next_expiration(0)
64  {
65  AbstractWorker::initialize("key-exchange");
66 
67  // add exchange protocols
68  (new NoneProtocol(*this))->add(_protocols);
69  (new DHProtocol(*this))->add(_protocols);
70  (new HashProtocol(*this))->add(_protocols);
71  (new QRCodeProtocol(*this))->add(_protocols);
72  (new NFCProtocol(*this))->add(_protocols);
73 
74 #ifdef HAVE_OPENSSL_JPAKE_H
75  (new JPAKEProtocol(*this))->add(_protocols);
76 #endif
77  }
78 
80  {
81  // wait until the main-thread is terminated
82  join();
83 
84  // free all sessions
85  for (std::map<std::string, KeyExchangeSession*>::iterator it = _sessionmap.begin(); it != _sessionmap.end(); ++it)
86  {
87  KeyExchangeSession *session = (*it).second;
88  delete session;
89  }
90  _sessionmap.clear();
91  }
92 
94  {
95  _queue.abort();
96  }
97 
98  void KeyExchanger::componentUp() throw ()
99  {
102 
103  // reset the queue
104  _queue.reset();
105  }
106 
108  {
109  // initialize all protocols
110  for (std::map<int, KeyExchangeProtocol*>::iterator it = _protocols.begin(); it != _protocols.end(); ++it)
111  {
112  KeyExchangeProtocol *p = (*it).second;
113  p->initialize();
114  }
115 
116  try
117  {
118  while (true)
119  {
120  Task *t = _queue.poll();
121  std::auto_ptr<Task> killer(t);
122 
123  // execute the task
124  t->execute(*this);
125 
126  ibrcommon::Thread::yield();
127  }
128  }
129  catch (const ibrcommon::QueueUnblockedException &e)
130  {
131  // exit loop
132  }
133  }
134 
136  {
139  }
140 
141  const std::string KeyExchanger::getName() const
142  {
143  return "KeyExchanger";
144  }
145 
147  {
148  // do not receive own bundles
150 
151  try
152  {
153  // read payload block
155 
156  // read the data of the bundle -locked
157  {
158  ibrcommon::BLOB::Reference ref = p.getBLOB();
159  ibrcommon::BLOB::iostream stream = ref.iostream();
160 
161  // read the data
163  (*stream) >> data;
164 
165  // distribute the received message as event
167  }
168 
169  } catch (const ibrcommon::Exception&) {}
170  }
171 
172  void KeyExchanger::raiseEvent(const KeyExchangeEvent &kee) throw ()
173  {
174  _queue.push(new ExchangeTask(kee.getEID(), kee.getData()));
175  }
176 
178  {
180 
181  ibrcommon::MutexLock l(_expiration_lock);
182  if ((_next_expiration > 0) && (_next_expiration <= now))
183  {
184  // set next expiration to zero to prevent further expiration tasks
185  _next_expiration = 0;
186 
187  // queue task to free expired sessions
188  _queue.push(new ExpireTask(now));
189  }
190  }
191 
193  {
195 
196  try {
197  ibrcommon::BLOB::Reference ref = ibrcommon::BLOB::create();
198 
199  // create the payload of the bundle
200  {
201  ibrcommon::BLOB::iostream stream = ref.iostream();
202 
203  // write the data
204  (*stream) << data;
205  }
206 
207  // add the payload to the message
208  b.push_back(ref);
209 
210  // set the source
212 
213  // set source application
214  b.source.setApplication("key-exchange");
215 
216  // set the destination
217  b.destination = session.getPeer();
218 
219  // set destination application
220  b.destination.setApplication("key-exchange");
221 
222  // set high priority
225 
226  // set the the destination as singleton receiver
228 
229  // set the lifetime of the bundle to 60 seconds
230  b.lifetime = 300;
231 
232  transmit(b);
233 
234  // prevent expiration of the session
235  session.touch();
236  } catch (const ibrcommon::IOException &ex) {
237  IBRCOMMON_LOGGER_TAG(KeyExchanger::TAG, error) << "error while key exchange, Exception: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
238  }
239  }
240 
242  {
243  SecurityKey newKey;
244  try
245  {
246  newKey = session.getKey(SecurityKey::KEY_PUBLIC);
247  }
249  {
250  // This should never happen!!!
251  throw ibrcommon::Exception("Error while reading temp key");
252  }
253 
254  // prepare event
256 
257  try
258  {
259  // get the old stored key
261 
262  if (newKey == oldKey)
263  {
264  // merge flags
265  newKey.flags |= oldKey.flags;
266 
267  // update existing key
269 
270  event.setAction(KeyExchangeData::COMPLETE);
271  }
272  else
273  {
274  event.setAction(KeyExchangeData::NEWKEY_FOUND);
275 
276  // store new keys fingerprint
277  event.str(newKey.getFingerprint());
278  }
279  }
281  {
282  // no old key available - store the new key
284 
285  // store new keys fingerprint
286  event.str(newKey.getFingerprint());
287  }
288 
289  // trigger further actions
290  KeyExchangeEvent::raise(session.getPeer(), event);
291 
292  if (event.getAction() == KeyExchangeData::COMPLETE) {
293  // release the session
294  freeSession(session.getPeer(), session.getUniqueId());
295  }
296  }
297 
298  void KeyExchanger::error(KeyExchangeSession &session, bool reportError)
299  {
300  // generate an error report
303  if (reportError) submit(session, error);
304  }
305 
306  KeyExchanger::Task::~Task()
307  {
308  }
309 
310  KeyExchanger::ExchangeTask::ExchangeTask(const dtn::data::EID &peer, const dtn::security::KeyExchangeData &data)
311  : _peer(peer), _data(data)
312  {}
313 
314  void KeyExchanger::ExchangeTask::execute(KeyExchanger &exchanger) throw ()
315  {
316  try
317  {
318  // get the protocol instance
319  std::map<int, KeyExchangeProtocol*>::iterator p_it;
320 
321  switch (_data.getProtocol())
322  {
323  case 100:
324  {
325  // get the session
326  KeyExchangeSession &session = exchanger.getSession(_peer, _data);
327 
328  if (_data.getStep() == 0)
329  {
330  // finalize the session
331  exchanger.error(session, false);
332  }
333  else
334  {
335  // finalize the session
336  exchanger.finish(session);
337  }
338  return;
339  }
340 
341  case 101:
342  {
343  // get the session
344  KeyExchangeSession &session = exchanger.getSession(_peer, _data);
345 
346  if (_data.getStep() == 0)
347  {
348  // discard the new key stored in the session
349  }
350  else
351  {
352  // accept the new key stored in the session
353  const SecurityKey key = session.getKey(SecurityKey::KEY_PUBLIC);
354 
355  // store temporary key as public key of the peer
357 
358  // prepare event
359  KeyExchangeData event(KeyExchangeData::COMPLETE, session);
360  event.str(key.getFingerprint());
361 
362  // trigger further actions
363  KeyExchangeEvent::raise(session.getPeer(), event);
364  }
365 
366  // clean-up the session
367  exchanger.freeSession(_peer, session.getUniqueId());
368  return;
369  }
370 
371  default:
372  {
373  // get the protocol instance
374  p_it = exchanger._protocols.find(_data.getProtocol());
375  break;
376  }
377  }
378 
379  if (p_it == exchanger._protocols.end())
380  {
381  // error - protocol not supported
382  throw ibrcommon::Exception("key-exchange message for unsupported protocol received");
383  }
384 
385  KeyExchangeProtocol &p = (*p_it->second);
386 
387  if (_data.getAction() == KeyExchangeData::ERROR)
388  {
389  // clean-up the session
390  exchanger.freeSession(_peer, _data.getSessionId());
391  }
392  else if (_data.getAction() == KeyExchangeData::START)
393  {
394  // create a session
395  KeyExchangeSession &session = exchanger.createSession(p, _peer);
396 
397  // assign session to data object
398  _data.setSession(session);
399 
400  try {
401  // start session
402  p.begin(session, _data);
403  } catch (ibrcommon::Exception &e) {
404  // trigger error handling
405  exchanger.error(session, false);
406 
407  throw;
408  }
409  }
410  else if ((_data.getAction() == KeyExchangeData::REQUEST) && (_data.getStep() == 0))
411  {
412  // create a session
413  KeyExchangeSession &session = exchanger.createSession(p, _peer, _data);
414 
415  // assign session to data object
416  _data.setSession(session);
417 
418  try {
419  // execute the next step of the session
420  p.step(session, _data);
421  } catch (ibrcommon::Exception &e) {
422  // trigger error handling
423  exchanger.error(session, true);
424 
425  throw;
426  }
427  }
428  else if ((_data.getAction() == KeyExchangeData::REQUEST) || (_data.getAction() == KeyExchangeData::RESPONSE))
429  {
430  // get the session
431  KeyExchangeSession &session = exchanger.getSession(_peer, _data);
432 
433  // assign session to data object
434  _data.setSession(session);
435 
436  try {
437  // execute the next step of the session
438  p.step(session, _data);
439  } catch (ibrcommon::Exception &e) {
440  // trigger error handling
441  exchanger.error(session, true);
442 
443  throw;
444  }
445  }
446  }
447  catch (ibrcommon::Exception &e)
448  {
449  IBRCOMMON_LOGGER_TAG(KeyExchanger::TAG, error) << e.what() << IBRCOMMON_LOGGER_ENDL;
450  }
451  }
452 
453  KeyExchanger::ExpireTask::ExpireTask(const dtn::data::Timestamp timestamp)
454  : _timestamp(timestamp)
455  {}
456 
457  void KeyExchanger::ExpireTask::execute(KeyExchanger &exchanger) throw ()
458  {
459  // free expired sessions
460  exchanger.expire(_timestamp);
461  }
462 
463  void KeyExchanger::expire(const dtn::data::Timestamp timestamp)
464  {
465  dtn::data::Timestamp next_expiration = 0;
466 
467  // free expired sessions
468  for (std::map<std::string, KeyExchangeSession*>::iterator it = _sessionmap.begin(); it != _sessionmap.end(); ++it)
469  {
470  KeyExchangeSession &session = *(*it).second;
471 
472  if (session.getExpiration() <= timestamp)
473  {
474  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 25) << "session expired for peer " << session.getPeer().getString() << ", ID: " << session.getUniqueId() << IBRCOMMON_LOGGER_ENDL;
475 
476  // expired - trigger an error
477  // the error event will finally delete the session
478  error(session, false);
479  }
480  else
481  {
482  if ((next_expiration == 0) || (next_expiration > session.getExpiration()))
483  {
484  next_expiration = session.getExpiration();
485  }
486  }
487  }
488 
489  // set next expiration time-stamp
490  ibrcommon::MutexLock l(_expiration_lock);
491  _next_expiration = next_expiration;
492  }
493 
494  KeyExchangeSession& KeyExchanger::createSession(KeyExchangeProtocol &p, const dtn::data::EID &peer, const dtn::security::KeyExchangeData &data)
495  {
496  KeyExchangeSession* session = p.createSession(peer, data.getSessionId());
497  _sessionmap[session->getSessionKey()] = session;
498 
499  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 20) << "key-exchange session created for " << peer.getString() << ", ID: " << session->getUniqueId() << IBRCOMMON_LOGGER_ENDL;
500 
501  // force expiration checking
502  ibrcommon::MutexLock l(_expiration_lock);
503  _next_expiration = 1;
504 
505  return *session;
506  }
507 
508  KeyExchangeSession& KeyExchanger::createSession(KeyExchangeProtocol &p, const dtn::data::EID &peer)
509  {
510  KeyExchangeSession* session = p.createSession(peer, (unsigned int)dtn::utils::Random::gen_number());
511  _sessionmap[session->getSessionKey()] = session;
512 
513  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 20) << "key-exchange session created for " << peer.getString() << ", ID: " << session->getUniqueId() << IBRCOMMON_LOGGER_ENDL;
514 
515  // force expiration checking
516  ibrcommon::MutexLock l(_expiration_lock);
517  _next_expiration = 1;
518 
519  return *session;
520  }
521 
522  KeyExchangeSession& KeyExchanger::getSession(const dtn::data::EID &peer, const dtn::security::KeyExchangeData &data) throw (ibrcommon::Exception)
523  {
524  const std::string session_key = KeyExchangeSession::getSessionKey(peer, data.getSessionId());
525 
526  std::map<std::string, KeyExchangeSession*>::iterator it = _sessionmap.find(session_key);
527  if (it == _sessionmap.end())
528  {
529  std::stringstream ss;
530  ss << "Session " << data.getSessionId() << " for " << peer.getString() << " not found";
531  throw ibrcommon::Exception(ss.str());
532  }
533  return *(*it).second;
534  }
535 
536  void KeyExchanger::freeSession(const dtn::data::EID &peer, const unsigned int uniqueId)
537  {
538  const std::string session_key = KeyExchangeSession::getSessionKey(peer, uniqueId);
539 
540  std::map<std::string, KeyExchangeSession*>::iterator it = _sessionmap.find(session_key);
541  if (it == _sessionmap.end())
542  {
543  // this should never happen
544  IBRCOMMON_LOGGER_DEBUG_TAG(KeyExchanger::TAG, 25) << "Session not found for " << peer.getString() << ", ID: " << uniqueId << IBRCOMMON_LOGGER_ENDL;
545  return;
546  }
547 
548  delete it->second;
549  _sessionmap.erase(it);
550 
551  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 25) << "session free'd for " << peer.getString() << ", ID: " << uniqueId << IBRCOMMON_LOGGER_ENDL;
552  }
553  } /* namespace security */
554 } /* namespace dtn */
static SecurityKeyManager & getInstance()
const dtn::data::EID & getPeer() const
unsigned int getSessionId() const
static dtn::data::EID local
Definition: BundleCore.h:79
static void add(EventReceiver< E > *receiver)
dtn::security::SecurityKey getKey(const dtn::security::SecurityKey::KeyType type=dtn::security::SecurityKey::KEY_UNSPEC) const
bool sameHost(const std::string &other) const
Definition: EID.cpp:322
const std::string & getSessionKey() const
virtual void callbackBundleReceived(const dtn::data::Bundle &b)
void setApplication(const dtn::data::Number &app)
Definition: EID.cpp:403
static void remove(const EventReceiver< E > *receiver)
virtual void error(KeyExchangeSession &session, bool reportError)
virtual void raiseEvent(const dtn::security::KeyExchangeEvent &evt)
virtual void finish(KeyExchangeSession &session)
void transmit(dtn::data::Bundle &bundle)
static int gen_number()
Definition: Random.cpp:51
dtn::security::SecurityKey get(const dtn::data::EID &ref, const dtn::security::SecurityKey::KeyType type=dtn::security::SecurityKey::KEY_UNSPEC) const
dtn::data::SDNV< unsigned int > flags
Definition: SecurityKey.h:86
virtual const std::string getFingerprint() const
std::string getString() const
Definition: EID.cpp:374
virtual const std::string getName() const
T & push_back()
Definition: Bundle.h:180
iterator find(block_t blocktype)
Definition: Bundle.cpp:307
ibrcommon::BLOB::Reference getBLOB() const
static dtn::data::Timestamp getMonotonicTimestamp()
Definition: Clock.cpp:175
void store(const dtn::security::SecurityKey &key, const std::string &data)
virtual void submit(KeyExchangeSession &session, const KeyExchangeData &data)
void set(FLAGS flag, bool value)
dtn::data::EID source
Definition: BundleID.h:53
static void raise(const dtn::data::EID &eid, const dtn::security::KeyExchangeData &data)