From 02176fcb0f6301c314cda146de19955c6780718d Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 21 Jun 2013 14:22:46 -0400 Subject: [PATCH] implement AES-CM encryption and adding auth tag, which completes in-kernel AES-CM SRTP support --- kernel-module/xt_MEDIAPROXY.c | 159 ++++++++++++++++++++++++---------- 1 file changed, 115 insertions(+), 44 deletions(-) diff --git a/kernel-module/xt_MEDIAPROXY.c b/kernel-module/xt_MEDIAPROXY.c index 881102b84..f0da1c4e9 100644 --- a/kernel-module/xt_MEDIAPROXY.c +++ b/kernel-module/xt_MEDIAPROXY.c @@ -33,6 +33,7 @@ MODULE_LICENSE("GPL"); #define MAX_ID 64 /* - 1 */ +#define MAX_SKB_TAIL_ROOM (128 + 20) #define MIPF "%i:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x:%u" #define MIPP(x) (x).family, \ @@ -1552,23 +1553,23 @@ static int parse_rtp(struct rtp_parsed *rtp, struct sk_buff *skb) { memset(rtp, 0, sizeof(*rtp)); if (skb->len < sizeof(*rtp->header)) - return -1; + goto error; rtp->header = (void *) skb->data; if ((rtp->header->v_p_x_cc & 0xc0) != 0x80) /* version 2 */ - return -1; + goto error; rtp->header_len = sizeof(*rtp->header); /* csrc list */ rtp->header_len += (rtp->header->v_p_x_cc & 0xf) * 4; if (skb->len < rtp->header_len) - return -1; + goto error; rtp->payload = skb->data + rtp->header_len; rtp->payload_len = skb->len - rtp->header_len; if ((rtp->header->v_p_x_cc & 0x10)) { /* extension */ if (rtp->payload_len < sizeof(*ext)) - return -1; + goto error; ext = (void *) rtp->payload; ext_len = 4 + ntohs(ext->length) * 4; if (rtp->payload_len < ext_len) @@ -1580,6 +1581,10 @@ static int parse_rtp(struct rtp_parsed *rtp, struct sk_buff *skb) { DBG("rtp header parsed, payload length is %u\n", rtp->payload_len); return 0; + +error: + memset(rtp, 0, sizeof(*rtp)); + return -1; } /* XXX shared code */ @@ -1623,31 +1628,13 @@ static u_int64_t packet_index(struct mp_crypto_context *c, return index; } -static int srtp_auth_validate(struct mp_crypto_context *c, +static int srtp_hash(unsigned char *hmac, + struct mp_crypto_context *c, 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_int32_t roc; - - if (s->hmac == MPH_NULL) - return 0; - if (!c->hmac) - return 0; - if (!c->shash) - return -1; - - if (r->payload_len < s->auth_tag_len) - return -1; - - r->payload_len -= s->auth_tag_len; - auth_tag = r->payload + r->payload_len; - - if (r->payload_len < s->mki_len) - return -1; - r->payload_len -= s->mki_len; + struct shash_desc *dsc; if (!s->auth_tag_len) return 0; @@ -1677,20 +1664,108 @@ static int srtp_auth_validate(struct mp_crypto_context *c, hmac[8], hmac[9], hmac[10], hmac[11], hmac[12], hmac[13], hmac[14], hmac[15], hmac[16], hmac[17], hmac[18], hmac[19]); - DBG("packet auth tag %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + + return 0; + +error: + kfree(dsc); + return -1; +} + +/* XXX shared code */ +static void rtp_append_mki(struct rtp_parsed *r, struct mediaproxy_srtp *c) { + u_int32_t mki_part; + unsigned char *p; + + if (!c->mki_len) + return; + + p = r->payload + r->payload_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); + + r->payload_len += c->mki_len; +} + +static int srtp_authenticate(struct mp_crypto_context *c, + struct mediaproxy_srtp *s, struct rtp_parsed *r, + u_int64_t pkt_idx) +{ + unsigned char hmac[20]; + + if (!r->header) + return 0; + if (s->hmac == MPH_NULL) + return 0; + if (!c->hmac) + return 0; + if (!c->shash) + return -1; + + if (srtp_hash(hmac, c, s, r, pkt_idx)) + return -1; + + rtp_append_mki(r, s); + + memcpy(r->payload + r->payload_len, hmac, s->auth_tag_len); + r->payload_len += s->auth_tag_len; + + return 0; +} + +static int srtp_auth_validate(struct mp_crypto_context *c, + struct mediaproxy_srtp *s, struct rtp_parsed *r, + u_int64_t pkt_idx) +{ + unsigned char *auth_tag; + unsigned char hmac[20]; + + if (s->hmac == MPH_NULL) + return 0; + if (!c->hmac) + return 0; + if (!c->shash) + return -1; + + if (r->payload_len < s->auth_tag_len) + return -1; + + r->payload_len -= s->auth_tag_len; + auth_tag = r->payload + r->payload_len; + + if (r->payload_len < s->mki_len) + return -1; + r->payload_len -= s->mki_len; + + if (!s->auth_tag_len) + return 0; + + DBG("packet auth tag %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", auth_tag[0], auth_tag[1], auth_tag[2], auth_tag[3], auth_tag[4], auth_tag[5], auth_tag[6], auth_tag[7], - auth_tag[8], auth_tag[9], auth_tag[10], auth_tag[11], - auth_tag[12], auth_tag[13], auth_tag[14], auth_tag[15], - auth_tag[16], auth_tag[17], auth_tag[18], auth_tag[19]); + auth_tag[8], auth_tag[9]); + + if (srtp_hash(hmac, c, s, r, pkt_idx)) + return -1; if (memcmp(auth_tag, hmac, s->auth_tag_len)) return -1; + return 0; -error: - kfree(dsc); - return -1; } @@ -1729,6 +1804,8 @@ static inline int srtp_encrypt(struct mp_crypto_context *c, struct mediaproxy_srtp *s, struct rtp_parsed *r, u_int64_t pkt_idx) { + if (!r->header) + return 0; if (!c->cipher->encrypt) return 0; return c->cipher->encrypt(c, s, r, pkt_idx); @@ -1819,6 +1896,10 @@ not_rtp: } } + srtp_encrypt(&g->encrypt, &g->target.encrypt, &rtp, pkt_idx); + skb_put(skb, g->target.encrypt.mki_len + g->target.encrypt.auth_tag_len); + srtp_authenticate(&g->encrypt, &g->target.encrypt, &rtp, pkt_idx); + err = send_proxy_packet(skb, &g->target.src_addr, &g->target.dst_addr, g->target.tos); spin_lock_irqsave(&g->stats_lock, flags); @@ -1857,17 +1938,12 @@ static unsigned int mediaproxy4(struct sk_buff *oskb, const struct xt_action_par struct sk_buff *skb; struct iphdr *ih; struct mediaproxy_table *t; - int headroom; t = get_table(pinfo->id); if (!t) goto skip; - headroom = MAX_HEADER - sizeof(*ih); - if (skb_headroom(oskb) >= headroom) - skb = skb_copy(oskb, GFP_ATOMIC); - else - skb = skb_copy_expand(oskb, headroom, 0, GFP_ATOMIC); + skb = skb_copy_expand(oskb, MAX_HEADER, MAX_SKB_TAIL_ROOM, GFP_ATOMIC); if (!skb) goto skip3; @@ -1899,17 +1975,12 @@ static unsigned int mediaproxy6(struct sk_buff *oskb, const struct xt_action_par struct sk_buff *skb; struct ipv6hdr *ih; struct mediaproxy_table *t; - int headroom; t = get_table(pinfo->id); if (!t) goto skip; - headroom = MAX_HEADER - sizeof(*ih); - if (skb_headroom(oskb) >= headroom) - skb = skb_copy(oskb, GFP_ATOMIC); - else - skb = skb_copy_expand(oskb, headroom, 0, GFP_ATOMIC); + skb = skb_copy_expand(oskb, MAX_HEADER, MAX_SKB_TAIL_ROOM, GFP_ATOMIC); if (!skb) goto skip3;