blob: d7d59d19560df8049dc61c6dd37a347802789b4b [file]
// 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())
}
}