Skip to content

Commit

Permalink
srtp: locking of srtp_tx and rx objects
Browse files Browse the repository at this point in the history
 * critical objects are srtp_tx and srtp_rx, both got there own mutex
 * any access on these objects are locked with the corresponding lock
 * receiv and send handler use trylock, therefore are nonblocking
 * media_txrekey handler defined to generate a new tx key without
   removing the hole menc_media of the stream
  • Loading branch information
cHuberCoffee committed Apr 25, 2024
1 parent c56087d commit 8c0a0ca
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 23 deletions.
99 changes: 84 additions & 15 deletions modules/srtp/srtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ struct menc_st {
/* base64_decoding worst case encoded 32+12 key */
uint8_t key_rx[46];
struct srtp *srtp_tx, *srtp_rx;
mtx_t *mtx_tx, *mtx_rx;
RE_ATOMIC bool use_srtp;
bool got_sdp;
char *crypto_suite;
mtx_t *mtx; /*< Mutex protects above fields */

void *rtpsock;
void *rtcpsock;
Expand Down Expand Up @@ -75,9 +75,16 @@ static void destructor(void *arg)
mem_deref(st->rtpsock);
mem_deref(st->rtcpsock);

mem_deref(st->srtp_tx);
mem_deref(st->srtp_rx);
mem_deref(st->mtx);
mtx_lock(st->mtx_tx);
st->srtp_tx = mem_deref(st->srtp_tx);
mtx_unlock(st->mtx_tx);

mtx_lock(st->mtx_rx);
st->srtp_rx = mem_deref(st->srtp_rx);
mtx_unlock(st->mtx_rx);

mem_deref(st->mtx_tx);
mem_deref(st->mtx_rx);
}


Expand Down Expand Up @@ -169,21 +176,27 @@ static int start_srtp(struct menc_st *st, const char *suite_name)
len = get_master_keylen(suite);

/* allocate and initialize the SRTP session */
mtx_lock(st->mtx_tx);
if (!st->srtp_tx) {
err = srtp_alloc(&st->srtp_tx, suite, st->key_tx, len, 0);
if (err) {
warning("srtp: srtp_alloc TX failed (%m)\n", err);
mtx_unlock(st->mtx_tx);
return err;
}
}
mtx_unlock(st->mtx_tx);

mtx_lock(st->mtx_rx);
if (!st->srtp_rx) {
err = srtp_alloc(&st->srtp_rx, suite, st->key_rx, len, 0);
if (err) {
warning("srtp: srtp_alloc RX failed (%m)\n", err);
mtx_unlock(st->mtx_rx);
return err;
}
}
mtx_unlock(st->mtx_rx);

/* use SRTP for this stream/session */
re_atomic_rlx_set(&st->use_srtp, true);
Expand All @@ -202,13 +215,26 @@ static bool send_handler(int *err, struct sa *dst, struct mbuf *mb, void *arg)
if (!re_atomic_rlx(&st->use_srtp) || !is_rtp_or_rtcp(mb))
return false;

lerr = mtx_trylock(st->mtx_tx) != thrd_success;
if (lerr)
goto out;

if (!st->srtp_tx) {
lerr = EBUSY;
warning("srtp: srtp_tx not ready (%m)\n", err);
goto unlock_out;
}

if (is_rtcp_packet(mb)) {
lerr = srtcp_encrypt(st->srtp_tx, mb);
}
else {
lerr = srtp_encrypt(st->srtp_tx, mb);
}

unlock_out:
mtx_unlock(st->mtx_tx);
out:
if (lerr) {
warning("srtp: failed to encrypt %s-packet"
" with %zu bytes (%m)\n",
Expand All @@ -235,7 +261,16 @@ static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg)
if (!re_atomic_rlx(&st->use_srtp) || !is_rtp_or_rtcp(mb))
return false;

mtx_lock(st->mtx);
err = mtx_trylock(st->mtx_rx) != thrd_success;
if (err)
goto out;

if (!st->srtp_rx) {
err = EBUSY;
warning("srtp: srtp_rx not ready (%m)\n", err);
goto out;
}

if (is_rtcp_packet(mb)) {
err = srtcp_decrypt(st->srtp_rx, mb);
if (err) {
Expand All @@ -250,8 +285,9 @@ static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg)
" with %zu bytes (%m)\n", len, err);
}
}
mtx_unlock(st->mtx);

mtx_unlock(st->mtx_rx);
out:
return err ? true : false;
}

