| // Copyright 2026 The BoringSSL Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| //! TLS Alerts |
| |
| use core::{ |
| ffi::{CStr, c_int}, |
| fmt, |
| }; |
| |
| use bssl_macros::bssl_enum; |
| |
| bssl_enum! { |
| #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| #[non_exhaustive] |
| /// TLS alert description |
| /// |
| /// These alert variants have [IANA entries]. |
| /// |
| /// [IANA entries]: <https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-6> |
| pub enum AlertDescription : u8 { |
| /// `close_notify` |
| /// |
| /// This alert notifies the recipient that the sender will not send any more messages on |
| /// this connection. |
| /// Any data received after a closure alert has been received MUST be ignored. |
| CloseNotify = bssl_sys::SSL_AD_CLOSE_NOTIFY as u8, |
| /// `unexpected_message` |
| /// |
| /// This alert signals a fatal error. |
| /// The connection must be terminated. |
| UnexpectedMessage = bssl_sys::SSL_AD_UNEXPECTED_MESSAGE as u8, |
| /// `bad_record_mac` |
| /// |
| /// This alert signals a fatal decryption error. |
| /// The connection must be terminated. |
| BadRecordMac = bssl_sys::SSL_AD_BAD_RECORD_MAC as u8, |
| /// `decryption_failed`, reserved and used up until TLS 1.3. |
| DecryptionFailed = bssl_sys::SSL_AD_DECRYPTION_FAILED as u8, |
| /// `record_overflow` |
| /// |
| /// This alert signals that a record of length more than 2^14 bytes |
| /// was received. |
| /// The connection must be terminated. |
| RecordOverflow = bssl_sys::SSL_AD_RECORD_OVERFLOW as u8, |
| /// `decompression_failure`, reserved and used up until TLS 1.3. |
| DecompressionFailure = bssl_sys::SSL_AD_DECOMPRESSION_FAILURE as u8, |
| /// `handshake_failure` |
| /// |
| /// This alert signals a fatal handshake error due to failure to negotiate a supported |
| /// set of parameters. |
| /// The handshake must be aborted. |
| HandshakeFailure = bssl_sys::SSL_AD_HANDSHAKE_FAILURE as u8, |
| /// `no_certificate`, reserved and used up until TLS 1.3. |
| NoCertificate = bssl_sys::SSL_AD_NO_CERTIFICATE as u8, |
| /// `bad_certificate` |
| /// |
| /// This alert signals a certificate verification error. |
| /// The reason could be the use of insecure parameters such as `SHA-1` or `MD5` hash |
| /// algorithms, or the signature verification failed. |
| /// The handshake must be aborted. |
| BadCertificate = bssl_sys::SSL_AD_BAD_CERTIFICATE as u8, |
| /// `unsupported_certificate` |
| /// |
| /// This alert signals an unsupported certificate was transmitted. |
| /// The connection must be terminated. |
| UnsupportedCertificate = bssl_sys::SSL_AD_UNSUPPORTED_CERTIFICATE as u8, |
| /// `certificate_revoked` |
| /// |
| /// This alert signals a certificate was revoked. |
| /// The connection must be terminated. |
| CertificateRevoked = bssl_sys::SSL_AD_CERTIFICATE_REVOKED as u8, |
| /// `certificate_expired` |
| /// |
| /// This alert signals a certificate has expired. |
| /// The connection must be terminated. |
| CertificateExpired = bssl_sys::SSL_AD_CERTIFICATE_EXPIRED as u8, |
| /// `certificate_unknown` |
| /// |
| /// This alert signals some other unspecified issue arose in processing the certificate, |
| /// rendering it unacceptable. |
| /// The connection must be terminated. |
| CertificateUnknown = bssl_sys::SSL_AD_CERTIFICATE_UNKNOWN as u8, |
| /// `illegal_parameter` |
| /// |
| /// A field in the handshake was incorrect or inconsistent with other fields. |
| /// This alert is used for errors which conform to the formal protocol syntax, |
| /// but are otherwise incorrect. |
| /// The connection must be terminated. |
| IllegalParameter = bssl_sys::SSL_AD_ILLEGAL_PARAMETER as u8, |
| /// `unknown_ca` |
| /// |
| /// A valid certificate chain or partial chain was received, |
| /// but the certificate was not accepted because the CA certificate could not be located |
| /// or could not be matched with a known trust anchor. |
| /// The connection must be terminated. |
| UnknownCa = bssl_sys::SSL_AD_UNKNOWN_CA as u8, |
| /// `access_denied` |
| /// |
| /// A valid certificate or PSK was received, but when access control was applied, |
| /// the sender decided not to proceed with negotiation. |
| /// The connection must be terminated. |
| AccessDenied = bssl_sys::SSL_AD_ACCESS_DENIED as u8, |
| /// `decode_error` |
| /// |
| /// A message could not be decoded because some field was out of the specified range or |
| /// the length of the message was incorrect. |
| /// This alert is used for errors where the message does not conform to the formal |
| /// protocol syntax. |
| /// This alert should never be observed in communication between proper implementations, |
| /// except when messages were corrupted in the network. |
| /// The connection must be terminated. |
| DecodeError = bssl_sys::SSL_AD_DECODE_ERROR as u8, |
| /// `decrypt_error` |
| /// |
| /// A handshake cryptographic operation, which is not on the record layer, has failed, |
| /// including inability to correctly verify a signature, validate a `Finished` message |
| /// or a PSK binder. |
| /// The connection must be terminated. |
| DecryptError = bssl_sys::SSL_AD_DECRYPT_ERROR as u8, |
| /// `export_restriction`, reserved and used up until TLS 1.3. |
| /// |
| /// The connection must be terminated. |
| ExportRestriction = bssl_sys::SSL_AD_EXPORT_RESTRICTION as u8, |
| /// `protocol_version` |
| /// |
| /// The protocol version the peer has attempted to negotiate is recognized |
| /// but not supported. |
| /// The connection must be terminated. |
| ProtocolVersion = bssl_sys::SSL_AD_PROTOCOL_VERSION as u8, |
| /// `insufficient_security` |
| /// |
| /// Returned instead of "handshake_failure" when a negotiation has failed specifically |
| /// because the server requires parameters more secure than those supported by the client. |
| /// The connection must be terminated. |
| InsufficientSecurity = bssl_sys::SSL_AD_INSUFFICIENT_SECURITY as u8, |
| /// `internal_error` |
| /// |
| /// An internal error unrelated to the peer or the correctness of the protocol, |
| /// such as a memory allocation failure, makes it impossible to continue. |
| /// The connection must be terminated. |
| InternalError = bssl_sys::SSL_AD_INTERNAL_ERROR as u8, |
| /// `inappropriate_fallback` |
| /// |
| /// Sent by a server in response to an invalid connection retry attempt from a client. |
| /// The connection must be terminated. |
| InappropriateFallback = bssl_sys::SSL_AD_INAPPROPRIATE_FALLBACK as u8, |
| /// `user_cancelled` |
| /// |
| /// This alert notifies the recipient that the sender is canceling the handshake |
| /// for some reason unrelated to a protocol failure. |
| UserCancelled = bssl_sys::SSL_AD_USER_CANCELLED as u8, |
| /// `no_renegotiation`, reserved and used up until TLS 1.3. |
| NoRenegotiation = bssl_sys::SSL_AD_NO_RENEGOTIATION as u8, |
| /// `missing_extension` |
| /// |
| /// Sent by endpoints that receive a handshake message not containing an extension that |
| /// is mandatory to send for the offered TLS version or other negotiated parameters. |
| /// The connection must be terminated. |
| MissingExtension = bssl_sys::SSL_AD_MISSING_EXTENSION as u8, |
| /// `unsupported_extension` |
| /// |
| /// Sent by endpoints receiving any handshake message containing an extension in a |
| /// `ServerHello`, `HelloRetryRequest`, `EncryptedExtensions`, or `Certificate` not first |
| /// offered in the corresponding `ClientHello` or `CertificateRequest`. |
| UnsupportedExtension = bssl_sys::SSL_AD_UNSUPPORTED_EXTENSION as u8, |
| /// `certificate_unobtainable`, reserved and used up until TLS 1.3. |
| CertificateUnobtainable = bssl_sys::SSL_AD_CERTIFICATE_UNOBTAINABLE as u8, |
| /// `unrecognized_name` |
| /// |
| /// Sent by servers when no server exists identified by the name provided by the client via |
| /// the `server_name` extension. |
| UnrecognizedName = bssl_sys::SSL_AD_UNRECOGNIZED_NAME as u8, |
| /// `bad_certificate_status_response` |
| /// |
| /// Sent by clients when an invalid or unacceptable OCSP response is provided by the server |
| /// via the `status_request` extension. |
| BadCertificateStatusResponse = bssl_sys::SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE as u8, |
| /// `bad_certificate_hash_value`, reserved and used up until TLS 1.3. |
| BadCertificateHashValue = bssl_sys::SSL_AD_BAD_CERTIFICATE_HASH_VALUE as u8, |
| /// `unknown_psk_identity` |
| /// |
| /// Sent by servers when PSK key establishment is desired but no acceptable PSK identity is |
| /// provided by the client. |
| /// Sending this alert is optional. |
| /// Servers may instead choose to send a `decrypt_error` alert to merely indicate an invalid |
| /// PSK identity. |
| UnknownPskIdentity = bssl_sys::SSL_AD_UNKNOWN_PSK_IDENTITY as u8, |
| /// `certificate_required` |
| /// |
| /// Sent by servers when a client certificate is desired but none was provided by |
| /// the client. |
| CertificateRequired = bssl_sys::SSL_AD_CERTIFICATE_REQUIRED as u8, |
| /// `no_application_protocol` |
| /// |
| /// Sent by servers when a client `application_layer_protocol_negotiation` extension |
| /// advertises only protocols that the server does not support. |
| NoApplicationProtocol = bssl_sys::SSL_AD_NO_APPLICATION_PROTOCOL as u8, |
| /// `ech_required` |
| /// |
| /// The client must send this alert when it offered an `encrypted_client_hello` extension |
| /// but was not accepted by the server. |
| EchRequired = bssl_sys::SSL_AD_ECH_REQUIRED as u8, |
| } |
| } |
| |
| impl AlertDescription { |
| /// Extract long description of the alert. |
| pub fn get_description(self) -> &'static str { |
| let cstr = unsafe { |
| // Safety: we are only accessing static NUL-terminated string data that is plain ASCII. |
| CStr::from_ptr(bssl_sys::SSL_alert_desc_string_long(self as c_int)) |
| }; |
| cstr.to_str() |
| .expect("BoringSSL description string unexpectedly contains non-UTF-8 bytes") |
| } |
| } |
| |
| impl fmt::Display for AlertDescription { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| write!(f, "{}", self.get_description()) |
| } |
| } |