Commit 7e5ab23c authored by Jakub Adam's avatar Jakub Adam Committed by Olivier Crête

ms-ice: legacy FINGERPRINT mode

In order to preserve compatibility with clients which use custom CRC
lookup table from [MS-ICE2], whenever a connectivity check request or
reply is sent, an additional message is sent along. These two messages
differ only in FINGERPRINT attribute - one uses regular CRC lookup table
for calculation, the other uses the modified table.

When a message is received and FINGERPRINT doesn't pass validation using
regular CRC table, the receiver also tries to verify using the modified
table.

[MS-ICE2] 3.1.4.8.2 describes this procedure.

The commit fixes compatibility with older MSOC and Lync clients.

Differential Revision: https://phabricator.freedesktop.org/D1138
parent dab34160
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include "agent-priv.h" #include "agent-priv.h"
#include "conncheck.h" #include "conncheck.h"
#include "discovery.h" #include "discovery.h"
#include "stun/stun5389.h"
#include "stun/usages/ice.h" #include "stun/usages/ice.h"
#include "stun/usages/bind.h" #include "stun/usages/bind.h"
#include "stun/usages/turn.h" #include "stun/usages/turn.h"
...@@ -778,7 +779,37 @@ static guint32 peer_reflexive_candidate_priority (NiceAgent *agent, ...@@ -778,7 +779,37 @@ static guint32 peer_reflexive_candidate_priority (NiceAgent *agent,
return priority; return priority;
} }
static void ms_ice2_legacy_conncheck_send(StunMessage *msg, NiceSocket *sock,
const NiceAddress *remote_addr)
{
uint32_t *fingerprint_attr;
uint32_t fingerprint_orig;
uint16_t fingerprint_len;
size_t buffer_len;
fingerprint_attr = (uint32_t *)stun_message_find (msg,
STUN_ATTRIBUTE_FINGERPRINT, &fingerprint_len);
if (fingerprint_attr == NULL) {
nice_debug ("FINGERPRINT not found.");
return;
}
if (fingerprint_len != sizeof (fingerprint_orig)) {
nice_debug ("Unexpected FINGERPRINT length %u.", fingerprint_len);
return;
}
memcpy (&fingerprint_orig, fingerprint_attr, sizeof (fingerprint_orig));
buffer_len = stun_message_length (msg);
*fingerprint_attr = stun_fingerprint (msg->buffer, buffer_len, TRUE);
agent_socket_send (sock, remote_addr, buffer_len, (gchar *)msg->buffer);
memcpy (fingerprint_attr, &fingerprint_orig, sizeof (fingerprint_orig));
}
/* /*
* Timer callback that handles initiating and managing connectivity * Timer callback that handles initiating and managing connectivity
...@@ -883,6 +914,11 @@ static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent) ...@@ -883,6 +914,11 @@ static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent)
agent_socket_send (p->local->sockptr, &p->remote->addr, buf_len, agent_socket_send (p->local->sockptr, &p->remote->addr, buf_len,
(gchar *)p->keepalive.stun_buffer); (gchar *)p->keepalive.stun_buffer);
if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
ms_ice2_legacy_conncheck_send (&p->keepalive.stun_message,
p->local->sockptr, &p->remote->addr);
}
nice_debug ("Agent %p : stun_bind_keepalive for pair %p res %d.", nice_debug ("Agent %p : stun_bind_keepalive for pair %p res %d.",
agent, p, (int) buf_len); agent, p, (int) buf_len);
} else { } else {
...@@ -2167,6 +2203,11 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair) ...@@ -2167,6 +2203,11 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
agent_socket_send (pair->sockptr, &pair->remote->addr, agent_socket_send (pair->sockptr, &pair->remote->addr,
buffer_len, (gchar *)pair->stun_buffer); buffer_len, (gchar *)pair->stun_buffer);
if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
ms_ice2_legacy_conncheck_send (&pair->stun_message, pair->sockptr,
&pair->remote->addr);
}
timeout = stun_timer_remainder (&pair->timer); timeout = stun_timer_remainder (&pair->timer);
/* note: convert from milli to microseconds for g_time_val_add() */ /* note: convert from milli to microseconds for g_time_val_add() */
g_get_current_time (&pair->next_tick); g_get_current_time (&pair->next_tick);
...@@ -2372,12 +2413,15 @@ static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *str ...@@ -2372,12 +2413,15 @@ static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *str
* @param toaddr address to which reply is sent * @param toaddr address to which reply is sent
* @param socket the socket over which the request came * @param socket the socket over which the request came
* @param rbuf_len length of STUN message to send * @param rbuf_len length of STUN message to send
* @param rbuf buffer containing the STUN message to send * @param msg the STUN message to send
* @param use_candidate whether the request had USE_CANDIDATE attribute * @param use_candidate whether the request had USE_CANDIDATE attribute
* *
* @pre (rcand == NULL || nice_address_equal(rcand->addr, toaddr) == TRUE) * @pre (rcand == NULL || nice_address_equal(rcand->addr, toaddr) == TRUE)
*/ */
static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceCandidate *lcand, NiceCandidate *rcand, const NiceAddress *toaddr, NiceSocket *sockptr, size_t rbuf_len, uint8_t *rbuf, gboolean use_candidate) static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream,
NiceComponent *component, NiceCandidate *lcand, NiceCandidate *rcand,
const NiceAddress *toaddr, NiceSocket *sockptr, size_t rbuf_len,
StunMessage *msg, gboolean use_candidate)
{ {
g_assert (rcand == NULL || nice_address_equal(&rcand->addr, toaddr) == TRUE); g_assert (rcand == NULL || nice_address_equal(&rcand->addr, toaddr) == TRUE);
...@@ -2393,7 +2437,10 @@ static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream, Nice ...@@ -2393,7 +2437,10 @@ static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream, Nice
(int)use_candidate); (int)use_candidate);
} }
agent_socket_send (sockptr, toaddr, rbuf_len, (const gchar*)rbuf); agent_socket_send (sockptr, toaddr, rbuf_len, (const gchar*)msg->buffer);
if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
ms_ice2_legacy_conncheck_send(msg, sockptr, toaddr);
}
if (rcand) { if (rcand) {
/* note: upon successful check, make the reserve check immediately */ /* note: upon successful check, make the reserve check immediately */
...@@ -3601,7 +3648,7 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream, ...@@ -3601,7 +3648,7 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream,
} }
priv_reply_to_conn_check (agent, stream, component, local_candidate, priv_reply_to_conn_check (agent, stream, component, local_candidate,
remote_candidate, from, nicesock, rbuf_len, rbuf, use_candidate); remote_candidate, from, nicesock, rbuf_len, &msg, use_candidate);
if (component->remote_candidates == NULL) { if (component->remote_candidates == NULL) {
/* case: We've got a valid binding request to a local candidate /* case: We've got a valid binding request to a local candidate
......
...@@ -98,13 +98,48 @@ bool stun_agent_default_validater (StunAgent *agent, ...@@ -98,13 +98,48 @@ bool stun_agent_default_validater (StunAgent *agent,
} }
static bool stun_agent_check_fingerprint(StunAgent *agent, StunMessage *msg)
{
uint32_t fpr;
uint32_t crc32;
uint16_t msg_len;
/* Looks for FINGERPRINT */
if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) !=
STUN_MESSAGE_RETURN_SUCCESS) {
stun_debug ("STUN demux error: no FINGERPRINT attribute!");
return FALSE;
}
msg_len = stun_message_length (msg);
/* Checks FINGERPRINT */
crc32 = stun_fingerprint (msg->buffer, msg_len, FALSE);
fpr = ntohl (fpr);
if (fpr != crc32) {
uint16_t palen;
/* [MS-ICE2] 3.1.4.8.2 Connectivity Checks Phase - legacy compatibility */
if (agent->compatibility == STUN_COMPATIBILITY_MSICE2 &&
stun_message_find (msg, STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION,
&palen) == NULL &&
fpr == stun_fingerprint (msg->buffer, msg_len, TRUE)) {
return TRUE;
}
stun_debug ("STUN demux error: bad fingerprint: 0x%08x, expected: 0x%08x!",
fpr, crc32);
return FALSE;
}
return TRUE;
}
StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg, StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
const uint8_t *buffer, size_t buffer_len, const uint8_t *buffer, size_t buffer_len,
StunMessageIntegrityValidate validater, void * validater_data) StunMessageIntegrityValidate validater, void * validater_data)
{ {
StunTransactionId msg_id; StunTransactionId msg_id;
uint32_t fpr;
uint32_t crc32;
int len; int len;
uint8_t *username = NULL; uint8_t *username = NULL;
uint16_t username_len; uint16_t username_len;
...@@ -148,18 +183,7 @@ StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg, ...@@ -148,18 +183,7 @@ StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 || if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
agent->compatibility == STUN_COMPATIBILITY_MSICE2) && agent->compatibility == STUN_COMPATIBILITY_MSICE2) &&
agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) { agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
/* Looks for FINGERPRINT */ if (stun_agent_check_fingerprint(agent, msg) == FALSE) {
if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) !=
STUN_MESSAGE_RETURN_SUCCESS) {
stun_debug ("STUN demux error: no FINGERPRINT attribute!");
return STUN_VALIDATION_BAD_REQUEST;
}
/* Checks FINGERPRINT */
crc32 = stun_fingerprint (msg->buffer, stun_message_length (msg), FALSE);
fpr = ntohl (fpr);
if (fpr != crc32) {
stun_debug ("STUN demux error: bad fingerprint: 0x%08x,"
" expected: 0x%08x!", fpr, crc32);
return STUN_VALIDATION_BAD_REQUEST; return STUN_VALIDATION_BAD_REQUEST;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment