summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorglenvt18 <glenvt18@gmail.com>2017-10-15 10:11:21 +0300
committerAlfred E. Heggestad <alfred.heggestad@gmail.com>2017-10-15 09:11:21 +0200
commita4fd1665c8911c80e8cce5a5cc9b7e9314222bdd (patch)
tree80abceb4ee8103a2e9c3aedf9f770f1ff6ac8853
parent6cd9a9d9f988a6eb83b0a816f6098d252a3f741a (diff)
modules/zrtp: add signaling hash support (#311)
Use SDP attribute a=zrtp-hash to protect the Hello message (RFC 6189, section 8.1).
-rw-r--r--docs/examples/config3
-rw-r--r--modules/zrtp/zrtp.c148
-rw-r--r--src/config.c5
3 files changed, 153 insertions, 3 deletions
diff --git a/docs/examples/config b/docs/examples/config
index 0bb37e5..1eabd62 100644
--- a/docs/examples/config
+++ b/docs/examples/config
@@ -170,5 +170,8 @@ ice_debug no
ice_nomination regular # {regular,aggressive}
ice_mode full # {full,lite}
+# ZRTP
+#zrtp_hash no # Disable SDP zrtp-hash (not recommended)
+
# sndfile #
snd_path /tmp/
diff --git a/modules/zrtp/zrtp.c b/modules/zrtp/zrtp.c
index 115db1c..28ae48f 100644
--- a/modules/zrtp/zrtp.c
+++ b/modules/zrtp/zrtp.c
@@ -26,6 +26,13 @@
* Thanks:
*
* Ingo Feinerer
+ *
+ * Configuration options:
+ *
+ \verbatim
+ zrtp_hash {yes,no} # Enable SDP zrtp-hash (recommended)
+ \endverbatim
+ *
*/
@@ -35,10 +42,14 @@ enum {
struct menc_sess {
zrtp_session_t *zrtp_session;
+ menc_error_h *errorh;
+ void *arg;
+ struct tmr abort_timer;
+ int err;
};
struct menc_media {
- const struct menc_sess *sess;
+ struct menc_sess *sess;
struct udp_helper *uh_rtp;
struct udp_helper *uh_rtcp;
struct sa raddr;
@@ -53,6 +64,10 @@ static zrtp_config_t zrtp_config;
static zrtp_zid_t zid;
+/* RFC 6189, section 8.1. */
+static bool use_sig_hash = true;
+
+
enum pkt_type {
PKT_TYPE_UNKNOWN = 0,
PKT_TYPE_RTP = 1,
@@ -93,6 +108,8 @@ static void session_destructor(void *arg)
{
struct menc_sess *st = arg;
+ tmr_cancel(&st->abort_timer);
+
if (st->zrtp_session)
zrtp_session_down(st->zrtp_session);
}
@@ -112,6 +129,32 @@ static void media_destructor(void *arg)
}
+static void abort_timer_h(void *arg)
+{
+ struct menc_sess *sess = arg;
+
+ if (sess->errorh) {
+ sess->errorh(sess->err, sess->arg);
+ sess->errorh = NULL;
+ }
+}
+
+
+static void abort_call(struct menc_sess *sess)
+{
+ if (!sess->err) {
+ sess->err = EPIPE;
+ tmr_start(&sess->abort_timer, 0, abort_timer_h, sess);
+ }
+}
+
+
+static bool drop_packets(const struct menc_media *st)
+{
+ return (st)? st->sess->err != 0 : true;
+}
+
+
static bool udp_helper_send(int *err, struct sa *dst,
struct mbuf *mb, void *arg)
{
@@ -121,6 +164,9 @@ static bool udp_helper_send(int *err, struct sa *dst,
const char *proto_name = "rtp";
enum pkt_type ptype = get_packet_type(mb);
+ if (drop_packets(st))
+ return true;
+
length = (unsigned int)mbuf_get_left(mb);
/* only RTP/RTCP packets should be processed */
@@ -168,6 +214,9 @@ static bool udp_helper_recv(struct sa *src, struct mbuf *mb, void *arg)
const char *proto_name = "srtp";
enum pkt_type ptype = get_packet_type(mb);
+ if (drop_packets(st))
+ return true;
+
length = (unsigned int)mbuf_get_left(mb);
if (ptype == PKT_TYPE_RTCP) {
@@ -198,6 +247,63 @@ static bool udp_helper_recv(struct sa *src, struct mbuf *mb, void *arg)
}
+static int sig_hash_encode(struct zrtp_stream_t *stream,
+ struct sdp_media *m)
+{
+ char buf[ZRTP_SIGN_ZRTP_HASH_LENGTH + 1];
+ zrtp_status_t s;
+ int err = 0;
+
+ s = zrtp_signaling_hash_get(stream, buf, sizeof(buf));
+ if (s != zrtp_status_ok) {
+ warning("zrtp: zrtp_signaling_hash_get: status = %d\n", s);
+ return EINVAL;
+ }
+
+ err = sdp_media_set_lattr(m, true, "zrtp-hash", "%s %s",
+ ZRTP_PROTOCOL_VERSION, buf);
+ if (err) {
+ warning("zrtp: sdp_media_set_lattr: %d\n", err);
+ }
+
+ return err;
+}
+
+
+static void sig_hash_decode(struct zrtp_stream_t *stream,
+ const struct sdp_media *m)
+{
+ const char *attr_val;
+ struct pl major, minor, hash;
+ uint32_t version;
+ int err;
+ zrtp_status_t s;
+
+ attr_val = sdp_media_rattr(m, "zrtp-hash");
+ if (!attr_val)
+ return;
+
+ err = re_regex(attr_val, strlen(attr_val),
+ "[0-9]+.[0-9]2 [0-9a-f]+",
+ &major, &minor, &hash);
+ if (err || hash.l < ZRTP_SIGN_ZRTP_HASH_LENGTH) {
+ warning("zrtp: malformed zrtp-hash attribute, ignoring...\n");
+ return;
+ }
+
+ version = pl_u32(&major) * 100 + pl_u32(&minor);
+ /* more version checks? */
+ if (version < 110) {
+ warning("zrtp: zrtp-hash: version (%d) is too low, "
+ "ignoring...", version);
+ }
+
+ s = zrtp_signaling_hash_set(stream, hash.p, (uint32_t)hash.l);
+ if (s != zrtp_status_ok)
+ warning("zrtp: zrtp_signaling_hash_set: status = %d\n", s);
+}
+
+
static int session_alloc(struct menc_sess **sessp, struct sdp_session *sdp,
bool offerer, menc_error_h *errorh, void *arg)
{
@@ -205,8 +311,6 @@ static int session_alloc(struct menc_sess **sessp, struct sdp_session *sdp,
zrtp_status_t s;
int err = 0;
(void)offerer;
- (void)errorh;
- (void)arg;
if (!sessp || !sdp)
return EINVAL;
@@ -215,6 +319,11 @@ static int session_alloc(struct menc_sess **sessp, struct sdp_session *sdp,
if (!st)
return ENOMEM;
+ st->errorh = errorh;
+ st->arg = arg;
+ st->err = 0;
+ tmr_init(&st->abort_timer);
+
s = zrtp_session_init(zrtp_global, NULL, zid,
ZRTP_SIGNALING_ROLE_UNKNOWN, &st->zrtp_session);
if (s != zrtp_status_ok) {
@@ -277,6 +386,12 @@ static int media_alloc(struct menc_media **stp, struct menc_sess *sess,
zrtp_stream_set_userdata(st->zrtp_stream, st);
+ if (use_sig_hash) {
+ err = sig_hash_encode(st->zrtp_stream, sdpm);
+ if (err)
+ goto out;
+ }
+
out:
if (err) {
mem_deref(st);
@@ -289,6 +404,9 @@ static int media_alloc(struct menc_media **stp, struct menc_sess *sess,
if (sa_isset(sdp_media_raddr(sdpm), SA_ALL)) {
st->raddr = *sdp_media_raddr(sdpm);
+ if (use_sig_hash)
+ sig_hash_decode(st->zrtp_stream, sdpm);
+
s = zrtp_stream_start(st->zrtp_stream, rtp_sess_ssrc(rtp));
if (s != zrtp_status_ok) {
warning("zrtp: zrtp_stream_start: status = %d\n", s);
@@ -307,6 +425,9 @@ static int on_send_packet(const zrtp_stream_t *stream,
struct mbuf *mb;
int err;
+ if (drop_packets(st))
+ return zrtp_status_ok;
+
if (!sa_isset(&st->raddr, SA_ALL))
return zrtp_status_ok;
@@ -355,6 +476,23 @@ static void on_zrtp_secure(zrtp_stream_t *stream)
}
+static void on_zrtp_security_event(zrtp_stream_t *stream,
+ zrtp_security_event_t event)
+{
+ if (event == ZRTP_EVENT_WRONG_SIGNALING_HASH) {
+ const struct menc_media *st = zrtp_stream_get_userdata(stream);
+
+ warning("zrtp: Attack detected!!! Signaling hash from the "
+ "zrtp-hash SDP attribute doesn't match the hash of "
+ "the Hello message. Aborting the call.\n");
+
+ /* As this was called from zrtp_process_xxx(), we need
+ a safe shutdown. */
+ abort_call(st->sess);
+ }
+}
+
+
static struct menc menc_zrtp = {
LE_INIT, "zrtp", "RTP/AVP", session_alloc, media_alloc
};
@@ -428,6 +566,8 @@ static int module_init(void)
FILE *f;
int ret, err;
+ (void)conf_get_bool(conf_cur(), "zrtp_hash", &use_sig_hash);
+
zrtp_log_set_log_engine(zrtp_log);
zrtp_config_defaults(&zrtp_config);
@@ -439,6 +579,8 @@ static int module_init(void)
zrtp_config.cb.misc_cb.on_send_packet = on_send_packet;
zrtp_config.cb.event_cb.on_zrtp_secure = on_zrtp_secure;
+ zrtp_config.cb.event_cb.on_zrtp_security_event =
+ on_zrtp_security_event;
err = conf_path_get(config_path, sizeof(config_path));
if (err) {
diff --git a/src/config.c b/src/config.c
index eb83c67..6662b3c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -807,6 +807,11 @@ int config_write_template(const char *file, const struct config *cfg)
"ice_mode\t\tfull\t# {full,lite}\n");
(void)re_fprintf(f,
+ "\n# ZRTP\n"
+ "#zrtp_hash\t\tno # Disable SDP zrtp-hash "
+ "(not recommended)\n");
+
+ (void)re_fprintf(f,
"\n# Menu\n"
"#redial_attempts\t\t3 # Num or <inf>\n"
"#redial_delay\t\t5 # Delay in seconds\n");