#[cfg(feature = "client")]
use super::client::ClientHs;
use super::server::ServerHs;
use super::{alert, CipherSuite, Error, Level, NamedGroup, Result};
use crate::crypto::sha2::{HashAlg, Hasher, Output};
use std::collections::VecDeque;
pub(crate) enum Event {
Msg(Level, Vec<u8>),
Ccs,
Secrets { level: Level, client: Vec<u8>, server: Vec<u8> },
#[cfg(feature = "tls12")]
ChangeCipher12(super::record::RecordCipher),
}
pub(crate) struct Shared {
pub events: VecDeque<Event>,
pub expect_level: Level,
pub done: bool,
pub suite: Option<CipherSuite>,
pub group: Option<NamedGroup>,
pub alpn: Option<Vec<u8>>,
pub sni: Option<String>,
pub peer_certs: Vec<Vec<u8>>,
pub resumed: bool,
pub quic_tp: Option<Vec<u8>>,
pub peer_tp: Option<Vec<u8>>,
pub exporter_master: Option<Vec<u8>>,
pub max_message: usize,
pub early_data_offered: bool,
#[cfg(feature = "tls12")]
pub tls12: Option<super::tls12::Tls12Suite>,
#[cfg(feature = "tls12")]
pub pending_read12: Option<super::record::RecordCipher>,
#[cfg(feature = "tls12")]
pub exporter12: Option<super::tls12::Exporter12>,
#[cfg(feature = "revocation")]
pub ocsp_response: Option<Vec<u8>>,
}
impl Shared {
pub fn new(quic_tp: Option<Vec<u8>>, max_message: usize) -> Shared {
Shared {
events: VecDeque::new(),
expect_level: Level::Initial,
done: false,
suite: None,
group: None,
alpn: None,
sni: None,
peer_certs: Vec::new(),
resumed: false,
quic_tp,
peer_tp: None,
exporter_master: None,
max_message,
early_data_offered: false,
#[cfg(feature = "tls12")]
tls12: None,
#[cfg(feature = "tls12")]
pending_read12: None,
#[cfg(feature = "tls12")]
exporter12: None,
#[cfg(feature = "revocation")]
ocsp_response: None,
}
}
#[inline]
pub fn is_tls12(&self) -> bool {
#[cfg(feature = "tls12")]
return self.tls12.is_some();
#[cfg(not(feature = "tls12"))]
false
}
pub fn is_quic(&self) -> bool {
self.quic_tp.is_some()
}
pub fn send(&mut self, level: Level, msg: Vec<u8>) {
self.events.push_back(Event::Msg(level, msg));
}
}
#[allow(clippy::large_enum_variant)] pub(crate) enum Engine {
Server(Box<ServerHs>),
#[cfg(feature = "client")]
Client(Box<ClientHs>),
}
impl Engine {
pub fn handle(&mut self, level: Level, msg: &[u8]) -> Result<()> {
if level != self.shared().expect_level {
return Err(Error::unexpected("handshake message at this encryption level"));
}
match self {
Engine::Server(s) => s.handle(msg),
#[cfg(feature = "client")]
Engine::Client(c) => c.handle(msg),
}
}
pub fn shared(&self) -> &Shared {
match self {
Engine::Server(s) => &s.sh,
#[cfg(feature = "client")]
Engine::Client(c) => &c.sh,
}
}
pub fn shared_mut(&mut self) -> &mut Shared {
match self {
Engine::Server(s) => &mut s.sh,
#[cfg(feature = "client")]
Engine::Client(c) => &mut c.sh,
}
}
pub fn is_client(&self) -> bool {
#[cfg(feature = "client")]
return matches!(self, Engine::Client(_));
#[cfg(not(feature = "client"))]
false
}
}
pub(crate) struct HsReader {
buf: Vec<u8>,
level: Level,
}
impl HsReader {
pub fn new() -> HsReader {
HsReader { buf: Vec::new(), level: Level::Initial }
}
pub fn push(&mut self, level: Level, data: &[u8]) -> Result<()> {
if !self.buf.is_empty() && level != self.level {
return Err(Error::unexpected("key change inside a handshake message"));
}
self.level = level;
self.buf.extend_from_slice(data);
Ok(())
}
pub fn next(&mut self, max: usize) -> Result<Option<(Level, Vec<u8>)>> {
if self.buf.len() < 4 {
return Ok(None);
}
let len = (self.buf[1] as usize) << 16 | (self.buf[2] as usize) << 8 | self.buf[3] as usize;
if len > max {
return Err(Error::proto(alert::DECODE_ERROR, "handshake message too large"));
}
if self.buf.len() < 4 + len {
return Ok(None);
}
let rest = self.buf.split_off(4 + len);
let msg = std::mem::replace(&mut self.buf, rest);
Ok(Some((self.level, msg)))
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
}
#[derive(Clone)]
pub(crate) enum Transcript {
Buffer(Vec<u8>),
Hash(Hasher),
}
impl Transcript {
pub fn add(&mut self, m: &[u8]) {
match self {
Transcript::Buffer(b) => b.extend_from_slice(m),
Transcript::Hash(h) => h.update(m),
}
}
pub fn start(&mut self, alg: HashAlg) {
if let Transcript::Buffer(b) = self {
let mut h = Hasher::new(alg);
h.update(b);
*self = Transcript::Hash(h);
}
}
pub fn hash(&self) -> Output {
match self {
Transcript::Hash(h) => h.current(),
Transcript::Buffer(_) => unreachable!("transcript hash before the suite is known"),
}
}
pub fn hash_with(&self, extra: &[u8]) -> Output {
match self {
Transcript::Hash(h) => {
let mut h = h.clone();
h.update(extra);
h.finish()
}
Transcript::Buffer(_) => unreachable!("transcript hash before the suite is known"),
}
}
}
pub(crate) fn parse_certificate(body: &[u8]) -> Result<(Vec<u8>, Vec<Vec<u8>>)> {
parse_certificate_status(body).map(|(c, l, _)| (c, l))
}
pub(crate) fn parse_certificate_status(body: &[u8]) -> Result<(Vec<u8>, Vec<Vec<u8>>, Option<Vec<u8>>)> {
use super::codec::Reader;
let mut r = Reader::new(body, "Certificate");
let ctx = r.vec8()?.to_vec();
let list = r.vec24()?;
r.finish()?;
let mut lr = Reader::new(list, "Certificate");
let mut certs = Vec::new();
let mut staple = None;
while !lr.is_empty() {
let c = lr.vec24()?;
if c.is_empty() {
return Err(Error::decode("Certificate"));
}
let exts = lr.vec16()?;
if certs.is_empty() && !exts.is_empty() {
for (t, d) in super::codec::parse_extensions(exts)? {
if t == 5 {
staple = Some(parse_certificate_status_body(d)?);
}
}
}
certs.push(c.to_vec());
if certs.len() > 16 {
return Err(Error::proto(alert::BAD_CERTIFICATE, "certificate chain too long"));
}
}
Ok((ctx, certs, staple))
}
pub(crate) fn parse_certificate_status_body(d: &[u8]) -> Result<Vec<u8>> {
use super::codec::Reader;
let mut r = Reader::new(d, "CertificateStatus");
if r.u8()? != 1 {
return Err(Error::proto(alert::BAD_CERTIFICATE_STATUS_RESPONSE, "unsupported certificate status type"));
}
let resp = r.vec24()?;
r.finish()?;
if resp.is_empty() {
return Err(Error::decode("CertificateStatus"));
}
Ok(resp.to_vec())
}
pub(crate) fn certificate_body(ctx: &[u8], chain: &[Vec<u8>], staple: Option<&[u8]>) -> Vec<u8> {
use super::codec::{put_u16, put_vec24, put_vec8};
let mut list = Vec::new();
for (i, c) in chain.iter().enumerate() {
put_vec24(&mut list, c);
#[cfg(not(feature = "revocation"))]
let _ = (i, staple);
#[cfg(not(feature = "revocation"))]
put_u16(&mut list, 0);
#[cfg(feature = "revocation")]
match staple.filter(|_| i == 0) {
Some(resp) => {
let mut status = vec![1u8];
put_vec24(&mut status, resp);
let mut e = Vec::new();
put_u16(&mut e, 5);
super::codec::put_vec16(&mut e, &status);
super::codec::put_vec16(&mut list, &e);
}
None => put_u16(&mut list, 0),
}
}
let mut body = Vec::with_capacity(4 + list.len());
put_vec8(&mut body, ctx);
put_vec24(&mut body, &list);
body
}