From edf3cf5430753a8f356f7f8ad100ff198ecbdfc4 Mon Sep 17 00:00:00 2001 From: "Alfred E. Heggestad" Date: Mon, 5 May 2014 18:40:06 +0000 Subject: [PATCH] added support for SRTP RFC 3711 -- Secure Real-time Transport Protocol (SRTP) --- Makefile | 2 +- docs/README | 3 + include/re.h | 1 + include/re_srtp.h | 26 ++++ src/srtp/README | 42 ++++++ src/srtp/misc.c | 99 ++++++++++++++ src/srtp/mod.mk | 11 ++ src/srtp/replay.c | 63 +++++++++ src/srtp/srtcp.c | 184 ++++++++++++++++++++++++++ src/srtp/srtp.c | 324 ++++++++++++++++++++++++++++++++++++++++++++++ src/srtp/srtp.h | 69 ++++++++++ src/srtp/stream.c | 95 ++++++++++++++ 12 files changed, 918 insertions(+), 1 deletion(-) create mode 100644 include/re_srtp.h create mode 100644 src/srtp/README create mode 100644 src/srtp/misc.c create mode 100644 src/srtp/mod.mk create mode 100644 src/srtp/replay.c create mode 100644 src/srtp/srtcp.c create mode 100644 src/srtp/srtp.c create mode 100644 src/srtp/srtp.h create mode 100644 src/srtp/stream.c diff --git a/Makefile b/Makefile index 585eabf..49670bd 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ MODULES += list mbuf hash MODULES += fmt tmr main mem dbg sys lock mqueue MODULES += mod conf MODULES += bfcp -MODULES += aes +MODULES += aes srtp INSTALL := install ifeq ($(DESTDIR),) diff --git a/docs/README b/docs/README index 98f0795..3cb8138 100644 --- a/docs/README +++ b/docs/README @@ -52,6 +52,7 @@ Modules: * sipevent unstable SIP Event framework * sipreg testing SIP register client * sipsess unstable SIP Sessions +* srtp unstable Secure Real-time Transport Protocol (SRTP) * stun unstable Session Traversal Utilities for NAT (STUN) * sys testing System information * tcp testing TCP transport @@ -93,6 +94,7 @@ Features: * RFC 3556 - SDP Bandwidth Modifiers for RTCP Bandwidth * RFC 3581 - An Extension to SIP for Symmetric Response Routing * RFC 3605 - RTCP attribute in SDP +* RFC 3711 - The Secure Real-time Transport Protocol (SRTP) * RFC 3969 - The IANA URI Parameter Registry for SIP * RFC 3994 - Indication of Message Composition for Instant Messaging * RFC 4346 - The TLS Protocol Version 1.1 @@ -112,6 +114,7 @@ Features: * RFC 5780 - NAT Behaviour Discovery Using STUN * RFC 6026 - Correct Transaction Handling for 2xx Resp. to SIP INVITE Requests * RFC 6156 - TURN Extension for IPv6 +* RFC 6188 - The Use of AES-192 and AES-256 in Secure RTP * RFC 6455 - The WebSocket Protocol * Symmetric RTP * ITU-T G.711 Appendix I and Appendix II diff --git a/include/re.h b/include/re.h index ddc441a..edec85b 100644 --- a/include/re.h +++ b/include/re.h @@ -48,6 +48,7 @@ extern "C" { #include "re_sipsess.h" #include "re_stun.h" #include "re_natbd.h" +#include "re_srtp.h" #include "re_sys.h" #include "re_tcp.h" #include "re_telev.h" diff --git a/include/re_srtp.h b/include/re_srtp.h new file mode 100644 index 0000000..2d34d4a --- /dev/null +++ b/include/re_srtp.h @@ -0,0 +1,26 @@ +/** + * @file re_srtp.h Secure Real-time Transport Protocol (SRTP) + * + * Copyright (C) 2010 Creytiv.com + */ + + +enum srtp_suite { + SRTP_AES_CM_128_HMAC_SHA1_32, + SRTP_AES_CM_128_HMAC_SHA1_80, + SRTP_AES_256_CM_HMAC_SHA1_32, + SRTP_AES_256_CM_HMAC_SHA1_80, +}; + +enum srtp_flags { + SRTP_UNENCRYPTED_SRTCP = 1<<1, +}; + +struct srtp; + +int srtp_alloc(struct srtp **srtpp, enum srtp_suite suite, + const uint8_t *key, size_t key_bytes, int flags); +int srtp_encrypt(struct srtp *srtp, struct mbuf *mb); +int srtp_decrypt(struct srtp *srtp, struct mbuf *mb); +int srtcp_encrypt(struct srtp *srtp, struct mbuf *mb); +int srtcp_decrypt(struct srtp *srtp, struct mbuf *mb); diff --git a/src/srtp/README b/src/srtp/README new file mode 100644 index 0000000..bd4b980 --- /dev/null +++ b/src/srtp/README @@ -0,0 +1,42 @@ +SRTP module +----------- + +The SRTP module implements Secure RTP as defined in RFC 3711. +It provides a clean and user friendly API and can be used +as a standalone module. + + + + +Requirements and features: + +RFC 3711 yes +RFC 6188 yes +Multiple Master keys: no +Key derivation rate: 0 (zero) +Salting keys: yes +SRTP protection: yes +SRTCP protection: yes +Replay protection: yes +Encryption: yes +Authentication: yes +MKI (Master Key Identifier): no +Authentication tag length: 32-bit and 80-bit +ROC (Roll Over Counter): yes +Master key lifetime: no +Multiple SSRCs: yes +Performance: better than libsrtp + +Cryptographic transforms: +- AES in Counter mode: yes +- AES in f8-mode: no +- NULL Cipher: no + +Authentication transform: +- HMAC-SHA1: yes +- NULL auth: no + +master key lengths: +- 128 bits yes +- 192 bits no +- 256 bits yes diff --git a/src/srtp/misc.c b/src/srtp/misc.c new file mode 100644 index 0000000..34c21c8 --- /dev/null +++ b/src/srtp/misc.c @@ -0,0 +1,99 @@ +/** + * @file srtp/misc.c SRTP functions + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "srtp.h" + + +/* + * Appendix A: Pseudocode for Index Determination + * + * In the following, signed arithmetic is assumed. + */ +uint64_t srtp_get_index(uint32_t roc, uint16_t s_l, uint16_t seq) +{ + int v; + + if (s_l < 32768) { + + if ((int)seq - (int)s_l > 32768) + v = (roc-1) & 0xffffffffu; + else + v = roc; + } + else { + if ((int)s_l - 32768 > seq) + v = (roc+1) & 0xffffffffu; + else + v = roc; + } + + return seq + v*65536; +} + + +int srtp_derive(uint8_t *out, size_t out_len, uint8_t label, + const uint8_t *master_key, size_t key_bytes, + const uint8_t *master_salt, size_t salt_bytes) +{ + uint8_t x[AES_BLOCK_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + static const uint8_t null[AES_BLOCK_SIZE * 2]; + struct aes *aes; + int err; + + if (!out || !master_key || !master_salt) + return EINVAL; + + if (out_len > sizeof(null) || salt_bytes > sizeof(x)) + return EINVAL; + + memcpy(x, master_salt, salt_bytes); + x[7] ^= label; + + err = aes_alloc(&aes, AES_MODE_CTR, master_key, key_bytes*8, x); + if (err) + return err; + + err = aes_encr(aes, out, null, out_len); + + mem_deref(aes); + + return err; + +} + + +void srtp_iv_calc(union vect128 *iv, const union vect128 *k_s, + uint32_t ssrc, uint64_t ix) +{ + if (!iv || !k_s) + return; + + iv->u32[0] = k_s->u32[0]; + iv->u32[1] = k_s->u32[1] ^ htonl(ssrc); + iv->u32[2] = k_s->u32[2] ^ htonl((uint32_t)(ix>>16)); + iv->u16[6] = k_s->u16[6] ^ htons((uint16_t)ix); + iv->u16[7] = 0; +} + + +const char *srtp_suite_name(enum srtp_suite suite) +{ + switch (suite) { + + case SRTP_AES_CM_128_HMAC_SHA1_32: return "AES_CM_128_HMAC_SHA1_32"; + case SRTP_AES_CM_128_HMAC_SHA1_80: return "AES_CM_128_HMAC_SHA1_80"; + case SRTP_AES_256_CM_HMAC_SHA1_32: return "AES_256_CM_HMAC_SHA1_32"; + case SRTP_AES_256_CM_HMAC_SHA1_80: return "AES_256_CM_HMAC_SHA1_80"; + default: return "?"; + } +} diff --git a/src/srtp/mod.mk b/src/srtp/mod.mk new file mode 100644 index 0000000..1494c8b --- /dev/null +++ b/src/srtp/mod.mk @@ -0,0 +1,11 @@ +# +# mod.mk +# +# Copyright (C) 2010 Creytiv.com +# + +SRCS += srtp/misc.c +SRCS += srtp/replay.c +SRCS += srtp/srtcp.c +SRCS += srtp/srtp.c +SRCS += srtp/stream.c diff --git a/src/srtp/replay.c b/src/srtp/replay.c new file mode 100644 index 0000000..8f99b89 --- /dev/null +++ b/src/srtp/replay.c @@ -0,0 +1,63 @@ +/** + * @file srtp/replay.c SRTP replay protection + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include "srtp.h" + + +enum { + SRTP_WINDOW_SIZE = 64 +}; + + +void srtp_replay_init(struct replay *replay) +{ + if (!replay) + return; + + replay->bitmap = 0; + replay->lix = 0; +} + + +/* + * Returns false if packet disallowed, true if packet permitted + */ +bool srtp_replay_check(struct replay *replay, uint64_t ix) +{ + uint64_t diff; + + if (!replay) + return false; + + if (ix > replay->lix) { + diff = ix - replay->lix; + + if (diff < SRTP_WINDOW_SIZE) { /* In window */ + replay->bitmap <<= diff; + replay->bitmap |= 1; /* set bit for this packet */ + } + else + replay->bitmap = 1; + + replay->lix = ix; + return true; + } + + diff = replay->lix - ix; + if (diff >= SRTP_WINDOW_SIZE) + return false; + + if (replay->bitmap & (1ULL << diff)) + return false; /* already seen */ + + /* mark as seen */ + replay->bitmap |= (1ULL << diff); + + return true; +} diff --git a/src/srtp/srtcp.c b/src/srtp/srtcp.c new file mode 100644 index 0000000..ee4fcc8 --- /dev/null +++ b/src/srtp/srtcp.c @@ -0,0 +1,184 @@ +/** + * @file srtcp.c Secure Real-time Transport Control Protocol (SRTCP) + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "srtp.h" + + +static int get_rtcp_ssrc(uint32_t *ssrc, struct mbuf *mb) +{ + if (mbuf_get_left(mb) < 8) + return EBADMSG; + + mbuf_advance(mb, 4); + *ssrc = ntohl(mbuf_read_u32(mb)); + + return 0; +} + + +int srtcp_encrypt(struct srtp *srtp, struct mbuf *mb) +{ + struct srtp_stream *strm; + struct comp *rtcp; + uint32_t ssrc; + size_t start; + int ep = 0; + int err; + + if (!srtp || !mb) + return EINVAL; + + rtcp = &srtp->rtcp; + start = mb->pos; + + err = get_rtcp_ssrc(&ssrc, mb); + if (err) + return err; + + strm = stream_get(srtp, ssrc); + if (!strm) + return ENOMEM; + + strm->rtcp_index = (strm->rtcp_index+1) & 0x7fffffff; + + if (rtcp->aes) { + union vect128 iv; + uint8_t *p = mbuf_buf(mb); + + srtp_iv_calc(&iv, &rtcp->k_s, ssrc, strm->rtcp_index); + + aes_set_iv(rtcp->aes, iv.u8); + err = aes_encr(rtcp->aes, p, p, mbuf_get_left(mb)); + if (err) + return err; + + ep = 1; + } + + /* append E-bit and SRTCP-index */ + mb->pos = mb->end; + err = mbuf_write_u32(mb, htonl(ep<<31 | strm->rtcp_index)); + if (err) + return err; + + if (rtcp->hmac) { + uint8_t tag[SHA_DIGEST_LENGTH]; + + mb->pos = start; + + err = hmac_digest(rtcp->hmac, tag, sizeof(tag), + mbuf_buf(mb), mbuf_get_left(mb)); + if (err) + return err; + + mb->pos = mb->end; + + err = mbuf_write_mem(mb, tag, rtcp->tag_len); + if (err) + return err; + } + + mb->pos = start; + + return 0; +} + + +int srtcp_decrypt(struct srtp *srtp, struct mbuf *mb) +{ + size_t start, eix_start, pld_start; + struct srtp_stream *strm; + struct comp *rtcp; + uint32_t v, ix; + uint32_t ssrc; + bool ep; + int err; + + if (!srtp || !mb) + return EINVAL; + + rtcp = &srtp->rtcp; + start = mb->pos; + + err = get_rtcp_ssrc(&ssrc, mb); + if (err) + return err; + + strm = stream_get(srtp, ssrc); + if (!strm) + return ENOMEM; + + pld_start = mb->pos; + + if (mbuf_get_left(mb) < (4 + rtcp->tag_len)) + return EBADMSG; + + /* Read out E-Bit, SRTCP-index and Authentication Tag */ + eix_start = mb->end - (4 + rtcp->tag_len); + mb->pos = eix_start; + v = ntohl(mbuf_read_u32(mb)); + + ep = (v >> 31) & 1; + ix = v & 0x7fffffff; + + if (rtcp->hmac) { + uint8_t tag[SHA_DIGEST_LENGTH], tag_pkt[SHA_DIGEST_LENGTH]; + const size_t tag_start = mb->pos; + + err = mbuf_read_mem(mb, tag_pkt, rtcp->tag_len); + if (err) + return err; + + mb->pos = start; + mb->end = tag_start; + + err = hmac_digest(rtcp->hmac, tag, sizeof(tag), + mbuf_buf(mb), mbuf_get_left(mb)); + if (err) + return err; + + if (0 != memcmp(tag, tag_pkt, rtcp->tag_len)) + return EAUTH; + + /* + * SRTCP replay protection is as defined in Section 3.3.2, + * but using the SRTCP index as the index i and a separate + * Replay List that is specific to SRTCP. + */ + if (!srtp_replay_check(&strm->replay_rtcp, ix)) + return EALREADY; + } + + mb->end = eix_start; + + if (rtcp->aes && ep) { + union vect128 iv; + uint8_t *p; + + mb->pos = pld_start; + p = mbuf_buf(mb); + + srtp_iv_calc(&iv, &rtcp->k_s, ssrc, ix); + + aes_set_iv(rtcp->aes, iv.u8); + err = aes_decr(rtcp->aes, p, p, mbuf_get_left(mb)); + if (err) + return err; + } + + mb->pos = start; + + return 0; +} diff --git a/src/srtp/srtp.c b/src/srtp/srtp.c new file mode 100644 index 0000000..7b4b831 --- /dev/null +++ b/src/srtp/srtp.c @@ -0,0 +1,324 @@ +/** + * @file srtp.c Secure Real-time Transport Protocol (SRTP) + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "srtp.h" + + +enum { + MAX_KEYLEN = 32, /**< Maximum keylength in bytes */ +}; + + +static inline int seq_diff(uint16_t x, uint16_t y) +{ + return (int)y - (int)x; +} + + +static int comp_init(struct comp *c, unsigned offs, + const uint8_t *key, size_t key_b, + const uint8_t *s, size_t s_b, + size_t tag_len, bool encrypted) +{ + uint8_t k_e[MAX_KEYLEN], k_a[SHA_DIGEST_LENGTH]; + int err = 0; + + if (key_b > sizeof(k_e)) + return EINVAL; + + if (tag_len > SHA_DIGEST_LENGTH) + return EINVAL; + + c->tag_len = tag_len; + + err |= srtp_derive(k_e, key_b, 0x00+offs, key, key_b, s, s_b); + err |= srtp_derive(k_a, sizeof(k_a), 0x01+offs, key, key_b, s, s_b); + err |= srtp_derive(c->k_s.u8, 14, 0x02+offs, key, key_b, s, s_b); + if (err) + return err; + + if (encrypted) { + err = aes_alloc(&c->aes, AES_MODE_CTR, k_e, key_b*8, NULL); + if (err) + return err; + } + + err = hmac_create(&c->hmac, HMAC_HASH_SHA1, k_a, sizeof(k_a)); + if (err) + return err; + + return err; +} + + +static void destructor(void *arg) +{ + struct srtp *srtp = arg; + + mem_deref(srtp->rtp.aes); + mem_deref(srtp->rtcp.aes); + mem_deref(srtp->rtp.hmac); + mem_deref(srtp->rtcp.hmac); + + list_flush(&srtp->streaml); +} + + +int srtp_alloc(struct srtp **srtpp, enum srtp_suite suite, + const uint8_t *key, size_t key_bytes, int flags) +{ + struct srtp *srtp; + const uint8_t *master_salt; + size_t cipher_bytes, auth_bytes; + int err = 0; + + if (!srtpp || !key) + return EINVAL; + + switch (suite) { + + case SRTP_AES_CM_128_HMAC_SHA1_80: + cipher_bytes = 16; + auth_bytes = 10; + break; + + case SRTP_AES_CM_128_HMAC_SHA1_32: + cipher_bytes = 16; + auth_bytes = 4; + break; + + case SRTP_AES_256_CM_HMAC_SHA1_80: + cipher_bytes = 32; + auth_bytes = 10; + break; + + case SRTP_AES_256_CM_HMAC_SHA1_32: + cipher_bytes = 32; + auth_bytes = 4; + break; + + default: + return ENOTSUP; + }; + + if ((cipher_bytes + SRTP_SALT_SIZE) != key_bytes) + return EINVAL; + + master_salt = &key[cipher_bytes]; + + srtp = mem_zalloc(sizeof(*srtp), destructor); + if (!srtp) + return ENOMEM; + + err |= comp_init(&srtp->rtp, 0, key, cipher_bytes, + master_salt, SRTP_SALT_SIZE, auth_bytes, true); + err |= comp_init(&srtp->rtcp, 3, key, cipher_bytes, + master_salt, SRTP_SALT_SIZE, auth_bytes, + !(flags & SRTP_UNENCRYPTED_SRTCP)); + if (err) + goto out; + + out: + if (err) + mem_deref(srtp); + else + *srtpp = srtp; + + return err; +} + + +int srtp_encrypt(struct srtp *srtp, struct mbuf *mb) +{ + struct srtp_stream *strm; + struct rtp_header hdr; + struct comp *comp; + size_t start; + uint64_t ix; + int err; + + if (!srtp || !mb) + return EINVAL; + + comp = &srtp->rtp; + + start = mb->pos; + + err = rtp_hdr_decode(&hdr, mb); + if (err) + return err; + + strm = stream_get_seq(srtp, hdr.ssrc, hdr.seq); + if (!strm) + return ENOMEM; + + /* Roll-Over Counter (ROC) */ + if (seq_diff(strm->s_l, hdr.seq) <= -32768) { + strm->roc++; + strm->s_l = 0; + } + + ix = 65536ULL * strm->roc + hdr.seq; + + if (comp->aes) { + union vect128 iv; + uint8_t *p = mbuf_buf(mb); + + srtp_iv_calc(&iv, &comp->k_s, strm->ssrc, ix); + + aes_set_iv(comp->aes, iv.u8); + err = aes_encr(comp->aes, p, p, mbuf_get_left(mb)); + if (err) + return err; + } + + if (comp->hmac) { + const size_t tag_start = mb->end; + uint8_t tag[SHA_DIGEST_LENGTH]; + + mb->pos = tag_start; + + err = mbuf_write_u32(mb, htonl(strm->roc)); + if (err) + return err; + + mb->pos = start; + + err = hmac_digest(comp->hmac, tag, sizeof(tag), + mbuf_buf(mb), mbuf_get_left(mb)); + if (err) + return err; + + mb->pos = mb->end = tag_start; + + err = mbuf_write_mem(mb, tag, comp->tag_len); + if (err) + return err; + } + + if (hdr.seq > strm->s_l) + strm->s_l = hdr.seq; + + mb->pos = start; + + return 0; +} + + +int srtp_decrypt(struct srtp *srtp, struct mbuf *mb) +{ + struct srtp_stream *strm; + struct rtp_header hdr; + struct comp *comp; + uint64_t ix; + size_t start; + int diff; + int err; + + if (!srtp || !mb) + return EINVAL; + + comp = &srtp->rtp; + + start = mb->pos; + + err = rtp_hdr_decode(&hdr, mb); + if (err) + return err; + + strm = stream_get_seq(srtp, hdr.ssrc, hdr.seq); + if (!strm) + return ENOMEM; + + diff = seq_diff(strm->s_l, hdr.seq); + if (diff > 32768) + return ETIMEDOUT; + + /* Roll-Over Counter (ROC) */ + if (diff <= -32768) { + strm->roc++; + strm->s_l = 0; + } + + ix = srtp_get_index(strm->roc, strm->s_l, hdr.seq); + + if (comp->hmac) { + uint8_t tag_calc[SHA_DIGEST_LENGTH]; + uint8_t tag_pkt[SHA_DIGEST_LENGTH]; + size_t pld_start, tag_start; + + if (mbuf_get_left(mb) < comp->tag_len) + return EBADMSG; + + pld_start = mb->pos; + tag_start = mb->end - comp->tag_len; + + mb->pos = tag_start; + + err = mbuf_read_mem(mb, tag_pkt, comp->tag_len); + if (err) + return err; + + mb->pos = mb->end = tag_start; + + err = mbuf_write_u32(mb, htonl(strm->roc)); + if (err) + return err; + + mb->pos = start; + + err = hmac_digest(comp->hmac, tag_calc, sizeof(tag_calc), + mbuf_buf(mb), mbuf_get_left(mb)); + if (err) + return err; + + mb->pos = pld_start; + mb->end = tag_start; + + if (0 != memcmp(tag_calc, tag_pkt, comp->tag_len)) + return EAUTH; + + /* + * 3.3.2. Replay Protection + * + * Secure replay protection is only possible when + * integrity protection is present. + */ + if (!srtp_replay_check(&strm->replay_rtp, ix)) + return EALREADY; + } + + if (comp->aes) { + + union vect128 iv; + uint8_t *p = mbuf_buf(mb); + + srtp_iv_calc(&iv, &comp->k_s, strm->ssrc, ix); + + aes_set_iv(comp->aes, iv.u8); + err = aes_decr(comp->aes, p, p, mbuf_get_left(mb)); + if (err) + return err; + } + + if (hdr.seq > strm->s_l) + strm->s_l = hdr.seq; + + mb->pos = start; + + return 0; +} diff --git a/src/srtp/srtp.h b/src/srtp/srtp.h new file mode 100644 index 0000000..80ecca4 --- /dev/null +++ b/src/srtp/srtp.h @@ -0,0 +1,69 @@ +/** + * @file srtp.h Secure Real-time Transport Protocol (SRTP) -- internal + * + * Copyright (C) 2010 Creytiv.com + */ + + +enum { + SRTP_SALT_SIZE = 14 +}; + + +/** Defines a 128-bit vector in network order */ +union vect128 { + uint64_t u64[ 2]; + uint32_t u32[ 4]; + uint16_t u16[ 8]; + uint8_t u8[16]; +}; + +/** Replay protection */ +struct replay { + uint64_t bitmap; /**< Session state - must be 64 bits */ + uint64_t lix; /**< Last received index */ +}; + +/** SRTP stream/context -- shared state between RTP/RTCP */ +struct srtp_stream { + struct le le; /**< Linked-list element */ + struct replay replay_rtp; /**< recv -- replay protection for RTP */ + struct replay replay_rtcp; /**< recv -- replay protection for RTCP */ + uint32_t ssrc; /**< SSRC -- lookup key */ + uint32_t roc; /**< send/recv Roll-Over Counter (ROC) */ + uint16_t s_l; /**< send/recv -- highest SEQ number */ + bool s_l_set; /**< True if s_l has been set */ + uint32_t rtcp_index; /**< RTCP-index for sending (31-bits) */ +}; + +/** SRTP Session */ +struct srtp { + struct comp { + struct aes *aes; /**< AES Context */ + struct hmac *hmac; /**< HMAC Context */ + union vect128 k_s; /**< Derived salting key (14 bytes) */ + size_t tag_len; /**< Authentication tag length [bytes] */ + } rtp, rtcp; + + struct list streaml; /**< SRTP-streams (struct srtp_stream) */ +}; + + +struct srtp_stream *stream_get(struct srtp *srtp, uint32_t ssrc); +struct srtp_stream *stream_get_seq(struct srtp *srtp, uint32_t ssrc, + uint16_t seq); + + +int srtp_derive(uint8_t *out, size_t out_len, uint8_t label, + const uint8_t *master_key, size_t key_bytes, + const uint8_t *master_salt, size_t salt_bytes); +void srtp_iv_calc(union vect128 *iv, const union vect128 *k_s, + uint32_t ssrc, uint64_t ix); +uint64_t srtp_get_index(uint32_t roc, uint16_t s_l, uint16_t seq); +const char *srtp_suite_name(enum srtp_suite suite); + + +/* Replay protection */ + +void srtp_replay_init(struct replay *replay); +bool srtp_replay_check(struct replay *replay, uint64_t ix); diff --git a/src/srtp/stream.c b/src/srtp/stream.c new file mode 100644 index 0000000..ee2c06e --- /dev/null +++ b/src/srtp/stream.c @@ -0,0 +1,95 @@ +/** + * @file srtp/stream.c Secure Real-time Transport Protocol (SRTP) -- stream + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include "srtp.h" + + +enum { + MAX_STREAMS = 8, /**< Maximum number of SRTP streams */ +}; + + +static void stream_destructor(void *arg) +{ + struct srtp_stream *strm = arg; + + list_unlink(&strm->le); +} + + +static struct srtp_stream *stream_find(struct srtp *srtp, uint32_t ssrc) +{ + struct le *le; + + for (le = srtp->streaml.head; le; le = le->next) { + + struct srtp_stream *strm = le->data; + + if (strm->ssrc == ssrc) + return strm; + } + + return NULL; +} + + +static struct srtp_stream *stream_new(struct srtp *srtp, uint32_t ssrc) +{ + struct srtp_stream *strm; + + if (list_count(&srtp->streaml) >= MAX_STREAMS) + return NULL; + + strm = mem_zalloc(sizeof(*strm), stream_destructor); + if (!strm) + return NULL; + + strm->ssrc = ssrc; + srtp_replay_init(&strm->replay_rtp); + srtp_replay_init(&strm->replay_rtcp); + + list_append(&srtp->streaml, &strm->le, strm); + + return strm; +} + + +struct srtp_stream *stream_get(struct srtp *srtp, uint32_t ssrc) +{ + struct srtp_stream *strm; + + if (!srtp) + return NULL; + + strm = stream_find(srtp, ssrc); + if (strm) + return strm; + + return stream_new(srtp, ssrc); +} + + +struct srtp_stream *stream_get_seq(struct srtp *srtp, uint32_t ssrc, + uint16_t seq) +{ + struct srtp_stream *strm; + + strm = stream_get(srtp, ssrc); + if (!strm) + return NULL; + + /* Set the initial sequence number once only */ + if (!strm->s_l_set) { + strm->s_l = seq; + strm->s_l_set = true; + } + + return strm; +}