Browse Source

parsing of the sdp crypto attribute

git.mgm/mediaproxy-ng/github/master
Richard Fuchs 13 years ago
parent
commit
e63edeb875
8 changed files with 307 additions and 38 deletions
  1. +3
    -2
      daemon/Makefile
  2. +21
    -2
      daemon/call.c
  3. +4
    -2
      daemon/call.h
  4. +78
    -0
      daemon/crypto.c
  5. +63
    -0
      daemon/crypto.h
  6. +134
    -29
      daemon/sdp.c
  7. +2
    -1
      daemon/sdp.h
  8. +2
    -2
      daemon/str.h

+ 3
- 2
daemon/Makefile View File

@ -16,7 +16,7 @@ else
CFLAGS+= -O3
endif
LDFLAGS= -ldl -rdynamic
LDFLAGS= -ldl -rdynamic -lm
LDFLAGS+= `pkg-config --libs glib-2.0`
LDFLAGS+= `pkg-config --libs gthread-2.0`
LDFLAGS+= `pkg-config --libs zlib`
@ -32,7 +32,8 @@ LDFLAGS+= `dpkg-buildflags --get LDFLAGS`
endif
SRCS= main.c kernel.c poller.c aux.c control_tcp.c streambuf.c call.c control_udp.c redis.c \
bencode.c cookie_cache.c udp_listener.c control_ng.c sdp.c str.c stun.c rtcp.c
bencode.c cookie_cache.c udp_listener.c control_ng.c sdp.c str.c stun.c rtcp.c \
crypto.c
OBJS= $(SRCS:.c=.o)


+ 21
- 2
daemon/call.c View File

