From 429fc387b5090e4e681f9075c12af9d28d4cd6dd Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Thu, 28 Feb 2019 13:32:52 +0100 Subject: [PATCH] jingle_drls_srtp: Add a new parser and serialiser. --- src/hashes.rs | 4 +-- src/jingle_dtls_srtp.rs | 78 +++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ src/ns.rs | 3 ++ src/util/helpers.rs | 25 +++++++++++++ 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 src/jingle_dtls_srtp.rs diff --git a/src/hashes.rs b/src/hashes.rs index c097d03..e1be62b 100644 --- a/src/hashes.rs +++ b/src/hashes.rs @@ -133,8 +133,8 @@ impl FromStr for Sha1HexAttribute { fn from_str(hex: &str) -> Result { let mut bytes = vec![]; for i in 0..hex.len() / 2 { - let byte = u8::from_str_radix(&hex[2 * i..2 * i + 2], 16); - bytes.push(byte?); + let byte = u8::from_str_radix(&hex[2 * i..2 * i + 2], 16)?; + bytes.push(byte); } Ok(Sha1HexAttribute(Hash::new(Algo::Sha_1, bytes))) } diff --git a/src/jingle_dtls_srtp.rs b/src/jingle_dtls_srtp.rs new file mode 100644 index 0000000..29b6417 --- /dev/null +++ b/src/jingle_dtls_srtp.rs @@ -0,0 +1,78 @@ +// Copyright (c) 2019 Emmanuel Gil Peyrot +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use crate::util::helpers::ColonSeparatedHex; +use crate::hashes::Algo; + +generate_attribute!( + /// Indicates which of the end points should initiate the TCP connection establishment. + Setup, "setup", { + /// The endpoint will initiate an outgoing connection. + Active => "active", + + /// The endpoint will accept an incoming connection. + Passive => "passive", + + /// The endpoint is willing to accept an incoming connection or to initiate an outgoing + /// connection. + Actpass => "actpass", + + /* + /// The endpoint does not want the connection to be established for the time being. + /// + /// Note that this value isn’t used, as per the XEP. + Holdconn => "holdconn", + */ + } +); + +// TODO: use a hashes::Hash instead of two different fields here. +generate_element!( + /// Fingerprint of the key used for a DTLS handshake. + Fingerprint, "fingerprint", JINGLE_DTLS, + attributes: [ + /// The hash algorithm used for this fingerprint. + hash: Required = "hash", + + /// Indicates which of the end points should initiate the TCP connection establishment. + setup: Required = "setup" + ], + text: ( + /// Hash value of this fingerprint. + value: ColonSeparatedHex> + ) +); + +mod tests { + use super::*; + use minidom::Element; + use try_from::TryFrom; + + #[cfg(target_pointer_width = "32")] + #[test] + fn test_size() { + assert_size!(Setup, 1); + assert_size!(Fingerprint, 32); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_size() { + assert_size!(Setup, 1); + assert_size!(Fingerprint, 64); + } + + #[test] + fn test_ex1() { + let elem: Element = "02:1A:CC:54:27:AB:EB:9C:53:3F:3E:4B:65:2E:7D:46:3F:54:42:CD:54:F1:7A:03:A2:7D:F9:B0:7F:46:19:B2" + .parse() + .unwrap(); + let fingerprint = Fingerprint::try_from(elem).unwrap(); + assert_eq!(fingerprint.setup, Setup::Actpass); + assert_eq!(fingerprint.hash, Algo::Sha_256); + assert_eq!(fingerprint.value, [2, 26, 204, 84, 39, 171, 235, 156, 83, 63, 62, 75, 101, 46, 125, 70, 63, 84, 66, 205, 84, 241, 122, 3, 162, 125, 249, 176, 127, 70, 25, 178]); + } +} diff --git a/src/lib.rs b/src/lib.rs index ca7840b..2a6c3ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -158,6 +158,9 @@ pub mod mam; /// XEP-0319: Last User Interaction in Presence pub mod idle; +/// XEP-0320: Use of DTLS-SRTP in Jingle Sessions +pub mod jingle_dtls_srtp; + /// XEP-0353: Jingle Message Initiation pub mod jingle_message; diff --git a/src/ns.rs b/src/ns.rs index 321c6fa..1897dbb 100644 --- a/src/ns.rs +++ b/src/ns.rs @@ -156,6 +156,9 @@ pub const MAM: &str = "urn:xmpp:mam:2"; /// XEP-0319: Last User Interaction in Presence pub const IDLE: &str = "urn:xmpp:idle:1"; +/// XEP-0320: Use of DTLS-SRTP in Jingle Sessions +pub const JINGLE_DTLS: &str = "urn:xmpp:jingle:apps:dtls:0"; + /// XEP-0353: Jingle Message Initiation pub const JINGLE_MESSAGE: &str = "urn:xmpp:jingle-message:0"; diff --git a/src/util/helpers.rs b/src/util/helpers.rs index b383234..b7bdc84 100644 --- a/src/util/helpers.rs +++ b/src/util/helpers.rs @@ -65,3 +65,28 @@ impl WhitespaceAwareBase64 { Some(base64::encode(b)) } } + +/// Codec for colon-separated bytes of uppercase hexadecimal. +pub struct ColonSeparatedHex; + +impl ColonSeparatedHex { + pub fn decode(s: &str) -> Result, Error> { + let mut bytes = vec![]; + for i in 0..(1 + s.len()) / 3 { + let byte = u8::from_str_radix(&s[3 * i..3 * i + 2], 16)?; + if 3 * i + 2 < s.len() { + assert_eq!(&s[3 * i + 2..3 * i + 3], ":"); + } + bytes.push(byte); + } + Ok(bytes) + } + + pub fn encode(b: &[u8]) -> Option { + let mut bytes = vec![]; + for byte in b { + bytes.push(format!("{:02X}", byte)); + } + Some(bytes.join(":")) + } +}