rustls 0.15.0

Rustls is a modern TLS library written in Rust.
Documentation

use crate::msgs::codec::{Codec, Reader};
use crate::msgs::base::Payload;
use crate::msgs::alert::AlertMessagePayload;
use crate::msgs::ccs::ChangeCipherSpecPayload;
use crate::msgs::handshake::HandshakeMessagePayload;
use crate::msgs::enums::{ContentType, ProtocolVersion};
use crate::msgs::enums::{AlertLevel, AlertDescription};
use crate::msgs::enums::HandshakeType;

use std::mem;

#[derive(Debug)]
pub enum MessagePayload {
    Alert(AlertMessagePayload),
    Handshake(HandshakeMessagePayload),
    ChangeCipherSpec(ChangeCipherSpecPayload),
    Opaque(Payload),
}

impl MessagePayload {
    pub fn encode(&self, bytes: &mut Vec<u8>) {
        match *self {
            MessagePayload::Alert(ref x) => x.encode(bytes),
            MessagePayload::Handshake(ref x) => x.encode(bytes),
            MessagePayload::ChangeCipherSpec(ref x) => x.encode(bytes),
            MessagePayload::Opaque(ref x) => x.encode(bytes),
        }
    }

    pub fn decode_given_type(&self,
                             typ: ContentType,
                             vers: ProtocolVersion)
                             -> Option<MessagePayload> {
        if let MessagePayload::Opaque(ref payload) = *self {
            let mut r = Reader::init(&payload.0);
            let parsed = match typ {
                ContentType::Alert => {
                    Some(MessagePayload::Alert(AlertMessagePayload::read(&mut r)?))
                }
                ContentType::Handshake => {
                    let p = HandshakeMessagePayload::read_version(&mut r, vers)?;
                    Some(MessagePayload::Handshake(p))
                }
                ContentType::ChangeCipherSpec => {
                    let p = ChangeCipherSpecPayload::read(&mut r)?;
                    Some(MessagePayload::ChangeCipherSpec(p))
                }
                _ => None,
            };

            if r.any_left() { None } else { parsed }
        } else {
            None
        }
    }

    pub fn length(&self) -> usize {
        match *self {
            MessagePayload::Alert(ref x) => x.length(),
            MessagePayload::Handshake(ref x) => x.length(),
            MessagePayload::ChangeCipherSpec(ref x) => x.length(),
            MessagePayload::Opaque(ref x) => x.0.len(),
        }
    }

    pub fn new_opaque(data: Vec<u8>) -> MessagePayload {
        MessagePayload::Opaque(Payload::new(data))
    }
}

/// A TLS frame, named TLSPlaintext in the standard.
/// This type owns all memory for its interior parts.
#[derive(Debug)]
pub struct Message {
    pub typ: ContentType,
    pub version: ProtocolVersion,
    pub payload: MessagePayload,
}

impl Codec for Message {
    fn read(r: &mut Reader) -> Option<Message> {
        let typ = ContentType::read(r)?;
        let version = ProtocolVersion::read(r)?;
        let len = u16::read(r)?;

        let mut sub = r.sub(len as usize)?;
        let payload = Payload::read(&mut sub)?;

        Some(Message {
            typ,
            version,
            payload: MessagePayload::Opaque(payload),
        })
    }

    fn encode(&self, bytes: &mut Vec<u8>) {
        self.typ.encode(bytes);
        self.version.encode(bytes);
        (self.payload.length() as u16).encode(bytes);
        self.payload.encode(bytes);
    }
}

impl Message {
    /// Do some *very* lax checks on the header, and return
    /// None if it looks really broken.  Otherwise, return
    /// the length field.
    pub fn check_header(bytes: &[u8]) -> Option<usize> {
        let mut rd = Reader::init(bytes);

        let typ = ContentType::read(&mut rd)?;
        let version = ProtocolVersion::read(&mut rd)?;
        let len = u16::read(&mut rd)?;

        // Don't accept any new content-types.
        if let ContentType::Unknown(_) = typ {
            return None;
        }

        // Accept only versions 0x03XX for any XX.
        match version {
            ProtocolVersion::Unknown(ref v) if (v & 0xff00) != 0x0300 => {
                return None;
            }
            _ => (),
        };

        Some(len as usize)
    }

    pub fn is_content_type(&self, typ: ContentType) -> bool {
        self.typ == typ
    }

    pub fn is_handshake_type(&self, hstyp: HandshakeType) -> bool {
        // Bit of a layering violation, but OK.
        if !self.is_content_type(ContentType::Handshake) {
            return false;
        }

        if let MessagePayload::Handshake(ref hsp) = self.payload {
            hsp.typ == hstyp
        } else {
            false
        }
    }

    pub fn decode_payload(&mut self) -> bool {
        // Do we need a decode?
        if self.typ == ContentType::ApplicationData {
            return true;
        }

        if let Some(x) = self.payload.decode_given_type(self.typ, self.version) {
            self.payload = x;
            true
        } else {
            false
        }
    }

    pub fn take_payload(self) -> Vec<u8> {
        self.into_opaque().take_opaque_payload().unwrap().0
    }

    pub fn take_opaque_payload(&mut self) -> Option<Payload> {
        if let MessagePayload::Opaque(ref mut op) = self.payload {
            Some(mem::replace(op, Payload::empty()))
        } else {
            None
        }
    }

    pub fn into_opaque(self) -> Message {
        if let MessagePayload::Opaque(_) = self.payload {
            return self;
        }

        let mut buf = Vec::new();
        self.payload.encode(&mut buf);

        Message {
            typ: self.typ,
            version: self.version,
            payload: MessagePayload::new_opaque(buf),
        }
    }

    pub fn build_alert(level: AlertLevel, desc: AlertDescription) -> Message {
        Message {
            typ: ContentType::Alert,
            version: ProtocolVersion::TLSv1_2,
            payload: MessagePayload::Alert(AlertMessagePayload {
                level,
                description: desc,
            }),
        }
    }

    pub fn build_key_update_notify() -> Message {
        Message {
            typ: ContentType::Handshake,
            version: ProtocolVersion::TLSv1_3,
            payload: MessagePayload::Handshake(HandshakeMessagePayload::build_key_update_notify()),
        }
    }
}

impl<'a> Message {
    pub fn to_borrowed(&'a self) -> BorrowMessage<'a> {
        if let MessagePayload::Opaque(ref p) = self.payload {
            BorrowMessage {
                typ: self.typ,
                version: self.version,
                payload: &p.0
            }
        } else {
            unreachable!("to_borrowed must have opaque message");
        }
    }
}


/// A TLS frame, named TLSPlaintext in the standard.
///
/// This type differs from `Message` because it borrows
/// its payload.  You can make a `Message` from an
/// `BorrowMessage`, but this involves a copy.
///
/// This type also cannot decode its internals and
/// is not a `Codec` type, only `Message` can do that.
#[derive(Debug)]
pub struct BorrowMessage<'a> {
    pub typ: ContentType,
    pub version: ProtocolVersion,
    pub payload: &'a [u8],
}