diff options
author | glenvt18 <glenvt18@gmail.com> | 2017-10-15 10:11:21 +0300 |
---|---|---|
committer | Alfred E. Heggestad <alfred.heggestad@gmail.com> | 2017-10-15 09:11:21 +0200 |
commit | a4fd1665c8911c80e8cce5a5cc9b7e9314222bdd (patch) | |
tree | 80abceb4ee8103a2e9c3aedf9f770f1ff6ac8853 | |
parent | 6cd9a9d9f988a6eb83b0a816f6098d252a3f741a (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/config | 3 | ||||
-rw-r--r-- | modules/zrtp/zrtp.c | 148 | ||||
-rw-r--r-- | src/config.c | 5 |
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"); |