Skip to main content

rtc_dtls/record_layer/
mod.rs

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