From: Christian Grothoff Date: Fri, 21 Oct 2011 07:36:45 +0000 (+0000) Subject: fixing 1792: validate signature in disconnect request X-Git-Tag: initial-import-from-subversion-38251~16359 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=aa8bd9308ea05cd501348ae5f17447253b92ac5c;p=oweals%2Fgnunet.git fixing 1792: validate signature in disconnect request --- diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index 561873cd9..6273816c7 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -276,9 +276,7 @@ plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer, NULL); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT: - /* FIXME: do some validation to prevent an attacker from sending - * a fake disconnect message... */ - GST_neighbours_force_disconnect (peer); + GST_neighbours_handle_disconnect_message (peer, message); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE: GST_neighbours_keepalive (peer); diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c index 23ff82f91..efb94b6f1 100644 --- a/src/transport/gnunet-service-transport_neighbours.c +++ b/src/transport/gnunet-service-transport_neighbours.c @@ -111,12 +111,18 @@ struct SessionDisconnectMessage */ struct GNUNET_TIME_AbsoluteNBO timestamp; + /** + * Public key of the sender. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + /** * Signature of the peer that sends us the disconnect. Only * valid if the timestamp is AFTER the timestamp from the * corresponding 'CONNECT' message. */ struct GNUNET_CRYPTO_RsaSignature signature; + }; @@ -1169,9 +1175,11 @@ GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target) disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT); disconnect_msg.reserved = htonl (0); disconnect_msg.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + - sizeof (struct GNUNET_TIME_AbsoluteNBO)); + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + sizeof (struct GNUNET_TIME_AbsoluteNBO) ); disconnect_msg.purpose.purpose = htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT); disconnect_msg.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + disconnect_msg.public_key = GST_my_public_key; GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (GST_my_private_key, &disconnect_msg.purpose, @@ -1194,6 +1202,72 @@ GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target) } +/** + * We received a disconnect message from the given peer, + * validate and process. + * + * @param peer sender of the message + * @param msg the disconnect message + */ +void +GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *msg) +{ + struct NeighbourMapEntry *n; + const struct SessionDisconnectMessage *sdm; + GNUNET_HashCode hc; + + if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage)) + { + // GNUNET_break_op (0); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# disconnect messages ignored (old format)"), 1, + GNUNET_NO); + return; + } + sdm = (const struct SessionDisconnectMessage* ) msg; + n = lookup_neighbour (peer); + if (NULL == n) + return; /* gone already */ + if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <= + n->connect_ts.abs_value) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# disconnect messages ignored (timestamp)"), 1, + GNUNET_NO); + return; + } + GNUNET_CRYPTO_hash (&sdm->public_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &hc); + if (0 != memcmp (peer, + &hc, + sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break_op (0); + return; + } + if (ntohl (sdm->purpose.size) != + sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + sizeof (struct GNUNET_TIME_AbsoluteNBO)) + { + GNUNET_break_op (0); + return; + } + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT, + &sdm->purpose, + &sdm->signature, + &sdm->public_key)) + { + GNUNET_break_op (0); + return; + } + GST_neighbours_force_disconnect (peer); +} + + /** * We received a 'SESSION_CONNECT' message from the other peer. * Consider switching to it. diff --git a/src/transport/gnunet-service-transport_neighbours.h b/src/transport/gnunet-service-transport_neighbours.h index 2f6962a67..27f7aae31 100644 --- a/src/transport/gnunet-service-transport_neighbours.h +++ b/src/transport/gnunet-service-transport_neighbours.h @@ -232,6 +232,17 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count); +/** + * We received a disconnect message from the given peer, + * validate and process. + * + * @param peer sender of the message + * @param msg the disconnect message + */ +void +GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *msg); + #endif /* end of file gnunet-service-transport_neighbours.h */