webrtc_dtls/record_layer/
mod.rs

1pub mod record_layer_header;
2
3#[cfg(test)]
4mod record_layer_test;
5
6use std::io::{Read, Write};
7
8use record_layer_header::*;
9
10use super::content::*;
11use super::error::*;
12use crate::alert::Alert;
13use crate::application_data::ApplicationData;
14use crate::change_cipher_spec::ChangeCipherSpec;
15use crate::handshake::Handshake;
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    pub record_layer_header: RecordLayerHeader,
40    pub content: Content,
41}
42
43impl RecordLayer {
44    pub fn new(protocol_version: ProtocolVersion, epoch: u16, content: Content) -> Self {
45        RecordLayer {
46            record_layer_header: RecordLayerHeader {
47                content_type: content.content_type(),
48                protocol_version,
49                epoch,
50                sequence_number: 0,
51                content_len: content.size() as u16,
52            },
53            content,
54        }
55    }
56
57    pub fn marshal<W: Write>(&self, writer: &mut W) -> Result<()> {
58        self.record_layer_header.marshal(writer)?;
59        self.content.marshal(writer)?;
60        Ok(())
61    }
62
63    pub fn unmarshal<R: Read>(reader: &mut R) -> Result<Self> {
64        let record_layer_header = RecordLayerHeader::unmarshal(reader)?;
65        let content = match record_layer_header.content_type {
66            ContentType::Alert => Content::Alert(Alert::unmarshal(reader)?),
67            ContentType::ApplicationData => {
68                Content::ApplicationData(ApplicationData::unmarshal(reader)?)
69            }
70            ContentType::ChangeCipherSpec => {
71                Content::ChangeCipherSpec(ChangeCipherSpec::unmarshal(reader)?)
72            }
73            ContentType::Handshake => Content::Handshake(Handshake::unmarshal(reader)?),
74            _ => return Err(Error::Other("Invalid Content Type".to_owned())),
75        };
76
77        Ok(RecordLayer {
78            record_layer_header,
79            content,
80        })
81    }
82}
83
84// Note that as with TLS, multiple handshake messages may be placed in
85// the same DTLS record, provided that there is room and that they are
86// part of the same flight.  Thus, there are two acceptable ways to pack
87// two DTLS messages into the same datagram: in the same record or in
88// separate records.
89// https://tools.ietf.org/html/rfc6347#section-4.2.3
90pub(crate) fn unpack_datagram(buf: &[u8]) -> Result<Vec<Vec<u8>>> {
91    let mut out = vec![];
92
93    let mut offset = 0;
94    while buf.len() != offset {
95        if buf.len() - offset <= RECORD_LAYER_HEADER_SIZE {
96            return Err(Error::ErrInvalidPacketLength);
97        }
98
99        let pkt_len = RECORD_LAYER_HEADER_SIZE
100            + (((buf[offset + RECORD_LAYER_HEADER_SIZE - 2] as usize) << 8)
101                | buf[offset + RECORD_LAYER_HEADER_SIZE - 1] as usize);
102        if offset + pkt_len > buf.len() {
103            return Err(Error::ErrInvalidPacketLength);
104        }
105
106        out.push(buf[offset..offset + pkt_len].to_vec());
107        offset += pkt_len
108    }
109
110    Ok(out)
111}