Skip to main content

internet/ietf/tls1_0/encoding/
change_cipher_spec.rs

1//! Change Cipher Spec encoding following [RFC 2246].
2//!
3//! Encoding is supported for the following structures:
4//!
5//!  - [`ChangeCipherSpecType`]
6//!  - [`ChangeCipherSpec`]
7//!
8//! [RFC 2246]: https://datatracker.ietf.org/doc/html/rfc2246
9
10use crate::{
11    Buf,
12    BufError::{self},
13    BufMut, BufResult, Codec, Cursor,
14};
15
16/// A ChangeCipherSpec type following [Section 7.1].
17///
18/// [Section 7.1]: https://datatracker.ietf.org/doc/html/rfc2246#section-7.1
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[repr(u8)]
21pub enum ChangeCipherSpecType {
22    /// change_cipher_spec(1)
23    ChangeCipherSpec = 1,
24}
25
26impl Codec for ChangeCipherSpecType {
27    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
28        (*self as u8).encode(writer, ())
29    }
30
31    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
32        match u8::decode(reader, ())? {
33            x if x == (Self::ChangeCipherSpec as u8) => Ok(Self::ChangeCipherSpec),
34            _ => Err(BufError::UnexpectedValue),
35        }
36    }
37}
38
39/// A ChangeCipherSpec following [Section 7.1].
40///
41/// [Section 7.1]: https://datatracker.ietf.org/doc/html/rfc2246#section-7.1
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
43pub struct ChangeCipherSpec {
44    /// The type of the change cipher spec.
45    pub type_: ChangeCipherSpecType,
46}
47
48impl Codec for ChangeCipherSpec {
49    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
50        self.type_.encode(writer, ())
51    }
52
53    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
54        Ok(Self {
55            type_: ChangeCipherSpecType::decode(reader, ())?,
56        })
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use core::fmt::Debug;
63
64    use super::{ChangeCipherSpec, ChangeCipherSpecType};
65    use crate::{Codec, Cursor};
66
67    fn codec_roundtrip<T: Codec<C> + Debug + Eq, C: Copy>(
68        etalon_struct: T,
69        etalon_bytes: &[u8],
70        context: C,
71    ) {
72        let mut encoded_bytes = vec![];
73        {
74            let writer = &mut Cursor::new(&mut encoded_bytes);
75            etalon_struct.encode(writer, context).unwrap();
76        }
77        assert_eq!(etalon_bytes, &encoded_bytes);
78
79        let decoded_struct = {
80            let reader = &mut Cursor::new(&mut encoded_bytes);
81            T::decode(reader, context).unwrap()
82        };
83        assert_eq!(etalon_struct, decoded_struct);
84
85        encoded_bytes.fill(0x00);
86        {
87            let writer = &mut Cursor::new(&mut encoded_bytes);
88            decoded_struct.encode(writer, context).unwrap();
89        }
90        assert_eq!(etalon_bytes, &encoded_bytes);
91    }
92
93    #[test]
94    fn change_cipher_spec() {
95        let etalon_bytes = &[0x01];
96        let etalon_struct = ChangeCipherSpec {
97            type_: ChangeCipherSpecType::ChangeCipherSpec,
98        };
99
100        codec_roundtrip(etalon_struct, etalon_bytes, ());
101    }
102}