Commit 67da4884 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

SRTP/SRTCP receive window for replay attack protection

parent 0eeb4286
...@@ -72,11 +72,16 @@ int main (void) ...@@ -72,11 +72,16 @@ int main (void)
for (;;) for (;;)
{ {
len = read (fd, buf, sizeof (buf)); len = read (fd, buf, sizeof (buf));
if (srtp_recv (s, buf, &len)) int val = srtp_recv (s, buf, &len);
fputs ("Cannot decrypt!\n", stderr); if (val)
{
fprintf (stderr, "Cannot decrypt: %s\n", strerror (val));
continue;
}
puts ((char *)buf + 12); puts ((char *)buf + 12);
if (srtp_send (s, buf, &len, sizeof (buf)) || srtp_recv (s, buf, &len)) //if (srtp_send (s, buf, &len, sizeof (buf)) || srtp_recv (s, buf, &len))
break; // break;
puts ((char *)buf + 12); puts ((char *)buf + 12);
} }
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
/* TODO: /* TODO:
* Useful stuff: * Useful stuff:
* - ROC profile thingy (multicast really needs this) * - ROC profile thingy (multicast really needs this)
* - replay protection
* *
* Useless stuff (because nothing depends on it): * Useless stuff (because nothing depends on it):
* - non-nul key derivation rate * - non-nul key derivation rate
...@@ -440,6 +439,7 @@ rtp_digest (srtp_session_t *s, const uint8_t *data, size_t len) ...@@ -440,6 +439,7 @@ rtp_digest (srtp_session_t *s, const uint8_t *data, size_t len)
* *
* @return 0 on success, in case of error: * @return 0 on success, in case of error:
* EINVAL malformatted RTP packet * EINVAL malformatted RTP packet
* EACCES replayed packet or out-of-window or sync lost
*/ */
static int srtp_crypt (srtp_session_t *s, uint8_t *buf, size_t len) static int srtp_crypt (srtp_session_t *s, uint8_t *buf, size_t len)
{ {
...@@ -473,11 +473,22 @@ static int srtp_crypt (srtp_session_t *s, uint8_t *buf, size_t len) ...@@ -473,11 +473,22 @@ static int srtp_crypt (srtp_session_t *s, uint8_t *buf, size_t len)
memcpy (&ssrc, buf + 8, 4); memcpy (&ssrc, buf + 8, 4);
/* Updates ROC and sequence (it's safe now) */ /* Updates ROC and sequence (it's safe now) */
if (roc > s->rtp_roc) int16_t diff = seq - s->rtp_seq;
if (diff > 0)
{
/* Sequence in the future, good */
s->rtp.window = s->rtp.window << diff;
s->rtp.window |= 1;
s->rtp_seq = seq, s->rtp_roc = roc; s->rtp_seq = seq, s->rtp_roc = roc;
}
else else
if (seq > s->rtp_seq) {
s->rtp_seq = seq; /* Sequence in the past/present, bad */
diff = -diff;
if ((diff >= 64) || ((s->rtp.window >> diff) & 1))
return EACCES; /* Replay attack */
s->rtp.window |= 1 << diff;
}
/* Encrypt/Decrypt */ /* Encrypt/Decrypt */
if (s->flags & SRTP_UNENCRYPTED) if (s->flags & SRTP_UNENCRYPTED)
...@@ -504,6 +515,7 @@ static int srtp_crypt (srtp_session_t *s, uint8_t *buf, size_t len) ...@@ -504,6 +515,7 @@ static int srtp_crypt (srtp_session_t *s, uint8_t *buf, size_t len)
* @return 0 on success, in case of error: * @return 0 on success, in case of error:
* EINVAL malformatted RTP packet or internal error * EINVAL malformatted RTP packet or internal error
* ENOSPC bufsize is too small (to add authentication tag) * ENOSPC bufsize is too small (to add authentication tag)
* EACCES packet would trigger a replay error on receiver
*/ */
int int
srtp_send (srtp_session_t *s, uint8_t *buf, size_t *lenp, size_t bufsize) srtp_send (srtp_session_t *s, uint8_t *buf, size_t *lenp, size_t bufsize)
...@@ -543,7 +555,6 @@ int ...@@ -543,7 +555,6 @@ int
srtp_recv (srtp_session_t *s, uint8_t *buf, size_t *lenp) srtp_recv (srtp_session_t *s, uint8_t *buf, size_t *lenp)
{ {
size_t len = *lenp; size_t len = *lenp;
/* FIXME: anti-replay */
if (!(s->flags & SRTP_UNAUTHENTICATED)) if (!(s->flags & SRTP_UNAUTHENTICATED))
{ {
...@@ -600,12 +611,31 @@ static int srtcp_crypt (srtp_session_t *s, uint8_t *buf, size_t len) ...@@ -600,12 +611,31 @@ static int srtcp_crypt (srtp_session_t *s, uint8_t *buf, size_t len)
if ((len < 12) || ((buf[0] >> 6) != 2)) if ((len < 12) || ((buf[0] >> 6) != 2))
return EINVAL; return EINVAL;
/* Updates SRTCP index (safe here) */
uint32_t index; uint32_t index;
memcpy (&index, buf + len, 4); memcpy (&index, buf + len, 4);
index = ntohl (index); index = ntohl (index);
if (((index - s->rtcp_index) & 0x7fffffff) < 0x40000000) if (((index >> 31) != 0) != ((s->flags & SRTCP_UNENCRYPTED) == 0))
s->rtcp_index = index; /* Update index */ return EINVAL; // E-bit mismatch
index &= ~(1 << 31); // clear E-bit for counter
/* Updates SRTCP index (safe here) */
int32_t diff = index - s->rtcp_index;
if (diff > 0)
{
/* Packet in the future, good */
s->rtcp.window = s->rtcp.window << diff;
s->rtcp.window |= 1;
s->rtcp_index = index;
}
else
{
/* Packet in the past/present, bad */
diff = -diff;
if ((diff >= 64) || ((s->rtcp.window >> diff) & 1))
return EACCES; // replay attack!
s->rtp.window |= 1 << diff;
}
/* Crypts SRTCP */ /* Crypts SRTCP */
if (s->flags & SRTCP_UNENCRYPTED) if (s->flags & SRTCP_UNENCRYPTED)
...@@ -678,7 +708,6 @@ int ...@@ -678,7 +708,6 @@ int
srtcp_recv (srtp_session_t *s, uint8_t *buf, size_t *lenp) srtcp_recv (srtp_session_t *s, uint8_t *buf, size_t *lenp)
{ {
size_t len = *lenp; size_t len = *lenp;
/* FIXME: anti-replay ?? */
if (len < (4u + s->tag_len)) if (len < (4u + s->tag_len))
return EINVAL; return EINVAL;
......
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