Browse Source

implement srtcp encryption, decryption and authentication

git.mgm/mediaproxy-ng/github/master
Richard Fuchs 13 years ago
parent
commit
db72130792
8 changed files with 290 additions and 114 deletions
  1. +3
    -3
      daemon/call.c
  2. +52
    -2
      daemon/crypto.c
  3. +29
    -11
      daemon/crypto.h
  4. +92
    -11
      daemon/rtcp.c
  5. +22
    -0
      daemon/rtcp.h
  6. +82
    -87
      daemon/rtp.c
  7. +5
    -0
      daemon/rtp.h
  8. +5
    -0
      daemon/str.h

+ 3
- 3
daemon/call.c View File

@ -224,16 +224,16 @@ static int call_avpf2avp(str *s, struct streamrelay *r) {
return rtcp_avpf2avp(s);
}
static int call_avp2savp_rtp(str *s, struct streamrelay *r) {
return rtp_savp2avp(s, &r->peer.crypto.out);
return rtp_avp2savp(s, &r->peer.crypto.out);
}
static int call_avp2savp_rtcp(str *s, struct streamrelay *r) {
return 0;
return rtcp_avp2savp(s, &r->peer.crypto.out);
}
static int call_savp2avp_rtp(str *s, struct streamrelay *r) {
return rtp_savp2avp(s, &r->peer.crypto.in);
}
static int call_savp2avp_rtcp(str *s, struct streamrelay *r) {
return 0;
return rtcp_savp2avp(s, &r->peer.crypto.in);
}


+ 52
- 2
daemon/crypto.c View File

