use trial & error approach to guess ROC in case of SRTP auth failures

Fixes #71
pull/81/head
Richard Fuchs 10 years ago
parent deba231143
commit fb9ed6ef0a

@ -184,13 +184,37 @@ int rtp_savp2avp(str *s, struct crypto_context *c) {
s, &payload)) s, &payload))
return -1; return -1;
if (auth_tag.len) { if (!auth_tag.len)
goto decrypt;
/* authenticate */
assert(sizeof(hmac) >= auth_tag.len); assert(sizeof(hmac) >= auth_tag.len);
c->params.crypto_suite->hash_rtp(c, hmac, &to_auth, index); c->params.crypto_suite->hash_rtp(c, hmac, &to_auth, index);
if (str_memcmp(&auth_tag, hmac)) if (!str_memcmp(&auth_tag, hmac))
goto error; goto decrypt;
/* possible ROC mismatch, attempt to guess */
/* first, let's see if we missed a rollover */
index += 0x10000;
c->params.crypto_suite->hash_rtp(c, hmac, &to_auth, index);
if (!str_memcmp(&auth_tag, hmac))
goto decrypt_idx;
/* or maybe we did a rollover too many */
if (index >= 0x20000) {
index -= 0x20000;
c->params.crypto_suite->hash_rtp(c, hmac, &to_auth, index);
if (!str_memcmp(&auth_tag, hmac))
goto decrypt_idx;
} }
/* last guess: reset ROC to zero */
index &= 0xffff;
c->params.crypto_suite->hash_rtp(c, hmac, &to_auth, index);
if (!str_memcmp(&auth_tag, hmac))
goto decrypt_idx;
goto error;
decrypt_idx:
c->last_index = index;
decrypt:
if (crypto_decrypt_rtp(c, rtp, &to_decrypt, index)) if (crypto_decrypt_rtp(c, rtp, &to_decrypt, index))
return -1; return -1;

@ -1899,6 +1899,17 @@ static u_int64_t packet_index(struct re_crypto_context *c,
return index; return index;
} }
static void update_packet_index(struct re_crypto_context *c,
struct rtpengine_srtp *s, u_int64_t idx)
{
unsigned long flags;
spin_lock_irqsave(&c->lock, flags);
s->last_index = idx;
c->roc = (idx >> 16);
spin_unlock_irqrestore(&c->lock, flags);
}
static int srtp_hash(unsigned char *hmac, static int srtp_hash(unsigned char *hmac,
struct re_crypto_context *c, struct re_crypto_context *c,
struct rtpengine_srtp *s, struct rtp_parsed *r, struct rtpengine_srtp *s, struct rtp_parsed *r,
@ -1983,10 +1994,11 @@ static int srtp_authenticate(struct re_crypto_context *c,
static int srtp_auth_validate(struct re_crypto_context *c, static int srtp_auth_validate(struct re_crypto_context *c,
struct rtpengine_srtp *s, struct rtp_parsed *r, struct rtpengine_srtp *s, struct rtp_parsed *r,
u_int64_t pkt_idx) u_int64_t *pkt_idx_p)
{ {
unsigned char *auth_tag; unsigned char *auth_tag;
unsigned char hmac[20]; unsigned char hmac[20];
u_int64_t pkt_idx = *pkt_idx_p;
if (s->hmac == REH_NULL) if (s->hmac == REH_NULL)
return 0; return 0;
@ -2015,12 +2027,36 @@ static int srtp_auth_validate(struct re_crypto_context *c,
if (srtp_hash(hmac, c, s, r, pkt_idx)) if (srtp_hash(hmac, c, s, r, pkt_idx))
return -1; return -1;
if (!memcmp(auth_tag, hmac, s->auth_tag_len))
goto ok;
if (memcmp(auth_tag, hmac, s->auth_tag_len)) /* possible ROC mismatch, attempt to guess */
/* first, let's see if we missed a rollover */
pkt_idx += 0x10000;
if (srtp_hash(hmac, c, s, r, pkt_idx))
return -1; return -1;
if (!memcmp(auth_tag, hmac, s->auth_tag_len))
goto ok;
/* or maybe we did a rollover too many */
if (pkt_idx >= 0x20000) {
pkt_idx -= 0x20000;
if (srtp_hash(hmac, c, s, r, pkt_idx))
return -1;
if (!memcmp(auth_tag, hmac, s->auth_tag_len))
goto ok;
}
/* last guess: reset ROC to zero */
pkt_idx &= 0xffff;
if (srtp_hash(hmac, c, s, r, pkt_idx))
return -1;
if (!memcmp(auth_tag, hmac, s->auth_tag_len))
goto ok;
return 0; return -1;
ok:
*pkt_idx_p = pkt_idx;
return 0;
} }
@ -2114,7 +2150,7 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t,
unsigned long flags; unsigned long flags;
u_int32_t *u32; u_int32_t *u32;
struct rtp_parsed rtp; struct rtp_parsed rtp;
u_int64_t pkt_idx = 0; u_int64_t pkt_idx = 0, pkt_idx_u;
skb_reset_transport_header(skb); skb_reset_transport_header(skb);
uh = udp_hdr(skb); uh = udp_hdr(skb);
@ -2177,9 +2213,11 @@ src_check_ok:
} }
if (g->target.rtcp_mux && is_muxed_rtcp(&rtp)) if (g->target.rtcp_mux && is_muxed_rtcp(&rtp))
goto skip1; goto skip1;
pkt_idx = packet_index(&g->decrypt, &g->target.decrypt, rtp.header); pkt_idx_u = pkt_idx = packet_index(&g->decrypt, &g->target.decrypt, rtp.header);
if (srtp_auth_validate(&g->decrypt, &g->target.decrypt, &rtp, pkt_idx)) if (srtp_auth_validate(&g->decrypt, &g->target.decrypt, &rtp, &pkt_idx))
goto skip_error; goto skip_error;
if (pkt_idx != pkt_idx_u)
update_packet_index(&g->decrypt, &g->target.decrypt, pkt_idx);
if (srtp_decrypt(&g->decrypt, &g->target.decrypt, &rtp, pkt_idx)) if (srtp_decrypt(&g->decrypt, &g->target.decrypt, &rtp, pkt_idx))
goto skip_error; goto skip_error;

Loading…
Cancel
Save