use crate::builder::{ConfigBuilder, WantsCipherSuites};
use crate::conn::{Connection, ConnectionCommon, IoState, PlaintextSink, Reader, Writer};
use crate::error::Error;
use crate::key;
use crate::keylog::KeyLog;
use crate::kx::SupportedKxGroup;
#[cfg(feature = "quic")]
use crate::msgs::enums::AlertDescription;
use crate::msgs::enums::ProtocolVersion;
use crate::msgs::enums::SignatureScheme;
use crate::msgs::handshake::ServerExtension;
use crate::sign;
use crate::suites::SupportedCipherSuite;
use crate::verify;
#[cfg(feature = "quic")]
use crate::{conn::Protocol, quic};
use std::fmt;
use std::io::{self, IoSlice};
use std::marker::PhantomData;
use std::sync::Arc;
#[macro_use]
mod hs;
pub(crate) mod builder;
mod common;
pub(crate) mod handy;
mod tls12;
mod tls13;
pub trait StoresServerSessions: Send + Sync {
fn put(&self, key: Vec<u8>, value: Vec<u8>) -> bool;
fn get(&self, key: &[u8]) -> Option<Vec<u8>>;
fn take(&self, key: &[u8]) -> Option<Vec<u8>>;
}
pub trait ProducesTickets: Send + Sync {
fn enabled(&self) -> bool;
fn lifetime(&self) -> u32;
fn encrypt(&self, plain: &[u8]) -> Option<Vec<u8>>;
fn decrypt(&self, cipher: &[u8]) -> Option<Vec<u8>>;
}
pub trait ResolvesServerCert: Send + Sync {
fn resolve(&self, client_hello: ClientHello) -> Option<Arc<sign::CertifiedKey>>;
}
pub struct ClientHello<'a> {
server_name: Option<webpki::DnsNameRef<'a>>,
signature_schemes: &'a [SignatureScheme],
alpn: Option<&'a [&'a [u8]]>,
}
impl<'a> ClientHello<'a> {
fn new(
server_name: Option<webpki::DnsNameRef<'a>>,
signature_schemes: &'a [SignatureScheme],
alpn: Option<&'a [&'a [u8]]>,
) -> Self {
ClientHello {
server_name,
signature_schemes,
alpn,
}
}
pub fn server_name(&self) -> Option<&str> {
self.server_name
.as_ref()
.and_then(|s| std::str::from_utf8(s.as_ref()).ok())
}
pub fn signature_schemes(&self) -> &[SignatureScheme] {
self.signature_schemes
}
pub fn alpn(&self) -> Option<&'a [&'a [u8]]> {
self.alpn
}
}
#[derive(Clone)]
pub struct ServerConfig {
cipher_suites: Vec<SupportedCipherSuite>,
kx_groups: Vec<&'static SupportedKxGroup>,
pub ignore_client_order: bool,
pub max_fragment_size: Option<usize>,
pub session_storage: Arc<dyn StoresServerSessions + Send + Sync>,
pub ticketer: Arc<dyn ProducesTickets>,
pub cert_resolver: Arc<dyn ResolvesServerCert>,
pub alpn_protocols: Vec<Vec<u8>>,
versions: crate::versions::EnabledVersions,
verifier: Arc<dyn verify::ClientCertVerifier>,
pub key_log: Arc<dyn KeyLog>,
#[cfg(feature = "quic")] #[doc(hidden)]
pub max_early_data_size: u32,
}
impl ServerConfig {
pub fn builder() -> ConfigBuilder<Self, WantsCipherSuites> {
ConfigBuilder {
state: WantsCipherSuites,
side: PhantomData::default(),
}
}
#[doc(hidden)]
pub fn supports_version(&self, v: ProtocolVersion) -> bool {
self.versions.contains(v)
&& self
.cipher_suites
.iter()
.any(|cs| cs.version().version == v)
}
}
pub struct ServerConnection {
common: ConnectionCommon,
state: Option<Box<dyn hs::State>>,
data: ServerConnectionData,
}
impl ServerConnection {
pub fn new(config: Arc<ServerConfig>) -> Result<Self, Error> {
Self::from_config(config, vec![])
}
fn from_config(
config: Arc<ServerConfig>,
extra_exts: Vec<ServerExtension>,
) -> Result<Self, Error> {
Ok(Self {
common: ConnectionCommon::new(config.max_fragment_size, false)?,
state: Some(Box::new(hs::ExpectClientHello::new(config, extra_exts))),
data: ServerConnectionData::default(),
})
}
pub fn sni_hostname(&self) -> Option<&str> {
self.data.get_sni_str()
}
pub fn received_resumption_data(&self) -> Option<&[u8]> {
self.data
.received_resumption_data
.as_ref()
.map(|x| &x[..])
}
pub fn set_resumption_data(&mut self, data: &[u8]) {
assert!(data.len() < 2usize.pow(15));
self.data.resumption_data = data.into();
}
pub fn reject_early_data(&mut self) {
assert!(
self.is_handshaking(),
"cannot retroactively reject early data"
);
self.data.reject_early_data = true;
}
fn send_some_plaintext(&mut self, buf: &[u8]) -> usize {
let mut st = self.state.take();
if let Some(st) = st.as_mut() {
st.perhaps_write_key_update(&mut self.common);
}
self.state = st;
self.common.send_some_plaintext(buf)
}
}
impl Connection for ServerConnection {
fn read_tls(&mut self, rd: &mut dyn io::Read) -> io::Result<usize> {
self.common.read_tls(rd)
}
fn write_tls(&mut self, wr: &mut dyn io::Write) -> io::Result<usize> {
self.common.write_tls(wr)
}
fn process_new_packets(&mut self) -> Result<IoState, Error> {
self.common
.process_new_packets(&mut self.state, &mut self.data)
}
fn wants_read(&self) -> bool {
self.common.wants_read()
}
fn wants_write(&self) -> bool {
!self.common.sendable_tls.is_empty()
}
fn is_handshaking(&self) -> bool {
!self.common.traffic
}
fn set_buffer_limit(&mut self, len: Option<usize>) {
self.common.set_buffer_limit(len)
}
fn send_close_notify(&mut self) {
self.common.send_close_notify()
}
fn peer_certificates(&self) -> Option<&[key::Certificate]> {
self.data.client_cert_chain.as_deref()
}
fn alpn_protocol(&self) -> Option<&[u8]> {
self.common.get_alpn_protocol()
}
fn protocol_version(&self) -> Option<ProtocolVersion> {
self.common.negotiated_version
}
fn export_keying_material(
&self,
output: &mut [u8],
label: &[u8],
context: Option<&[u8]>,
) -> Result<(), Error> {
self.state
.as_ref()
.ok_or(Error::HandshakeNotComplete)
.and_then(|st| st.export_keying_material(output, label, context))
}
fn negotiated_cipher_suite(&self) -> Option<SupportedCipherSuite> {
self.common.get_suite()
}
fn writer(&mut self) -> Writer {
Writer::new(self)
}
fn reader(&mut self) -> Reader {
self.common.reader()
}
}
impl PlaintextSink for ServerConnection {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Ok(self.send_some_plaintext(buf))
}
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let mut sz = 0;
for buf in bufs {
sz += self.send_some_plaintext(buf);
}
Ok(sz)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl fmt::Debug for ServerConnection {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ServerConnection")
.finish()
}
}
#[derive(Default)]
struct ServerConnectionData {
sni: Option<webpki::DnsName>,
received_resumption_data: Option<Vec<u8>>,
resumption_data: Vec<u8>,
client_cert_chain: Option<Vec<key::Certificate>>,
#[allow(dead_code)] reject_early_data: bool,
}
impl ServerConnectionData {
fn get_sni_str(&self) -> Option<&str> {
self.sni.as_ref().map(AsRef::as_ref)
}
fn get_sni(&self) -> Option<verify::DnsName> {
self.sni
.as_ref()
.map(|name| verify::DnsName(name.clone()))
}
}
#[cfg(feature = "quic")]
impl quic::QuicExt for ServerConnection {
fn quic_transport_parameters(&self) -> Option<&[u8]> {
self.common
.quic
.params
.as_ref()
.map(|v| v.as_ref())
}
fn zero_rtt_keys(&self) -> Option<quic::DirectionalKeys> {
Some(quic::DirectionalKeys::new(
self.common
.get_suite()
.and_then(|suite| suite.tls13())?,
self.common.quic.early_secret.as_ref()?,
))
}
fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> {
quic::read_hs(&mut self.common, plaintext)?;
self.common
.process_new_handshake_messages(&mut self.state, &mut self.data)
}
fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<quic::Keys> {
quic::write_hs(&mut self.common, buf)
}
fn alert(&self) -> Option<AlertDescription> {
self.common.quic.alert
}
fn next_1rtt_keys(&mut self) -> Option<quic::PacketKeySet> {
quic::next_1rtt_keys(&mut self.common)
}
}
#[cfg(feature = "quic")]
pub trait ServerQuicExt {
fn new_quic(
config: Arc<ServerConfig>,
quic_version: quic::Version,
params: Vec<u8>,
) -> Result<ServerConnection, Error> {
if !config.supports_version(ProtocolVersion::TLSv1_3) {
return Err(Error::General(
"TLS 1.3 support is required for QUIC".into(),
));
}
if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff {
return Err(Error::General(
"QUIC sessions must set a max early data of 0 or 2^32-1".into(),
));
}
let ext = match quic_version {
quic::Version::V1Draft => ServerExtension::TransportParametersDraft(params),
quic::Version::V1 => ServerExtension::TransportParameters(params),
};
let mut new = ServerConnection::from_config(config, vec![ext])?;
new.common.protocol = Protocol::Quic;
Ok(new)
}
}
#[cfg(feature = "quic")]
impl ServerQuicExt for ServerConnection {}