@ -7,11 +7,14 @@
#include "str.h"
#include "aux.h"
#include "rtp.h"
#include "rtcp.h"
static int aes_cm_encrypt_rtp(struct crypto_context *, struct rtp_header *, str *, u_int64_t);
static int aes_cm_encrypt_rtcp(struct crypto_context *, struct rtcp_packet *, str *, u_int64_t);
static int hmac_sha1_rtp(struct crypto_context *, char *out, str *in, u_int64_t);
static int hmac_sha1_rtcp(struct crypto_context *, char *out, str *in);
/* all lengths are in bits, some code assumes everything to be multiples of 8 */
const struct crypto_suite crypto_suites[] = {
@ -32,7 +35,10 @@ const struct crypto_suite crypto_suites[] = {
.srtcp_auth_key_len = 160,
.encrypt_rtp = aes_cm_encrypt_rtp,
.decrypt_rtp = aes_cm_encrypt_rtp,
.encrypt_rtcp = aes_cm_encrypt_rtcp,
.decrypt_rtcp = aes_cm_encrypt_rtcp,
.hash_rtp = hmac_sha1_rtp,
.hash_rtcp = hmac_sha1_rtcp,
},
{
.name = "AES_CM_128_HMAC_SHA1_32",
@ -51,7 +57,10 @@ const struct crypto_suite crypto_suites[] = {
.srtcp_auth_key_len = 160,
.encrypt_rtp = aes_cm_encrypt_rtp,
.decrypt_rtp = aes_cm_encrypt_rtp,
.encrypt_rtcp = aes_cm_encrypt_rtcp,
.decrypt_rtcp = aes_cm_encrypt_rtcp,
.hash_rtp = hmac_sha1_rtp,
.hash_rtcp = hmac_sha1_rtcp,
},
{
.name = "F8_128_HMAC_SHA1_80",
@ -69,6 +78,7 @@ const struct crypto_suite crypto_suites[] = {
.srtp_auth_key_len = 160,
.srtcp_auth_key_len = 160,
.hash_rtp = hmac_sha1_rtp,
.hash_rtcp = hmac_sha1_rtcp,
},
};
@ -197,7 +207,7 @@ int crypto_gen_session_key(struct crypto_context *c, str *out, unsigned char lab
}
/* rfc 3711 section 4.1.1 */
static int aes_cm_encrypt_rtp(struct crypto_context *c, struct rtp_header *r, str *s, u_int64_t idx) {
static int aes_cm_encrypt(struct crypto_context *c, u_int32_t ssrc, str *s, u_int64_t idx) {
unsigned char iv[16];
unsigned char *p;
int i;
@ -205,7 +215,7 @@ static int aes_cm_encrypt_rtp(struct crypto_context *c, struct rtp_header *r, st
ZERO(iv);
memcpy(iv, c->session_salt, 14);
p = (void *) &r->ssrc;
p = (void *) &ssrc;
for (i = 0; i < 4; i++)
iv[i + 4] = iv[i + 4] ^ p[i];
@ -217,6 +227,16 @@ static int aes_cm_encrypt_rtp(struct crypto_context *c, struct rtp_header *r, st
return 0;
}
/* rfc 3711 section 4.1 */
static int aes_cm_encrypt_rtp(struct crypto_context *c, struct rtp_header *r, str *s, u_int64_t idx) {
return aes_cm_encrypt(c, r->ssrc, s, idx);
}
/* rfc 3711 sections 3.4 and 4.1 */
static int aes_cm_encrypt_rtcp(struct crypto_context *c, struct rtcp_packet *r, str *s, u_int64_t idx) {
return aes_cm_encrypt(c, r->ssrc, s, idx);
}
/* rfc 3711, sections 4.2 and 4.2.1 */
static int hmac_sha1_rtp(struct crypto_context *c, char *out, str *in, u_int64_t index) {
unsigned char hmac[20];
@ -235,3 +255,33 @@ static int hmac_sha1_rtp(struct crypto_context *c, char *out, str *in, u_int64_t
return 0;
}
/* rfc 3711, sections 4.2 and 4.2.1 */
static int hmac_sha1_rtcp(struct crypto_context *c, char *out, str *in) {
unsigned char hmac[20];
HMAC(EVP_sha1(), c->session_auth_key, c->crypto_suite->srtcp_auth_key_len / 8,
(unsigned char *) in->s, in->len, hmac, NULL);
assert(sizeof(hmac) >= c->crypto_suite->srtcp_auth_tag / 8);
memcpy(out, hmac, c->crypto_suite->srtcp_auth_tag / 8);
return 0;
}
int crypto_gen_session_keys(struct crypto_context *c) {
str s;
str_init_len(&s, c->session_key, c->crypto_suite->session_key_len);
if (crypto_gen_session_key(c, &s, 0x00))
return -1;
str_init_len(&s, c->session_auth_key, c->crypto_suite->srtp_auth_key_len);
if (crypto_gen_session_key(c, &s, 0x01))
return -1;
str_init_len(&s, c->session_salt, c->crypto_suite->session_salt_len);
if (crypto_gen_session_key(c, &s, 0x02))
return -1;
c->have_session_key = 1;
return 0;
}

+ 29
- 11
daemon/crypto.h View File

@ -26,9 +26,12 @@ enum mac {
struct crypto_context;
struct rtp_header;
struct rtcp_packet;
typedef int (*crypto_func)(struct crypto_context *, struct rtp_header *, str *, u_int64_t);
typedef int (*hash_func)(struct crypto_context *, char *out, str *in, u_int64_t);
typedef int (*crypto_func_rtp)(struct crypto_context *, struct rtp_header *, str *, u_int64_t);
typedef int (*crypto_func_rtcp)(struct crypto_context *, struct rtcp_packet *, str *, u_int64_t);
typedef int (*hash_func_rtp)(struct crypto_context *, char *out, str *in, u_int64_t);
typedef int (*hash_func_rtcp)(struct crypto_context *, char *out, str *in);
struct crypto_suite {
const char *name;
@ -47,9 +50,12 @@ struct crypto_suite {
srtcp_lifetime;
enum cipher cipher;
enum mac mac;
crypto_func encrypt_rtp,
decrypt_rtp;
hash_func hash_rtp;
crypto_func_rtp encrypt_rtp,
decrypt_rtp;
crypto_func_rtcp encrypt_rtcp,
decrypt_rtcp;
hash_func_rtp hash_rtp;
hash_func_rtcp hash_rtcp;
};
struct crypto_context {
@ -88,24 +94,36 @@ extern const int num_crypto_suites;
const struct crypto_suite *crypto_find_suite(const str *);
int crypto_gen_session_keys(struct crypto_context *c);
int crypto_gen_session_key(struct crypto_context *, str *, unsigned char);
static inline int crypto_encrypt_rtp(struct crypto_context *c, struct rtp_header *rtp,
str *payload, u_int64_t index)
{
if (!c || !c->crypto_suite)
return -1;
return c->crypto_suite->encrypt_rtp(c, rtp, payload, index);
}
static inline int crypto_decrypt_rtp(struct crypto_context *c, struct rtp_header *rtp,
str *payload, u_int64_t index)
{
if (!c || !c->crypto_suite)
return -1;
return c->crypto_suite->decrypt_rtp(c, rtp, payload, index);
}
static inline int crypto_encrypt_rtcp(struct crypto_context *c, struct rtcp_packet *rtcp,
str *payload, u_int64_t index)
{
return c->crypto_suite->encrypt_rtcp(c, rtcp, payload, index);
}
static inline int crypto_decrypt_rtcp(struct crypto_context *c, struct rtcp_packet *rtcp,
str *payload, u_int64_t index)
{
return c->crypto_suite->decrypt_rtcp(c, rtcp, payload, index);
}
static inline int crypto_check_session_keys(struct crypto_context *c) {
if (c->have_session_key)
return 0;
if (!c->crypto_suite)
return -1;
return crypto_gen_session_keys(c);
}


+ 92
- 11
daemon/rtcp.c View File

@ -7,6 +7,8 @@
#include "str.h"
#include "call.h"
#include "log.h"
#include "rtp.h"
#include "crypto.h"
@ -31,17 +33,6 @@
struct rtcp_header {
unsigned char v_p_x;
unsigned char pt;
u_int16_t length;
} __attribute__ ((packed));
struct rtcp_packet {
struct rtcp_header header;
u_int32_t ssrc;
} __attribute__ ((packed));
struct report_block {
u_int32_t ssrc;
unsigned char fraction_lost;
@ -320,3 +311,93 @@ int rtcp_avpf2avp(str *s) {
return 0;
}
static int rtcp_payload(struct rtcp_packet **out, str *p, const str *s) {
struct rtcp_packet *rtcp;
if (s->len < sizeof(*rtcp))
return -1;
rtcp = (void *) s->s;
if ((rtcp->header.v_p_x & 0xc0) != 0x80) /* version 2 */
return -1;
if (rtcp->header.pt != RTCP_PT_SR
&& rtcp->header.pt != RTCP_PT_RR)
return -1;
*p = *s;
str_shift(p, sizeof(*rtcp));
*out = rtcp;
return 0;
}
/* rfc 3711 section 3.4 */
int rtcp_avp2savp(str *s, struct crypto_context *c) {
struct rtcp_packet *rtcp;
u_int32_t *idx;
str to_auth, payload;
if (rtcp_payload(&rtcp, &payload, s))
return -1;
if (crypto_check_session_keys(c))
return -1;
if (crypto_encrypt_rtcp(c, rtcp, &payload, c->num_packets))
return -1;
idx = (void *) s->s + s->len;
*idx = htonl(0x80000000ULL | c->num_packets++);
s->len += sizeof(*idx);
to_auth = *s;
rtp_append_mki(s, c);
c->crypto_suite->hash_rtcp(c, s->s + s->len, &to_auth);
s->len += c->crypto_suite->srtp_auth_tag / 8;
return 0;
}
/* rfc 3711 section 3.4 */
int rtcp_savp2avp(str *s, struct crypto_context *c) {
struct rtcp_packet *rtcp;
str payload, to_auth, to_decrypt, auth_tag;
u_int32_t idx, *idx_p;
char hmac[20];
if (rtcp_payload(&rtcp, &payload, s))
return -1;
if (crypto_check_session_keys(c))
return -1;
if (srtp_payloads(&to_auth, &to_decrypt, &auth_tag, NULL,
c->crypto_suite->srtcp_auth_tag, c->mki_len,
s, &payload))
return -1;
if (to_decrypt.len < sizeof(idx))
return -1;
to_decrypt.len -= sizeof(idx);
idx_p = (void *) to_decrypt.s + to_decrypt.len;
idx = ntohl(*idx_p);
assert(sizeof(hmac) >= auth_tag.len);
c->crypto_suite->hash_rtcp(c, hmac, &to_auth);
if (str_memcmp(&auth_tag, hmac))
return -1;
if (idx & 0x80000000ULL) {
if (crypto_decrypt_rtcp(c, rtcp, &to_decrypt, idx & 0x7fffffffULL))
return -1;
}
*s = to_auth;
to_auth.len -= sizeof(idx);
return 0;
}

+ 22
- 0
daemon/rtcp.h View File

@ -3,6 +3,28 @@
#include "str.h"
struct crypto_context;
struct rtcp_header {
unsigned char v_p_x;
unsigned char pt;
u_int16_t length;
} __attribute__ ((packed));
struct rtcp_packet {
struct rtcp_header header;
u_int32_t ssrc;
} __attribute__ ((packed));
int rtcp_avpf2avp(str *);
int rtcp_avp2savp(str *, struct crypto_context *);
int rtcp_savp2avp(str *, struct crypto_context *);
#endif

+ 82
- 87
daemon/rtp.c View File

@ -10,29 +10,7 @@
static inline int check_session_key(struct crypto_context *c) {
str s;
if (c->have_session_key)
return 0;
if (!c->crypto_suite)
return -1;
str_init_len(&s, c->session_key, c->crypto_suite->session_key_len);
if (crypto_gen_session_key(c, &s, 0x00))
return -1;
str_init_len(&s, c->session_auth_key, c->crypto_suite->srtp_auth_key_len);
if (crypto_gen_session_key(c, &s, 0x01))
return -1;
str_init_len(&s, c->session_salt, c->crypto_suite->session_salt_len);
if (crypto_gen_session_key(c, &s, 0x02))
return -1;
c->have_session_key = 1;
return 0;
}
static int rtp_payload(str *p, str *s) {
static int rtp_payload(struct rtp_header **out, str *p, const str *s) {
struct rtp_header *rtp;
struct rtp_extension *ext;
@ -59,6 +37,8 @@ static int rtp_payload(str *p, str *s) {
return -1;
}
*out = rtp;
return 0;
}
@ -94,21 +74,46 @@ static u_int64_t packet_index(struct crypto_context *c, struct rtp_header *rtp)
return index;
}
void rtp_append_mki(str *s, struct crypto_context *c) {
u_int32_t mki_part;
char *p;
if (!c->mki_len)
return;
/* RTP_BUFFER_TAIL_ROOM guarantees enough room */
p = s->s + s->len;
memset(p, 0, c->mki_len);
if (c->mki_len > 4) {
mki_part = (c->mki & 0xffffffff00000000ULL) >> 32;
mki_part = htonl(mki_part);
if (c->mki_len < 8)
memcpy(p, ((char *) &mki_part) + (8 - c->mki_len), c->mki_len - 4);
else
memcpy(p + (c->mki_len - 8), &mki_part, 4);
}
mki_part = (c->mki & 0xffffffffULL);
mki_part = htonl(mki_part);
if (c->mki_len < 4)
memcpy(p, ((char *) &mki_part) + (4 - c->mki_len), c->mki_len);
else
memcpy(p + (c->mki_len - 4), &mki_part, 4);
s->len += c->mki_len;
}
/* rfc 3711, section 3.3 */
/* XXX some error handling/logging here */
int rtp_avp2savp(str *s, struct crypto_context *c) {
struct rtp_header *rtp;
str payload, to_auth;
u_int64_t index;
char *pl_end;
u_int32_t mki_part;
if (rtp_payload(&payload, s))
if (rtp_payload(&rtp, &payload, s))
return -1;
if (check_session_key(c))
if (crypto_check_session_keys(c))
return -1;
rtp = (void *) s->s;
index = packet_index(c, rtp);
/* rfc 3711 section 3.1 */
@ -116,38 +121,15 @@ int rtp_avp2savp(str *s, struct crypto_context *c) {
if (crypto_encrypt_rtp(c, rtp, &payload, index))
return -1;
pl_end = s->s + s->len;
to_auth = *s;
if (c->mki_len) {
/* RTP_BUFFER_TAIL_ROOM guarantees enough room */
memset(pl_end, 0, c->mki_len);
if (c->mki_len > 4) {
mki_part = (c->mki & 0xffffffff00000000ULL) >> 32;
mki_part = htonl(mki_part);
if (c->mki_len < 8)
memcpy(pl_end, ((char *) &mki_part) + (8 - c->mki_len), c->mki_len - 4);
else
memcpy(pl_end + (c->mki_len - 8), &mki_part, 4);
}
mki_part = (c->mki & 0xffffffffULL);
mki_part = htonl(mki_part);
if (c->mki_len < 4)
memcpy(pl_end, ((char *) &mki_part) + (4 - c->mki_len), c->mki_len);
else
memcpy(pl_end + (c->mki_len - 4), &mki_part, 4);
pl_end += c->mki_len;
to_auth.len += c->mki_len;
}
rtp_append_mki(s, c);
if (c->crypto_suite->srtp_auth_tag) {
c->crypto_suite->hash_rtp(c, pl_end, &to_auth, index);
pl_end += c->crypto_suite->srtp_auth_tag / 8;
c->crypto_suite->hash_rtp(c, s->s + s->len, &to_auth, index);
s->len += c->crypto_suite->srtp_auth_tag / 8;
}
s->len = pl_end - s->s;
return 0;
}
@ -155,55 +137,68 @@ int rtp_avp2savp(str *s, struct crypto_context *c) {
int rtp_savp2avp(str *s, struct crypto_context *c) {
struct rtp_header *rtp;
u_int64_t index;
str payload, mki, to_auth;
char hmac[20], *auth_tag = NULL;
int i;
str payload, to_auth, to_decrypt, auth_tag;
char hmac[20];
if (rtp_payload(&payload, s))
if (rtp_payload(&rtp, &payload, s))
return -1;
if (check_session_key(c))
if (crypto_check_session_keys(c))
return -1;
rtp = (void *) s->s;
index = packet_index(c, rtp);
if (srtp_payloads(&to_auth, &to_decrypt, &auth_tag, NULL,
c->crypto_suite->srtp_auth_tag, c->mki_len,
s, &payload))
return -1;
/* rfc 3711 section 3.1 */
to_auth = *s;
if (c->crypto_suite->srtp_auth_tag) {
i = c->crypto_suite->srtp_auth_tag / 8;
assert(sizeof(hmac) >= i);
if (payload.len < i)
if (auth_tag.len) {
assert(sizeof(hmac) >= auth_tag.len);
c->crypto_suite->hash_rtp(c, hmac, &to_auth, index);
if (str_memcmp(&auth_tag, hmac))
return -1;
auth_tag = payload.s + payload.len - i;
payload.len -= i;
to_auth.len -= i;
}
if (c->mki_len) {
if (payload.len < c->mki_len)
return -1;
if (crypto_decrypt_rtp(c, rtp, &to_decrypt, index))
return -1;
str_init_len(&mki, payload.s - c->mki_len, c->mki_len);
payload.len -= c->mki_len;
to_auth.len -= c->mki_len;
*s = to_auth;
/* ignoring the mki for now */
}
return 0;
}
if (c->crypto_suite->srtp_auth_tag) {
c->crypto_suite->hash_rtp(c, hmac, &to_auth, index);
if (memcmp(hmac, auth_tag, c->crypto_suite->srtp_auth_tag / 8))
/* rfc 3711 section 3.1 and 3.4 */
int srtp_payloads(str *to_auth, str *to_decrypt, str *auth_tag, str *mki,
int auth_len, int mki_len,
const str *packet, const str *payload)
{
auth_len /= 8; /* given in bits */
*to_auth = *packet;
*to_decrypt = *payload;
/* packet and payload should be identical except for the respective header */
assert(to_auth->s + to_auth->len == to_decrypt->s + to_decrypt->len);
assert(to_decrypt->s >= to_auth->s);
*auth_tag = STR_NULL;
if (auth_len) {
if (to_decrypt->len < auth_len)
return -1;
str_init_len(auth_tag, to_decrypt->s + to_decrypt->len - auth_len, auth_len);
to_decrypt->len -= auth_len;
to_auth->len -= auth_len;
}
if (crypto_decrypt_rtp(c, rtp, &payload, index))
return -1;
if (mki)
*mki = STR_NULL;
if (mki_len) {
if (to_decrypt->len < mki_len)
return -1;
*s = to_auth;
if (mki)
str_init_len(mki, to_decrypt->s - mki_len, mki_len);
to_decrypt->len -= mki_len;
to_auth->len -= mki_len;
}
return 0;
}

+ 5
- 0
daemon/rtp.h View File

@ -30,6 +30,11 @@ struct rtp_extension {
int rtp_avp2savp(str *, struct crypto_context *);
int rtp_savp2avp(str *, struct crypto_context *);
void rtp_append_mki(str *s, struct crypto_context *c);
int srtp_payloads(str *to_auth, str *to_decrypt, str *auth_tag, str *mki,
int auth_len, int mki_len,
const str *packet, const str *payload);


+ 5
- 0
daemon/str.h View File

@ -51,6 +51,8 @@ static inline str *str_dup(const str *s);
static inline str *str_chunk_insert(GStringChunk *c, const str *s);
/* shifts pointer by len chars and decrements len. returns -1 if buffer too short, 0 otherwise */
static inline int str_shift(str *s, int len);
/* binary compares str object with memory chunk of equal size */
static inline int str_memcmp(const str *s, void *m);
/* asprintf() analogs */
#define str_sprintf(fmt, a...) __str_sprintf(STR_MALLOC_PADDING fmt, a)
@ -196,5 +198,8 @@ static inline str *g_string_free_str(GString *gs) {
g_string_free(gs, FALSE);
return ret;
}
static inline int str_memcmp(const str *s, void *m) {
return memcmp(s->s, m, s->len);
}
#endif

Loading…
Cancel
Save