fix sign api for to address #6164
[oweals/gnunet.git] / src / core / gnunet-service-core_kx.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2013, 2016 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file core/gnunet-service-core_kx.c
23  * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other
24  * peers
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet-service-core_kx.h"
29 #include "gnunet-service-core.h"
30 #include "gnunet-service-core_sessions.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_constants.h"
34 #include "gnunet_signatures.h"
35 #include "gnunet_protocols.h"
36 #include "core.h"
37
38 /**
39  * Enable expensive (and possibly problematic for privacy!) logging of KX.
40  */
41 #define DEBUG_KX 0
42
43 /**
44  * How long do we wait for SET_KEY confirmation initially?
45  */
46 #define INITIAL_SET_KEY_RETRY_FREQUENCY \
47   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
48
49 /**
50  * What is the minimum frequency for a PING message?
51  */
52 #define MIN_PING_FREQUENCY \
53   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
54
55 /**
56  * How often do we rekey?
57  */
58 #define REKEY_FREQUENCY \
59   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
60
61 /**
62  * What time difference do we tolerate?
63  */
64 #define REKEY_TOLERANCE \
65   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
66
67 /**
68  * What is the maximum age of a message for us to consider processing
69  * it?  Note that this looks at the timestamp used by the other peer,
70  * so clock skew between machines does come into play here.  So this
71  * should be picked high enough so that a little bit of clock skew
72  * does not prevent peers from connecting to us.
73  */
74 #define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS
75
76
77 GNUNET_NETWORK_STRUCT_BEGIN
78
79 /**
80  * Message transmitted with the signed ephemeral key of a peer.  The
81  * session key is then derived from the two ephemeral keys (ECDHE).
82  */
83 struct EphemeralKeyMessage
84 {
85   /**
86    * Message type is #GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY.
87    */
88   struct GNUNET_MessageHeader header;
89
90   /**
91    * Status of the sender (should be in `enum PeerStateMachine`), nbo.
92    */
93   int32_t sender_status GNUNET_PACKED;
94
95   /**
96    * An ECC signature of the @e origin_identity asserting the validity
97    * of the given ephemeral key.
98    */
99   struct GNUNET_CRYPTO_EddsaSignature signature;
100
101   /**
102    * Information about what is being signed.
103    */
104   struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
105
106   /**
107    * At what time was this key created (beginning of validity).
108    */
109   struct GNUNET_TIME_AbsoluteNBO creation_time;
110
111   /**
112    * When does the given ephemeral key expire (end of validity).
113    */
114   struct GNUNET_TIME_AbsoluteNBO expiration_time;
115
116   /**
117    * Ephemeral public ECC key.
118    */
119   struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
120
121   /**
122    * Public key of the signing peer (persistent version, not the
123    * ephemeral public key).
124    */
125   struct GNUNET_PeerIdentity origin_identity;
126 };
127
128
129 /**
130  * We're sending an (encrypted) PING to the other peer to check if it
131  * can decrypt.  The other peer should respond with a PONG with the
132  * same content, except this time encrypted with the receiver's key.
133  */
134 struct PingMessage
135 {
136   /**
137    * Message type is #GNUNET_MESSAGE_TYPE_CORE_PING.
138    */
139   struct GNUNET_MessageHeader header;
140
141   /**
142    * Seed for the IV
143    */
144   uint32_t iv_seed GNUNET_PACKED;
145
146   /**
147    * Intended target of the PING, used primarily to check
148    * that decryption actually worked.
149    */
150   struct GNUNET_PeerIdentity target;
151
152   /**
153    * Random number chosen to make replay harder.
154    */
155   uint32_t challenge GNUNET_PACKED;
156 };
157
158
159 /**
160  * Response to a PING.  Includes data from the original PING.
161  */
162 struct PongMessage
163 {
164   /**
165    * Message type is #GNUNET_MESSAGE_TYPE_CORE_PONG.
166    */
167   struct GNUNET_MessageHeader header;
168
169   /**
170    * Seed for the IV
171    */
172   uint32_t iv_seed GNUNET_PACKED;
173
174   /**
175    * Random number to make replay attacks harder.
176    */
177   uint32_t challenge GNUNET_PACKED;
178
179   /**
180    * Reserved, always zero.
181    */
182   uint32_t reserved;
183
184   /**
185    * Intended target of the PING, used primarily to check
186    * that decryption actually worked.
187    */
188   struct GNUNET_PeerIdentity target;
189 };
190
191
192 /**
193  * Encapsulation for encrypted messages exchanged between
194  * peers.  Followed by the actual encrypted data.
195  */
196 struct EncryptedMessage
197 {
198   /**
199    * Message type is #GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE.
200    */
201   struct GNUNET_MessageHeader header;
202
203   /**
204    * Random value used for IV generation.
205    */
206   uint32_t iv_seed GNUNET_PACKED;
207
208   /**
209    * MAC of the encrypted message (starting at @e sequence_number),
210    * used to verify message integrity. Everything after this value
211    * (excluding this value itself) will be encrypted and
212    * authenticated.  #ENCRYPTED_HEADER_SIZE must be set to the offset
213    * of the *next* field.
214    */
215   struct GNUNET_HashCode hmac;
216
217   /**
218    * Sequence number, in network byte order.  This field
219    * must be the first encrypted/decrypted field
220    */
221   uint32_t sequence_number GNUNET_PACKED;
222
223   /**
224    * Reserved, always zero.
225    */
226   uint32_t reserved GNUNET_PACKED;
227
228   /**
229    * Timestamp.  Used to prevent replay of ancient messages
230    * (recent messages are caught with the sequence number).
231    */
232   struct GNUNET_TIME_AbsoluteNBO timestamp;
233 };
234 GNUNET_NETWORK_STRUCT_END
235
236
237 /**
238  * Number of bytes (at the beginning) of `struct EncryptedMessage`
239  * that are NOT encrypted.
240  */
241 #define ENCRYPTED_HEADER_SIZE \
242   (offsetof (struct EncryptedMessage, sequence_number))
243
244
245 /**
246  * Information about the status of a key exchange with another peer.
247  */
248 struct GSC_KeyExchangeInfo
249 {
250   /**
251    * DLL.
252    */
253   struct GSC_KeyExchangeInfo *next;
254
255   /**
256    * DLL.
257    */
258   struct GSC_KeyExchangeInfo *prev;
259
260   /**
261    * Identity of the peer.
262    */
263   const struct GNUNET_PeerIdentity *peer;
264
265   /**
266    * Message queue for sending messages to @a peer.
267    */
268   struct GNUNET_MQ_Handle *mq;
269
270   /**
271    * Our message stream tokenizer (for encrypted payload).
272    */
273   struct GNUNET_MessageStreamTokenizer *mst;
274
275   /**
276    * PING message we transmit to the other peer.
277    */
278   struct PingMessage ping;
279
280   /**
281    * Ephemeral public ECC key of the other peer.
282    */
283   struct GNUNET_CRYPTO_EcdhePublicKey other_ephemeral_key;
284
285   /**
286    * Key we use to encrypt our messages for the other peer
287    * (initialized by us when we do the handshake).
288    */
289   struct GNUNET_CRYPTO_SymmetricSessionKey encrypt_key;
290
291   /**
292    * Key we use to decrypt messages from the other peer
293    * (given to us by the other peer during the handshake).
294    */
295   struct GNUNET_CRYPTO_SymmetricSessionKey decrypt_key;
296
297   /**
298    * At what time did the other peer generate the decryption key?
299    */
300   struct GNUNET_TIME_Absolute foreign_key_expires;
301
302   /**
303    * When should the session time out (if there are no PONGs)?
304    */
305   struct GNUNET_TIME_Absolute timeout;
306
307   /**
308    * What was the last timeout we informed our monitors about?
309    */
310   struct GNUNET_TIME_Absolute last_notify_timeout;
311
312   /**
313    * At what frequency are we currently re-trying SET_KEY messages?
314    */
315   struct GNUNET_TIME_Relative set_key_retry_frequency;
316
317   /**
318    * ID of task used for re-trying SET_KEY and PING message.
319    */
320   struct GNUNET_SCHEDULER_Task *retry_set_key_task;
321
322   /**
323    * ID of task used for sending keep-alive pings.
324    */
325   struct GNUNET_SCHEDULER_Task *keep_alive_task;
326
327   /**
328    * Bit map indicating which of the 32 sequence numbers before the
329    * last were received (good for accepting out-of-order packets and
330    * estimating reliability of the connection)
331    */
332   uint32_t last_packets_bitmap;
333
334   /**
335    * last sequence number received on this connection (highest)
336    */
337   uint32_t last_sequence_number_received;
338
339   /**
340    * last sequence number transmitted
341    */
342   uint32_t last_sequence_number_sent;
343
344   /**
345    * What was our PING challenge number (for this peer)?
346    */
347   uint32_t ping_challenge;
348
349   /**
350    * #GNUNET_YES if this peer currently has excess bandwidth.
351    */
352   int has_excess_bandwidth;
353
354   /**
355    * What is our connection status?
356    */
357   enum GNUNET_CORE_KxState status;
358 };
359
360
361 /**
362  * Transport service.
363  */
364 static struct GNUNET_TRANSPORT_CoreHandle *transport;
365
366 /**
367  * Our private key.
368  */
369 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
370
371 /**
372  * Our ephemeral private key.
373  */
374 static struct GNUNET_CRYPTO_EcdhePrivateKey *my_ephemeral_key;
375
376 /**
377  * Current message we send for a key exchange.
378  */
379 static struct EphemeralKeyMessage current_ekm;
380
381 /**
382  * DLL head.
383  */
384 static struct GSC_KeyExchangeInfo *kx_head;
385
386 /**
387  * DLL tail.
388  */
389 static struct GSC_KeyExchangeInfo *kx_tail;
390
391 /**
392  * Task scheduled for periodic re-generation (and thus rekeying) of our
393  * ephemeral key.
394  */
395 static struct GNUNET_SCHEDULER_Task *rekey_task;
396
397 /**
398  * Notification context for broadcasting to monitors.
399  */
400 static struct GNUNET_NotificationContext *nc;
401
402
403 /**
404  * Calculate seed value we should use for a message.
405  *
406  * @param kx key exchange context
407  */
408 static uint32_t
409 calculate_seed (struct GSC_KeyExchangeInfo *kx)
410 {
411   /* Note: may want to make this non-random and instead
412      derive from key material to avoid having an undetectable
413      side-channel */
414   return htonl (
415     GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
416 }
417
418
419 /**
420  * Inform all monitors about the KX state of the given peer.
421  *
422  * @param kx key exchange state to inform about
423  */
424 static void
425 monitor_notify_all (struct GSC_KeyExchangeInfo *kx)
426 {
427   struct MonitorNotifyMessage msg;
428
429   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
430   msg.header.size = htons (sizeof(msg));
431   msg.state = htonl ((uint32_t) kx->status);
432   msg.peer = *kx->peer;
433   msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
434   GNUNET_notification_context_broadcast (nc, &msg.header, GNUNET_NO);
435   kx->last_notify_timeout = kx->timeout;
436 }
437
438
439 /**
440  * Derive an authentication key from "set key" information
441  *
442  * @param akey authentication key to derive
443  * @param skey session key to use
444  * @param seed seed to use
445  */
446 static void
447 derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey,
448                  const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
449                  uint32_t seed)
450 {
451   static const char ctx[] = "authentication key";
452
453 #if DEBUG_KX
454   struct GNUNET_HashCode sh;
455
456   GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
457   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458               "Deriving Auth key from SKEY %s and seed %u\n",
459               GNUNET_h2s (&sh),
460               (unsigned int) seed);
461 #endif
462   GNUNET_CRYPTO_hmac_derive_key (akey,
463                                  skey,
464                                  &seed,
465                                  sizeof(seed),
466                                  skey,
467                                  sizeof(
468                                    struct GNUNET_CRYPTO_SymmetricSessionKey),
469                                  ctx,
470                                  sizeof(ctx),
471                                  NULL);
472 }
473
474
475 /**
476  * Derive an IV from packet information
477  *
478  * @param iv initialization vector to initialize
479  * @param skey session key to use
480  * @param seed seed to use
481  * @param identity identity of the other peer to use
482  */
483 static void
484 derive_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
485            const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
486            uint32_t seed,
487            const struct GNUNET_PeerIdentity *identity)
488 {
489   static const char ctx[] = "initialization vector";
490
491 #if DEBUG_KX
492   struct GNUNET_HashCode sh;
493
494   GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
495   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
496               "Deriving IV from SKEY %s and seed %u for peer %s\n",
497               GNUNET_h2s (&sh),
498               (unsigned int) seed,
499               GNUNET_i2s (identity));
500 #endif
501   GNUNET_CRYPTO_symmetric_derive_iv (iv,
502                                      skey,
503                                      &seed,
504                                      sizeof(seed),
505                                      identity,
506                                      sizeof(struct GNUNET_PeerIdentity),
507                                      ctx,
508                                      sizeof(ctx),
509                                      NULL);
510 }
511
512
513 /**
514  * Derive an IV from pong packet information
515  *
516  * @param iv initialization vector to initialize
517  * @param skey session key to use
518  * @param seed seed to use
519  * @param challenge nonce to use
520  * @param identity identity of the other peer to use
521  */
522 static void
523 derive_pong_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
524                 const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
525                 uint32_t seed,
526                 uint32_t challenge,
527                 const struct GNUNET_PeerIdentity *identity)
528 {
529   static const char ctx[] = "pong initialization vector";
530
531 #if DEBUG_KX
532   struct GNUNET_HashCode sh;
533
534   GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
535   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536               "Deriving PONG IV from SKEY %s and seed %u/%u for %s\n",
537               GNUNET_h2s (&sh),
538               (unsigned int) seed,
539               (unsigned int) challenge,
540               GNUNET_i2s (identity));
541 #endif
542   GNUNET_CRYPTO_symmetric_derive_iv (iv,
543                                      skey,
544                                      &seed,
545                                      sizeof(seed),
546                                      identity,
547                                      sizeof(struct GNUNET_PeerIdentity),
548                                      &challenge,
549                                      sizeof(challenge),
550                                      ctx,
551                                      sizeof(ctx),
552                                      NULL);
553 }
554
555
556 /**
557  * Derive an AES key from key material
558  *
559  * @param sender peer identity of the sender
560  * @param receiver peer identity of the sender
561  * @param key_material high entropy key material to use
562  * @param skey set to derived session key
563  */
564 static void
565 derive_aes_key (const struct GNUNET_PeerIdentity *sender,
566                 const struct GNUNET_PeerIdentity *receiver,
567                 const struct GNUNET_HashCode *key_material,
568                 struct GNUNET_CRYPTO_SymmetricSessionKey *skey)
569 {
570   static const char ctx[] = "aes key generation vector";
571
572 #if DEBUG_KX
573   struct GNUNET_HashCode sh;
574
575   GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
576   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
577               "Deriving AES Keys for %s to %s from %s\n",
578               GNUNET_i2s (sender),
579               GNUNET_i2s2 (receiver),
580               GNUNET_h2s (key_material));
581 #endif
582   GNUNET_CRYPTO_kdf (skey,
583                      sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey),
584                      ctx,
585                      sizeof(ctx),
586                      key_material,
587                      sizeof(struct GNUNET_HashCode),
588                      sender,
589                      sizeof(struct GNUNET_PeerIdentity),
590                      receiver,
591                      sizeof(struct GNUNET_PeerIdentity),
592                      NULL);
593 }
594
595
596 /**
597  * Encrypt size bytes from @a in and write the result to @a out.  Use the
598  * @a kx key for outbound traffic of the given neighbour.
599  *
600  * @param kx key information context
601  * @param iv initialization vector to use
602  * @param in ciphertext
603  * @param out plaintext
604  * @param size size of @a in/@a out
605  * @return #GNUNET_OK on success
606  */
607 static int
608 do_encrypt (struct GSC_KeyExchangeInfo *kx,
609             const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
610             const void *in,
611             void *out,
612             size_t size)
613 {
614   if (size != (uint16_t) size)
615   {
616     GNUNET_break (0);
617     return GNUNET_NO;
618   }
619   GNUNET_assert (size == GNUNET_CRYPTO_symmetric_encrypt (in,
620                                                           (uint16_t) size,
621                                                           &kx->encrypt_key,
622                                                           iv,
623                                                           out));
624   GNUNET_STATISTICS_update (GSC_stats,
625                             gettext_noop ("# bytes encrypted"),
626                             size,
627                             GNUNET_NO);
628   /* the following is too sensitive to write to log files by accident,
629      so we require manual intervention to get this one... */
630 #if DEBUG_KX
631   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
632               "Encrypted %u bytes for `%s' using key %u, IV %u\n",
633               (unsigned int) size,
634               GNUNET_i2s (kx->peer),
635               (unsigned int) kx->encrypt_key.crc32,
636               GNUNET_CRYPTO_crc32_n (iv, sizeof(iv)));
637 #endif
638   return GNUNET_OK;
639 }
640
641
642 /**
643  * Decrypt size bytes from @a in and write the result to @a out.  Use
644  * the @a kx key for inbound traffic of the given neighbour.  This
645  * function does NOT do any integrity-checks on the result.
646  *
647  * @param kx key information context
648  * @param iv initialization vector to use
649  * @param in ciphertext
650  * @param out plaintext
651  * @param size size of @a in / @a out
652  * @return #GNUNET_OK on success
653  */
654 static int
655 do_decrypt (struct GSC_KeyExchangeInfo *kx,
656             const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
657             const void *in,
658             void *out,
659             size_t size)
660 {
661   if (size != (uint16_t) size)
662   {
663     GNUNET_break (0);
664     return GNUNET_NO;
665   }
666   if ((kx->status != GNUNET_CORE_KX_STATE_KEY_RECEIVED) &&
667       (kx->status != GNUNET_CORE_KX_STATE_UP) &&
668       (kx->status != GNUNET_CORE_KX_STATE_REKEY_SENT))
669   {
670     GNUNET_break_op (0);
671     return GNUNET_SYSERR;
672   }
673   if (size != GNUNET_CRYPTO_symmetric_decrypt (in,
674                                                (uint16_t) size,
675                                                &kx->decrypt_key,
676                                                iv,
677                                                out))
678   {
679     GNUNET_break (0);
680     return GNUNET_SYSERR;
681   }
682   GNUNET_STATISTICS_update (GSC_stats,
683                             gettext_noop ("# bytes decrypted"),
684                             size,
685                             GNUNET_NO);
686   /* the following is too sensitive to write to log files by accident,
687      so we require manual intervention to get this one... */
688 #if DEBUG_KX
689   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
690               "Decrypted %u bytes from `%s' using key %u, IV %u\n",
691               (unsigned int) size,
692               GNUNET_i2s (kx->peer),
693               (unsigned int) kx->decrypt_key.crc32,
694               GNUNET_CRYPTO_crc32_n (iv, sizeof(*iv)));
695 #endif
696   return GNUNET_OK;
697 }
698
699
700 /**
701  * Send our key (and encrypted PING) to the other peer.
702  *
703  * @param kx key exchange context
704  */
705 static void
706 send_key (struct GSC_KeyExchangeInfo *kx);
707
708
709 /**
710  * Task that will retry #send_key() if our previous attempt failed.
711  *
712  * @param cls our `struct GSC_KeyExchangeInfo`
713  */
714 static void
715 set_key_retry_task (void *cls)
716 {
717   struct GSC_KeyExchangeInfo *kx = cls;
718
719   kx->retry_set_key_task = NULL;
720   kx->set_key_retry_frequency =
721     GNUNET_TIME_STD_BACKOFF (kx->set_key_retry_frequency);
722   GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
723   send_key (kx);
724 }
725
726
727 /**
728  * Create a fresh PING message for transmission to the other peer.
729  *
730  * @param kx key exchange context to create PING for
731  */
732 static void
733 setup_fresh_ping (struct GSC_KeyExchangeInfo *kx)
734 {
735   struct PingMessage pp;
736   struct PingMessage *pm;
737   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
738
739   pm = &kx->ping;
740   kx->ping_challenge =
741     GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
742   pm->header.size = htons (sizeof(struct PingMessage));
743   pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
744   pm->iv_seed = calculate_seed (kx);
745   derive_iv (&iv, &kx->encrypt_key, pm->iv_seed, kx->peer);
746   pp.challenge = kx->ping_challenge;
747   pp.target = *kx->peer;
748   do_encrypt (kx,
749               &iv,
750               &pp.target,
751               &pm->target,
752               sizeof(struct PingMessage)
753               - ((void *) &pm->target - (void *) pm));
754 }
755
756
757 /**
758  * Deliver P2P message to interested clients.  Invokes send twice,
759  * once for clients that want the full message, and once for clients
760  * that only want the header
761  *
762  * @param cls the `struct GSC_KeyExchangeInfo`
763  * @param m the message
764  * @return #GNUNET_OK on success,
765  *    #GNUNET_NO to stop further processing (no error)
766  *    #GNUNET_SYSERR to stop further processing with error
767  */
768 static int
769 deliver_message (void *cls, const struct GNUNET_MessageHeader *m)
770 {
771   struct GSC_KeyExchangeInfo *kx = cls;
772
773   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
774               "Decrypted message of type %d from %s\n",
775               ntohs (m->type),
776               GNUNET_i2s (kx->peer));
777   if (GNUNET_CORE_KX_STATE_UP != kx->status)
778   {
779     GNUNET_STATISTICS_update (GSC_stats,
780                               gettext_noop ("# PAYLOAD dropped (out of order)"),
781                               1,
782                               GNUNET_NO);
783     return GNUNET_OK;
784   }
785   switch (ntohs (m->type))
786   {
787   case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
788   case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
789     GSC_SESSIONS_set_typemap (kx->peer, m);
790     return GNUNET_OK;
791
792   case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
793     GSC_SESSIONS_confirm_typemap (kx->peer, m);
794     return GNUNET_OK;
795
796   default:
797     GSC_CLIENTS_deliver_message (kx->peer,
798                                  m,
799                                  ntohs (m->size),
800                                  GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
801     GSC_CLIENTS_deliver_message (kx->peer,
802                                  m,
803                                  sizeof(struct GNUNET_MessageHeader),
804                                  GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
805   }
806   return GNUNET_OK;
807 }
808
809
810 /**
811  * Function called by transport to notify us that
812  * a peer connected to us (on the network level).
813  * Starts the key exchange with the given peer.
814  *
815  * @param cls closure (NULL)
816  * @param pid identity of the peer to do a key exchange with
817  * @return key exchange information context
818  */
819 static void *
820 handle_transport_notify_connect (void *cls,
821                                  const struct GNUNET_PeerIdentity *pid,
822                                  struct GNUNET_MQ_Handle *mq)
823 {
824   struct GSC_KeyExchangeInfo *kx;
825   struct GNUNET_HashCode h1;
826   struct GNUNET_HashCode h2;
827
828   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
829               "Initiating key exchange with `%s'\n",
830               GNUNET_i2s (pid));
831   GNUNET_STATISTICS_update (GSC_stats,
832                             gettext_noop ("# key exchanges initiated"),
833                             1,
834                             GNUNET_NO);
835   kx = GNUNET_new (struct GSC_KeyExchangeInfo);
836   kx->mst = GNUNET_MST_create (&deliver_message, kx);
837   kx->mq = mq;
838   kx->peer = pid;
839   kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
840   GNUNET_CONTAINER_DLL_insert (kx_head, kx_tail, kx);
841   kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
842   monitor_notify_all (kx);
843   GNUNET_CRYPTO_hash (pid, sizeof(struct GNUNET_PeerIdentity), &h1);
844   GNUNET_CRYPTO_hash (&GSC_my_identity,
845                       sizeof(struct GNUNET_PeerIdentity),
846                       &h2);
847   if (0 < GNUNET_CRYPTO_hash_cmp (&h1, &h2))
848   {
849     /* peer with "lower" identity starts KX, otherwise we typically end up
850        with both peers starting the exchange and transmit the 'set key'
851        message twice */
852     send_key (kx);
853   }
854   else
855   {
856     /* peer with "higher" identity starts a delayed KX, if the "lower" peer
857      * does not start a KX since it sees no reasons to do so  */
858     kx->retry_set_key_task =
859       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
860                                     &set_key_retry_task,
861                                     kx);
862   }
863   return kx;
864 }
865
866
867 /**
868  * Function called by transport telling us that a peer
869  * disconnected.
870  * Stop key exchange with the given peer.  Clean up key material.
871  *
872  * @param cls closure
873  * @param peer the peer that disconnected
874  * @param handler_cls the `struct GSC_KeyExchangeInfo` of the peer
875  */
876 static void
877 handle_transport_notify_disconnect (void *cls,
878                                     const struct GNUNET_PeerIdentity *peer,
879                                     void *handler_cls)
880 {
881   struct GSC_KeyExchangeInfo *kx = handler_cls;
882
883   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
884               "Peer `%s' disconnected from us.\n",
885               GNUNET_i2s (peer));
886   GSC_SESSIONS_end (kx->peer);
887   GNUNET_STATISTICS_update (GSC_stats,
888                             gettext_noop ("# key exchanges stopped"),
889                             1,
890                             GNUNET_NO);
891   if (NULL != kx->retry_set_key_task)
892   {
893     GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
894     kx->retry_set_key_task = NULL;
895   }
896   if (NULL != kx->keep_alive_task)
897   {
898     GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
899     kx->keep_alive_task = NULL;
900   }
901   kx->status = GNUNET_CORE_KX_PEER_DISCONNECT;
902   monitor_notify_all (kx);
903   GNUNET_CONTAINER_DLL_remove (kx_head, kx_tail, kx);
904   GNUNET_MST_destroy (kx->mst);
905   GNUNET_free (kx);
906 }
907
908
909 /**
910  * Send our PING to the other peer.
911  *
912  * @param kx key exchange context
913  */
914 static void
915 send_ping (struct GSC_KeyExchangeInfo *kx)
916 {
917   struct GNUNET_MQ_Envelope *env;
918
919   GNUNET_STATISTICS_update (GSC_stats,
920                             gettext_noop ("# PING messages transmitted"),
921                             1,
922                             GNUNET_NO);
923   env = GNUNET_MQ_msg_copy (&kx->ping.header);
924   GNUNET_MQ_send (kx->mq, env);
925 }
926
927
928 /**
929  * Derive fresh session keys from the current ephemeral keys.
930  *
931  * @param kx session to derive keys for
932  */
933 static void
934 derive_session_keys (struct GSC_KeyExchangeInfo *kx)
935 {
936   struct GNUNET_HashCode key_material;
937
938   if (GNUNET_OK != GNUNET_CRYPTO_ecc_ecdh (my_ephemeral_key,
939                                            &kx->other_ephemeral_key,
940                                            &key_material))
941   {
942     GNUNET_break (0);
943     return;
944   }
945   derive_aes_key (&GSC_my_identity, kx->peer, &key_material, &kx->encrypt_key);
946   derive_aes_key (kx->peer, &GSC_my_identity, &key_material, &kx->decrypt_key);
947   memset (&key_material, 0, sizeof(key_material));
948   /* fresh key, reset sequence numbers */
949   kx->last_sequence_number_received = 0;
950   kx->last_packets_bitmap = 0;
951   setup_fresh_ping (kx);
952 }
953
954
955 /**
956  * We received a #GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY message.
957  * Validate and update our key material and status.
958  *
959  * @param cls key exchange status for the corresponding peer
960  * @param m the set key message we received
961  */
962 static void
963 handle_ephemeral_key (void *cls, const struct EphemeralKeyMessage *m)
964 {
965   struct GSC_KeyExchangeInfo *kx = cls;
966   struct GNUNET_TIME_Absolute start_t;
967   struct GNUNET_TIME_Absolute end_t;
968   struct GNUNET_TIME_Absolute now;
969   enum GNUNET_CORE_KxState sender_status;
970
971   end_t = GNUNET_TIME_absolute_ntoh (m->expiration_time);
972   if (((GNUNET_CORE_KX_STATE_KEY_RECEIVED == kx->status) ||
973        (GNUNET_CORE_KX_STATE_UP == kx->status) ||
974        (GNUNET_CORE_KX_STATE_REKEY_SENT == kx->status)) &&
975       (end_t.abs_value_us < kx->foreign_key_expires.abs_value_us))
976   {
977     GNUNET_STATISTICS_update (GSC_stats,
978                               gettext_noop ("# old ephemeral keys ignored"),
979                               1,
980                               GNUNET_NO);
981     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
982                 "Received expired EPHEMERAL_KEY from %s\n",
983                 GNUNET_i2s (&m->origin_identity));
984     return;
985   }
986   if (0 == memcmp (&m->ephemeral_key,
987                    &kx->other_ephemeral_key,
988                    sizeof(m->ephemeral_key)))
989   {
990     GNUNET_STATISTICS_update (GSC_stats,
991                               gettext_noop (
992                                 "# duplicate ephemeral keys ignored"),
993                               1,
994                               GNUNET_NO);
995     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
996                 "Ignoring duplicate EPHEMERAL_KEY from %s\n",
997                 GNUNET_i2s (&m->origin_identity));
998     return;
999   }
1000   if (0 != memcmp (&m->origin_identity,
1001                    kx->peer,
1002                    sizeof(struct GNUNET_PeerIdentity)))
1003   {
1004     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1005                 "Received EPHEMERAL_KEY from %s, but expected %s\n",
1006                 GNUNET_i2s (&m->origin_identity),
1007                 GNUNET_i2s_full (kx->peer));
1008     GNUNET_break_op (0);
1009     return;
1010   }
1011   if ((ntohl (m->purpose.size) !=
1012        sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
1013        + sizeof(struct GNUNET_TIME_AbsoluteNBO)
1014        + sizeof(struct GNUNET_TIME_AbsoluteNBO)
1015        + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
1016        + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) ||
1017       (GNUNET_OK !=
1018        GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY,
1019                                     &m->purpose,
1020                                     &m->signature,
1021                                     &m->origin_identity.public_key)))
1022   {
1023     /* invalid signature */
1024     GNUNET_break_op (0);
1025     GNUNET_STATISTICS_update (GSC_stats,
1026                               gettext_noop (
1027                                 "# EPHEMERAL_KEYs rejected (bad signature)"),
1028                               1,
1029                               GNUNET_NO);
1030     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1031                 "Received EPHEMERAL_KEY from %s with bad signature\n",
1032                 GNUNET_i2s (&m->origin_identity));
1033     return;
1034   }
1035   now = GNUNET_TIME_absolute_get ();
1036   start_t = GNUNET_TIME_absolute_ntoh (m->creation_time);
1037   if ((end_t.abs_value_us <
1038        GNUNET_TIME_absolute_subtract (now, REKEY_TOLERANCE).abs_value_us) ||
1039       (start_t.abs_value_us >
1040        GNUNET_TIME_absolute_add (now, REKEY_TOLERANCE).abs_value_us))
1041   {
1042     GNUNET_log (
1043       GNUNET_ERROR_TYPE_WARNING,
1044       _ (
1045         "EPHEMERAL_KEY from peer `%s' rejected as its validity range does not match our system time (%llu not in [%llu,%llu]).\n"),
1046       GNUNET_i2s (kx->peer),
1047       (unsigned long long) now.abs_value_us,
1048       (unsigned long long) start_t.abs_value_us,
1049       (unsigned long long) end_t.abs_value_us);
1050     GNUNET_STATISTICS_update (GSC_stats,
1051                               gettext_noop (
1052                                 "# EPHEMERAL_KEY messages rejected due to time"),
1053                               1,
1054                               GNUNET_NO);
1055     return;
1056   }
1057 #if DEBUG_KX
1058   {
1059     struct GNUNET_HashCode eh;
1060
1061     GNUNET_CRYPTO_hash (&m->ephemeral_key, sizeof(m->ephemeral_key), &eh);
1062     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1063                 "Received valid EPHEMERAL_KEY `%s' from `%s' in state %d.\n",
1064                 GNUNET_h2s (&eh),
1065                 GNUNET_i2s (kx->peer),
1066                 kx->status);
1067   }
1068 #endif
1069   GNUNET_STATISTICS_update (GSC_stats,
1070                             gettext_noop ("# valid ephemeral keys received"),
1071                             1,
1072                             GNUNET_NO);
1073   kx->other_ephemeral_key = m->ephemeral_key;
1074   kx->foreign_key_expires = end_t;
1075   derive_session_keys (kx);
1076
1077   /* check if we still need to send the sender our key */
1078   sender_status = (enum GNUNET_CORE_KxState) ntohl (m->sender_status);
1079   switch (sender_status)
1080   {
1081   case GNUNET_CORE_KX_STATE_DOWN:
1082     GNUNET_break_op (0);
1083     break;
1084
1085   case GNUNET_CORE_KX_STATE_KEY_SENT:
1086     /* fine, need to send our key after updating our status, see below */
1087     GSC_SESSIONS_reinit (kx->peer);
1088     break;
1089
1090   case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1091     /* other peer already got our key, but typemap did go down */
1092     GSC_SESSIONS_reinit (kx->peer);
1093     break;
1094
1095   case GNUNET_CORE_KX_STATE_UP:
1096     /* other peer already got our key, typemap NOT down */
1097     break;
1098
1099   case GNUNET_CORE_KX_STATE_REKEY_SENT:
1100     /* other peer already got our key, typemap NOT down */
1101     break;
1102
1103   default:
1104     GNUNET_break (0);
1105     break;
1106   }
1107   /* check if we need to confirm everything is fine via PING + PONG */
1108   switch (kx->status)
1109   {
1110   case GNUNET_CORE_KX_STATE_DOWN:
1111     GNUNET_assert (NULL == kx->keep_alive_task);
1112     kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED;
1113     monitor_notify_all (kx);
1114     if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1115       send_key (kx);
1116     else
1117       send_ping (kx);
1118     break;
1119
1120   case GNUNET_CORE_KX_STATE_KEY_SENT:
1121     GNUNET_assert (NULL == kx->keep_alive_task);
1122     kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED;
1123     monitor_notify_all (kx);
1124     if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1125       send_key (kx);
1126     else
1127       send_ping (kx);
1128     break;
1129
1130   case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1131     GNUNET_assert (NULL == kx->keep_alive_task);
1132     if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1133       send_key (kx);
1134     else
1135       send_ping (kx);
1136     break;
1137
1138   case GNUNET_CORE_KX_STATE_UP:
1139     kx->status = GNUNET_CORE_KX_STATE_REKEY_SENT;
1140     monitor_notify_all (kx);
1141     if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1142       send_key (kx);
1143     else
1144       send_ping (kx);
1145     break;
1146
1147   case GNUNET_CORE_KX_STATE_REKEY_SENT:
1148     if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1149       send_key (kx);
1150     else
1151       send_ping (kx);
1152     break;
1153
1154   default:
1155     GNUNET_break (0);
1156     break;
1157   }
1158 }
1159
1160
1161 /**
1162  * We received a PING message.  Validate and transmit
1163  * a PONG message.
1164  *
1165  * @param cls key exchange status for the corresponding peer
1166  * @param m the encrypted PING message itself
1167  */
1168 static void
1169 handle_ping (void *cls, const struct PingMessage *m)
1170 {
1171   struct GSC_KeyExchangeInfo *kx = cls;
1172   struct PingMessage t;
1173   struct PongMessage tx;
1174   struct PongMessage *tp;
1175   struct GNUNET_MQ_Envelope *env;
1176   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1177
1178   GNUNET_STATISTICS_update (GSC_stats,
1179                             gettext_noop ("# PING messages received"),
1180                             1,
1181                             GNUNET_NO);
1182   if ((kx->status != GNUNET_CORE_KX_STATE_KEY_RECEIVED) &&
1183       (kx->status != GNUNET_CORE_KX_STATE_UP) &&
1184       (kx->status != GNUNET_CORE_KX_STATE_REKEY_SENT))
1185   {
1186     /* ignore */
1187     GNUNET_STATISTICS_update (GSC_stats,
1188                               gettext_noop (
1189                                 "# PING messages dropped (out of order)"),
1190                               1,
1191                               GNUNET_NO);
1192     return;
1193   }
1194   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1195               "Core service receives PING request from `%s'.\n",
1196               GNUNET_i2s (kx->peer));
1197   derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity);
1198   if (GNUNET_OK != do_decrypt (kx,
1199                                &iv,
1200                                &m->target,
1201                                &t.target,
1202                                sizeof(struct PingMessage)
1203                                - ((void *) &m->target - (void *) m)))
1204   {
1205     GNUNET_break_op (0);
1206     return;
1207   }
1208   if (0 !=
1209       memcmp (&t.target, &GSC_my_identity, sizeof(struct GNUNET_PeerIdentity)))
1210   {
1211     if (GNUNET_CORE_KX_STATE_REKEY_SENT != kx->status)
1212       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1213                   "Decryption of PING from peer `%s' failed, PING for `%s'?\n",
1214                   GNUNET_i2s (kx->peer),
1215                   GNUNET_i2s2 (&t.target));
1216     else
1217       GNUNET_log (
1218         GNUNET_ERROR_TYPE_DEBUG,
1219         "Decryption of PING from peer `%s' failed after rekey (harmless)\n",
1220         GNUNET_i2s (kx->peer));
1221     GNUNET_break_op (0);
1222     return;
1223   }
1224   /* construct PONG */
1225   tx.reserved = 0;
1226   tx.challenge = t.challenge;
1227   tx.target = t.target;
1228   env = GNUNET_MQ_msg (tp, GNUNET_MESSAGE_TYPE_CORE_PONG);
1229   tp->iv_seed = calculate_seed (kx);
1230   derive_pong_iv (&iv, &kx->encrypt_key, tp->iv_seed, t.challenge, kx->peer);
1231   do_encrypt (kx,
1232               &iv,
1233               &tx.challenge,
1234               &tp->challenge,
1235               sizeof(struct PongMessage)
1236               - ((void *) &tp->challenge - (void *) tp));
1237   GNUNET_STATISTICS_update (GSC_stats,
1238                             gettext_noop ("# PONG messages created"),
1239                             1,
1240                             GNUNET_NO);
1241   GNUNET_MQ_send (kx->mq, env);
1242 }
1243
1244
1245 /**
1246  * Task triggered when a neighbour entry is about to time out
1247  * (and we should prevent this by sending a PING).
1248  *
1249  * @param cls the `struct GSC_KeyExchangeInfo`
1250  */
1251 static void
1252 send_keep_alive (void *cls)
1253 {
1254   struct GSC_KeyExchangeInfo *kx = cls;
1255   struct GNUNET_TIME_Relative retry;
1256   struct GNUNET_TIME_Relative left;
1257
1258   kx->keep_alive_task = NULL;
1259   left = GNUNET_TIME_absolute_get_remaining (kx->timeout);
1260   if (0 == left.rel_value_us)
1261   {
1262     GNUNET_STATISTICS_update (GSC_stats,
1263                               gettext_noop ("# sessions terminated by timeout"),
1264                               1,
1265                               GNUNET_NO);
1266     GSC_SESSIONS_end (kx->peer);
1267     kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1268     monitor_notify_all (kx);
1269     send_key (kx);
1270     return;
1271   }
1272   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1273               "Sending KEEPALIVE to `%s'\n",
1274               GNUNET_i2s (kx->peer));
1275   GNUNET_STATISTICS_update (GSC_stats,
1276                             gettext_noop ("# keepalive messages sent"),
1277                             1,
1278                             GNUNET_NO);
1279   setup_fresh_ping (kx);
1280   send_ping (kx);
1281   retry = GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2),
1282                                     MIN_PING_FREQUENCY);
1283   kx->keep_alive_task =
1284     GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, kx);
1285 }
1286
1287
1288 /**
1289  * We've seen a valid message from the other peer.
1290  * Update the time when the session would time out
1291  * and delay sending our keep alive message further.
1292  *
1293  * @param kx key exchange where we saw activity
1294  */
1295 static void
1296 update_timeout (struct GSC_KeyExchangeInfo *kx)
1297 {
1298   struct GNUNET_TIME_Relative delta;
1299
1300   kx->timeout =
1301     GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1302   delta =
1303     GNUNET_TIME_absolute_get_difference (kx->last_notify_timeout, kx->timeout);
1304   if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
1305   {
1306     /* we only notify monitors about timeout changes if those
1307        are bigger than the threshold (5s) */
1308     monitor_notify_all (kx);
1309   }
1310   if (NULL != kx->keep_alive_task)
1311     GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
1312   kx->keep_alive_task = GNUNET_SCHEDULER_add_delayed (
1313     GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
1314     &send_keep_alive,
1315     kx);
1316 }
1317
1318
1319 /**
1320  * We received a PONG message.  Validate and update our status.
1321  *
1322  * @param kx key exchange context for the the PONG
1323  * @param m the encrypted PONG message itself
1324  */
1325 static void
1326 handle_pong (void *cls, const struct PongMessage *m)
1327 {
1328   struct GSC_KeyExchangeInfo *kx = cls;
1329   struct PongMessage t;
1330   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1331
1332   GNUNET_STATISTICS_update (GSC_stats,
1333                             gettext_noop ("# PONG messages received"),
1334                             1,
1335                             GNUNET_NO);
1336   switch (kx->status)
1337   {
1338   case GNUNET_CORE_KX_STATE_DOWN:
1339     GNUNET_STATISTICS_update (GSC_stats,
1340                               gettext_noop (
1341                                 "# PONG messages dropped (connection down)"),
1342                               1,
1343                               GNUNET_NO);
1344     return;
1345
1346   case GNUNET_CORE_KX_STATE_KEY_SENT:
1347     GNUNET_STATISTICS_update (GSC_stats,
1348                               gettext_noop (
1349                                 "# PONG messages dropped (out of order)"),
1350                               1,
1351                               GNUNET_NO);
1352     return;
1353
1354   case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1355     break;
1356
1357   case GNUNET_CORE_KX_STATE_UP:
1358     break;
1359
1360   case GNUNET_CORE_KX_STATE_REKEY_SENT:
1361     break;
1362
1363   default:
1364     GNUNET_break (0);
1365     return;
1366   }
1367   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1368               "Core service receives PONG response from `%s'.\n",
1369               GNUNET_i2s (kx->peer));
1370   /* mark as garbage, just to be sure */
1371   memset (&t, 255, sizeof(t));
1372   derive_pong_iv (&iv,
1373                   &kx->decrypt_key,
1374                   m->iv_seed,
1375                   kx->ping_challenge,
1376                   &GSC_my_identity);
1377   if (GNUNET_OK != do_decrypt (kx,
1378                                &iv,
1379                                &m->challenge,
1380                                &t.challenge,
1381                                sizeof(struct PongMessage)
1382                                - ((void *) &m->challenge - (void *) m)))
1383   {
1384     GNUNET_break_op (0);
1385     return;
1386   }
1387   GNUNET_STATISTICS_update (GSC_stats,
1388                             gettext_noop ("# PONG messages decrypted"),
1389                             1,
1390                             GNUNET_NO);
1391   if ((0 !=
1392        memcmp (&t.target, kx->peer, sizeof(struct GNUNET_PeerIdentity))) ||
1393       (kx->ping_challenge != t.challenge))
1394   {
1395     /* PONG malformed */
1396     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1397                 "Received malformed PONG wanted sender `%s' with challenge %u\n",
1398                 GNUNET_i2s (kx->peer),
1399                 (unsigned int) kx->ping_challenge);
1400     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1401                 "Received malformed PONG received from `%s' with challenge %u\n",
1402                 GNUNET_i2s (&t.target),
1403                 (unsigned int) t.challenge);
1404     return;
1405   }
1406   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1407               "Received valid PONG from `%s'\n",
1408               GNUNET_i2s (kx->peer));
1409   /* no need to resend key any longer */
1410   if (NULL != kx->retry_set_key_task)
1411   {
1412     GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
1413     kx->retry_set_key_task = NULL;
1414   }
1415   switch (kx->status)
1416   {
1417   case GNUNET_CORE_KX_STATE_DOWN:
1418     GNUNET_assert (0);  /* should be impossible */
1419     return;
1420
1421   case GNUNET_CORE_KX_STATE_KEY_SENT:
1422     GNUNET_assert (0);  /* should be impossible */
1423     return;
1424
1425   case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1426     GNUNET_STATISTICS_update (GSC_stats,
1427                               gettext_noop (
1428                                 "# session keys confirmed via PONG"),
1429                               1,
1430                               GNUNET_NO);
1431     kx->status = GNUNET_CORE_KX_STATE_UP;
1432     monitor_notify_all (kx);
1433     GSC_SESSIONS_create (kx->peer, kx);
1434     GNUNET_assert (NULL == kx->keep_alive_task);
1435     update_timeout (kx);
1436     break;
1437
1438   case GNUNET_CORE_KX_STATE_UP:
1439     GNUNET_STATISTICS_update (GSC_stats,
1440                               gettext_noop ("# timeouts prevented via PONG"),
1441                               1,
1442                               GNUNET_NO);
1443     update_timeout (kx);
1444     break;
1445
1446   case GNUNET_CORE_KX_STATE_REKEY_SENT:
1447     GNUNET_STATISTICS_update (GSC_stats,
1448                               gettext_noop (
1449                                 "# rekey operations confirmed via PONG"),
1450                               1,
1451                               GNUNET_NO);
1452     kx->status = GNUNET_CORE_KX_STATE_UP;
1453     monitor_notify_all (kx);
1454     update_timeout (kx);
1455     break;
1456
1457   default:
1458     GNUNET_break (0);
1459     break;
1460   }
1461 }
1462
1463
1464 /**
1465  * Send our key to the other peer.
1466  *
1467  * @param kx key exchange context
1468  */
1469 static void
1470 send_key (struct GSC_KeyExchangeInfo *kx)
1471 {
1472   struct GNUNET_MQ_Envelope *env;
1473
1474   GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
1475   if (NULL != kx->retry_set_key_task)
1476   {
1477     GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
1478     kx->retry_set_key_task = NULL;
1479   }
1480   /* always update sender status in SET KEY message */
1481 #if DEBUG_KX
1482   {
1483     struct GNUNET_HashCode hc;
1484
1485     GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1486                         sizeof(current_ekm.ephemeral_key),
1487                         &hc);
1488     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1489                 "Sending EPHEMERAL_KEY %s to `%s' (my status: %d)\n",
1490                 GNUNET_h2s (&hc),
1491                 GNUNET_i2s (kx->peer),
1492                 kx->status);
1493   }
1494 #endif
1495   current_ekm.sender_status = htonl ((int32_t) (kx->status));
1496   env = GNUNET_MQ_msg_copy (&current_ekm.header);
1497   GNUNET_MQ_send (kx->mq, env);
1498   if (GNUNET_CORE_KX_STATE_KEY_SENT != kx->status)
1499     send_ping (kx);
1500   kx->retry_set_key_task =
1501     GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency,
1502                                   &set_key_retry_task,
1503                                   kx);
1504 }
1505
1506
1507 /**
1508  * Encrypt and transmit a message with the given payload.
1509  *
1510  * @param kx key exchange context
1511  * @param payload payload of the message
1512  * @param payload_size number of bytes in @a payload
1513  */
1514 void
1515 GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
1516                              const void *payload,
1517                              size_t payload_size)
1518 {
1519   size_t used = payload_size + sizeof(struct EncryptedMessage);
1520   char pbuf[used]; /* plaintext */
1521   struct EncryptedMessage *em; /* encrypted message */
1522   struct EncryptedMessage *ph; /* plaintext header */
1523   struct GNUNET_MQ_Envelope *env;
1524   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1525   struct GNUNET_CRYPTO_AuthKey auth_key;
1526
1527   ph = (struct EncryptedMessage *) pbuf;
1528   ph->sequence_number = htonl (++kx->last_sequence_number_sent);
1529   ph->iv_seed = calculate_seed (kx);
1530   ph->reserved = 0;
1531   ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1532   GNUNET_memcpy (&ph[1], payload, payload_size);
1533   env = GNUNET_MQ_msg_extra (em,
1534                              payload_size,
1535                              GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE);
1536   em->iv_seed = ph->iv_seed;
1537   derive_iv (&iv, &kx->encrypt_key, ph->iv_seed, kx->peer);
1538   GNUNET_assert (GNUNET_OK == do_encrypt (kx,
1539                                           &iv,
1540                                           &ph->sequence_number,
1541                                           &em->sequence_number,
1542                                           used - ENCRYPTED_HEADER_SIZE));
1543 #if DEBUG_KX
1544   {
1545     struct GNUNET_HashCode hc;
1546
1547     GNUNET_CRYPTO_hash (&ph->sequence_number,
1548                         used - ENCRYPTED_HEADER_SIZE,
1549                         &hc);
1550     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1551                 "Encrypted payload `%s' of %u bytes for %s\n",
1552                 GNUNET_h2s (&hc),
1553                 (unsigned int) (used - ENCRYPTED_HEADER_SIZE),
1554                 GNUNET_i2s (kx->peer));
1555   }
1556 #endif
1557   derive_auth_key (&auth_key, &kx->encrypt_key, ph->iv_seed);
1558   GNUNET_CRYPTO_hmac (&auth_key,
1559                       &em->sequence_number,
1560                       used - ENCRYPTED_HEADER_SIZE,
1561                       &em->hmac);
1562 #if DEBUG_KX
1563   {
1564     struct GNUNET_HashCode hc;
1565
1566     GNUNET_CRYPTO_hash (&auth_key, sizeof(auth_key), &hc);
1567     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1568                 "For peer %s, used AC %s to create hmac %s\n",
1569                 GNUNET_i2s (kx->peer),
1570                 GNUNET_h2s (&hc),
1571                 GNUNET_h2s2 (&em->hmac));
1572   }
1573 #endif
1574   kx->has_excess_bandwidth = GNUNET_NO;
1575   GNUNET_MQ_send (kx->mq, env);
1576 }
1577
1578
1579 /**
1580  * We received an encrypted message.  Check that it is
1581  * well-formed (size-wise).
1582  *
1583  * @param cls key exchange context for encrypting the message
1584  * @param m encrypted message
1585  * @return #GNUNET_OK if @a msg is well-formed (size-wise)
1586  */
1587 static int
1588 check_encrypted (void *cls, const struct EncryptedMessage *m)
1589 {
1590   uint16_t size = ntohs (m->header.size) - sizeof(*m);
1591
1592   if (size < sizeof(struct GNUNET_MessageHeader))
1593   {
1594     GNUNET_break_op (0);
1595     return GNUNET_SYSERR;
1596   }
1597   return GNUNET_OK;
1598 }
1599
1600
1601 /**
1602  * We received an encrypted message.  Decrypt, validate and
1603  * pass on to the appropriate clients.
1604  *
1605  * @param cls key exchange context for encrypting the message
1606  * @param m encrypted message
1607  */
1608 static void
1609 handle_encrypted (void *cls, const struct EncryptedMessage *m)
1610 {
1611   struct GSC_KeyExchangeInfo *kx = cls;
1612   struct EncryptedMessage *pt; /* plaintext */
1613   struct GNUNET_HashCode ph;
1614   uint32_t snum;
1615   struct GNUNET_TIME_Absolute t;
1616   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1617   struct GNUNET_CRYPTO_AuthKey auth_key;
1618   uint16_t size = ntohs (m->header.size);
1619   char buf[size] GNUNET_ALIGN;
1620
1621   if (GNUNET_CORE_KX_STATE_UP != kx->status)
1622   {
1623     GNUNET_STATISTICS_update (GSC_stats,
1624                               gettext_noop (
1625                                 "# DATA message dropped (out of order)"),
1626                               1,
1627                               GNUNET_NO);
1628     return;
1629   }
1630   if (0 ==
1631       GNUNET_TIME_absolute_get_remaining (kx->foreign_key_expires).rel_value_us)
1632   {
1633     GNUNET_log (
1634       GNUNET_ERROR_TYPE_WARNING,
1635       _ (
1636         "Session to peer `%s' went down due to key expiration (should not happen)\n"),
1637       GNUNET_i2s (kx->peer));
1638     GNUNET_STATISTICS_update (GSC_stats,
1639                               gettext_noop (
1640                                 "# sessions terminated by key expiration"),
1641                               1,
1642                               GNUNET_NO);
1643     GSC_SESSIONS_end (kx->peer);
1644     if (NULL != kx->keep_alive_task)
1645     {
1646       GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
1647       kx->keep_alive_task = NULL;
1648     }
1649     kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1650     monitor_notify_all (kx);
1651     send_key (kx);
1652     return;
1653   }
1654
1655   /* validate hash */
1656 #if DEBUG_KX
1657   {
1658     struct GNUNET_HashCode hc;
1659
1660     GNUNET_CRYPTO_hash (&m->sequence_number, size - ENCRYPTED_HEADER_SIZE, &hc);
1661     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1662                 "Received encrypted payload `%s' of %u bytes from %s\n",
1663                 GNUNET_h2s (&hc),
1664                 (unsigned int) (size - ENCRYPTED_HEADER_SIZE),
1665                 GNUNET_i2s (kx->peer));
1666   }
1667 #endif
1668   derive_auth_key (&auth_key, &kx->decrypt_key, m->iv_seed);
1669   GNUNET_CRYPTO_hmac (&auth_key,
1670                       &m->sequence_number,
1671                       size - ENCRYPTED_HEADER_SIZE,
1672                       &ph);
1673 #if DEBUG_KX
1674   {
1675     struct GNUNET_HashCode hc;
1676
1677     GNUNET_CRYPTO_hash (&auth_key, sizeof(auth_key), &hc);
1678     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1679                 "For peer %s, used AC %s to verify hmac %s\n",
1680                 GNUNET_i2s (kx->peer),
1681                 GNUNET_h2s (&hc),
1682                 GNUNET_h2s2 (&m->hmac));
1683   }
1684 #endif
1685   if (0 != memcmp (&ph, &m->hmac, sizeof(struct GNUNET_HashCode)))
1686   {
1687     /* checksum failed */
1688     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1689                 "Failed checksum validation for a message from `%s'\n",
1690                 GNUNET_i2s (kx->peer));
1691     return;
1692   }
1693   derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity);
1694   /* decrypt */
1695   if (GNUNET_OK != do_decrypt (kx,
1696                                &iv,
1697                                &m->sequence_number,
1698                                &buf[ENCRYPTED_HEADER_SIZE],
1699                                size - ENCRYPTED_HEADER_SIZE))
1700   {
1701     GNUNET_break_op (0);
1702     return;
1703   }
1704   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1705               "Decrypted %u bytes from %s\n",
1706               (unsigned int) (size - ENCRYPTED_HEADER_SIZE),
1707               GNUNET_i2s (kx->peer));
1708   pt = (struct EncryptedMessage *) buf;
1709
1710   /* validate sequence number */
1711   snum = ntohl (pt->sequence_number);
1712   if (kx->last_sequence_number_received == snum)
1713   {
1714     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1715                 "Received duplicate message, ignoring.\n");
1716     /* duplicate, ignore */
1717     GNUNET_STATISTICS_update (GSC_stats,
1718                               gettext_noop ("# bytes dropped (duplicates)"),
1719                               size,
1720                               GNUNET_NO);
1721     return;
1722   }
1723   if ((kx->last_sequence_number_received > snum) &&
1724       (kx->last_sequence_number_received - snum > 32))
1725   {
1726     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1727                 "Received ancient out of sequence message, ignoring.\n");
1728     /* ancient out of sequence, ignore */
1729     GNUNET_STATISTICS_update (GSC_stats,
1730                               gettext_noop (
1731                                 "# bytes dropped (out of sequence)"),
1732                               size,
1733                               GNUNET_NO);
1734     return;
1735   }
1736   if (kx->last_sequence_number_received > snum)
1737   {
1738     uint32_t rotbit = 1U << (kx->last_sequence_number_received - snum - 1);
1739
1740     if ((kx->last_packets_bitmap & rotbit) != 0)
1741     {
1742       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1743                   "Received duplicate message, ignoring.\n");
1744       GNUNET_STATISTICS_update (GSC_stats,
1745                                 gettext_noop ("# bytes dropped (duplicates)"),
1746                                 size,
1747                                 GNUNET_NO);
1748       /* duplicate, ignore */
1749       return;
1750     }
1751     kx->last_packets_bitmap |= rotbit;
1752   }
1753   if (kx->last_sequence_number_received < snum)
1754   {
1755     unsigned int shift = (snum - kx->last_sequence_number_received);
1756
1757     if (shift >= 8 * sizeof(kx->last_packets_bitmap))
1758       kx->last_packets_bitmap = 0;
1759     else
1760       kx->last_packets_bitmap <<= shift;
1761     kx->last_sequence_number_received = snum;
1762   }
1763
1764   /* check timestamp */
1765   t = GNUNET_TIME_absolute_ntoh (pt->timestamp);
1766   if (GNUNET_TIME_absolute_get_duration (t).rel_value_us >
1767       MAX_MESSAGE_AGE.rel_value_us)
1768   {
1769     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1770                 "Message received far too old (%s). Content ignored.\n",
1771                 GNUNET_STRINGS_relative_time_to_string (
1772                   GNUNET_TIME_absolute_get_duration (t),
1773                   GNUNET_YES));
1774     GNUNET_STATISTICS_update (GSC_stats,
1775                               gettext_noop (
1776                                 "# bytes dropped (ancient message)"),
1777                               size,
1778                               GNUNET_NO);
1779     return;
1780   }
1781
1782   /* process decrypted message(s) */
1783   update_timeout (kx);
1784   GNUNET_STATISTICS_update (GSC_stats,
1785                             gettext_noop ("# bytes of payload decrypted"),
1786                             size - sizeof(struct EncryptedMessage),
1787                             GNUNET_NO);
1788   if (GNUNET_OK !=
1789       GNUNET_MST_from_buffer (kx->mst,
1790                               &buf[sizeof(struct EncryptedMessage)],
1791                               size - sizeof(struct EncryptedMessage),
1792                               GNUNET_YES,
1793                               GNUNET_NO))
1794     GNUNET_break_op (0);
1795 }
1796
1797
1798 /**
1799  * One of our neighbours has excess bandwidth, remember this.
1800  *
1801  * @param cls NULL
1802  * @param pid identity of the peer with excess bandwidth
1803  * @param connect_cls the `struct Neighbour`
1804  */
1805 static void
1806 handle_transport_notify_excess_bw (void *cls,
1807                                    const struct GNUNET_PeerIdentity *pid,
1808                                    void *connect_cls)
1809 {
1810   struct GSC_KeyExchangeInfo *kx = connect_cls;
1811
1812   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1813               "Peer %s has excess bandwidth available\n",
1814               GNUNET_i2s (pid));
1815   kx->has_excess_bandwidth = GNUNET_YES;
1816   GSC_SESSIONS_solicit (pid);
1817 }
1818
1819
1820 /**
1821  * Setup the message that links the ephemeral key to our persistent
1822  * public key and generate the appropriate signature.
1823  */
1824 static void
1825 sign_ephemeral_key ()
1826 {
1827   current_ekm.header.size = htons (sizeof(struct EphemeralKeyMessage));
1828   current_ekm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY);
1829   current_ekm.sender_status = 0; /* to be set later */
1830   current_ekm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY);
1831   current_ekm.purpose.size =
1832     htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
1833            + sizeof(struct GNUNET_TIME_AbsoluteNBO)
1834            + sizeof(struct GNUNET_TIME_AbsoluteNBO)
1835            + sizeof(struct GNUNET_CRYPTO_EcdhePublicKey)
1836            + sizeof(struct GNUNET_PeerIdentity));
1837   current_ekm.creation_time =
1838     GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1839   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (GSC_cfg,
1840                                                           "core",
1841                                                           "USE_EPHEMERAL_KEYS"))
1842   {
1843     current_ekm.expiration_time =
1844       GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (
1845                                    GNUNET_TIME_relative_add (REKEY_FREQUENCY,
1846                                                              REKEY_TOLERANCE)));
1847   }
1848   else
1849   {
1850     current_ekm.expiration_time =
1851       GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
1852   }
1853   GNUNET_CRYPTO_ecdhe_key_get_public (my_ephemeral_key,
1854                                       &current_ekm.ephemeral_key);
1855   current_ekm.origin_identity = GSC_my_identity;
1856   GNUNET_assert (GNUNET_OK ==
1857                  GNUNET_CRYPTO_eddsa_sign_ (my_private_key,
1858                                             &current_ekm.purpose,
1859                                             &current_ekm.signature));
1860 }
1861
1862
1863 /**
1864  * Task run to trigger rekeying.
1865  *
1866  * @param cls closure, NULL
1867  */
1868 static void
1869 do_rekey (void *cls)
1870 {
1871   struct GSC_KeyExchangeInfo *pos;
1872
1873   rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, &do_rekey, NULL);
1874   if (NULL != my_ephemeral_key)
1875     GNUNET_free (my_ephemeral_key);
1876   my_ephemeral_key = GNUNET_CRYPTO_ecdhe_key_create ();
1877   GNUNET_assert (NULL != my_ephemeral_key);
1878   sign_ephemeral_key ();
1879   {
1880     struct GNUNET_HashCode eh;
1881
1882     GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1883                         sizeof(current_ekm.ephemeral_key),
1884                         &eh);
1885     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Rekeying to %s\n", GNUNET_h2s (&eh));
1886   }
1887   for (pos = kx_head; NULL != pos; pos = pos->next)
1888   {
1889     if (GNUNET_CORE_KX_STATE_UP == pos->status)
1890     {
1891       pos->status = GNUNET_CORE_KX_STATE_REKEY_SENT;
1892       monitor_notify_all (pos);
1893       derive_session_keys (pos);
1894     }
1895     if (GNUNET_CORE_KX_STATE_DOWN == pos->status)
1896     {
1897       pos->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1898       monitor_notify_all (pos);
1899     }
1900     monitor_notify_all (pos);
1901     send_key (pos);
1902   }
1903 }
1904
1905
1906 /**
1907  * Initialize KX subsystem.
1908  *
1909  * @param pk private key to use for the peer
1910  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1911  */
1912 int
1913 GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
1914 {
1915   struct GNUNET_MQ_MessageHandler handlers[] =
1916   { GNUNET_MQ_hd_fixed_size (ephemeral_key,
1917                              GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY,
1918                              struct EphemeralKeyMessage,
1919                              NULL),
1920     GNUNET_MQ_hd_fixed_size (ping,
1921                              GNUNET_MESSAGE_TYPE_CORE_PING,
1922                              struct PingMessage,
1923                              NULL),
1924     GNUNET_MQ_hd_fixed_size (pong,
1925                              GNUNET_MESSAGE_TYPE_CORE_PONG,
1926                              struct PongMessage,
1927                              NULL),
1928     GNUNET_MQ_hd_var_size (encrypted,
1929                            GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE,
1930                            struct EncryptedMessage,
1931                            NULL),
1932     GNUNET_MQ_handler_end () };
1933
1934   my_private_key = pk;
1935   GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
1936                                       &GSC_my_identity.public_key);
1937   my_ephemeral_key = GNUNET_CRYPTO_ecdhe_key_create ();
1938   if (NULL == my_ephemeral_key)
1939   {
1940     GNUNET_break (0);
1941     GNUNET_free (my_private_key);
1942     my_private_key = NULL;
1943     return GNUNET_SYSERR;
1944   }
1945   sign_ephemeral_key ();
1946   {
1947     struct GNUNET_HashCode eh;
1948
1949     GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1950                         sizeof(current_ekm.ephemeral_key),
1951                         &eh);
1952     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1953                 "Starting with ephemeral key %s\n",
1954                 GNUNET_h2s (&eh));
1955   }
1956
1957   nc = GNUNET_notification_context_create (1);
1958   rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, &do_rekey, NULL);
1959   transport =
1960     GNUNET_TRANSPORT_core_connect (GSC_cfg,
1961                                    &GSC_my_identity,
1962                                    handlers,
1963                                    NULL,
1964                                    &handle_transport_notify_connect,
1965                                    &handle_transport_notify_disconnect,
1966                                    &handle_transport_notify_excess_bw);
1967   if (NULL == transport)
1968   {
1969     GSC_KX_done ();
1970     return GNUNET_SYSERR;
1971   }
1972   return GNUNET_OK;
1973 }
1974
1975
1976 /**
1977  * Shutdown KX subsystem.
1978  */
1979 void
1980 GSC_KX_done ()
1981 {
1982   if (NULL != transport)
1983   {
1984     GNUNET_TRANSPORT_core_disconnect (transport);
1985     transport = NULL;
1986   }
1987   if (NULL != rekey_task)
1988   {
1989     GNUNET_SCHEDULER_cancel (rekey_task);
1990     rekey_task = NULL;
1991   }
1992   if (NULL != my_ephemeral_key)
1993   {
1994     GNUNET_free (my_ephemeral_key);
1995     my_ephemeral_key = NULL;
1996   }
1997   if (NULL != my_private_key)
1998   {
1999     GNUNET_free (my_private_key);
2000     my_private_key = NULL;
2001   }
2002   if (NULL != nc)
2003   {
2004     GNUNET_notification_context_destroy (nc);
2005     nc = NULL;
2006   }
2007 }
2008
2009
2010 /**
2011  * Check how many messages are queued for the given neighbour.
2012  *
2013  * @param kxinfo data about neighbour to check
2014  * @return number of items in the message queue
2015  */
2016 unsigned int
2017 GSC_NEIGHBOURS_get_queue_length (const struct GSC_KeyExchangeInfo *kxinfo)
2018 {
2019   return GNUNET_MQ_get_length (kxinfo->mq);
2020 }
2021
2022
2023 /**
2024  * Check if the given neighbour has excess bandwidth available.
2025  *
2026  * @param target neighbour to check
2027  * @return #GNUNET_YES if excess bandwidth is available, #GNUNET_NO if not
2028  */
2029 int
2030 GSC_NEIGHBOURS_check_excess_bandwidth (const struct GSC_KeyExchangeInfo *kxinfo)
2031 {
2032   return kxinfo->has_excess_bandwidth;
2033 }
2034
2035
2036 /**
2037  * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request.  For this
2038  * request type, the client does not have to have transmitted an INIT
2039  * request.  All current peers are returned, regardless of which
2040  * message types they accept.
2041  *
2042  * @param mq message queue to add for monitoring
2043  */
2044 void
2045 GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq)
2046 {
2047   struct GNUNET_MQ_Envelope *env;
2048   struct MonitorNotifyMessage *done_msg;
2049   struct GSC_KeyExchangeInfo *kx;
2050
2051   GNUNET_notification_context_add (nc, mq);
2052   for (kx = kx_head; NULL != kx; kx = kx->next)
2053   {
2054     struct GNUNET_MQ_Envelope *env;
2055     struct MonitorNotifyMessage *msg;
2056
2057     env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
2058     msg->state = htonl ((uint32_t) kx->status);
2059     msg->peer = *kx->peer;
2060     msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
2061     GNUNET_MQ_send (mq, env);
2062   }
2063   env = GNUNET_MQ_msg (done_msg, GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
2064   done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
2065   done_msg->timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
2066   GNUNET_MQ_send (mq, env);
2067 }
2068
2069
2070 /* end of gnunet-service-core_kx.c */