| use crate::msgs::enums::{ProtocolVersion, HandshakeType}; |
| use crate::msgs::enums::{CipherSuite, Compression, ExtensionType, ECPointFormat}; |
| use crate::msgs::enums::{HashAlgorithm, SignatureAlgorithm, ServerNameType}; |
| use crate::msgs::enums::{SignatureScheme, KeyUpdateRequest, NamedGroup}; |
| use crate::msgs::enums::{ClientCertificateType, CertificateStatusType}; |
| use crate::msgs::enums::ECCurveType; |
| use crate::msgs::enums::PSKKeyExchangeMode; |
| use crate::msgs::base::{Payload, PayloadU8, PayloadU16, PayloadU24}; |
| use crate::msgs::codec; |
| use crate::msgs::codec::{Codec, Reader}; |
| use crate::key; |
| |
| #[cfg(feature = "logging")] |
| use crate::log::warn; |
| |
| use std::fmt; |
| use std::io::Write; |
| use std::collections; |
| use std::mem; |
| use webpki; |
| |
| macro_rules! declare_u8_vec( |
| ($name:ident, $itemtype:ty) => { |
| pub type $name = Vec<$itemtype>; |
| |
| impl Codec for $name { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| codec::encode_vec_u8(bytes, self); |
| } |
| |
| fn read(r: &mut Reader) -> Option<$name> { |
| codec::read_vec_u8::<$itemtype>(r) |
| } |
| } |
| } |
| ); |
| |
| macro_rules! declare_u16_vec( |
| ($name:ident, $itemtype:ty) => { |
| pub type $name = Vec<$itemtype>; |
| |
| impl Codec for $name { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| codec::encode_vec_u16(bytes, self); |
| } |
| |
| fn read(r: &mut Reader) -> Option<$name> { |
| codec::read_vec_u16::<$itemtype>(r) |
| } |
| } |
| } |
| ); |
| |
| declare_u16_vec!(VecU16OfPayloadU8, PayloadU8); |
| declare_u16_vec!(VecU16OfPayloadU16, PayloadU16); |
| |
| #[derive(Debug, PartialEq, Clone)] |
| pub struct Random([u8; 32]); |
| |
| static HELLO_RETRY_REQUEST_RANDOM: Random = Random([ |
| 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, |
| 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, |
| 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, |
| 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, |
| ]); |
| |
| static ZERO_RANDOM: Random = Random([0u8; 32]); |
| |
| impl Codec for Random { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| bytes.extend_from_slice(&self.0); |
| } |
| |
| fn read(r: &mut Reader) -> Option<Random> { |
| let bytes = r.take(32)?; |
| let mut opaque = [0; 32]; |
| opaque.clone_from_slice(bytes); |
| |
| Some(Random(opaque)) |
| } |
| } |
| |
| impl Random { |
| pub fn from_slice(bytes: &[u8]) -> Random { |
| let mut rd = Reader::init(bytes); |
| Random::read(&mut rd).unwrap() |
| } |
| |
| pub fn write_slice(&self, mut bytes: &mut [u8]) { |
| let buf = self.get_encoding(); |
| bytes.write_all(&buf).unwrap(); |
| } |
| } |
| |
| #[derive(Copy, Clone)] |
| pub struct SessionID { |
| len: usize, |
| data: [u8; 32], |
| } |
| |
| impl fmt::Debug for SessionID { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| let mut t = f.debug_tuple("SessionID"); |
| for i in 0..self.len() { |
| t.field(&self.data[i]); |
| } |
| t.finish() |
| } |
| } |
| |
| impl PartialEq for SessionID { |
| fn eq(&self, other: &Self) -> bool { |
| if self.len != other.len { |
| return false; |
| } |
| |
| let mut diff = 0u8; |
| for i in 0..self.len { |
| diff |= self.data[i] ^ other.data[i] |
| } |
| |
| diff == 0u8 |
| } |
| } |
| |
| impl Codec for SessionID { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| debug_assert!(self.len <= 32); |
| bytes.push(self.len as u8); |
| bytes.extend_from_slice(&self.data[..self.len]); |
| } |
| |
| fn read(r: &mut Reader) -> Option<SessionID> { |
| let len = u8::read(r)? as usize; |
| if len > 32 { |
| return None; |
| } |
| |
| let bytes = r.take(len)?; |
| let mut out = [0u8; 32]; |
| out[..len].clone_from_slice(&bytes[..len]); |
| |
| Some(SessionID { |
| data: out, |
| len, |
| }) |
| } |
| } |
| |
| impl SessionID { |
| pub fn new(bytes: &[u8]) -> SessionID { |
| debug_assert!(bytes.len() <= 32); |
| let mut d = [0u8; 32]; |
| d[..bytes.len()].clone_from_slice(&bytes[..]); |
| |
| SessionID { |
| data: d, |
| len: bytes.len(), |
| } |
| } |
| |
| pub fn empty() -> SessionID { |
| SessionID { |
| data: [0u8; 32], |
| len: 0, |
| } |
| } |
| |
| pub fn len(&self) -> usize { |
| self.len |
| } |
| |
| pub fn is_empty(&self) -> bool { |
| self.len == 0 |
| } |
| } |
| |
| #[derive(Clone, Debug)] |
| pub struct UnknownExtension { |
| pub typ: ExtensionType, |
| pub payload: Payload, |
| } |
| |
| impl UnknownExtension { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.payload.encode(bytes); |
| } |
| |
| fn read(typ: ExtensionType, r: &mut Reader) -> Option<UnknownExtension> { |
| let payload = Payload::read(r)?; |
| Some(UnknownExtension { |
| typ, |
| payload, |
| }) |
| } |
| } |
| |
| declare_u8_vec!(ECPointFormatList, ECPointFormat); |
| |
| pub trait SupportedPointFormats { |
| fn supported() -> ECPointFormatList; |
| } |
| |
| impl SupportedPointFormats for ECPointFormatList { |
| fn supported() -> ECPointFormatList { |
| vec![ECPointFormat::Uncompressed] |
| } |
| } |
| |
| declare_u16_vec!(NamedGroups, NamedGroup); |
| |
| declare_u16_vec!(SupportedSignatureSchemes, SignatureScheme); |
| |
| pub trait DecomposedSignatureScheme { |
| fn sign(&self) -> SignatureAlgorithm; |
| fn make(alg: SignatureAlgorithm, hash: HashAlgorithm) -> SignatureScheme; |
| } |
| |
| impl DecomposedSignatureScheme for SignatureScheme { |
| fn sign(&self) -> SignatureAlgorithm { |
| match *self { |
| SignatureScheme::RSA_PKCS1_SHA1 | |
| SignatureScheme::RSA_PKCS1_SHA256 | |
| SignatureScheme::RSA_PKCS1_SHA384 | |
| SignatureScheme::RSA_PKCS1_SHA512 | |
| SignatureScheme::RSA_PSS_SHA256 | |
| SignatureScheme::RSA_PSS_SHA384 | |
| SignatureScheme::RSA_PSS_SHA512 => SignatureAlgorithm::RSA, |
| SignatureScheme::ECDSA_NISTP256_SHA256 | |
| SignatureScheme::ECDSA_NISTP384_SHA384 | |
| SignatureScheme::ECDSA_NISTP521_SHA512 => SignatureAlgorithm::ECDSA, |
| _ => SignatureAlgorithm::Unknown(0), |
| } |
| } |
| |
| fn make(alg: SignatureAlgorithm, hash: HashAlgorithm) -> SignatureScheme { |
| use crate::msgs::enums::SignatureAlgorithm::{RSA, ECDSA}; |
| use crate::msgs::enums::HashAlgorithm::{SHA1, SHA256, SHA384, SHA512}; |
| |
| match (alg, hash) { |
| (RSA, SHA1) => SignatureScheme::RSA_PKCS1_SHA1, |
| (RSA, SHA256) => SignatureScheme::RSA_PKCS1_SHA256, |
| (RSA, SHA384) => SignatureScheme::RSA_PKCS1_SHA384, |
| (RSA, SHA512) => SignatureScheme::RSA_PKCS1_SHA512, |
| (ECDSA, SHA256) => SignatureScheme::ECDSA_NISTP256_SHA256, |
| (ECDSA, SHA384) => SignatureScheme::ECDSA_NISTP384_SHA384, |
| (ECDSA, SHA512) => SignatureScheme::ECDSA_NISTP521_SHA512, |
| (_, _) => unreachable!(), |
| } |
| } |
| } |
| |
| #[derive(Clone, Debug)] |
| pub enum ServerNamePayload { |
| HostName(webpki::DNSName), |
| Unknown(Payload), |
| } |
| |
| impl ServerNamePayload { |
| fn read_hostname(r: &mut Reader) -> Option<ServerNamePayload> { |
| let len = u16::read(r)? as usize; |
| let name = r.take(len)?; |
| let dns_name = match webpki::DNSNameRef::try_from_ascii(name) { |
| Ok(dns_name) => dns_name, |
| Err(_) => { |
| warn!("Illegal SNI hostname received {:?}", name); |
| return None; |
| } |
| }; |
| Some(ServerNamePayload::HostName(dns_name.into())) |
| } |
| |
| fn encode_hostname(name: webpki::DNSNameRef, bytes: &mut Vec<u8>) { |
| let dns_name_str: &str = name.into(); |
| (dns_name_str.len() as u16).encode(bytes); |
| bytes.extend_from_slice(dns_name_str.as_bytes()); |
| } |
| |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| match *self { |
| ServerNamePayload::HostName(ref r) => ServerNamePayload::encode_hostname(r.as_ref(), bytes), |
| ServerNamePayload::Unknown(ref r) => r.encode(bytes), |
| } |
| } |
| } |
| |
| #[derive(Clone, Debug)] |
| pub struct ServerName { |
| pub typ: ServerNameType, |
| pub payload: ServerNamePayload, |
| } |
| |
| impl Codec for ServerName { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.typ.encode(bytes); |
| self.payload.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<ServerName> { |
| let typ = ServerNameType::read(r)?; |
| |
| let payload = match typ { |
| ServerNameType::HostName => ServerNamePayload::read_hostname(r)?, |
| _ => ServerNamePayload::Unknown(Payload::read(r)?), |
| }; |
| |
| Some(ServerName { |
| typ, |
| payload, |
| }) |
| } |
| } |
| |
| declare_u16_vec!(ServerNameRequest, ServerName); |
| |
| pub trait ConvertServerNameList { |
| fn has_duplicate_names_for_type(&self) -> bool; |
| fn get_single_hostname(&self) -> Option<webpki::DNSNameRef>; |
| } |
| |
| impl ConvertServerNameList for ServerNameRequest { |
| /// RFC6066: "The ServerNameList MUST NOT contain more than one name of the same name_type." |
| fn has_duplicate_names_for_type(&self) -> bool { |
| let mut seen = collections::HashSet::new(); |
| |
| for name in self { |
| if !seen.insert(name.typ.get_u8()) { |
| return true; |
| } |
| } |
| |
| false |
| } |
| |
| fn get_single_hostname(&self) -> Option<webpki::DNSNameRef> { |
| fn only_dns_hostnames(name: &ServerName) -> Option<webpki::DNSNameRef> { |
| if let ServerNamePayload::HostName(ref dns) = name.payload { |
| Some(dns.as_ref()) |
| } else { |
| None |
| } |
| } |
| |
| self.iter() |
| .filter_map(only_dns_hostnames) |
| .nth(0) |
| } |
| } |
| |
| pub type ProtocolNameList = VecU16OfPayloadU8; |
| |
| pub trait ConvertProtocolNameList { |
| fn from_slices(names: &[&[u8]]) -> Self; |
| fn to_slices(&self) -> Vec<&[u8]>; |
| fn as_single_slice(&self) -> Option<&[u8]>; |
| } |
| |
| impl ConvertProtocolNameList for ProtocolNameList { |
| fn from_slices(names: &[&[u8]]) -> ProtocolNameList { |
| let mut ret = Vec::new(); |
| |
| for name in names { |
| ret.push(PayloadU8::new(name.to_vec())); |
| } |
| |
| ret |
| } |
| |
| fn to_slices(&self) -> Vec<&[u8]> { |
| self.iter() |
| .map(|proto| -> &[u8] { &proto.0 }) |
| .collect::<Vec<&[u8]>>() |
| } |
| |
| fn as_single_slice(&self) -> Option<&[u8]> { |
| if self.len() == 1 { |
| Some(&self[0].0) |
| } else { |
| None |
| } |
| } |
| } |
| |
| // --- TLS 1.3 Key shares --- |
| #[derive(Clone, Debug)] |
| pub struct KeyShareEntry { |
| pub group: NamedGroup, |
| pub payload: PayloadU16, |
| } |
| |
| impl KeyShareEntry { |
| pub fn new(group: NamedGroup, payload: &[u8]) -> KeyShareEntry { |
| KeyShareEntry { |
| group, |
| payload: PayloadU16::new(payload.to_vec()), |
| } |
| } |
| } |
| |
| impl Codec for KeyShareEntry { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.group.encode(bytes); |
| self.payload.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<KeyShareEntry> { |
| let group = NamedGroup::read(r)?; |
| let payload = PayloadU16::read(r)?; |
| |
| Some(KeyShareEntry { |
| group, |
| payload, |
| }) |
| } |
| } |
| |
| // --- TLS 1.3 PresharedKey offers --- |
| #[derive(Clone, Debug)] |
| pub struct PresharedKeyIdentity { |
| pub identity: PayloadU16, |
| pub obfuscated_ticket_age: u32, |
| } |
| |
| impl PresharedKeyIdentity { |
| pub fn new(id: Vec<u8>, age: u32) -> PresharedKeyIdentity { |
| PresharedKeyIdentity { |
| identity: PayloadU16::new(id), |
| obfuscated_ticket_age: age, |
| } |
| } |
| } |
| |
| impl Codec for PresharedKeyIdentity { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.identity.encode(bytes); |
| self.obfuscated_ticket_age.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<PresharedKeyIdentity> { |
| Some(PresharedKeyIdentity { |
| identity: PayloadU16::read(r)?, |
| obfuscated_ticket_age: u32::read(r)?, |
| }) |
| } |
| } |
| |
| declare_u16_vec!(PresharedKeyIdentities, PresharedKeyIdentity); |
| pub type PresharedKeyBinder = PayloadU8; |
| pub type PresharedKeyBinders = VecU16OfPayloadU8; |
| |
| #[derive(Clone, Debug)] |
| pub struct PresharedKeyOffer { |
| pub identities: PresharedKeyIdentities, |
| pub binders: PresharedKeyBinders, |
| } |
| |
| impl PresharedKeyOffer { |
| /// Make a new one with one entry. |
| pub fn new(id: PresharedKeyIdentity, binder: Vec<u8>) -> PresharedKeyOffer { |
| PresharedKeyOffer { |
| identities: vec![ id ], |
| binders: vec![ PresharedKeyBinder::new(binder) ], |
| } |
| } |
| } |
| |
| impl Codec for PresharedKeyOffer { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.identities.encode(bytes); |
| self.binders.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<PresharedKeyOffer> { |
| Some(PresharedKeyOffer { |
| identities: PresharedKeyIdentities::read(r)?, |
| binders: PresharedKeyBinders::read(r)?, |
| }) |
| } |
| } |
| |
| // --- RFC6066 certificate status request --- |
| type ResponderIDs = VecU16OfPayloadU16; |
| |
| #[derive(Clone, Debug)] |
| pub struct OCSPCertificateStatusRequest { |
| pub responder_ids: ResponderIDs, |
| pub extensions: PayloadU16, |
| } |
| |
| impl Codec for OCSPCertificateStatusRequest { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| CertificateStatusType::OCSP.encode(bytes); |
| self.responder_ids.encode(bytes); |
| self.extensions.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<OCSPCertificateStatusRequest> { |
| Some(OCSPCertificateStatusRequest { |
| responder_ids: ResponderIDs::read(r)?, |
| extensions: PayloadU16::read(r)?, |
| }) |
| } |
| } |
| |
| #[derive(Clone, Debug)] |
| pub enum CertificateStatusRequest { |
| OCSP(OCSPCertificateStatusRequest), |
| Unknown((CertificateStatusType, Payload)) |
| } |
| |
| impl Codec for CertificateStatusRequest { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| match *self { |
| CertificateStatusRequest::OCSP(ref r) => r.encode(bytes), |
| CertificateStatusRequest::Unknown((typ, ref payload)) => { |
| typ.encode(bytes); |
| payload.encode(bytes); |
| } |
| } |
| } |
| |
| fn read(r: &mut Reader) -> Option<CertificateStatusRequest> { |
| let typ = CertificateStatusType::read(r)?; |
| |
| match typ { |
| CertificateStatusType::OCSP => { |
| let ocsp_req = OCSPCertificateStatusRequest::read(r)?; |
| Some(CertificateStatusRequest::OCSP(ocsp_req)) |
| } |
| _ => { |
| let data = Payload::read(r)?; |
| Some(CertificateStatusRequest::Unknown((typ, data))) |
| } |
| } |
| } |
| } |
| |
| impl CertificateStatusRequest { |
| pub fn build_ocsp() -> CertificateStatusRequest { |
| let ocsp = OCSPCertificateStatusRequest { |
| responder_ids: ResponderIDs::new(), |
| extensions: PayloadU16::empty(), |
| }; |
| CertificateStatusRequest::OCSP(ocsp) |
| } |
| } |
| |
| // --- |
| // SCTs |
| |
| pub type SCTList = VecU16OfPayloadU16; |
| |
| // --- |
| |
| declare_u8_vec!(PSKKeyExchangeModes, PSKKeyExchangeMode); |
| declare_u16_vec!(KeyShareEntries, KeyShareEntry); |
| declare_u8_vec!(ProtocolVersions, ProtocolVersion); |
| |
| #[derive(Clone, Debug)] |
| pub enum ClientExtension { |
| ECPointFormats(ECPointFormatList), |
| NamedGroups(NamedGroups), |
| SignatureAlgorithms(SupportedSignatureSchemes), |
| ServerName(ServerNameRequest), |
| SessionTicketRequest, |
| SessionTicketOffer(Payload), |
| Protocols(ProtocolNameList), |
| SupportedVersions(ProtocolVersions), |
| KeyShare(KeyShareEntries), |
| PresharedKeyModes(PSKKeyExchangeModes), |
| PresharedKey(PresharedKeyOffer), |
| Cookie(PayloadU16), |
| ExtendedMasterSecretRequest, |
| CertificateStatusRequest(CertificateStatusRequest), |
| SignedCertificateTimestampRequest, |
| TransportParameters(Vec<u8>), |
| EarlyData, |
| Unknown(UnknownExtension), |
| } |
| |
| impl ClientExtension { |
| pub fn get_type(&self) -> ExtensionType { |
| match *self { |
| ClientExtension::ECPointFormats(_) => ExtensionType::ECPointFormats, |
| ClientExtension::NamedGroups(_) => ExtensionType::EllipticCurves, |
| ClientExtension::SignatureAlgorithms(_) => ExtensionType::SignatureAlgorithms, |
| ClientExtension::ServerName(_) => ExtensionType::ServerName, |
| ClientExtension::SessionTicketRequest | |
| ClientExtension::SessionTicketOffer(_) => ExtensionType::SessionTicket, |
| ClientExtension::Protocols(_) => ExtensionType::ALProtocolNegotiation, |
| ClientExtension::SupportedVersions(_) => ExtensionType::SupportedVersions, |
| ClientExtension::KeyShare(_) => ExtensionType::KeyShare, |
| ClientExtension::PresharedKeyModes(_) => ExtensionType::PSKKeyExchangeModes, |
| ClientExtension::PresharedKey(_) => ExtensionType::PreSharedKey, |
| ClientExtension::Cookie(_) => ExtensionType::Cookie, |
| ClientExtension::ExtendedMasterSecretRequest => ExtensionType::ExtendedMasterSecret, |
| ClientExtension::CertificateStatusRequest(_) => ExtensionType::StatusRequest, |
| ClientExtension::SignedCertificateTimestampRequest => ExtensionType::SCT, |
| ClientExtension::TransportParameters(_) => ExtensionType::TransportParameters, |
| ClientExtension::EarlyData => ExtensionType::EarlyData, |
| ClientExtension::Unknown(ref r) => r.typ, |
| } |
| } |
| } |
| |
| impl Codec for ClientExtension { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.get_type().encode(bytes); |
| |
| let mut sub: Vec<u8> = Vec::new(); |
| match *self { |
| ClientExtension::ECPointFormats(ref r) => r.encode(&mut sub), |
| ClientExtension::NamedGroups(ref r) => r.encode(&mut sub), |
| ClientExtension::SignatureAlgorithms(ref r) => r.encode(&mut sub), |
| ClientExtension::ServerName(ref r) => r.encode(&mut sub), |
| ClientExtension::SessionTicketRequest | |
| ClientExtension::ExtendedMasterSecretRequest | |
| ClientExtension::SignedCertificateTimestampRequest | |
| ClientExtension::EarlyData => (), |
| ClientExtension::SessionTicketOffer(ref r) => r.encode(&mut sub), |
| ClientExtension::Protocols(ref r) => r.encode(&mut sub), |
| ClientExtension::SupportedVersions(ref r) => r.encode(&mut sub), |
| ClientExtension::KeyShare(ref r) => r.encode(&mut sub), |
| ClientExtension::PresharedKeyModes(ref r) => r.encode(&mut sub), |
| ClientExtension::PresharedKey(ref r) => r.encode(&mut sub), |
| ClientExtension::Cookie(ref r) => r.encode(&mut sub), |
| ClientExtension::CertificateStatusRequest(ref r) => r.encode(&mut sub), |
| ClientExtension::TransportParameters(ref r) => sub.extend_from_slice(r), |
| ClientExtension::Unknown(ref r) => r.encode(&mut sub), |
| } |
| |
| (sub.len() as u16).encode(bytes); |
| bytes.append(&mut sub); |
| } |
| |
| fn read(r: &mut Reader) -> Option<ClientExtension> { |
| let typ = ExtensionType::read(r)?; |
| let len = u16::read(r)? as usize; |
| let mut sub = r.sub(len)?; |
| |
| Some(match typ { |
| ExtensionType::ECPointFormats => { |
| ClientExtension::ECPointFormats(ECPointFormatList::read(&mut sub)?) |
| } |
| ExtensionType::EllipticCurves => { |
| ClientExtension::NamedGroups(NamedGroups::read(&mut sub)?) |
| } |
| ExtensionType::SignatureAlgorithms => { |
| let schemes = SupportedSignatureSchemes::read(&mut sub)?; |
| ClientExtension::SignatureAlgorithms(schemes) |
| } |
| ExtensionType::ServerName => { |
| ClientExtension::ServerName(ServerNameRequest::read(&mut sub)?) |
| } |
| ExtensionType::SessionTicket => { |
| if sub.any_left() { |
| ClientExtension::SessionTicketOffer(Payload::read(&mut sub)?) |
| } else { |
| ClientExtension::SessionTicketRequest |
| } |
| } |
| ExtensionType::ALProtocolNegotiation => { |
| ClientExtension::Protocols(ProtocolNameList::read(&mut sub)?) |
| } |
| ExtensionType::SupportedVersions => { |
| ClientExtension::SupportedVersions(ProtocolVersions::read(&mut sub)?) |
| } |
| ExtensionType::KeyShare => { |
| ClientExtension::KeyShare(KeyShareEntries::read(&mut sub)?) |
| } |
| ExtensionType::PSKKeyExchangeModes => { |
| ClientExtension::PresharedKeyModes(PSKKeyExchangeModes::read(&mut sub)?) |
| } |
| ExtensionType::PreSharedKey => { |
| ClientExtension::PresharedKey(PresharedKeyOffer::read(&mut sub)?) |
| } |
| ExtensionType::Cookie => ClientExtension::Cookie(PayloadU16::read(&mut sub)?), |
| ExtensionType::ExtendedMasterSecret if !sub.any_left() => { |
| ClientExtension::ExtendedMasterSecretRequest |
| } |
| ExtensionType::StatusRequest => { |
| let csr = CertificateStatusRequest::read(&mut sub)?; |
| ClientExtension::CertificateStatusRequest(csr) |
| } |
| ExtensionType::SCT if !sub.any_left() => { |
| ClientExtension::SignedCertificateTimestampRequest |
| } |
| ExtensionType::TransportParameters => { |
| ClientExtension::TransportParameters(sub.rest().to_vec()) |
| } |
| ExtensionType::EarlyData if !sub.any_left() => { |
| ClientExtension::EarlyData |
| } |
| _ => ClientExtension::Unknown(UnknownExtension::read(typ, &mut sub)?), |
| }) |
| } |
| } |
| |
| impl ClientExtension { |
| /// Make a basic SNI ServerNameRequest quoting `hostname`. |
| pub fn make_sni(dns_name: webpki::DNSNameRef) -> ClientExtension { |
| let name = ServerName { |
| typ: ServerNameType::HostName, |
| payload: ServerNamePayload::HostName(dns_name.into()), |
| }; |
| |
| ClientExtension::ServerName(vec![ name ]) |
| } |
| } |
| |
| #[derive(Clone, Debug)] |
| pub enum ServerExtension { |
| ECPointFormats(ECPointFormatList), |
| ServerNameAck, |
| SessionTicketAck, |
| RenegotiationInfo(PayloadU8), |
| Protocols(ProtocolNameList), |
| KeyShare(KeyShareEntry), |
| PresharedKey(u16), |
| ExtendedMasterSecretAck, |
| CertificateStatusAck, |
| SignedCertificateTimestamp(SCTList), |
| SupportedVersions(ProtocolVersion), |
| TransportParameters(Vec<u8>), |
| EarlyData, |
| Unknown(UnknownExtension), |
| } |
| |
| impl ServerExtension { |
| pub fn get_type(&self) -> ExtensionType { |
| match *self { |
| ServerExtension::ECPointFormats(_) => ExtensionType::ECPointFormats, |
| ServerExtension::ServerNameAck => ExtensionType::ServerName, |
| ServerExtension::SessionTicketAck => ExtensionType::SessionTicket, |
| ServerExtension::RenegotiationInfo(_) => ExtensionType::RenegotiationInfo, |
| ServerExtension::Protocols(_) => ExtensionType::ALProtocolNegotiation, |
| ServerExtension::KeyShare(_) => ExtensionType::KeyShare, |
| ServerExtension::PresharedKey(_) => ExtensionType::PreSharedKey, |
| ServerExtension::ExtendedMasterSecretAck => ExtensionType::ExtendedMasterSecret, |
| ServerExtension::CertificateStatusAck => ExtensionType::StatusRequest, |
| ServerExtension::SignedCertificateTimestamp(_) => ExtensionType::SCT, |
| ServerExtension::SupportedVersions(_) => ExtensionType::SupportedVersions, |
| ServerExtension::TransportParameters(_) => ExtensionType::TransportParameters, |
| ServerExtension::EarlyData => ExtensionType::EarlyData, |
| ServerExtension::Unknown(ref r) => r.typ, |
| } |
| } |
| } |
| |
| impl Codec for ServerExtension { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.get_type().encode(bytes); |
| |
| let mut sub: Vec<u8> = Vec::new(); |
| match *self { |
| ServerExtension::ECPointFormats(ref r) => r.encode(&mut sub), |
| ServerExtension::ServerNameAck | |
| ServerExtension::SessionTicketAck | |
| ServerExtension::ExtendedMasterSecretAck | |
| ServerExtension::CertificateStatusAck | |
| ServerExtension::EarlyData => (), |
| ServerExtension::RenegotiationInfo(ref r) => r.encode(&mut sub), |
| ServerExtension::Protocols(ref r) => r.encode(&mut sub), |
| ServerExtension::KeyShare(ref r) => r.encode(&mut sub), |
| ServerExtension::PresharedKey(r) => r.encode(&mut sub), |
| ServerExtension::SignedCertificateTimestamp(ref r) => r.encode(&mut sub), |
| ServerExtension::SupportedVersions(ref r) => r.encode(&mut sub), |
| ServerExtension::TransportParameters(ref r) => sub.extend_from_slice(r), |
| ServerExtension::Unknown(ref r) => r.encode(&mut sub), |
| } |
| |
| (sub.len() as u16).encode(bytes); |
| bytes.append(&mut sub); |
| } |
| |
| fn read(r: &mut Reader) -> Option<ServerExtension> { |
| let typ = ExtensionType::read(r)?; |
| let len = u16::read(r)? as usize; |
| let mut sub = r.sub(len)?; |
| |
| Some(match typ { |
| ExtensionType::ECPointFormats => { |
| ServerExtension::ECPointFormats(ECPointFormatList::read(&mut sub)?) |
| } |
| ExtensionType::ServerName => ServerExtension::ServerNameAck, |
| ExtensionType::SessionTicket => ServerExtension::SessionTicketAck, |
| ExtensionType::StatusRequest => ServerExtension::CertificateStatusAck, |
| ExtensionType::RenegotiationInfo => { |
| ServerExtension::RenegotiationInfo(PayloadU8::read(&mut sub)?) |
| } |
| ExtensionType::ALProtocolNegotiation => { |
| ServerExtension::Protocols(ProtocolNameList::read(&mut sub)?) |
| } |
| ExtensionType::KeyShare => { |
| ServerExtension::KeyShare(KeyShareEntry::read(&mut sub)?) |
| } |
| ExtensionType::PreSharedKey => { |
| ServerExtension::PresharedKey(u16::read(&mut sub)?) |
| } |
| ExtensionType::ExtendedMasterSecret => ServerExtension::ExtendedMasterSecretAck, |
| ExtensionType::SCT => { |
| let scts = SCTList::read(&mut sub)?; |
| ServerExtension::SignedCertificateTimestamp(scts) |
| } |
| ExtensionType::SupportedVersions => { |
| ServerExtension::SupportedVersions(ProtocolVersion::read(&mut sub)?) |
| } |
| ExtensionType::TransportParameters => { |
| ServerExtension::TransportParameters(sub.rest().to_vec()) |
| } |
| ExtensionType::EarlyData => ServerExtension::EarlyData, |
| _ => ServerExtension::Unknown(UnknownExtension::read(typ, &mut sub)?), |
| }) |
| } |
| } |
| |
| impl ServerExtension { |
| pub fn make_alpn(proto: &[&[u8]]) -> ServerExtension { |
| ServerExtension::Protocols(ProtocolNameList::from_slices(proto)) |
| } |
| |
| pub fn make_empty_renegotiation_info() -> ServerExtension { |
| let empty = Vec::new(); |
| ServerExtension::RenegotiationInfo(PayloadU8::new(empty)) |
| } |
| |
| pub fn make_sct(sctl: Vec<u8>) -> ServerExtension { |
| let scts = SCTList::read_bytes(&sctl) |
| .expect("invalid SCT list"); |
| ServerExtension::SignedCertificateTimestamp(scts) |
| } |
| } |
| |
| #[derive(Debug)] |
| pub struct ClientHelloPayload { |
| pub client_version: ProtocolVersion, |
| pub random: Random, |
| pub session_id: SessionID, |
| pub cipher_suites: Vec<CipherSuite>, |
| pub compression_methods: Vec<Compression>, |
| pub extensions: Vec<ClientExtension>, |
| } |
| |
| impl Codec for ClientHelloPayload { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.client_version.encode(bytes); |
| self.random.encode(bytes); |
| self.session_id.encode(bytes); |
| codec::encode_vec_u16(bytes, &self.cipher_suites); |
| codec::encode_vec_u8(bytes, &self.compression_methods); |
| |
| if !self.extensions.is_empty() { |
| codec::encode_vec_u16(bytes, &self.extensions); |
| } |
| } |
| |
| fn read(r: &mut Reader) -> Option<ClientHelloPayload> { |
| let mut ret = ClientHelloPayload { |
| client_version: ProtocolVersion::read(r)?, |
| random: Random::read(r)?, |
| session_id: SessionID::read(r)?, |
| cipher_suites: codec::read_vec_u16::<CipherSuite>(r)?, |
| compression_methods: codec::read_vec_u8::<Compression>(r)?, |
| extensions: Vec::new(), |
| }; |
| |
| if r.any_left() { |
| ret.extensions = codec::read_vec_u16::<ClientExtension>(r)?; |
| } |
| |
| Some(ret) |
| } |
| } |
| |
| impl ClientHelloPayload { |
| /// Returns true if there is more than one extension of a given |
| /// type. |
| pub fn has_duplicate_extension(&self) -> bool { |
| let mut seen = collections::HashSet::new(); |
| |
| for ext in &self.extensions { |
| let typ = ext.get_type().get_u16(); |
| |
| if seen.contains(&typ) { |
| return true; |
| } |
| seen.insert(typ); |
| } |
| |
| false |
| } |
| |
| pub fn find_extension(&self, ext: ExtensionType) -> Option<&ClientExtension> { |
| self.extensions.iter().find(|x| x.get_type() == ext) |
| } |
| |
| pub fn get_sni_extension(&self) -> Option<&ServerNameRequest> { |
| let ext = self.find_extension(ExtensionType::ServerName)?; |
| match *ext { |
| ClientExtension::ServerName(ref req) => Some(req), |
| _ => None, |
| } |
| } |
| |
| pub fn get_sigalgs_extension(&self) -> Option<&SupportedSignatureSchemes> { |
| let ext = self.find_extension(ExtensionType::SignatureAlgorithms)?; |
| match *ext { |
| ClientExtension::SignatureAlgorithms(ref req) => Some(req), |
| _ => None, |
| } |
| } |
| |
| pub fn get_namedgroups_extension(&self) -> Option<&NamedGroups> { |
| let ext = self.find_extension(ExtensionType::EllipticCurves)?; |
| match *ext { |
| ClientExtension::NamedGroups(ref req) => Some(req), |
| _ => None, |
| } |
| } |
| |
| pub fn get_ecpoints_extension(&self) -> Option<&ECPointFormatList> { |
| let ext = self.find_extension(ExtensionType::ECPointFormats)?; |
| match *ext { |
| ClientExtension::ECPointFormats(ref req) => Some(req), |
| _ => None, |
| } |
| } |
| |
| pub fn get_alpn_extension(&self) -> Option<&ProtocolNameList> { |
| let ext = self.find_extension(ExtensionType::ALProtocolNegotiation)?; |
| match *ext { |
| ClientExtension::Protocols(ref req) => Some(req), |
| _ => None, |
| } |
| } |
| |
| pub fn get_quic_params_extension(&self) -> Option<Vec<u8>> { |
| let ext = self.find_extension(ExtensionType::TransportParameters)?; |
| match *ext { |
| ClientExtension::TransportParameters(ref bytes) => Some(bytes.to_vec()), |
| _ => None, |
| } |
| } |
| |
| pub fn get_ticket_extension(&self) -> Option<&ClientExtension> { |
| self.find_extension(ExtensionType::SessionTicket) |
| } |
| |
| pub fn get_versions_extension(&self) -> Option<&ProtocolVersions> { |
| let ext = self.find_extension(ExtensionType::SupportedVersions)?; |
| match *ext { |
| ClientExtension::SupportedVersions(ref vers) => Some(vers), |
| _ => None, |
| } |
| } |
| |
| pub fn get_keyshare_extension(&self) -> Option<&KeyShareEntries> { |
| let ext = self.find_extension(ExtensionType::KeyShare)?; |
| match *ext { |
| ClientExtension::KeyShare(ref shares) => Some(shares), |
| _ => None, |
| } |
| } |
| |
| pub fn has_keyshare_extension_with_duplicates(&self) -> bool { |
| let entries = self.get_keyshare_extension(); |
| if entries.is_none() { |
| return false; |
| } |
| |
| let mut seen = collections::HashSet::new(); |
| |
| for kse in entries.unwrap() { |
| let grp = kse.group.get_u16(); |
| |
| if seen.contains(&grp) { |
| return true; |
| } |
| |
| seen.insert(grp); |
| } |
| |
| false |
| } |
| |
| pub fn get_psk(&self) -> Option<&PresharedKeyOffer> { |
| let ext = self.find_extension(ExtensionType::PreSharedKey)?; |
| match *ext { |
| ClientExtension::PresharedKey(ref psk) => Some(psk), |
| _ => None, |
| } |
| } |
| |
| pub fn check_psk_ext_is_last(&self) -> bool { |
| self.extensions |
| .last() |
| .map_or(false, |ext| ext.get_type() == ExtensionType::PreSharedKey) |
| } |
| |
| pub fn get_psk_modes(&self) -> Option<&PSKKeyExchangeModes> { |
| let ext = self.find_extension(ExtensionType::PSKKeyExchangeModes)?; |
| match *ext { |
| ClientExtension::PresharedKeyModes(ref psk_modes) => Some(psk_modes), |
| _ => None, |
| } |
| } |
| |
| pub fn psk_mode_offered(&self, mode: PSKKeyExchangeMode) -> bool { |
| self.get_psk_modes() |
| .map(|modes| modes.contains(&mode)) |
| .or(Some(false)) |
| .unwrap() |
| } |
| |
| |
| pub fn set_psk_binder(&mut self, binder: Vec<u8>) { |
| let last_extension = self.extensions.last_mut().unwrap(); |
| if let ClientExtension::PresharedKey(ref mut offer) = *last_extension { |
| offer.binders[0] = PresharedKeyBinder::new(binder); |
| } |
| } |
| |
| pub fn ems_support_offered(&self) -> bool { |
| self.find_extension(ExtensionType::ExtendedMasterSecret) |
| .is_some() |
| } |
| |
| pub fn early_data_extension_offered(&self) -> bool { |
| self.find_extension(ExtensionType::EarlyData).is_some() |
| } |
| } |
| |
| #[derive(Debug)] |
| pub enum HelloRetryExtension { |
| KeyShare(NamedGroup), |
| Cookie(PayloadU16), |
| SupportedVersions(ProtocolVersion), |
| Unknown(UnknownExtension), |
| } |
| |
| impl HelloRetryExtension { |
| pub fn get_type(&self) -> ExtensionType { |
| match *self { |
| HelloRetryExtension::KeyShare(_) => ExtensionType::KeyShare, |
| HelloRetryExtension::Cookie(_) => ExtensionType::Cookie, |
| HelloRetryExtension::SupportedVersions(_) => ExtensionType::SupportedVersions, |
| HelloRetryExtension::Unknown(ref r) => r.typ, |
| } |
| } |
| } |
| |
| impl Codec for HelloRetryExtension { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.get_type().encode(bytes); |
| |
| let mut sub: Vec<u8> = Vec::new(); |
| match *self { |
| HelloRetryExtension::KeyShare(ref r) => r.encode(&mut sub), |
| HelloRetryExtension::Cookie(ref r) => r.encode(&mut sub), |
| HelloRetryExtension::SupportedVersions(ref r) => r.encode(&mut sub), |
| HelloRetryExtension::Unknown(ref r) => r.encode(&mut sub), |
| } |
| |
| (sub.len() as u16).encode(bytes); |
| bytes.append(&mut sub); |
| } |
| |
| fn read(r: &mut Reader) -> Option<HelloRetryExtension> { |
| let typ = ExtensionType::read(r)?; |
| let len = u16::read(r)? as usize; |
| let mut sub = r.sub(len)?; |
| |
| Some(match typ { |
| ExtensionType::KeyShare => { |
| HelloRetryExtension::KeyShare(NamedGroup::read(&mut sub)?) |
| } |
| ExtensionType::Cookie => { |
| HelloRetryExtension::Cookie(PayloadU16::read(&mut sub)?) |
| } |
| ExtensionType::SupportedVersions => { |
| HelloRetryExtension::SupportedVersions(ProtocolVersion::read(&mut sub)?) |
| } |
| _ => HelloRetryExtension::Unknown(UnknownExtension::read(typ, &mut sub)?), |
| }) |
| } |
| } |
| |
| #[derive(Debug)] |
| pub struct HelloRetryRequest { |
| pub legacy_version: ProtocolVersion, |
| pub session_id: SessionID, |
| pub cipher_suite: CipherSuite, |
| pub extensions: Vec<HelloRetryExtension>, |
| } |
| |
| impl Codec for HelloRetryRequest { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.legacy_version.encode(bytes); |
| HELLO_RETRY_REQUEST_RANDOM.encode(bytes); |
| self.session_id.encode(bytes); |
| self.cipher_suite.encode(bytes); |
| Compression::Null.encode(bytes); |
| codec::encode_vec_u16(bytes, &self.extensions); |
| } |
| |
| fn read(r: &mut Reader) -> Option<HelloRetryRequest> { |
| let session_id = SessionID::read(r)?; |
| let cipher_suite = CipherSuite::read(r)?; |
| let compression = Compression::read(r)?; |
| |
| if compression != Compression::Null { |
| return None; |
| } |
| |
| Some(HelloRetryRequest { |
| legacy_version: ProtocolVersion::Unknown(0), |
| session_id, |
| cipher_suite, |
| extensions: codec::read_vec_u16::<HelloRetryExtension>(r)?, |
| }) |
| } |
| } |
| |
| impl HelloRetryRequest { |
| /// Returns true if there is more than one extension of a given |
| /// type. |
| pub fn has_duplicate_extension(&self) -> bool { |
| let mut seen = collections::HashSet::new(); |
| |
| for ext in &self.extensions { |
| let typ = ext.get_type().get_u16(); |
| |
| if seen.contains(&typ) { |
| return true; |
| } |
| seen.insert(typ); |
| } |
| |
| false |
| } |
| |
| pub fn has_unknown_extension(&self) -> bool { |
| self.extensions |
| .iter() |
| .any(|ext| { |
| ext.get_type() != ExtensionType::KeyShare && |
| ext.get_type() != ExtensionType::SupportedVersions && |
| ext.get_type() != ExtensionType::Cookie |
| }) |
| } |
| |
| fn find_extension(&self, ext: ExtensionType) -> Option<&HelloRetryExtension> { |
| self.extensions.iter().find(|x| x.get_type() == ext) |
| } |
| |
| pub fn get_requested_key_share_group(&self) -> Option<NamedGroup> { |
| let ext = self.find_extension(ExtensionType::KeyShare)?; |
| match *ext { |
| HelloRetryExtension::KeyShare(grp) => Some(grp), |
| _ => None, |
| } |
| } |
| |
| pub fn get_cookie(&self) -> Option<&PayloadU16> { |
| let ext = self.find_extension(ExtensionType::Cookie)?; |
| match *ext { |
| HelloRetryExtension::Cookie(ref ck) => Some(ck), |
| _ => None, |
| } |
| } |
| |
| pub fn get_supported_versions(&self) -> Option<ProtocolVersion> { |
| let ext = self.find_extension(ExtensionType::SupportedVersions)?; |
| match *ext { |
| HelloRetryExtension::SupportedVersions(ver) => Some(ver), |
| _ => None, |
| } |
| } |
| } |
| |
| #[derive(Debug)] |
| pub struct ServerHelloPayload { |
| pub legacy_version: ProtocolVersion, |
| pub random: Random, |
| pub session_id: SessionID, |
| pub cipher_suite: CipherSuite, |
| pub compression_method: Compression, |
| pub extensions: Vec<ServerExtension>, |
| } |
| |
| impl Codec for ServerHelloPayload { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.legacy_version.encode(bytes); |
| self.random.encode(bytes); |
| |
| self.session_id.encode(bytes); |
| self.cipher_suite.encode(bytes); |
| self.compression_method.encode(bytes); |
| |
| if !self.extensions.is_empty() { |
| codec::encode_vec_u16(bytes, &self.extensions); |
| } |
| } |
| |
| // minus version and random, which have already been read. |
| fn read(r: &mut Reader) -> Option<ServerHelloPayload> { |
| let session_id = SessionID::read(r)?; |
| let suite = CipherSuite::read(r)?; |
| let compression = Compression::read(r)?; |
| |
| let mut ret = ServerHelloPayload { |
| legacy_version: ProtocolVersion::Unknown(0), |
| random: ZERO_RANDOM.clone(), |
| session_id, |
| cipher_suite: suite, |
| compression_method: compression, |
| extensions: Vec::new(), |
| }; |
| |
| if r.any_left() { |
| ret.extensions = codec::read_vec_u16::<ServerExtension>(r)?; |
| } |
| |
| Some(ret) |
| } |
| } |
| |
| impl HasServerExtensions for ServerHelloPayload { |
| fn get_extensions(&self) -> &[ServerExtension] { |
| &self.extensions |
| } |
| } |
| |
| impl ServerHelloPayload { |
| pub fn get_key_share(&self) -> Option<&KeyShareEntry> { |
| let ext = self.find_extension(ExtensionType::KeyShare)?; |
| match *ext { |
| ServerExtension::KeyShare(ref share) => Some(share), |
| _ => None, |
| } |
| } |
| |
| pub fn get_psk_index(&self) -> Option<u16> { |
| let ext = self.find_extension(ExtensionType::PreSharedKey)?; |
| match *ext { |
| ServerExtension::PresharedKey(ref index) => Some(*index), |
| _ => None, |
| } |
| } |
| |
| pub fn get_ecpoints_extension(&self) -> Option<&ECPointFormatList> { |
| let ext = self.find_extension(ExtensionType::ECPointFormats)?; |
| match *ext { |
| ServerExtension::ECPointFormats(ref fmts) => Some(fmts), |
| _ => None, |
| } |
| } |
| |
| pub fn ems_support_acked(&self) -> bool { |
| self.find_extension(ExtensionType::ExtendedMasterSecret) |
| .is_some() |
| } |
| |
| pub fn get_sct_list(&self) -> Option<&SCTList> { |
| let ext = self.find_extension(ExtensionType::SCT)?; |
| match *ext { |
| ServerExtension::SignedCertificateTimestamp(ref sctl) => Some(sctl), |
| _ => None, |
| } |
| } |
| |
| pub fn get_supported_versions(&self) -> Option<ProtocolVersion> { |
| let ext = self.find_extension(ExtensionType::SupportedVersions)?; |
| match *ext { |
| ServerExtension::SupportedVersions(vers) => Some(vers), |
| _ => None, |
| } |
| } |
| } |
| |
| pub type CertificatePayload = Vec<key::Certificate>; |
| |
| impl Codec for CertificatePayload { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| codec::encode_vec_u24(bytes, self); |
| } |
| |
| fn read(r: &mut Reader) -> Option<CertificatePayload> { |
| // 64KB of certificates is plenty, 16MB is obviously silly |
| codec::read_vec_u24_limited(r, 0x10000) |
| } |
| } |
| |
| // TLS1.3 changes the Certificate payload encoding. |
| // That's annoying. It means the parsing is not |
| // context-free any more. |
| |
| #[derive(Debug)] |
| pub enum CertificateExtension { |
| CertificateStatus(CertificateStatus), |
| SignedCertificateTimestamp(SCTList), |
| Unknown(UnknownExtension), |
| } |
| |
| impl CertificateExtension { |
| pub fn get_type(&self) -> ExtensionType { |
| match *self { |
| CertificateExtension::CertificateStatus(_) => ExtensionType::StatusRequest, |
| CertificateExtension::SignedCertificateTimestamp(_) => ExtensionType::SCT, |
| CertificateExtension::Unknown(ref r) => r.typ, |
| } |
| } |
| |
| pub fn make_sct(sct_list: Vec<u8>) -> CertificateExtension { |
| let sctl = SCTList::read_bytes(&sct_list) |
| .expect("invalid SCT list"); |
| CertificateExtension::SignedCertificateTimestamp(sctl) |
| } |
| |
| pub fn get_cert_status(&self) -> Option<&Vec<u8>> { |
| match *self { |
| CertificateExtension::CertificateStatus(ref cs) => Some(&cs.ocsp_response.0), |
| _ => None |
| } |
| } |
| |
| pub fn get_sct_list(&self) -> Option<&SCTList> { |
| match *self { |
| CertificateExtension::SignedCertificateTimestamp(ref sctl) => Some(sctl), |
| _ => None |
| } |
| } |
| } |
| |
| impl Codec for CertificateExtension { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.get_type().encode(bytes); |
| |
| let mut sub: Vec<u8> = Vec::new(); |
| match *self { |
| CertificateExtension::CertificateStatus(ref r) => r.encode(&mut sub), |
| CertificateExtension::SignedCertificateTimestamp(ref r) => r.encode(&mut sub), |
| CertificateExtension::Unknown(ref r) => r.encode(&mut sub), |
| } |
| |
| (sub.len() as u16).encode(bytes); |
| bytes.append(&mut sub); |
| } |
| |
| fn read(r: &mut Reader) -> Option<CertificateExtension> { |
| let typ = ExtensionType::read(r)?; |
| let len = u16::read(r)? as usize; |
| let mut sub = r.sub(len)?; |
| |
| Some(match typ { |
| ExtensionType::StatusRequest => { |
| let st = CertificateStatus::read(&mut sub)?; |
| CertificateExtension::CertificateStatus(st) |
| } |
| ExtensionType::SCT => { |
| let scts = SCTList::read(&mut sub)?; |
| CertificateExtension::SignedCertificateTimestamp(scts) |
| } |
| _ => CertificateExtension::Unknown(UnknownExtension::read(typ, &mut sub)?), |
| }) |
| } |
| } |
| |
| declare_u16_vec!(CertificateExtensions, CertificateExtension); |
| |
| #[derive(Debug)] |
| pub struct CertificateEntry { |
| pub cert: key::Certificate, |
| pub exts: CertificateExtensions, |
| } |
| |
| impl Codec for CertificateEntry { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.cert.encode(bytes); |
| self.exts.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<CertificateEntry> { |
| Some(CertificateEntry { |
| cert: key::Certificate::read(r)?, |
| exts: CertificateExtensions::read(r)?, |
| }) |
| } |
| } |
| |
| impl CertificateEntry { |
| pub fn new(cert: key::Certificate) -> CertificateEntry { |
| CertificateEntry { |
| cert, |
| exts: Vec::new(), |
| } |
| } |
| |
| pub fn has_duplicate_extension(&self) -> bool { |
| let mut seen = collections::HashSet::new(); |
| |
| for ext in &self.exts { |
| let typ = ext.get_type().get_u16(); |
| |
| if seen.contains(&typ) { |
| return true; |
| } |
| seen.insert(typ); |
| } |
| |
| false |
| } |
| |
| pub fn has_unknown_extension(&self) -> bool { |
| self.exts |
| .iter() |
| .any(|ext| { |
| ext.get_type() != ExtensionType::StatusRequest && |
| ext.get_type() != ExtensionType::SCT |
| }) |
| } |
| |
| pub fn get_ocsp_response(&self) -> Option<&Vec<u8>> { |
| self.exts |
| .iter() |
| .find(|ext| ext.get_type() == ExtensionType::StatusRequest) |
| .and_then(CertificateExtension::get_cert_status) |
| } |
| |
| pub fn get_scts(&self) -> Option<&SCTList> { |
| self.exts |
| .iter() |
| .find(|ext| ext.get_type() == ExtensionType::SCT) |
| .and_then(CertificateExtension::get_sct_list) |
| } |
| } |
| |
| #[derive(Debug)] |
| pub struct CertificatePayloadTLS13 { |
| pub context: PayloadU8, |
| pub entries: Vec<CertificateEntry>, |
| } |
| |
| impl Codec for CertificatePayloadTLS13 { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.context.encode(bytes); |
| codec::encode_vec_u24(bytes, &self.entries); |
| } |
| |
| fn read(r: &mut Reader) -> Option<CertificatePayloadTLS13> { |
| Some(CertificatePayloadTLS13 { |
| context: PayloadU8::read(r)?, |
| entries: codec::read_vec_u24_limited::<CertificateEntry>(r, 0x10000)?, |
| }) |
| } |
| } |
| |
| impl CertificatePayloadTLS13 { |
| pub fn new(entries: Vec<CertificateEntry>) -> CertificatePayloadTLS13 { |
| CertificatePayloadTLS13 { |
| context: PayloadU8::empty(), |
| entries, |
| } |
| } |
| |
| pub fn any_entry_has_duplicate_extension(&self) -> bool { |
| for entry in &self.entries { |
| if entry.has_duplicate_extension() { |
| return true; |
| } |
| } |
| |
| false |
| } |
| |
| pub fn any_entry_has_unknown_extension(&self) -> bool { |
| for entry in &self.entries { |
| if entry.has_unknown_extension() { |
| return true; |
| } |
| } |
| |
| false |
| } |
| |
| pub fn any_entry_has_extension(&self) -> bool { |
| for entry in &self.entries { |
| if !entry.exts.is_empty() { |
| return true; |
| } |
| } |
| |
| false |
| } |
| |
| pub fn get_end_entity_ocsp(&self) -> Vec<u8> { |
| self.entries.first() |
| .and_then(CertificateEntry::get_ocsp_response) |
| .cloned() |
| .unwrap_or_else( Vec::new) |
| } |
| |
| pub fn get_end_entity_scts(&self) -> Option<SCTList> { |
| self.entries.first() |
| .and_then(CertificateEntry::get_scts) |
| .cloned() |
| } |
| |
| pub fn convert(&self) -> CertificatePayload { |
| let mut ret = Vec::new(); |
| for entry in &self.entries { |
| ret.push(entry.cert.clone()); |
| } |
| ret |
| } |
| } |
| |
| #[derive(Debug)] |
| pub enum KeyExchangeAlgorithm { |
| BulkOnly, |
| DH, |
| DHE, |
| RSA, |
| ECDH, |
| ECDHE, |
| } |
| |
| // We don't support arbitrary curves. It's a terrible |
| // idea and unnecessary attack surface. Please, |
| // get a grip. |
| #[derive(Debug)] |
| pub struct ECParameters { |
| pub curve_type: ECCurveType, |
| pub named_group: NamedGroup, |
| } |
| |
| impl Codec for ECParameters { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.curve_type.encode(bytes); |
| self.named_group.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<ECParameters> { |
| let ct = ECCurveType::read(r)?; |
| |
| if ct != ECCurveType::NamedCurve { |
| return None; |
| } |
| |
| let grp = NamedGroup::read(r)?; |
| |
| Some(ECParameters { |
| curve_type: ct, |
| named_group: grp, |
| }) |
| } |
| } |
| |
| #[derive(Debug, Clone)] |
| pub struct DigitallySignedStruct { |
| pub scheme: SignatureScheme, |
| pub sig: PayloadU16, |
| } |
| |
| impl DigitallySignedStruct { |
| pub fn new(scheme: SignatureScheme, sig: Vec<u8>) -> DigitallySignedStruct { |
| DigitallySignedStruct { |
| scheme, |
| sig: PayloadU16::new(sig), |
| } |
| } |
| } |
| |
| impl Codec for DigitallySignedStruct { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.scheme.encode(bytes); |
| self.sig.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<DigitallySignedStruct> { |
| let scheme = SignatureScheme::read(r)?; |
| let sig = PayloadU16::read(r)?; |
| |
| Some(DigitallySignedStruct { |
| scheme, |
| sig, |
| }) |
| } |
| } |
| |
| #[derive(Debug)] |
| pub struct ClientECDHParams { |
| pub public: PayloadU8, |
| } |
| |
| impl Codec for ClientECDHParams { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.public.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<ClientECDHParams> { |
| let pb = PayloadU8::read(r)?; |
| Some(ClientECDHParams { public: pb }) |
| } |
| } |
| |
| #[derive(Debug)] |
| pub struct ServerECDHParams { |
| pub curve_params: ECParameters, |
| pub public: PayloadU8, |
| } |
| |
| impl ServerECDHParams { |
| pub fn new(named_group: NamedGroup, pubkey: &[u8]) -> ServerECDHParams { |
| ServerECDHParams { |
| curve_params: ECParameters { |
| curve_type: ECCurveType::NamedCurve, |
| named_group, |
| }, |
| public: PayloadU8::new(pubkey.to_vec()), |
| } |
| } |
| } |
| |
| impl Codec for ServerECDHParams { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.curve_params.encode(bytes); |
| self.public.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<ServerECDHParams> { |
| let cp = ECParameters::read(r)?; |
| let pb = PayloadU8::read(r)?; |
| |
| Some(ServerECDHParams { |
| curve_params: cp, |
| public: pb, |
| }) |
| } |
| } |
| |
| #[derive(Debug)] |
| pub struct ECDHEServerKeyExchange { |
| pub params: ServerECDHParams, |
| pub dss: DigitallySignedStruct, |
| } |
| |
| impl Codec for ECDHEServerKeyExchange { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.params.encode(bytes); |
| self.dss.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<ECDHEServerKeyExchange> { |
| let params = ServerECDHParams::read(r)?; |
| let dss = DigitallySignedStruct::read(r)?; |
| |
| Some(ECDHEServerKeyExchange { |
| params, |
| dss, |
| }) |
| } |
| } |
| |
| #[derive(Debug)] |
| pub enum ServerKeyExchangePayload { |
| ECDHE(ECDHEServerKeyExchange), |
| Unknown(Payload), |
| } |
| |
| impl Codec for ServerKeyExchangePayload { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| match *self { |
| ServerKeyExchangePayload::ECDHE(ref x) => x.encode(bytes), |
| ServerKeyExchangePayload::Unknown(ref x) => x.encode(bytes), |
| } |
| } |
| |
| fn read(r: &mut Reader) -> Option<ServerKeyExchangePayload> { |
| // read as Unknown, fully parse when we know the |
| // KeyExchangeAlgorithm |
| Payload::read(r).map(ServerKeyExchangePayload::Unknown) |
| } |
| } |
| |
| impl ServerKeyExchangePayload { |
| pub fn unwrap_given_kxa(&self, kxa: &KeyExchangeAlgorithm) -> Option<ServerKeyExchangePayload> { |
| if let ServerKeyExchangePayload::Unknown(ref unk) = *self { |
| let mut rd = Reader::init(&unk.0); |
| |
| let result = match *kxa { |
| KeyExchangeAlgorithm::ECDHE => { |
| ECDHEServerKeyExchange::read(&mut rd) |
| .map(ServerKeyExchangePayload::ECDHE) |
| } |
| _ => None, |
| }; |
| |
| if !rd.any_left() { |
| return result; |
| }; |
| } |
| |
| None |
| } |
| |
| pub fn encode_params(&self, bytes: &mut Vec<u8>) { |
| bytes.clear(); |
| |
| if let ServerKeyExchangePayload::ECDHE(ref x) = *self { |
| x.params.encode(bytes); |
| } |
| } |
| |
| pub fn get_sig(&self) -> Option<DigitallySignedStruct> { |
| match *self { |
| ServerKeyExchangePayload::ECDHE(ref x) => Some(x.dss.clone()), |
| _ => None, |
| } |
| } |
| } |
| |
| // -- EncryptedExtensions (TLS1.3 only) -- |
| declare_u16_vec!(EncryptedExtensions, ServerExtension); |
| |
| pub trait HasServerExtensions { |
| fn get_extensions(&self) -> &[ServerExtension]; |
| |
| /// Returns true if there is more than one extension of a given |
| /// type. |
| fn has_duplicate_extension(&self) -> bool { |
| let mut seen = collections::HashSet::new(); |
| |
| for ext in self.get_extensions() { |
| let typ = ext.get_type().get_u16(); |
| |
| if seen.contains(&typ) { |
| return true; |
| } |
| seen.insert(typ); |
| } |
| |
| false |
| } |
| |
| fn find_extension(&self, ext: ExtensionType) -> Option<&ServerExtension> { |
| self.get_extensions().iter().find(|x| x.get_type() == ext) |
| } |
| |
| fn get_alpn_protocol(&self) -> Option<&[u8]> { |
| let ext = self.find_extension(ExtensionType::ALProtocolNegotiation)?; |
| match *ext { |
| ServerExtension::Protocols(ref protos) => protos.as_single_slice(), |
| _ => None, |
| } |
| } |
| |
| fn get_quic_params_extension(&self) -> Option<Vec<u8>> { |
| let ext = self.find_extension(ExtensionType::TransportParameters)?; |
| match *ext { |
| ServerExtension::TransportParameters(ref bytes) => Some(bytes.to_vec()), |
| _ => None, |
| } |
| } |
| |
| fn early_data_extension_offered(&self) -> bool { |
| self.find_extension(ExtensionType::EarlyData).is_some() |
| } |
| } |
| |
| impl HasServerExtensions for EncryptedExtensions { |
| fn get_extensions(&self) -> &[ServerExtension] { |
| self |
| } |
| } |
| |
| // -- CertificateRequest and sundries -- |
| declare_u8_vec!(ClientCertificateTypes, ClientCertificateType); |
| pub type DistinguishedName = PayloadU16; |
| pub type DistinguishedNames = VecU16OfPayloadU16; |
| |
| #[derive(Debug)] |
| pub struct CertificateRequestPayload { |
| pub certtypes: ClientCertificateTypes, |
| pub sigschemes: SupportedSignatureSchemes, |
| pub canames: DistinguishedNames, |
| } |
| |
| impl Codec for CertificateRequestPayload { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.certtypes.encode(bytes); |
| self.sigschemes.encode(bytes); |
| self.canames.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<CertificateRequestPayload> { |
| let certtypes = ClientCertificateTypes::read(r)?; |
| let sigschemes = SupportedSignatureSchemes::read(r)?; |
| let canames = DistinguishedNames::read(r)?; |
| |
| Some(CertificateRequestPayload { |
| certtypes, |
| sigschemes, |
| canames, |
| }) |
| } |
| } |
| |
| #[derive(Debug)] |
| pub enum CertReqExtension { |
| SignatureAlgorithms(SupportedSignatureSchemes), |
| AuthorityNames(DistinguishedNames), |
| Unknown(UnknownExtension), |
| } |
| |
| impl CertReqExtension { |
| pub fn get_type(&self) -> ExtensionType { |
| match *self { |
| CertReqExtension::SignatureAlgorithms(_) => ExtensionType::SignatureAlgorithms, |
| CertReqExtension::AuthorityNames(_) => ExtensionType::CertificateAuthorities, |
| CertReqExtension::Unknown(ref r) => r.typ, |
| } |
| } |
| } |
| |
| impl Codec for CertReqExtension { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.get_type().encode(bytes); |
| |
| let mut sub: Vec<u8> = Vec::new(); |
| match *self { |
| CertReqExtension::SignatureAlgorithms(ref r) => r.encode(&mut sub), |
| CertReqExtension::AuthorityNames(ref r) => r.encode(&mut sub), |
| CertReqExtension::Unknown(ref r) => r.encode(&mut sub), |
| } |
| |
| (sub.len() as u16).encode(bytes); |
| bytes.append(&mut sub); |
| } |
| |
| fn read(r: &mut Reader) -> Option<CertReqExtension> { |
| let typ = ExtensionType::read(r)?; |
| let len = u16::read(r)? as usize; |
| let mut sub = r.sub(len)?; |
| |
| Some(match typ { |
| ExtensionType::SignatureAlgorithms => { |
| let schemes = SupportedSignatureSchemes::read(&mut sub)?; |
| if schemes.is_empty() { |
| return None; |
| } |
| CertReqExtension::SignatureAlgorithms(schemes) |
| } |
| ExtensionType::CertificateAuthorities => { |
| let cas = DistinguishedNames::read(&mut sub)?; |
| CertReqExtension::AuthorityNames(cas) |
| } |
| _ => CertReqExtension::Unknown(UnknownExtension::read(typ, &mut sub)?), |
| }) |
| } |
| } |
| |
| declare_u16_vec!(CertReqExtensions, CertReqExtension); |
| |
| #[derive(Debug)] |
| pub struct CertificateRequestPayloadTLS13 { |
| pub context: PayloadU8, |
| pub extensions: CertReqExtensions, |
| } |
| |
| impl Codec for CertificateRequestPayloadTLS13 { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.context.encode(bytes); |
| self.extensions.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<CertificateRequestPayloadTLS13> { |
| let context = PayloadU8::read(r)?; |
| let extensions = CertReqExtensions::read(r)?; |
| |
| Some(CertificateRequestPayloadTLS13 { |
| context, |
| extensions, |
| }) |
| } |
| } |
| |
| impl CertificateRequestPayloadTLS13 { |
| pub fn find_extension(&self, ext: ExtensionType) -> Option<&CertReqExtension> { |
| self.extensions.iter().find(|x| x.get_type() == ext) |
| } |
| |
| pub fn get_sigalgs_extension(&self) -> Option<&SupportedSignatureSchemes> { |
| let ext = self.find_extension(ExtensionType::SignatureAlgorithms)?; |
| match *ext { |
| CertReqExtension::SignatureAlgorithms(ref sa) => Some(sa), |
| _ => None, |
| } |
| } |
| |
| pub fn get_authorities_extension(&self) -> Option<&DistinguishedNames> { |
| let ext = self.find_extension(ExtensionType::CertificateAuthorities)?; |
| match *ext { |
| CertReqExtension::AuthorityNames(ref an) => Some(an), |
| _ => None, |
| } |
| } |
| } |
| |
| // -- NewSessionTicket -- |
| #[derive(Debug)] |
| pub struct NewSessionTicketPayload { |
| pub lifetime_hint: u32, |
| pub ticket: PayloadU16, |
| } |
| |
| impl NewSessionTicketPayload { |
| pub fn new(lifetime_hint: u32, ticket: Vec<u8>) -> NewSessionTicketPayload { |
| NewSessionTicketPayload { |
| lifetime_hint, |
| ticket: PayloadU16::new(ticket), |
| } |
| } |
| } |
| |
| impl Codec for NewSessionTicketPayload { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.lifetime_hint.encode(bytes); |
| self.ticket.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<NewSessionTicketPayload> { |
| let lifetime = u32::read(r)?; |
| let ticket = PayloadU16::read(r)?; |
| |
| Some(NewSessionTicketPayload { |
| lifetime_hint: lifetime, |
| ticket, |
| }) |
| } |
| } |
| |
| // -- NewSessionTicket electric boogaloo -- |
| #[derive(Debug)] |
| pub enum NewSessionTicketExtension { |
| EarlyData(u32), |
| Unknown(UnknownExtension), |
| } |
| |
| impl NewSessionTicketExtension { |
| pub fn get_type(&self) -> ExtensionType { |
| match *self { |
| NewSessionTicketExtension::EarlyData(_) => ExtensionType::EarlyData, |
| NewSessionTicketExtension::Unknown(ref r) => r.typ, |
| } |
| } |
| } |
| |
| impl Codec for NewSessionTicketExtension { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.get_type().encode(bytes); |
| |
| let mut sub: Vec<u8> = Vec::new(); |
| match *self { |
| NewSessionTicketExtension::EarlyData(r) => r.encode(&mut sub), |
| NewSessionTicketExtension::Unknown(ref r) => r.encode(&mut sub), |
| } |
| |
| (sub.len() as u16).encode(bytes); |
| bytes.append(&mut sub); |
| } |
| |
| fn read(r: &mut Reader) -> Option<NewSessionTicketExtension> { |
| let typ = ExtensionType::read(r)?; |
| let len = u16::read(r)? as usize; |
| let mut sub = r.sub(len)?; |
| |
| Some(match typ { |
| ExtensionType::EarlyData => NewSessionTicketExtension::EarlyData(u32::read(&mut sub)?), |
| _ => { |
| NewSessionTicketExtension::Unknown(UnknownExtension::read(typ, &mut sub)?) |
| } |
| }) |
| } |
| } |
| |
| declare_u16_vec!(NewSessionTicketExtensions, NewSessionTicketExtension); |
| |
| #[derive(Debug)] |
| pub struct NewSessionTicketPayloadTLS13 { |
| pub lifetime: u32, |
| pub age_add: u32, |
| pub nonce: PayloadU8, |
| pub ticket: PayloadU16, |
| pub exts: NewSessionTicketExtensions, |
| } |
| |
| impl NewSessionTicketPayloadTLS13 { |
| pub fn new(lifetime: u32, |
| age_add: u32, |
| nonce: Vec<u8>, |
| ticket: Vec<u8>) -> NewSessionTicketPayloadTLS13 { |
| NewSessionTicketPayloadTLS13 { |
| lifetime, |
| age_add, |
| nonce: PayloadU8::new(nonce), |
| ticket: PayloadU16::new(ticket), |
| exts: vec![], |
| } |
| } |
| |
| pub fn find_extension(&self, ext: ExtensionType) -> Option<&NewSessionTicketExtension> { |
| self.exts.iter().find(|x| x.get_type() == ext) |
| } |
| |
| pub fn get_max_early_data_size(&self) -> Option<u32> { |
| let ext = self.find_extension(ExtensionType::EarlyData)?; |
| match *ext { |
| NewSessionTicketExtension::EarlyData(ref sz) => Some(*sz), |
| _ => None |
| } |
| } |
| } |
| |
| impl Codec for NewSessionTicketPayloadTLS13 { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| self.lifetime.encode(bytes); |
| self.age_add.encode(bytes); |
| self.nonce.encode(bytes); |
| self.ticket.encode(bytes); |
| self.exts.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<NewSessionTicketPayloadTLS13> { |
| let lifetime = u32::read(r)?; |
| let age_add = u32::read(r)?; |
| let nonce = PayloadU8::read(r)?; |
| let ticket = PayloadU16::read(r)?; |
| let exts = NewSessionTicketExtensions::read(r)?; |
| |
| Some(NewSessionTicketPayloadTLS13 { |
| lifetime, |
| age_add, |
| nonce, |
| ticket, |
| exts, |
| }) |
| } |
| } |
| |
| // -- RFC6066 certificate status types |
| |
| /// Only supports OCSP |
| #[derive(Debug)] |
| pub struct CertificateStatus { |
| pub ocsp_response: PayloadU24 |
| } |
| |
| impl Codec for CertificateStatus { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| CertificateStatusType::OCSP.encode(bytes); |
| self.ocsp_response.encode(bytes); |
| } |
| |
| fn read(r: &mut Reader) -> Option<CertificateStatus> { |
| let typ = CertificateStatusType::read(r)?; |
| |
| match typ { |
| CertificateStatusType::OCSP => { |
| Some(CertificateStatus { |
| ocsp_response: PayloadU24::read(r)? |
| }) |
| } |
| _ => None |
| } |
| } |
| } |
| |
| impl CertificateStatus { |
| pub fn new(ocsp: Vec<u8>) -> CertificateStatus { |
| CertificateStatus { ocsp_response: PayloadU24::new(ocsp) } |
| } |
| |
| pub fn take_ocsp_response(&mut self) -> Vec<u8> { |
| let new = PayloadU24::new(Vec::new()); |
| mem::replace(&mut self.ocsp_response, new).0 |
| } |
| } |
| |
| #[derive(Debug)] |
| pub enum HandshakePayload { |
| HelloRequest, |
| ClientHello(ClientHelloPayload), |
| ServerHello(ServerHelloPayload), |
| HelloRetryRequest(HelloRetryRequest), |
| Certificate(CertificatePayload), |
| CertificateTLS13(CertificatePayloadTLS13), |
| ServerKeyExchange(ServerKeyExchangePayload), |
| CertificateRequest(CertificateRequestPayload), |
| CertificateRequestTLS13(CertificateRequestPayloadTLS13), |
| CertificateVerify(DigitallySignedStruct), |
| ServerHelloDone, |
| EarlyData, |
| EndOfEarlyData, |
| ClientKeyExchange(Payload), |
| NewSessionTicket(NewSessionTicketPayload), |
| NewSessionTicketTLS13(NewSessionTicketPayloadTLS13), |
| EncryptedExtensions(EncryptedExtensions), |
| KeyUpdate(KeyUpdateRequest), |
| Finished(Payload), |
| CertificateStatus(CertificateStatus), |
| MessageHash(Payload), |
| Unknown(Payload), |
| } |
| |
| impl HandshakePayload { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| match *self { |
| HandshakePayload::HelloRequest | |
| HandshakePayload::ServerHelloDone | |
| HandshakePayload::EarlyData | |
| HandshakePayload::EndOfEarlyData => {} |
| HandshakePayload::ClientHello(ref x) => x.encode(bytes), |
| HandshakePayload::ServerHello(ref x) => x.encode(bytes), |
| HandshakePayload::HelloRetryRequest(ref x) => x.encode(bytes), |
| HandshakePayload::Certificate(ref x) => x.encode(bytes), |
| HandshakePayload::CertificateTLS13(ref x) => x.encode(bytes), |
| HandshakePayload::ServerKeyExchange(ref x) => x.encode(bytes), |
| HandshakePayload::ClientKeyExchange(ref x) => x.encode(bytes), |
| HandshakePayload::CertificateRequest(ref x) => x.encode(bytes), |
| HandshakePayload::CertificateRequestTLS13(ref x) => x.encode(bytes), |
| HandshakePayload::CertificateVerify(ref x) => x.encode(bytes), |
| HandshakePayload::NewSessionTicket(ref x) => x.encode(bytes), |
| HandshakePayload::NewSessionTicketTLS13(ref x) => x.encode(bytes), |
| HandshakePayload::EncryptedExtensions(ref x) => x.encode(bytes), |
| HandshakePayload::KeyUpdate(ref x) => x.encode(bytes), |
| HandshakePayload::Finished(ref x) => x.encode(bytes), |
| HandshakePayload::CertificateStatus(ref x) => x.encode(bytes), |
| HandshakePayload::MessageHash(ref x) => x.encode(bytes), |
| HandshakePayload::Unknown(ref x) => x.encode(bytes), |
| } |
| } |
| } |
| |
| #[derive(Debug)] |
| pub struct HandshakeMessagePayload { |
| pub typ: HandshakeType, |
| pub payload: HandshakePayload, |
| } |
| |
| impl Codec for HandshakeMessagePayload { |
| fn encode(&self, bytes: &mut Vec<u8>) { |
| // encode payload to learn length |
| let mut sub: Vec<u8> = Vec::new(); |
| self.payload.encode(&mut sub); |
| |
| // output type, length, and encoded payload |
| match self.typ { |
| HandshakeType::HelloRetryRequest => HandshakeType::ServerHello, |
| _ => self.typ, |
| }.encode(bytes); |
| codec::u24(sub.len() as u32).encode(bytes); |
| bytes.append(&mut sub); |
| } |
| |
| fn read(r: &mut Reader) -> Option<HandshakeMessagePayload> { |
| HandshakeMessagePayload::read_version(r, ProtocolVersion::TLSv1_2) |
| } |
| } |
| |
| impl HandshakeMessagePayload { |
| pub fn length(&self) -> usize { |
| let mut buf = Vec::new(); |
| self.encode(&mut buf); |
| buf.len() |
| } |
| |
| pub fn read_version(r: &mut Reader, vers: ProtocolVersion) -> Option<HandshakeMessagePayload> { |
| let mut typ = HandshakeType::read(r)?; |
| let len = codec::u24::read(r)?.0 as usize; |
| let mut sub = r.sub(len)?; |
| |
| let payload = match typ { |
| HandshakeType::HelloRequest if sub.left() == 0 => HandshakePayload::HelloRequest, |
| HandshakeType::ClientHello => { |
| HandshakePayload::ClientHello(ClientHelloPayload::read(&mut sub)?) |
| } |
| HandshakeType::ServerHello => { |
| let version = ProtocolVersion::read(&mut sub)?; |
| let random = Random::read(&mut sub)?; |
| |
| if random == HELLO_RETRY_REQUEST_RANDOM { |
| let mut hrr = HelloRetryRequest::read(&mut sub)?; |
| hrr.legacy_version = version; |
| typ = HandshakeType::HelloRetryRequest; |
| HandshakePayload::HelloRetryRequest(hrr) |
| } else { |
| let mut shp = ServerHelloPayload::read(&mut sub)?; |
| shp.legacy_version = version; |
| shp.random = random; |
| HandshakePayload::ServerHello(shp) |
| } |
| } |
| HandshakeType::Certificate if vers == ProtocolVersion::TLSv1_3 => { |
| let p = CertificatePayloadTLS13::read(&mut sub)?; |
| HandshakePayload::CertificateTLS13(p) |
| } |
| HandshakeType::Certificate => { |
| HandshakePayload::Certificate(CertificatePayload::read(&mut sub)?) |
| } |
| HandshakeType::ServerKeyExchange => { |
| let p = ServerKeyExchangePayload::read(&mut sub)?; |
| HandshakePayload::ServerKeyExchange(p) |
| } |
| HandshakeType::ServerHelloDone => { |
| if sub.any_left() { |
| return None; |
| } |
| HandshakePayload::ServerHelloDone |
| } |
| HandshakeType::ClientKeyExchange => { |
| HandshakePayload::ClientKeyExchange(Payload::read(&mut sub)?) |
| } |
| HandshakeType::CertificateRequest if vers == ProtocolVersion::TLSv1_3 => { |
| let p = CertificateRequestPayloadTLS13::read(&mut sub)?; |
| HandshakePayload::CertificateRequestTLS13(p) |
| } |
| HandshakeType::CertificateRequest => { |
| let p = CertificateRequestPayload::read(&mut sub)?; |
| HandshakePayload::CertificateRequest(p) |
| } |
| HandshakeType::CertificateVerify => { |
| HandshakePayload::CertificateVerify(DigitallySignedStruct::read(&mut sub)?) |
| } |
| HandshakeType::NewSessionTicket if vers == ProtocolVersion::TLSv1_3 => { |
| let p = NewSessionTicketPayloadTLS13::read(&mut sub)?; |
| HandshakePayload::NewSessionTicketTLS13(p) |
| } |
| HandshakeType::NewSessionTicket => { |
| let p = NewSessionTicketPayload::read(&mut sub)?; |
| HandshakePayload::NewSessionTicket(p) |
| } |
| HandshakeType::EncryptedExtensions => { |
| HandshakePayload::EncryptedExtensions(EncryptedExtensions::read(&mut sub)?) |
| } |
| HandshakeType::KeyUpdate => { |
| HandshakePayload::KeyUpdate(KeyUpdateRequest::read(&mut sub)?) |
| } |
| HandshakeType::Finished => { |
| HandshakePayload::Finished(Payload::read(&mut sub)?) |
| } |
| HandshakeType::CertificateStatus => { |
| HandshakePayload::CertificateStatus(CertificateStatus::read(&mut sub)?) |
| } |
| HandshakeType::MessageHash => { |
| // does not appear on the wire |
| return None; |
| } |
| HandshakeType::HelloRetryRequest => { |
| // not legal on wire |
| return None; |
| } |
| _ => HandshakePayload::Unknown(Payload::read(&mut sub)?), |
| }; |
| |
| if sub.any_left() { |
| None |
| } else { |
| Some(HandshakeMessagePayload { |
| typ, |
| payload, |
| }) |
| } |
| } |
| |
| pub fn build_key_update_notify() -> HandshakeMessagePayload { |
| HandshakeMessagePayload { |
| typ: HandshakeType::KeyUpdate, |
| payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), |
| } |
| } |
| |
| pub fn get_encoding_for_binder_signing(&self) -> Vec<u8> { |
| let mut ret = self.get_encoding(); |
| |
| let binder_len = match self.payload { |
| HandshakePayload::ClientHello(ref ch) => { |
| let offer = ch.get_psk().unwrap(); |
| |
| let mut binders_encoding = Vec::new(); |
| offer.binders.encode(&mut binders_encoding); |
| binders_encoding.len() |
| } |
| _ => 0, |
| }; |
| |
| let ret_len = ret.len() - binder_len; |
| ret.truncate(ret_len); |
| ret |
| } |
| |
| pub fn build_handshake_hash(hash: &[u8]) -> HandshakeMessagePayload { |
| HandshakeMessagePayload { |
| typ: HandshakeType::MessageHash, |
| payload: HandshakePayload::MessageHash(Payload::new(hash.to_vec())) |
| } |
| } |
| } |