summaryrefslogtreecommitdiff
path: root/modules/dtls_srtp/dtls_srtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/dtls_srtp/dtls_srtp.c')
-rw-r--r--modules/dtls_srtp/dtls_srtp.c243
1 files changed, 163 insertions, 80 deletions
diff --git a/modules/dtls_srtp/dtls_srtp.c b/modules/dtls_srtp/dtls_srtp.c
index b25c143..2796080 100644
--- a/modules/dtls_srtp/dtls_srtp.c
+++ b/modules/dtls_srtp/dtls_srtp.c
@@ -41,7 +41,7 @@ struct menc_sess {
/* media */
struct dtls_srtp {
- struct sock sockv[2];
+ struct comp compv[2];
const struct menc_sess *sess;
struct sdp_media *sdpm;
struct tmr tmr;
@@ -72,13 +72,14 @@ static void destructor(void *arg)
tmr_cancel(&st->tmr);
for (i=0; i<2; i++) {
- struct sock *s = &st->sockv[i];
-
- mem_deref(s->uh_srtp);
- mem_deref(s->dtls);
- mem_deref(s->app_sock); /* must be freed last */
- mem_deref(s->tx);
- mem_deref(s->rx);
+ struct comp *c = &st->compv[i];
+
+ mem_deref(c->uh_srtp);
+ mem_deref(c->tls_conn);
+ mem_deref(c->dtls_sock);
+ mem_deref(c->app_sock); /* must be freed last */
+ mem_deref(c->tx);
+ mem_deref(c->rx);
}
mem_deref(st->sdpm);
@@ -87,75 +88,52 @@ static void destructor(void *arg)
static bool verify_fingerprint(const struct sdp_session *sess,
const struct sdp_media *media,
- struct dtls_flow *tc)
+ struct tls_conn *tc)
{
struct pl hash;
- char hashstr[32];
- uint8_t md_sdp[64];
+ uint8_t md_sdp[32], md_dtls[32];
size_t sz_sdp = sizeof(md_sdp);
- struct tls_fingerprint tls_fp;
+ size_t sz_dtls;
+ enum tls_fingerprint type;
+ int err;
if (sdp_fingerprint_decode(sdp_rattr(sess, media, "fingerprint"),
&hash, md_sdp, &sz_sdp))
return false;
- pl_strcpy(&hash, hashstr, sizeof(hashstr));
+ if (0 == pl_strcasecmp(&hash, "sha-1")) {
+ type = TLS_FINGERPRINT_SHA1;
+ sz_dtls = 20;
+ }
+ else if (0 == pl_strcasecmp(&hash, "sha-256")) {
+ type = TLS_FINGERPRINT_SHA256;
+ sz_dtls = 32;
+ }
+ else {
+ warning("dtls_srtp: unknown fingerprint '%r'\n", &hash);
+ return false;
+ }
- if (dtls_get_remote_fingerprint(tc, hashstr, &tls_fp)) {
- warning("dtls_srtp: could not get DTLS fingerprint\n");
+ err = tls_peer_fingerprint(tc, type, md_dtls, sizeof(md_dtls));
+ if (err) {
+ warning("dtls_srtp: could not get DTLS fingerprint (%m)\n",
+ err);
return false;
}
- if (sz_sdp != tls_fp.len || 0 != memcmp(md_sdp, tls_fp.md, sz_sdp)) {
- warning("dtls_srtp: %s fingerprint mismatch\n", hashstr);
- info("DTLS: %w\n", tls_fp.md, (size_t)tls_fp.len);
+ if (sz_sdp != sz_dtls || 0 != memcmp(md_sdp, md_dtls, sz_sdp)) {
+ warning("dtls_srtp: %r fingerprint mismatch\n", &hash);
info("SDP: %w\n", md_sdp, sz_sdp);
+ info("DTLS: %w\n", md_dtls, sz_dtls);
return false;
}
- info("dtls_srtp: verified %s fingerprint OK\n", hashstr);
+ info("dtls_srtp: verified %r fingerprint OK\n", &hash);
return true;
}
-static void dtls_established_handler(int err, struct dtls_flow *flow,
- const char *profile,
- const struct key *client_key,
- const struct key *server_key,
- void *arg)
-{
- struct sock *sock = arg;
- const struct dtls_srtp *ds = sock->ds;
-
- if (!verify_fingerprint(ds->sess->sdp, ds->sdpm, flow)) {
- warning("dtls_srtp: could not verify remote fingerprint\n");
- if (ds->sess->errorh)
- ds->sess->errorh(EPIPE, ds->sess->arg);
- return;
- }
-
- sock->negotiated = true;
-
- info("dtls_srtp: ---> DTLS-SRTP complete (%s/%s) Profile=%s\n",
- sdp_media_name(ds->sdpm),
- sock->is_rtp ? "RTP" : "RTCP", profile);
-
- err |= srtp_stream_add(&sock->tx, profile,
- ds->active ? client_key : server_key,
- true);
-
- err |= srtp_stream_add(&sock->rx, profile,
- ds->active ? server_key : client_key,
- false);
-
- err |= srtp_install(sock);
- if (err) {
- warning("dtls_srtp: srtp_install: %m\n", err);
- }
-}
-
-
static int session_alloc(struct menc_sess **sessp,
struct sdp_session *sdp, bool offerer,
menc_error_h *errorh, void *arg)
@@ -170,10 +148,10 @@ static int session_alloc(struct menc_sess **sessp,
if (!sess)
return ENOMEM;
- sess->sdp = mem_ref(sdp);
+ sess->sdp = mem_ref(sdp);
sess->offerer = offerer;
- sess->errorh = errorh;
- sess->arg = arg;
+ sess->errorh = errorh;
+ sess->arg = arg;
/* RFC 4145 */
err = sdp_session_set_lattr(sdp, true, "setup",
@@ -197,27 +175,113 @@ static int session_alloc(struct menc_sess **sessp,
}
-static int media_start_sock(struct sock *sock, struct sdp_media *sdpm)
+static void dtls_estab_handler(void *arg)
+{
+ struct comp *comp = arg;
+ const struct dtls_srtp *ds = comp->ds;
+ enum srtp_suite suite;
+ uint8_t cli_key[30], srv_key[30];
+ int err;
+
+ if (!verify_fingerprint(ds->sess->sdp, ds->sdpm, comp->tls_conn)) {
+ warning("dtls_srtp: could not verify remote fingerprint\n");
+ if (ds->sess->errorh)
+ ds->sess->errorh(EPIPE, ds->sess->arg);
+ return;
+ }
+
+ err = tls_srtp_keyinfo(comp->tls_conn, &suite,
+ cli_key, sizeof(cli_key),
+ srv_key, sizeof(srv_key));
+ if (err) {
+ warning("dtls_srtp: could not get SRTP keyinfo (%m)\n", err);
+ return;
+ }
+
+ comp->negotiated = true;
+
+ info("dtls_srtp: ---> DTLS-SRTP complete (%s/%s) Profile=%s\n",
+ sdp_media_name(ds->sdpm),
+ comp->is_rtp ? "RTP" : "RTCP", srtp_suite_name(suite));
+
+ err |= srtp_stream_add(&comp->tx, suite,
+ ds->active ? cli_key : srv_key, 30, true);
+ err |= srtp_stream_add(&comp->rx, suite,
+ ds->active ? srv_key : cli_key, 30, false);
+
+ err |= srtp_install(comp);
+ if (err) {
+ warning("dtls_srtp: srtp_install: %m\n", err);
+ }
+
+ /* todo: notify application that crypto is up and running */
+}
+
+
+static void dtls_close_handler(int err, void *arg)
+{
+ struct comp *comp = arg;
+
+ info("dtls_srtp: dtls-connection closed (%m)\n", err);
+
+ if (!comp->negotiated) {
+
+ if (comp->ds->sess->errorh)
+ comp->ds->sess->errorh(err, comp->ds->sess->arg);
+ }
+}
+
+
+static void dtls_conn_handler(const struct sa *peer, void *arg)
+{
+ struct comp *comp = arg;
+ int err;
+ (void)peer;
+
+ err = dtls_accept(&comp->tls_conn, tls, comp->dtls_sock,
+ dtls_estab_handler, NULL, dtls_close_handler, comp);
+ if (err) {
+ warning("dtls_srtp: dtls_accept failed (%m)\n", err);
+ return;
+ }
+}
+
+
+static int component_start(struct comp *comp, struct sdp_media *sdpm)
{
struct sa raddr;
int err = 0;
- if (!sock->app_sock || sock->negotiated || sock->dtls)
+ if (!comp->app_sock || comp->negotiated || comp->dtls_sock)
return 0;
- if (sock->is_rtp)
+ if (comp->is_rtp)
raddr = *sdp_media_raddr(sdpm);
else
sdp_media_raddr_rtcp(sdpm, &raddr);
- if (sa_isset(&raddr, SA_ALL)) {
+ err = dtls_listen(&comp->dtls_sock, NULL,
+ comp->app_sock, 2, LAYER_DTLS,
+ dtls_conn_handler, comp);
+ if (err) {
+ warning("dtls_srtp: dtls_listen failed (%m)\n", err);
+ return err;
+ }
- err = dtls_flow_alloc(&sock->dtls, tls, sock->app_sock,
- dtls_established_handler, sock);
- if (err)
- return err;
+ if (sa_isset(&raddr, SA_ALL)) {
- err = dtls_flow_start(sock->dtls, &raddr, sock->ds->active);
+ if (comp->ds->active && !comp->tls_conn) {
+
+ err = dtls_connect(&comp->tls_conn, tls,
+ comp->dtls_sock, &raddr,
+ dtls_estab_handler, NULL,
+ dtls_close_handler, comp);
+ if (err) {
+ warning("dtls_srtp: dtls_connect()"
+ " failed (%m)\n", err);
+ return err;
+ }
+ }
}
return err;
@@ -231,16 +295,16 @@ static int media_start(struct dtls_srtp *st, struct sdp_media *sdpm)
if (st->started)
return 0;
- debug("dtls_srtp: media_start: '%s' mux=%d, active=%d\n",
- sdp_media_name(sdpm), st->mux, st->active);
+ info("dtls_srtp: media=%s -- start DTLS %s\n",
+ sdp_media_name(sdpm), st->active ? "client" : "server");
if (!sdp_media_has_media(sdpm))
return 0;
- err = media_start_sock(&st->sockv[0], sdpm);
+ err = component_start(&st->compv[0], sdpm);
if (!st->mux)
- err |= media_start_sock(&st->sockv[1], sdpm);
+ err |= component_start(&st->compv[1], sdpm);
if (err)
return err;
@@ -283,14 +347,14 @@ static int media_alloc(struct menc_media **mp, struct menc_sess *sess,
st->sess = sess;
st->sdpm = mem_ref(sdpm);
- st->sockv[0].app_sock = mem_ref(rtpsock);
- st->sockv[1].app_sock = mem_ref(rtcpsock);
+ st->compv[0].app_sock = mem_ref(rtpsock);
+ st->compv[1].app_sock = mem_ref(rtcpsock);
for (i=0; i<2; i++)
- st->sockv[i].ds = st;
+ st->compv[i].ds = st;
- st->sockv[0].is_rtp = true;
- st->sockv[1].is_rtp = false;
+ st->compv[0].is_rtp = true;
+ st->compv[1].is_rtp = false;
if (err) {
mem_deref(st);
@@ -300,7 +364,7 @@ static int media_alloc(struct menc_media **mp, struct menc_sess *sess,
*mp = (struct menc_media *)st;
setup:
- st->mux = (rtpsock == rtcpsock);
+ st->mux = (rtpsock == rtcpsock) || (rtcpsock == NULL);
setup = sdp_rattr(st->sess->sdp, st->sdpm, "setup");
if (setup) {
@@ -369,9 +433,28 @@ static int module_init(void)
return ENOSYS;
}
- err = dtls_alloc_selfsigned(&tls, "dtls@baresip", srtp_profiles);
- if (err)
+ err = tls_alloc(&tls, TLS_METHOD_DTLSV1, NULL, NULL);
+ if (err) {
+ warning("dtls_srtp: failed to create DTLS context (%m)\n",
+ err);
+ return err;
+ }
+
+ err = tls_set_selfsigned(tls, "dtls@baresip");
+ if (err) {
+ warning("dtls_srtp: failed to self-sign certificate (%m)\n",
+ err);
return err;
+ }
+
+ tls_set_verify_client(tls);
+
+ err = tls_set_srtp(tls, srtp_profiles);
+ if (err) {
+ warning("dtls_srtp: failed to enable SRTP profile (%m)\n",
+ err);
+ return err;
+ }
menc_register(&dtls_srtpf);
menc_register(&dtls_srtp);