added support for SRTP

RFC 3711 -- Secure Real-time Transport Protocol (SRTP)
This commit is contained in:
Alfred E. Heggestad 2014-05-05 18:40:06 +00:00
parent edd8b3c06e
commit edf3cf5430
12 changed files with 918 additions and 1 deletions

View file

@ -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),)

View file

@ -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

View file

@ -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"

26
include/re_srtp.h Normal file
View file

@ -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);

42
src/srtp/README Normal file
View file

@ -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

99
src/srtp/misc.c Normal file
View file

@ -0,0 +1,99 @@
/**
* @file srtp/misc.c SRTP functions
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_aes.h>
#include <re_sa.h>
#include <re_srtp.h>
#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 "?";
}
}

11
src/srtp/mod.mk Normal file
View file

@ -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

63
src/srtp/replay.c Normal file
View file

@ -0,0 +1,63 @@
/**
* @file srtp/replay.c SRTP replay protection
*
* Copyright (C) 2010 Creytiv.com
*/
#include <re_types.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_srtp.h>
#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;
}

184
src/srtp/srtcp.c Normal file
View file

@ -0,0 +1,184 @@
/**
* @file srtcp.c Secure Real-time Transport Control Protocol (SRTCP)
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_hmac.h>
#include <re_sha.h>
#include <re_aes.h>
#include <re_net.h>
#include <re_srtp.h>
#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;
}

324
src/srtp/srtp.c Normal file
View file

@ -0,0 +1,324 @@
/**
* @file srtp.c Secure Real-time Transport Protocol (SRTP)
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_hmac.h>
#include <re_sha.h>
#include <re_aes.h>
#include <re_sa.h>
#include <re_rtp.h>
#include <re_srtp.h>
#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;
}

69
src/srtp/srtp.h Normal file
View file

@ -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);

95
src/srtp/stream.c Normal file
View file

@ -0,0 +1,95 @@
/**
* @file srtp/stream.c Secure Real-time Transport Protocol (SRTP) -- stream
*
* Copyright (C) 2010 Creytiv.com
*/
#include <re_types.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_srtp.h>
#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;
}