1// Copyright (c) 2019 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
67use xso::{text::ColonSeparatedHex, AsXml, FromXml};
89use crate::hashes::{Algo, Hash};
10use crate::ns;
11use xso::error::Error;
1213generate_attribute!(
14/// Indicates which of the end points should initiate the TCP connection establishment.
15Setup, "setup", {
16/// The endpoint will initiate an outgoing connection.
17Active => "active",
1819/// The endpoint will accept an incoming connection.
20Passive => "passive",
2122/// The endpoint is willing to accept an incoming connection or to initiate an outgoing
23 /// connection.
24Actpass => "actpass",
2526/*
27 /// The endpoint does not want the connection to be established for the time being.
28 ///
29 /// Note that this value isn’t used, as per the XEP.
30 Holdconn => "holdconn",
31 */
32}
33);
3435// TODO: use a hashes::Hash instead of two different fields here.
36/// Fingerprint of the key used for a DTLS handshake.
37#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
38#[xml(namespace = ns::JINGLE_DTLS, name = "fingerprint")]
39pub struct Fingerprint {
40/// The hash algorithm used for this fingerprint.
41#[xml(attribute)]
42pub hash: Algo,
4344/// Indicates which of the end points should initiate the TCP connection establishment.
45#[xml(attribute)]
46pub setup: Setup,
4748/// Hash value of this fingerprint.
49#[xml(text(codec = ColonSeparatedHex))]
50pub value: Vec<u8>,
51}
5253impl Fingerprint {
54/// Create a new Fingerprint from a Setup and a Hash.
55pub fn from_hash(setup: Setup, hash: Hash) -> Fingerprint {
56 Fingerprint {
57 hash: hash.algo,
58 setup,
59 value: hash.hash,
60 }
61 }
6263/// Create a new Fingerprint from a Setup and parsing the hash.
64pub fn from_colon_separated_hex(
65 setup: Setup,
66 algo: &str,
67 hash: &str,
68 ) -> Result<Fingerprint, Error> {
69let algo = algo.parse()?;
70let hash = Hash::from_colon_separated_hex(algo, hash).map_err(Error::text_parse_error)?;
71Ok(Fingerprint::from_hash(setup, hash))
72 }
73}
7475#[cfg(test)]
76mod tests {
77use super::*;
78use minidom::Element;
7980#[cfg(target_pointer_width = "32")]
81 #[test]
82fn test_size() {
83assert_size!(Setup, 1);
84assert_size!(Fingerprint, 28);
85 }
8687#[cfg(target_pointer_width = "64")]
88 #[test]
89fn test_size() {
90assert_size!(Setup, 1);
91assert_size!(Fingerprint, 56);
92 }
9394#[test]
95fn test_ex1() {
96let 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>"
97.parse()
98 .unwrap();
99let fingerprint = Fingerprint::try_from(elem).unwrap();
100assert_eq!(fingerprint.setup, Setup::Actpass);
101assert_eq!(fingerprint.hash, Algo::Sha_256);
102assert_eq!(
103 fingerprint.value,
104 [
1052, 26, 204, 84, 39, 171, 235, 156, 83, 63, 62, 75, 101, 46, 125, 70, 63, 84, 66,
106205, 84, 241, 122, 3, 162, 125, 249, 176, 127, 70, 25, 178
107]
108 );
109 }
110}