1 #[cfg(test)] 2 mod alert_test; 3 4 use super::content::*; 5 use crate::error::Result; 6 7 use byteorder::{ReadBytesExt, WriteBytesExt}; 8 use std::fmt; 9 use std::io::{Read, Write}; 10 11 #[derive(Copy, Clone, PartialEq, Debug)] 12 pub(crate) enum AlertLevel { 13 Warning = 1, 14 Fatal = 2, 15 Invalid, 16 } 17 18 impl fmt::Display for AlertLevel { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 20 match *self { 21 AlertLevel::Warning => write!(f, "LevelWarning"), 22 AlertLevel::Fatal => write!(f, "LevelFatal"), 23 _ => write!(f, "Invalid alert level"), 24 } 25 } 26 } 27 28 impl From<u8> for AlertLevel { from(val: u8) -> Self29 fn from(val: u8) -> Self { 30 match val { 31 1 => AlertLevel::Warning, 32 2 => AlertLevel::Fatal, 33 _ => AlertLevel::Invalid, 34 } 35 } 36 } 37 38 #[derive(Copy, Clone, PartialEq, Debug)] 39 pub(crate) enum AlertDescription { 40 CloseNotify = 0, 41 UnexpectedMessage = 10, 42 BadRecordMac = 20, 43 DecryptionFailed = 21, 44 RecordOverflow = 22, 45 DecompressionFailure = 30, 46 HandshakeFailure = 40, 47 NoCertificate = 41, 48 BadCertificate = 42, 49 UnsupportedCertificate = 43, 50 CertificateRevoked = 44, 51 CertificateExpired = 45, 52 CertificateUnknown = 46, 53 IllegalParameter = 47, 54 UnknownCa = 48, 55 AccessDenied = 49, 56 DecodeError = 50, 57 DecryptError = 51, 58 ExportRestriction = 60, 59 ProtocolVersion = 70, 60 InsufficientSecurity = 71, 61 InternalError = 80, 62 UserCanceled = 90, 63 NoRenegotiation = 100, 64 UnsupportedExtension = 110, 65 Invalid, 66 } 67 68 impl fmt::Display for AlertDescription { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 70 match *self { 71 AlertDescription::CloseNotify => write!(f, "CloseNotify"), 72 AlertDescription::UnexpectedMessage => write!(f, "UnexpectedMessage"), 73 AlertDescription::BadRecordMac => write!(f, "BadRecordMac"), 74 AlertDescription::DecryptionFailed => write!(f, "DecryptionFailed"), 75 AlertDescription::RecordOverflow => write!(f, "RecordOverflow"), 76 AlertDescription::DecompressionFailure => write!(f, "DecompressionFailure"), 77 AlertDescription::HandshakeFailure => write!(f, "HandshakeFailure"), 78 AlertDescription::NoCertificate => write!(f, "NoCertificate"), 79 AlertDescription::BadCertificate => write!(f, "BadCertificate"), 80 AlertDescription::UnsupportedCertificate => write!(f, "UnsupportedCertificate"), 81 AlertDescription::CertificateRevoked => write!(f, "CertificateRevoked"), 82 AlertDescription::CertificateExpired => write!(f, "CertificateExpired"), 83 AlertDescription::CertificateUnknown => write!(f, "CertificateUnknown"), 84 AlertDescription::IllegalParameter => write!(f, "IllegalParameter"), 85 AlertDescription::UnknownCa => write!(f, "UnknownCA"), 86 AlertDescription::AccessDenied => write!(f, "AccessDenied"), 87 AlertDescription::DecodeError => write!(f, "DecodeError"), 88 AlertDescription::DecryptError => write!(f, "DecryptError"), 89 AlertDescription::ExportRestriction => write!(f, "ExportRestriction"), 90 AlertDescription::ProtocolVersion => write!(f, "ProtocolVersion"), 91 AlertDescription::InsufficientSecurity => write!(f, "InsufficientSecurity"), 92 AlertDescription::InternalError => write!(f, "InternalError"), 93 AlertDescription::UserCanceled => write!(f, "UserCanceled"), 94 AlertDescription::NoRenegotiation => write!(f, "NoRenegotiation"), 95 AlertDescription::UnsupportedExtension => write!(f, "UnsupportedExtension"), 96 _ => write!(f, "Invalid alert description"), 97 } 98 } 99 } 100 101 impl From<u8> for AlertDescription { from(val: u8) -> Self102 fn from(val: u8) -> Self { 103 match val { 104 0 => AlertDescription::CloseNotify, 105 10 => AlertDescription::UnexpectedMessage, 106 20 => AlertDescription::BadRecordMac, 107 21 => AlertDescription::DecryptionFailed, 108 22 => AlertDescription::RecordOverflow, 109 30 => AlertDescription::DecompressionFailure, 110 40 => AlertDescription::HandshakeFailure, 111 41 => AlertDescription::NoCertificate, 112 42 => AlertDescription::BadCertificate, 113 43 => AlertDescription::UnsupportedCertificate, 114 44 => AlertDescription::CertificateRevoked, 115 45 => AlertDescription::CertificateExpired, 116 46 => AlertDescription::CertificateUnknown, 117 47 => AlertDescription::IllegalParameter, 118 48 => AlertDescription::UnknownCa, 119 49 => AlertDescription::AccessDenied, 120 50 => AlertDescription::DecodeError, 121 51 => AlertDescription::DecryptError, 122 60 => AlertDescription::ExportRestriction, 123 70 => AlertDescription::ProtocolVersion, 124 71 => AlertDescription::InsufficientSecurity, 125 80 => AlertDescription::InternalError, 126 90 => AlertDescription::UserCanceled, 127 100 => AlertDescription::NoRenegotiation, 128 110 => AlertDescription::UnsupportedExtension, 129 _ => AlertDescription::Invalid, 130 } 131 } 132 } 133 134 // One of the content types supported by the TLS record layer is the 135 // alert type. Alert messages convey the severity of the message 136 // (warning or fatal) and a description of the alert. Alert messages 137 // with a level of fatal result in the immediate termination of the 138 // connection. In this case, other connections corresponding to the 139 // session may continue, but the session identifier MUST be invalidated, 140 // preventing the failed session from being used to establish new 141 // connections. Like other messages, alert messages are encrypted and 142 // compressed, as specified by the current connection state. 143 // https://tools.ietf.org/html/rfc5246#section-7.2 144 #[derive(Copy, Clone, PartialEq, Debug)] 145 pub struct Alert { 146 pub(crate) alert_level: AlertLevel, 147 pub(crate) alert_description: AlertDescription, 148 } 149 150 impl fmt::Display for Alert { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 152 write!(f, "Alert {}: {}", self.alert_level, self.alert_description) 153 } 154 } 155 156 impl Alert { content_type(&self) -> ContentType157 pub fn content_type(&self) -> ContentType { 158 ContentType::Alert 159 } 160 size(&self) -> usize161 pub fn size(&self) -> usize { 162 2 163 } 164 marshal<W: Write>(&self, writer: &mut W) -> Result<()>165 pub fn marshal<W: Write>(&self, writer: &mut W) -> Result<()> { 166 writer.write_u8(self.alert_level as u8)?; 167 writer.write_u8(self.alert_description as u8)?; 168 169 Ok(writer.flush()?) 170 } 171 unmarshal<R: Read>(reader: &mut R) -> Result<Self>172 pub fn unmarshal<R: Read>(reader: &mut R) -> Result<Self> { 173 let alert_level = reader.read_u8()?.into(); 174 let alert_description = reader.read_u8()?.into(); 175 176 Ok(Alert { 177 alert_level, 178 alert_description, 179 }) 180 } 181 } 182