rtc_dtls/handshake/
handshake_message_client_hello.rs

1#[cfg(test)]
2mod handshake_message_client_hello_test;
3
4use super::handshake_random::*;
5use super::*;
6use crate::cipher_suite::*;
7use crate::compression_methods::*;
8use crate::extension::*;
9use crate::record_layer::record_layer_header::*;
10
11use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
12use std::fmt;
13use std::io::{BufReader, BufWriter};
14
15/*
16When a client first connects to a server it is required to send
17the client hello as its first message.  The client can also send a
18client hello in response to a hello request or on its own
19initiative in order to renegotiate the security parameters in an
20existing connection.
21*/
22#[derive(Clone)]
23pub struct HandshakeMessageClientHello {
24    pub(crate) version: ProtocolVersion,
25    pub(crate) random: HandshakeRandom,
26    pub(crate) cookie: Vec<u8>,
27
28    pub(crate) cipher_suites: Vec<CipherSuiteId>,
29    pub(crate) compression_methods: CompressionMethods,
30    pub(crate) extensions: Vec<Extension>,
31}
32
33impl PartialEq for HandshakeMessageClientHello {
34    fn eq(&self, other: &Self) -> bool {
35        if !(self.version == other.version
36            && self.random == other.random
37            && self.cookie == other.cookie
38            && self.compression_methods == other.compression_methods
39            && self.extensions == other.extensions
40            && self.cipher_suites.len() == other.cipher_suites.len())
41        {
42            return false;
43        }
44
45        for i in 0..self.cipher_suites.len() {
46            if self.cipher_suites[i] != other.cipher_suites[i] {
47                return false;
48            }
49        }
50
51        true
52    }
53}
54
55impl fmt::Debug for HandshakeMessageClientHello {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        let mut cipher_suites_str = String::new();
58        for cipher_suite in &self.cipher_suites {
59            cipher_suites_str += &cipher_suite.to_string();
60            cipher_suites_str += " ";
61        }
62        let s = [
63            format!("version: {:?} random: {:?}", self.version, self.random),
64            format!("cookie: {:?}", self.cookie),
65            format!("cipher_suites: {cipher_suites_str:?}"),
66            format!("compression_methods: {:?}", self.compression_methods),
67            format!("extensions: {:?}", self.extensions),
68        ];
69        write!(f, "{}", s.join(" "))
70    }
71}
72
73const HANDSHAKE_MESSAGE_CLIENT_HELLO_VARIABLE_WIDTH_START: usize = 34;
74
75impl HandshakeMessageClientHello {
76    pub fn handshake_type(&self) -> HandshakeType {
77        HandshakeType::ClientHello
78    }
79
80    pub fn size(&self) -> usize {
81        let mut len = 0;
82
83        len += 2; // version.major+minor
84        len += self.random.size();
85
86        // SessionID
87        len += 1;
88
89        len += 1 + self.cookie.len();
90
91        len += 2 + 2 * self.cipher_suites.len();
92
93        len += self.compression_methods.size();
94
95        len += 2;
96        for extension in &self.extensions {
97            len += extension.size();
98        }
99
100        len
101    }
102
103    pub fn marshal<W: Write>(&self, writer: &mut W) -> Result<()> {
104        if self.cookie.len() > 255 {
105            return Err(Error::ErrCookieTooLong);
106        }
107
108        writer.write_u8(self.version.major)?;
109        writer.write_u8(self.version.minor)?;
110        self.random.marshal(writer)?;
111
112        // SessionID
113        writer.write_u8(0x00)?;
114
115        writer.write_u8(self.cookie.len() as u8)?;
116        writer.write_all(&self.cookie)?;
117
118        writer.write_u16::<BigEndian>(2 * self.cipher_suites.len() as u16)?;
119        for cipher_suite in &self.cipher_suites {
120            writer.write_u16::<BigEndian>(*cipher_suite as u16)?;
121        }
122
123        self.compression_methods.marshal(writer)?;
124
125        let mut extension_buffer = vec![];
126        {
127            let mut extension_writer = BufWriter::<&mut Vec<u8>>::new(extension_buffer.as_mut());
128            for extension in &self.extensions {
129                extension.marshal(&mut extension_writer)?;
130            }
131        }
132
133        writer.write_u16::<BigEndian>(extension_buffer.len() as u16)?;
134        writer.write_all(&extension_buffer)?;
135
136        Ok(writer.flush()?)
137    }
138
139    pub fn unmarshal<R: Read>(reader: &mut R) -> Result<Self> {
140        let major = reader.read_u8()?;
141        let minor = reader.read_u8()?;
142        let random = HandshakeRandom::unmarshal(reader)?;
143
144        // Session ID
145        reader.read_u8()?;
146
147        let cookie_len = reader.read_u8()? as usize;
148        let mut cookie = vec![0; cookie_len];
149        reader.read_exact(&mut cookie)?;
150
151        let cipher_suites_len = reader.read_u16::<BigEndian>()? as usize / 2;
152        let mut cipher_suites = vec![];
153        for _ in 0..cipher_suites_len {
154            let id: CipherSuiteId = reader.read_u16::<BigEndian>()?.into();
155            //let cipher_suite = cipher_suite_for_id(id)?;
156            cipher_suites.push(id);
157        }
158
159        let compression_methods = CompressionMethods::unmarshal(reader)?;
160        let mut extensions = vec![];
161
162        let extension_buffer_len = reader.read_u16::<BigEndian>()? as usize;
163        let mut extension_buffer = vec![0u8; extension_buffer_len];
164        reader.read_exact(&mut extension_buffer)?;
165
166        let mut offset = 0;
167        while offset < extension_buffer_len {
168            let mut extension_reader = BufReader::new(&extension_buffer[offset..]);
169            if let Ok(extension) = Extension::unmarshal(&mut extension_reader) {
170                extensions.push(extension);
171            } else {
172                log::warn!(
173                    "Unsupported Extension Type {} {}",
174                    extension_buffer[offset],
175                    extension_buffer[offset + 1]
176                );
177            }
178
179            let extension_len =
180                u16::from_be_bytes([extension_buffer[offset + 2], extension_buffer[offset + 3]])
181                    as usize;
182            offset += 4 + extension_len;
183        }
184
185        Ok(HandshakeMessageClientHello {
186            version: ProtocolVersion { major, minor },
187            random,
188            cookie,
189
190            cipher_suites,
191            compression_methods,
192            extensions,
193        })
194    }
195}