Expand Down Expand Up @@ -315,7 +351,9 @@ static int start_crypto(struct menc_st *st, const struct pl *key_info)
sizeof(st->key_rx) > olen ? olen : sizeof(st->key_rx))) {
info("srtp: %s: re-keying in progress\n",
stream_name(st->strm));
mtx_lock(st->mtx_rx);
st->srtp_rx = mem_deref(st->srtp_rx);
mtx_unlock(st->mtx_rx);
}

memcpy(st->key_rx, new_key, olen);
Expand Down Expand Up @@ -360,29 +398,56 @@ static bool sdp_attr_handler(const char *name, const char *value, void *arg)
if (!cryptosuite_issupported(&c.suite))
return false;

mtx_lock(st->mtx);
/* receiving crypto-suite changed -> reset srtp_rx */
if (st->srtp_rx && pl_strcmp(&c.suite, st->crypto_suite)) {
info ("srtp (%s-rx): cipher suite changed from %s to %r\n",
stream_name(st->strm), st->crypto_suite, &c.suite);
mtx_lock(st->mtx_rx);
st->srtp_rx = mem_deref(st->srtp_rx);
mtx_unlock(st->mtx_rx);
}

st->crypto_suite = mem_deref(st->crypto_suite);
pl_strdup(&st->crypto_suite, &c.suite);

if (start_crypto(st, &c.key_info)) {
mtx_unlock(st->mtx);
if (start_crypto(st, &c.key_info))
return false;
}

mtx_unlock(st->mtx);
sdp_enc(st, st->sdpm, c.tag, st->crypto_suite);

return true;
}


static int media_txrekey(struct menc_media *m)
{
const char *rattr = NULL;
struct menc_st *st = (struct menc_st *) m;
int err = 0;

if (!st)
return EINVAL;

mtx_lock(st->mtx_tx);
st->srtp_tx = mem_deref(st->srtp_tx);
mtx_unlock(st->mtx_tx);

rand_bytes(st->key_tx, sizeof(st->key_tx));

if (sdp_media_rattr(st->sdpm, "crypto")) {

rattr = sdp_media_rattr_apply(st->sdpm, "crypto",
sdp_attr_handler, st);
if (!rattr) {
warning("srtp: no valid a=crypto attribute from"
" remote peer\n");
}
}

return err;
}


static int session_alloc(struct menc_sess **sessp,
struct sdp_session *sdp, bool offerer,
menc_event_h *eventh, menc_error_h *errorh,
Expand Down Expand Up @@ -436,7 +501,8 @@ static int media_alloc(struct menc_media **stp, struct menc_sess *sess,
if (!st)
return ENOMEM;

err = mutex_alloc(&st->mtx);
err = mutex_alloc(&st->mtx_tx);
err |= mutex_alloc(&st->mtx_rx);
if (err)
return err;

Expand Down Expand Up @@ -509,21 +575,24 @@ static struct menc menc_srtp_opt = {
.id = "srtp",
.sdp_proto = "RTP/AVP",
.sessh = session_alloc,
.mediah = media_alloc
.mediah = media_alloc,
.txrekeyh = media_txrekey
};

static struct menc menc_srtp_mand = {
.id = "srtp-mand",
.sdp_proto = "RTP/SAVP",
.sessh = session_alloc,
.mediah = media_alloc
.mediah = media_alloc,
.txrekeyh = media_txrekey
};

static struct menc menc_srtp_mandf = {
.id = "srtp-mandf",
.sdp_proto = "RTP/SAVPF",
.sessh = session_alloc,
.mediah = media_alloc
.mediah = media_alloc,
.txrekeyh = media_txrekey
};


Expand Down
12 changes: 4 additions & 8 deletions src/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,21 +956,17 @@ int stream_update(struct stream *s)


/**
* Removes the media encryption state from a stream.
* Calls the transmission rekeying handler of the media encryption
*
* Only apply if SRTP module is used!
*
* The encryption consists of 1 encryption session state and N encryption
* media states.
*
* @param strm Stream to remove the media encryption state.
* @param strm Stream to rekey
*/
void stream_remove_menc_media_state(struct stream *strm)
{
if (!strm)
return;

strm->mes = mem_deref(strm->mes);
if (strm->menc->txrekeyh)
strm->menc->txrekeyh(strm->mes);
}


Expand Down

0 comments on commit 8c0a0ca

Please sign in to comment.