@ -112,7 +112,7 @@ static char *rtp_codecs[] = {
[33] = "MP2T",
[34] = "H263",
};
const char *transport_protocol_strings[__PROTO_RTP_LAST] = {
const char *transport_protocol_strings[__PROTO_LAST] = {
[PROTO_RTP_AVP] = "RTP/AVP",
[PROTO_RTP_SAVP] = "RTP/SAVP",
[PROTO_RTP_AVPF] = "RTP/AVPF",
@ -2283,6 +2283,24 @@ struct callstream *callstream_new(struct call *ca, int num) {
}
enum transport_protocol transport_protocol(const str *s) {
int i;
if (!s || !s->s)
goto out;
for (i = PROTO_UNKNOWN + 1; i < __PROTO_LAST; i++) {
if (strlen(transport_protocol_strings[i]) != s->len)
continue;
if (strncasecmp(transport_protocol_strings[i], s->s, s->len))
continue;
return i;
}
out:
return PROTO_UNKNOWN;
}
static void call_ng_process_flags(struct sdp_ng_flags *out, GQueue *streams, bencode_item_t *input) {
bencode_item_t *list, *it;
struct stream_input *si;
@ -2344,7 +2362,8 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, GQueue *streams, ben
out->ice_force = 1;
}
bencode_dictionary_get_str(input, "transport-protocol", &out->transport_protocol);
bencode_dictionary_get_str(input, "transport-protocol", &out->transport_protocol_str);
out->transport_protocol = transport_protocol(&out->transport_protocol_str);
}
static unsigned int stream_hash(struct stream_input *s) {


+ 4
- 2
daemon/call.h View File

@ -54,9 +54,9 @@ enum transport_protocol {
PROTO_RTP_AVPF,
PROTO_RTP_SAVPF,
__PROTO_RTP_LAST
__PROTO_LAST
};
extern const char *transport_protocol_strings[__PROTO_RTP_LAST];
extern const char *transport_protocol_strings[__PROTO_LAST];
struct stats {
u_int64_t packets;
@ -242,5 +242,7 @@ static inline str *call_str_init_dup(struct call *c, char *s) {
enum transport_protocol transport_protocol(const str *s);
#endif

+ 78
- 0
daemon/crypto.c View File

@ -0,0 +1,78 @@
#include "crypto.h"
#include <string.h>
#include "str.h"
/* all lengths are in bits, some code assumes everything to be multiples of 8 */
const struct crypto_suite_params crypto_suite_params[__CS_LAST] = {
[CS_AES_CM_128_HMAC_SHA1_80] = {
.name = "AES_CM_128_HMAC_SHA1_80",
.master_key_len = 128,
.master_salt_len = 112,
.srtp_lifetime = 1ULL << 48,
.srtcp_lifetime = 1ULL << 31,
.cipher = CIPHER_AES_CM,
.encryption_key = 128,
.mac = MAC_HMAC_SHA1,
.srtp_auth_tag = 80,
.srtcp_auth_tag = 80,
.srtp_auth_key_len = 160,
.srtcp_auth_key_len = 160,
},
[CS_AES_CM_128_HMAC_SHA1_32] = {
.name = "AES_CM_128_HMAC_SHA1_32",
.master_key_len = 128,
.master_salt_len = 112,
.srtp_lifetime = 1ULL << 48,
.srtcp_lifetime = 1ULL << 31,
.cipher = CIPHER_AES_CM,
.encryption_key = 128,
.mac = MAC_HMAC_SHA1,
.srtp_auth_tag = 32,
.srtcp_auth_tag = 80,
.srtp_auth_key_len = 160,
.srtcp_auth_key_len = 160,
},
[CS_F8_128_HMAC_SHA1_80] = {
.name = "F8_128_HMAC_SHA1_80",
.master_key_len = 128,
.master_salt_len = 112,
.srtp_lifetime = 1ULL << 48,
.srtcp_lifetime = 1ULL << 31,
.cipher = CIPHER_AES_F8,
.encryption_key = 128,
.mac = MAC_HMAC_SHA1,
.srtp_auth_tag = 80,
.srtcp_auth_tag = 80,
.srtp_auth_key_len = 160,
.srtcp_auth_key_len = 160,
},
};
enum crypto_suite crypto_find_suite(const str *s) {
int i, l;
const struct crypto_suite_params *cs;
for (i = CS_UNKNOWN + 1; i < __CS_LAST; i++) {
cs = &crypto_suite_params[i];
if (!cs->name)
continue;
l = strlen(cs->name);
if (l != s->len)
continue;
if (strncasecmp(cs->name, s->s, s->len))
continue;
return i;
}
return CS_UNKNOWN;
}

+ 63
- 0
daemon/crypto.h View File

@ -0,0 +1,63 @@
#ifndef _CRYPTO_H_
#define _CRYPTO_H_
#include "str.h"
/* XXX get rid of the enums and replace with struct pointers? */
enum crypto_suite {
CS_UNKNOWN = 0,
CS_AES_CM_128_HMAC_SHA1_80,
CS_AES_CM_128_HMAC_SHA1_32,
CS_F8_128_HMAC_SHA1_80,
__CS_LAST
};
enum cipher {
CIPHER_UNKNOWN = 0,
CIPHER_AES_CM,
CIPHER_AES_F8,
__CIPHER_LAST
};
enum mac {
MAC_UNKNOWN = 0,
MAC_HMAC_SHA1,
__MAC_LAST
};
struct crypto_suite_params {
const char *name;
unsigned int
master_key_len,
master_salt_len,
encryption_key,
srtp_auth_tag,
srtcp_auth_tag,
srtp_auth_key_len,
srtcp_auth_key_len;
unsigned long long int
srtp_lifetime,
srtcp_lifetime;
enum cipher cipher;
enum mac mac;
};
extern const struct crypto_suite_params crypto_suite_params[__CS_LAST];
enum crypto_suite crypto_find_suite(const str *);
#endif

+ 134
- 29
daemon/sdp.c View File

@ -4,11 +4,13 @@
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <math.h>
#include "call.h"
#include "log.h"
#include "str.h"
#include "call.h"
#include "crypto.h"
struct network_address {
str network_type;
@ -79,6 +81,26 @@ struct attribute_candidate {
int parsed:1;
};
struct attribute_crypto {
str tag_str;
str crypto_suite_str;
str key_params_str;
/* str session_params; */
str key_base64_str;
str lifetime_str;
str mki_str;
unsigned int tag;
enum crypto_suite crypto_suite;
str master_key;
str salt;
char key_salt_buf[30];
unsigned long long lifetime;
unsigned int mki,
mki_len;
};
struct sdp_attribute {
str full_line, /* including a= and \r\n */
line_value, /* without a= and without \r\n */
@ -92,11 +114,13 @@ struct sdp_attribute {
ATTR_RTCP,
ATTR_CANDIDATE,
ATTR_ICE,
ATTR_CRYPTO,
} attr;
union {
struct attribute_rtcp rtcp;
struct attribute_candidate candidate;
struct attribute_crypto crypto;
} u;
};
@ -240,6 +264,100 @@ static void attrs_init(struct sdp_attributes *a) {
NULL, (GDestroyNotify) g_queue_free);
}
static int parse_attribute_crypto(struct sdp_attribute *output) {
char *start, *end;
struct attribute_crypto *c;
const struct crypto_suite_params *cs;
int salt_key_len, enc_salt_key_len;
int b64_state = 0;
unsigned int b64_save = 0;
gsize ret;
str s;
output->attr = ATTR_CRYPTO;
start = output->value.s;
end = start + output->value.len;
EXTRACT_TOKEN(u.crypto.tag_str);
EXTRACT_TOKEN(u.crypto.crypto_suite_str);
EXTRACT_TOKEN(u.crypto.key_params_str);
c = &output->u.crypto;
c->crypto_suite = crypto_find_suite(&c->crypto_suite_str);
if (c->crypto_suite == CS_UNKNOWN)
return -1;
cs = &crypto_suite_params[c->crypto_suite];
/* assume everything is a multiple of 8 */
salt_key_len = (cs->master_key_len + cs->master_salt_len) / 8;
assert(sizeof(c->key_salt_buf) >= salt_key_len);
enc_salt_key_len = ceil((double) salt_key_len * 4.0/3.0);
if (c->key_params_str.len < 7 + enc_salt_key_len)
return -1;
if (strncasecmp(c->key_params_str.s, "inline:", 7))
return -1;
c->key_base64_str = c->key_params_str;
str_shift(&c->key_base64_str, 7);
ret = g_base64_decode_step(c->key_base64_str.s, enc_salt_key_len,
(guchar *) c->key_salt_buf, &b64_state, &b64_save);
if (ret != salt_key_len)
return -1;
c->master_key.s = c->key_salt_buf;
c->master_key.len = cs->master_key_len / 8;
c->salt.s = c->master_key.s + c->master_key.len;
c->salt.len = cs->master_salt_len / 8;
c->lifetime_str = c->key_params_str;
str_shift(&c->lifetime_str, 7 + enc_salt_key_len);
if (c->lifetime_str.len >= 2) {
if (c->lifetime_str.s[0] != '|')
return -1;
str_shift(&c->lifetime_str, 1);
str_chr_str(&c->mki_str, &c->lifetime_str, '|');
if (!c->mki_str.s) {
if (str_chr(&c->lifetime_str, ':')) {
c->mki_str = c->lifetime_str;
c->lifetime_str = STR_NULL;
}
}
else {
c->lifetime_str.len = c->mki_str.s - c->lifetime_str.s;
str_shift(&c->mki_str, 1);
}
}
else
c->lifetime_str = STR_NULL;
if (c->lifetime_str.s) {
if (c->lifetime_str.len >= 3 && !memcmp(c->lifetime_str.s, "2^", 2)) {
c->lifetime = strtoull(c->lifetime_str.s + 2, NULL, 10);
if (!c->lifetime || c->lifetime > 64)
return -1;
c->lifetime = 1 << c->lifetime;
}
else
c->lifetime = strtoull(c->lifetime_str.s, NULL, 10);
if (!c->lifetime || c->lifetime > cs->srtp_lifetime || c->lifetime > cs->srtcp_lifetime)
return -1;
}
if (c->mki_str.s) {
str_chr_str(&s, &c->mki_str, ':');
if (!s.s)
return -1;
c->mki = strtoul(c->mki_str.s, NULL, 10);
c->mki_len = strtoul(s.s + 1, NULL, 10);
if (!c->mki || !c->mki_len)
return -1;
}
return 0;
}
static int parse_attribute_rtcp(struct sdp_attribute *output) {
char *ep, *start, *end;
@ -311,11 +429,16 @@ static void parse_attribute(struct sdp_attribute *a) {
a->key.len += 1 + a->value.len;
}
/* XXX add error handling */
switch (a->name.len) {
case 4:
if (!str_cmp(&a->name, "rtcp"))
parse_attribute_rtcp(a);
break;
case 6:
if (!str_cmp(&a->name, "crypto"))
parse_attribute_crypto(a);
break;
case 7:
if (!str_cmp(&a->name, "ice-pwd"))
a->attr = ATTR_ICE;
@ -557,34 +680,6 @@ static int fill_stream_rtcp(struct stream_input *si, struct sdp_media *media, in
return 0;
}
static enum transport_protocol transport_protocol(str *s) {
switch (s->len) {
case 7:
if (!str_cmp(s, "RTP/AVP"))
return PROTO_RTP_AVP;
if (!str_cmp(s, "rtp/avp"))
return PROTO_RTP_AVP;
break;
case 8:
if (!str_cmp(s, "RTP/SAVP"))
return PROTO_RTP_SAVP;
if (!str_cmp(s, "rtp/savp"))
return PROTO_RTP_SAVP;
if (!str_cmp(s, "RTP/AVPF"))
return PROTO_RTP_AVPF;
if (!str_cmp(s, "rtp/avpf"))
return PROTO_RTP_AVPF;
break;
case 9:
if (!str_cmp(s, "rtp/savpf"))
return PROTO_RTP_SAVPF;
if (!str_cmp(s, "rtp/savpf"))
return PROTO_RTP_SAVPF;
break;
}
return PROTO_UNKNOWN;
}
int sdp_streams(const GQueue *sessions, GQueue *streams, GHashTable *streamhash, struct sdp_ng_flags *flags) {
struct sdp_session *session;
struct sdp_media *media;
@ -939,6 +1034,16 @@ static int process_media_attributes(struct sdp_chopper *chop, struct sdp_attribu
case ATTR_RTCP:
goto strip;
case ATTR_CRYPTO:
switch (flags->transport_protocol) {
case PROTO_RTP_AVP:
case PROTO_RTP_AVPF:
goto strip;
default:
break;
}
break;
default:
break;
}
@ -1122,7 +1227,7 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call,
goto error;
fill_relays(&rtp, &rtcp, m, off, sip);
rtp->peer.protocol = transport_protocol(&flags->transport_protocol);
rtp->peer.protocol = flags->transport_protocol;
rtcp->peer.protocol = rtp->peer.protocol;
if (replace_media_port(chop, media, rtp))


+ 2
- 1
daemon/sdp.h View File

@ -10,7 +10,8 @@ struct sdp_ng_flags {
int desired_family[2];
str received_from_family;
str received_from_address;
str transport_protocol;
str transport_protocol_str;
enum transport_protocol transport_protocol;
struct in6_addr parsed_address;
int asymmetric:1,
symmetric:1,


+ 2
- 2
daemon/str.h View File

@ -22,8 +22,8 @@ typedef struct _str str;
#define STR_FORMAT "%.*s"
#define STR_FMT(str) (str)->len, (str)->s
#define STR_FMT0(str) ((str) ? (str)->len : 6), ((str) ? (str)->s : "(NULL)")
#define STR_NULL (str) { NULL, 0 }
#define STR_EMPTY (str) { "", 0 }
#define STR_NULL ((str) { NULL, 0 })
#define STR_EMPTY ((str) { "", 0 })


Loading…
Cancel
Save