Skip to main content

rtc_dtls/record_layer/
mod.rs

1/// The record header: content type, version, epoch and sequence number.
2pub mod record_layer_header;
3
4#[cfg(test)]
5mod record_layer_test;
6
7use super::content::*;
8use crate::alert::Alert;
9use crate::application_data::ApplicationData;
10use crate::change_cipher_spec::ChangeCipherSpec;
11use crate::handshake::Handshake;
12use record_layer_header::*;
13use shared::error::*;
14
15use std::io::{Read, Write};
16
17/*
18 The TLS Record Layer which handles all data transport.
19 The record layer is assumed to sit directly on top of some
20 reliable transport such as TCP. The record layer can carry four types of content:
21
22 1. Handshake messages—used for algorithm negotiation and key establishment.
23 2. ChangeCipherSpec messages—really part of the handshake but technically a separate kind of message.
24 3. Alert messages—used to signal that errors have occurred
25 4. Application layer data
26
27 The DTLS record layer is extremely similar to that of TLS 1.1.  The
28 only change is the inclusion of an explicit sequence number in the
29 record.  This sequence number allows the recipient to correctly
30 verify the TLS MAC.
31*/
32/// ## Specifications
33///
34/// * [RFC 4347 §4.1]
35///
36/// [RFC 4347 §4.1]: https://tools.ietf.org/html/rfc4347#section-4.1
37#[derive(Debug, Clone, PartialEq)]
38pub struct RecordLayer {
39    /// The record's header.
40    pub record_layer_header: RecordLayerHeader,
41    /// The record's parsed body.
42    pub content: Content,
43}
44
45impl RecordLayer {
46    /// Builds a record around `content`, filling in its header.
47    pub fn new(protocol_version: ProtocolVersion, epoch: u16, content: Content) -> Self {
48        RecordLayer {
49            record_layer_header: RecordLayerHeader {
50                content_type: content.content_type(),
51                protocol_version,
52                epoch,
53                sequence_number: 0,
54                content_len: content.size() as u16,
55            },
56            content,
57        }
58    }
59
60    /// Encodes this message to `writer`.
61    ///
62    /// # Errors
63    ///
64    /// Fails on a write error, or if a field exceeds the length its wire format allows.
65    pub fn marshal<W: Write>(&self, writer: &mut W) -> Result<()> {
66        self.record_layer_header.marshal(writer)?;
67        self.content.marshal(writer)?;
68        Ok(())
69    }
70
71    /// Decodes one of these messages from `reader`.
72    ///
73    /// # Errors
74    ///
75    /// Fails if `reader` is truncated or its contents are not a valid encoding.
76    pub fn unmarshal<R: Read>(reader: &mut R) -> Result<Self> {
77        let record_layer_header = RecordLayerHeader::unmarshal(reader)?;
78        let content = match record_layer_header.content_type {
79            ContentType::Alert => Content::Alert(Alert::unmarshal(reader)?),
80            ContentType::ApplicationData => {
81                Content::ApplicationData(ApplicationData::unmarshal(reader)?)
82            }
83            ContentType::ChangeCipherSpec => {
84                Content::ChangeCipherSpec(ChangeCipherSpec::unmarshal(reader)?)
85            }
86            ContentType::Handshake => Content::Handshake(Handshake::unmarshal(reader)?),
87            _ => return Err(Error::Other("Invalid Content Type".to_owned())),
88        };
89
90        Ok(RecordLayer {
91            record_layer_header,
92            content,
93        })
94    }
95}
96
97// Note that as with TLS, multiple handshake messages may be placed in
98// the same DTLS record, provided that there is room and that they are
99// part of the same flight.  Thus, there are two acceptable ways to pack
100// two DTLS messages into the same datagram: in the same record or in
101// separate records.
102// https://tools.ietf.org/html/rfc6347#section-4.2.3
103pub(crate) fn unpack_datagram(buf: &[u8]) -> Result<Vec<Vec<u8>>> {
104    let mut out = vec![];
105
106    let mut offset = 0;
107    while buf.len() != offset {
108        if buf.len() - offset <= RECORD_LAYER_HEADER_SIZE {
109            return Err(Error::ErrInvalidPacketLength);
110        }
111
112        let pkt_len = RECORD_LAYER_HEADER_SIZE
113            + (((buf[offset + RECORD_LAYER_HEADER_SIZE - 2] as usize) << 8)
114                | buf[offset + RECORD_LAYER_HEADER_SIZE - 1] as usize);
115        if offset + pkt_len > buf.len() {
116            return Err(Error::ErrInvalidPacketLength);
117        }
118
119        out.push(buf[offset..offset + pkt_len].to_vec());
120        offset += pkt_len
121    }
122
123    Ok(out)
124}