diff --git a/kernel-module/xt_MEDIAPROXY.c b/kernel-module/xt_MEDIAPROXY.c index e59639c9d..881102b84 100644 --- a/kernel-module/xt_MEDIAPROXY.c +++ b/kernel-module/xt_MEDIAPROXY.c @@ -65,6 +65,8 @@ MODULE_LICENSE("GPL"); struct mp_hmac; struct mp_cipher; +struct rtp_parsed; +struct mp_crypto_context; @@ -108,6 +110,9 @@ static int proc_main_list_show(struct seq_file *, void *); static void table_push(struct mediaproxy_table *); static struct mediaproxy_target *get_target(struct mediaproxy_table *, u_int16_t); +static int srtp_encrypt_aes_cm(struct mp_crypto_context *, struct mediaproxy_srtp *, + struct rtp_parsed *, u_int64_t); + @@ -158,6 +163,10 @@ struct mediaproxy_table { struct mp_cipher { const char *name; const char *tfm_name; + int (*decrypt)(struct mp_crypto_context *, struct mediaproxy_srtp *, + struct rtp_parsed *, u_int64_t); + int (*encrypt)(struct mp_crypto_context *, struct mediaproxy_srtp *, + struct rtp_parsed *, u_int64_t); }; struct mp_hmac { @@ -250,6 +259,8 @@ static const struct mp_cipher mp_ciphers[] = { [MPC_AES_CM] = { .name = "AES-CM", .tfm_name = "aes", + .decrypt = srtp_encrypt_aes_cm, + .encrypt = srtp_encrypt_aes_cm, }, [MPC_AES_F8] = { .name = "AES-F8", @@ -894,7 +905,7 @@ static int validate_srtp(struct mediaproxy_srtp *s) { /* XXX shared code */ static void aes_ctr_128(unsigned char *out, const unsigned char *in, int in_len, - struct crypto_cipher *tfm, const char *iv) + struct crypto_cipher *tfm, const unsigned char *iv) { unsigned char ivx[16]; unsigned char key_block[16]; @@ -1613,14 +1624,16 @@ static u_int64_t packet_index(struct mp_crypto_context *c, } static int srtp_auth_validate(struct mp_crypto_context *c, - struct mediaproxy_srtp *s, struct rtp_parsed *r) + struct mediaproxy_srtp *s, struct rtp_parsed *r, + u_int64_t pkt_idx) { unsigned char *auth_tag; unsigned char hmac[20]; struct shash_desc *dsc; - u_int64_t pkt_idx; u_int32_t roc; + if (s->hmac == MPH_NULL) + return 0; if (!c->hmac) return 0; if (!c->shash) @@ -1639,7 +1652,6 @@ static int srtp_auth_validate(struct mp_crypto_context *c, if (!s->auth_tag_len) return 0; - pkt_idx = packet_index(c, s, r->header); roc = htonl((pkt_idx & 0xffffffff0000ULL) >> 16); dsc = kmalloc(sizeof(*dsc) + crypto_shash_descsize(c->shash), GFP_ATOMIC); @@ -1681,6 +1693,56 @@ error: return -1; } + +/* XXX shared code */ +static int srtp_encrypt_aes_cm(struct mp_crypto_context *c, + struct mediaproxy_srtp *s, struct rtp_parsed *r, + u_int64_t pkt_idx) +{ + unsigned char iv[16]; + u_int32_t *ivi; + u_int32_t idxh, idxl; + + if (s->cipher == MPC_NULL) + return 0; + if (!c->cipher) + return 0; + + memcpy(iv, c->session_salt, 14); + iv[14] = iv[15] = '\0'; + ivi = (void *) iv; + pkt_idx <<= 16; + idxh = htonl((pkt_idx & 0xffffffff00000000ULL) >> 32); + idxl = htonl(pkt_idx & 0xffffffffULL); + + ivi[1] ^= r->header->ssrc; + ivi[2] ^= idxh; + ivi[3] ^= idxl; + + aes_ctr_128(r->payload, r->payload, r->payload_len, c->tfm, iv); + + return 0; +} + + +static inline int srtp_encrypt(struct mp_crypto_context *c, + struct mediaproxy_srtp *s, struct rtp_parsed *r, + u_int64_t pkt_idx) +{ + if (!c->cipher->encrypt) + return 0; + return c->cipher->encrypt(c, s, r, pkt_idx); +} + +static inline int srtp_decrypt(struct mp_crypto_context *c, + struct mediaproxy_srtp *s, struct rtp_parsed *r, + u_int64_t pkt_idx) +{ + if (!c->cipher->decrypt) + return 0; + return c->cipher->decrypt(c, s, r, pkt_idx); +} + static unsigned int mediaproxy46(struct sk_buff *skb, struct mediaproxy_table *t) { struct udphdr *uh; struct mediaproxy_target *g; @@ -1690,6 +1752,7 @@ static unsigned int mediaproxy46(struct sk_buff *skb, struct mediaproxy_table *t unsigned long flags; u_int32_t *u32; struct rtp_parsed rtp; + u_int64_t pkt_idx = 0; skb_reset_transport_header(skb); uh = udp_hdr(skb); @@ -1729,8 +1792,20 @@ not_stun: if (parse_rtp(&rtp, skb)) goto not_rtp; - if (srtp_auth_validate(&g->decrypt, &g->target.decrypt, &rtp)) + pkt_idx = packet_index(&g->decrypt, &g->target.decrypt, rtp.header); + if (srtp_auth_validate(&g->decrypt, &g->target.decrypt, &rtp, pkt_idx)) goto skip3; + if (srtp_decrypt(&g->decrypt, &g->target.decrypt, &rtp, pkt_idx)) + goto skip3; + + skb_trim(skb, rtp.header_len + rtp.payload_len); + + DBG("packet payload decrypted as %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x...\n", + rtp.payload[0], rtp.payload[1], rtp.payload[2], rtp.payload[3], + rtp.payload[4], rtp.payload[5], rtp.payload[6], rtp.payload[7], + rtp.payload[8], rtp.payload[9], rtp.payload[10], rtp.payload[11], + rtp.payload[12], rtp.payload[13], rtp.payload[14], rtp.payload[15], + rtp.payload[16], rtp.payload[17], rtp.payload[18], rtp.payload[19]); not_rtp: if (g->target.mirror_addr.family) {