jingle_drls_srtp: Add a new parser and serialiser.

Emmanuel Gil Peyrot created

Change summary

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(-)

Detailed changes

src/hashes.rs πŸ”—

@@ -133,8 +133,8 @@ impl FromStr for Sha1HexAttribute {
     fn from_str(hex: &str) -> Result<Self, Self::Err> {
         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)))
     }

src/jingle_dtls_srtp.rs πŸ”—

@@ -0,0 +1,78 @@
+// Copyright (c) 2019 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+//
+// 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<Algo> = "hash",
+
+        /// Indicates which of the end points should initiate the TCP connection establishment.
+        setup: Required<Setup> = "setup"
+    ],
+    text: (
+        /// Hash value of this fingerprint.
+        value: ColonSeparatedHex<Vec<u8>>
+    )
+);
+
+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 = "<fingerprint xmlns='urn:xmpp:jingle:apps:dtls:0' hash='sha-256' setup='actpass'>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</fingerprint>"
+                .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]);
+    }
+}

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;
 

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";
 

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<Vec<u8>, 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<String> {
+        let mut bytes = vec![];
+        for byte in b {
+            bytes.push(format!("{:02X}", byte));
+        }
+        Some(bytes.join(":"))
+    }
+}