Skip to main content

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)]
23/// The client's opening message: its random, cookie, offered cipher suites and extensions.
24pub struct HandshakeMessageClientHello {
25    pub(crate) version: ProtocolVersion,
26    pub(crate) random: HandshakeRandom,
27    pub(crate) cookie: Vec<u8>,
28
29    pub(crate) cipher_suites: Vec<CipherSuiteId>,
30    pub(crate) compression_methods: CompressionMethods,
31    pub(crate) extensions: Vec<Extension>,
32}
33
34impl PartialEq for HandshakeMessageClientHello {
35    fn eq(&self, other: &Self) -> bool {
36        if !(self.version == other.version
37            && self.random == other.random
38            && self.cookie == other.cookie
39            && self.compression_methods == other.compression_methods
40            && self.extensions == other.extensions
41            && self.cipher_suites.len() == other.cipher_suites.len())
42        {
43            return false;
44        }
45
46        for i in 0..self.cipher_suites.len() {
47            if self.cipher_suites[i] != other.cipher_suites[i] {
48                return false;
49            }
50        }
51
52        true
53    }
54}
55
56impl fmt::Debug for HandshakeMessageClientHello {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        let mut cipher_suites_str = String::new();
59        for cipher_suite in &self.cipher_suites {
60            cipher_suites_str += &cipher_suite.to_string();
61            cipher_suites_str += " ";
62        }
63        let s = [
64            format!("version: {:?} random: {:?}", self.version, self.random),
65            format!("cookie: {:?}", self.cookie),
66            format!("cipher_suites: {cipher_suites_str:?}"),
67            format!("compression_methods: {:?}", self.compression_methods),
68            format!("extensions: {:?}", self.extensions),
69        ];
70        write!(f, "{}", s.join(" "))
71    }
72}
73
74const HANDSHAKE_MESSAGE_CLIENT_HELLO_VARIABLE_WIDTH_START: usize = 34;
75
76impl HandshakeMessageClientHello {
77    /// The handshake type that identifies this message on the wire.
78    pub fn handshake_type(&self) -> HandshakeType {
79        HandshakeType::ClientHello
80    }
81
82    /// The encoded size of this message in bytes.
83    pub fn size(&self) -> usize {
84        let mut len = 0;
85
86        len += 2; // version.major+minor
87        len += self.random.size();
88
89        // SessionID
90        len += 1;
91
92        len += 1 + self.cookie.len();
93
94        len += 2 + 2 * self.cipher_suites.len();
95
96        len += self.compression_methods.size();
97
98        len += 2;
99        for extension in &self.extensions {
100            len += extension.size();
101        }
102
103        len
104    }
105
106    /// Encodes this message to `writer`.
107    ///
108    /// # Errors
109    ///
110    /// Fails on a write error, or if a field exceeds the length its wire format allows.
111    pub fn marshal<W: Write>(&self, writer: &mut W) -> Result<()> {
112        if self.cookie.len() > 255 {
113            return Err(Error::ErrCookieTooLong);
114        }
115
116        writer.write_u8(self.version.major)?;
117        writer.write_u8(self.version.minor)?;
118        self.random.marshal(writer)?;
119
120        // SessionID
121        writer.write_u8(0x00)?;
122
123        writer.write_u8(self.cookie.len() as u8)?;
124        writer.write_all(&self.cookie)?;
125
126        writer.write_u16::<BigEndian>(2 * self.cipher_suites.len() as u16)?;
127        for cipher_suite in &self.cipher_suites {
128            writer.write_u16::<BigEndian>(*cipher_suite as u16)?;
129        }
130
131        self.compression_methods.marshal(writer)?;
132
133        let mut extension_buffer = vec![];
134        {
135            let mut extension_writer = BufWriter::<&mut Vec<u8>>::new(extension_buffer.as_mut());
136            for extension in &self.extensions {
137                extension.marshal(&mut extension_writer)?;
138            }
139        }
140
141        writer.write_u16::<BigEndian>(extension_buffer.len() as u16)?;
142        writer.write_all(&extension_buffer)?;
143
144        Ok(writer.flush()?)
145    }
146
147    /// Decodes one of these messages from `reader`.
148    ///
149    /// # Errors
150    ///
151    /// Fails if `reader` is truncated or its contents are not a valid encoding.
152    pub fn unmarshal<R: Read>(reader: &mut R) -> Result<Self> {
153        let major = reader.read_u8()?;
154        let minor = reader.read_u8()?;
155        let random = HandshakeRandom::unmarshal(reader)?;
156
157        // Session ID
158        reader.read_u8()?;
159
160        let cookie_len = reader.read_u8()? as usize;
161        let mut cookie = vec![0; cookie_len];
162        reader.read_exact(&mut cookie)?;
163
164        let cipher_suites_len = reader.read_u16::<BigEndian>()? as usize / 2;
165        let mut cipher_suites = vec![];
166        for _ in 0..cipher_suites_len {
167            let id: CipherSuiteId = reader.read_u16::<BigEndian>()?.into();
168            //let cipher_suite = cipher_suite_for_id(id)?;
169            cipher_suites.push(id);
170        }
171
172        let compression_methods = CompressionMethods::unmarshal(reader)?;
173        let mut extensions = vec![];
174
175        let extension_buffer_len = reader.read_u16::<BigEndian>()? as usize;
176        let mut extension_buffer = vec![0u8; extension_buffer_len];
177        reader.read_exact(&mut extension_buffer)?;
178
179        let mut offset = 0;
180        while offset < extension_buffer_len {
181            if offset + 4 > extension_buffer_len {
182                return Err(Error::ErrBufferTooSmall);
183            }
184
185            let mut extension_reader = BufReader::new(&extension_buffer[offset..]);
186            if let Ok(extension) = Extension::unmarshal(&mut extension_reader) {
187                extensions.push(extension);
188            } else {
189                log::warn!(
190                    "Unsupported Extension Type {} {}",
191                    extension_buffer[offset],
192                    extension_buffer[offset + 1]
193                );
194            }
195
196            let extension_len =
197                u16::from_be_bytes([extension_buffer[offset + 2], extension_buffer[offset + 3]])
198                    as usize;
199            offset += 4 + extension_len;
200        }
201
202        Ok(HandshakeMessageClientHello {
203            version: ProtocolVersion { major, minor },
204            random,
205            cookie,
206
207            cipher_suites,
208            compression_methods,
209            extensions,
210        })
211    }
212}