#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::string::ToString;
#[cfg(feature = "derive")]
use crate::Errorizable;
pub type Result<T> = core::result::Result<T, HandshakeError>;
#[cfg_attr(feature = "derive", derive(Errorizable))]
#[derive(Debug)]
pub enum HandshakeError {
#[cfg_attr(
feature = "derive",
error("Handshake invariant violation: transcript already locked")
)]
TranscriptAlreadyLocked,
#[cfg_attr(
feature = "derive",
error("Handshake invariant violation: transcript not locked")
)]
TranscriptNotLocked,
#[cfg_attr(
feature = "derive",
error("Handshake invariant violation: AEAD key already derived")
)]
AeadAlreadyDerived,
#[cfg_attr(
feature = "derive",
error("Handshake invariant violation: Finished already sent")
)]
FinishedAlreadySent,
#[cfg_attr(
feature = "derive",
error("Handshake invariant violation: Finished before transcript lock")
)]
FinishedBeforeTranscriptLock,
#[cfg_attr(feature = "derive", error("Invalid client key exchange message"))]
InvalidClientKeyExchange,
#[cfg_attr(feature = "derive", error("Invalid server key exchange message"))]
InvalidServerKeyExchange,
#[cfg_attr(feature = "derive", error("Invalid public key in handshake: {0}"))]
#[cfg_attr(feature = "derive", from)]
InvalidPublicKey(crate::crypto::sign::ecdsa::k256::elliptic_curve::Error),
#[cfg_attr(feature = "derive", error("Invalid certificate: {0}"))]
#[cfg_attr(feature = "derive", from)]
CertificateValidationError(crate::crypto::x509::error::CertificateValidationError),
#[cfg_attr(feature = "derive", error("Handshake signature verification failed"))]
SignatureVerificationFailed,
#[cfg_attr(feature = "derive", error("Signature error: {0}"))]
#[cfg_attr(feature = "derive", from)]
SignatureError(crate::crypto::sign::Error),
#[cfg_attr(feature = "derive", error("Handshake key derivation failed: {0}"))]
#[cfg_attr(feature = "derive", from)]
KeyDerivationFailed(crate::crypto::aead::Error),
#[cfg_attr(feature = "derive", error("DER error: {0}"))]
#[cfg_attr(feature = "derive", from)]
DerError(crate::der::Error),
#[cfg_attr(feature = "derive", error("SPKI error: {0}"))]
#[cfg_attr(feature = "derive", from)]
SpkiError(crate::spki::Error),
#[cfg_attr(feature = "derive", error("Key provider error: {0}"))]
#[cfg_attr(feature = "derive", from)]
KeyError(crate::crypto::key::KeyError),
#[cfg_attr(feature = "derive", error("CMS builder error: {0}"))]
#[cfg_attr(feature = "derive", from)]
CmsBuilderError(crate::cms::builder::Error),
#[cfg_attr(feature = "derive", error("Invalid handshake state"))]
InvalidState,
#[cfg_attr(feature = "derive", error("Missing server key"))]
MissingServerKey,
#[cfg_attr(feature = "derive", error("Missing server certificate"))]
MissingServerCertificate,
#[cfg_attr(feature = "derive", error("Missing client certificate"))]
MissingClientCertificate,
#[cfg_attr(feature = "derive", error("Invalid transcript hash"))]
InvalidTranscriptHash,
#[cfg_attr(
feature = "derive",
error("Server requires mutual authentication but client has no identity")
)]
MutualAuthRequired,
#[cfg_attr(
feature = "derive",
error("Peer identity changed during re-handshake - connection identity is immutable")
)]
PeerIdentityMismatch,
#[cfg_attr(feature = "derive", error("Missing client random from ClientHello"))]
MissingClientRandom,
#[cfg_attr(feature = "derive", error("Missing base session key"))]
MissingBaseSessionKey,
#[cfg_attr(feature = "derive", error("Missing client random"))]
MissingClientRandomState,
#[cfg_attr(feature = "derive", error("Missing server random"))]
MissingServerRandom,
#[cfg_attr(
feature = "derive",
error("CMS salt too short: {actual} bytes (minimum {minimum} required)")
)]
InsufficientSaltEntropy { actual: usize, minimum: usize },
#[cfg_attr(feature = "derive", error("Handshake aborted by peer: {0:?}"))]
AbortReceived(crate::transport::handshake::HandshakeAlert),
#[cfg_attr(feature = "derive", error("Handshake timeout"))]
Timeout,
#[cfg_attr(feature = "derive", error("Server selected profile not in client's offer"))]
InvalidProfileSelection,
#[cfg_attr(feature = "derive", error("Profile negotiation failed: {0}"))]
#[cfg_attr(feature = "derive", from)]
NegotiationError(crate::transport::handshake::negotiation::NegotiationError),
#[cfg_attr(feature = "derive", error("No mutually supported cryptographic profiles found"))]
NoMutualProfiles,
#[cfg_attr(
feature = "derive",
error("Dealer's choice failed: no supported profiles configured")
)]
NoSupportedProfiles,
#[cfg_attr(
feature = "derive",
error("Profile negotiation required but no profiles configured on server")
)]
NegotiationRequired,
#[cfg_attr(feature = "derive", error("Certificate rejected by policy: {0}"))]
#[cfg_attr(feature = "derive", from)]
CertificatePolicyError(crate::crypto::policy::CryptoPolicyError),
#[cfg_attr(feature = "derive", error("Attribute must contain exactly one value"))]
InvalidAttributeArity,
#[cfg_attr(feature = "derive", error("Duplicate attribute present"))]
DuplicateAttribute,
#[cfg_attr(feature = "derive", error("Required attribute missing"))]
MissingAttribute,
#[cfg_attr(feature = "derive", error("Nonce value not valid OCTET STRING"))]
InvalidNonceEncoding,
#[cfg_attr(feature = "derive", error("Nonce length mismatch: {0}"))]
NonceLengthError(crate::error::ReceivedExpectedError<usize, usize>),
#[cfg_attr(feature = "derive", error("OCTET STRING length mismatch: {0}"))]
OctetStringLengthError(crate::error::ReceivedExpectedError<usize, usize>),
#[cfg_attr(feature = "derive", error("Version/alert value not valid INTEGER"))]
InvalidIntegerEncoding,
#[cfg_attr(feature = "derive", error("INTEGER out of range"))]
IntegerOutOfRange,
#[cfg_attr(feature = "derive", error("Unknown alert code: {0:?}"))]
UnknownAlertCode(u8),
#[cfg_attr(feature = "derive", error("Certificate not yet valid"))]
CertificateNotYetValid,
#[cfg_attr(feature = "derive", error("Certificate expired"))]
CertificateExpired,
#[cfg_attr(feature = "derive", error("Invalid timestamp"))]
InvalidTimestamp,
#[cfg(feature = "ecies")]
#[cfg_attr(feature = "derive", error("ECIES operation failed: {0}"))]
#[cfg_attr(feature = "derive", from)]
EciesError(crate::crypto::ecies::EciesError),
#[cfg_attr(feature = "derive", error("Missing encrypted content in ECIES message"))]
MissingEncryptedContent,
#[cfg_attr(feature = "derive", error("Invalid decrypted payload size"))]
InvalidDecryptedPayloadSize,
#[cfg_attr(feature = "derive", error("client_random mismatch - possible replay attack"))]
ClientRandomMismatchReplay,
#[cfg_attr(feature = "derive", error("ECDH operation failed"))]
EcdhFailed,
#[cfg_attr(feature = "derive", error("KDF operation failed"))]
KdfError,
#[cfg_attr(
feature = "derive",
error("Invalid key size: expected {expected}, got {received}")
)]
InvalidKeySize { expected: usize, received: usize },
#[cfg_attr(feature = "derive", error("ASN.1 encoding error: {0}"))]
Asn1Error(der::Error),
#[cfg_attr(feature = "derive", error("Invalid recipient index"))]
InvalidRecipientIndex,
#[cfg_attr(feature = "derive", error("Missing UKM in KeyAgreeRecipientInfo"))]
MissingUkm,
#[cfg_attr(feature = "derive", error("Failed to parse originator public key"))]
InvalidOriginatorPublicKey,
#[cfg_attr(feature = "derive", error("Unsupported originator identifier type"))]
UnsupportedOriginatorIdentifier,
#[cfg_attr(feature = "derive", error("KARI builder already consumed"))]
KariBuilderConsumed,
#[cfg_attr(feature = "derive", error("Content encryption algorithm not set"))]
MissingContentEncryptionAlgorithm,
#[cfg_attr(
feature = "derive",
error("Key wrap algorithm not configured in security profile")
)]
MissingKeyWrapAlgorithm,
#[cfg_attr(
feature = "derive",
error("Negotiated key wrap algorithm unsupported (expected AES-128/192/256 key wrap)")
)]
UnsupportedKeyWrapAlgorithm,
#[cfg(all(feature = "builder", feature = "aead"))]
#[cfg_attr(feature = "derive", error("AES key wrap operation failed: {0}"))]
#[cfg_attr(feature = "derive", from)]
AesKeyWrap(crate::crypto::aead::aes_kw::Error),
#[cfg(feature = "kem")]
#[cfg_attr(
feature = "derive",
error("Hybrid key agreement integrity check failed: combined ECDH+KEM key validation error")
)]
HybridKariIntegrityCheckFailed,
#[cfg_attr(feature = "derive", error("Random generation failed"))]
RandomGenerationFailed,
#[cfg_attr(feature = "derive", error("Secret unavailable: {0}"))]
#[cfg_attr(feature = "derive", from)]
SecretUnavailable(crate::crypto::secret::SecretError),
#[cfg_attr(feature = "derive", error("Invalid OCTET STRING length: {0}"))]
InvalidOctetStringLength(&'static str),
}
#[cfg(not(feature = "derive"))]
impl core::fmt::Display for HandshakeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
HandshakeError::InvalidClientKeyExchange => write!(f, "Invalid client key exchange message"),
HandshakeError::InvalidServerKeyExchange => write!(f, "Invalid server key exchange message"),
HandshakeError::InvalidPublicKey(e) => write!(f, "Invalid public key in handshake: {}", e),
HandshakeError::CertificateValidationError(e) => write!(f, "Invalid certificate: {}", e),
HandshakeError::SpkiError(e) => write!(f, "SPKI error: {}", e),
HandshakeError::KeyError(e) => write!(f, "Key provider error: {}", e),
HandshakeError::CmsBuilderError(e) => write!(f, "CMS builder error: {}", e),
HandshakeError::SignatureVerificationFailed => write!(f, "Handshake signature verification failed"),
HandshakeError::KeyDerivationFailed(e) => write!(f, "Handshake key derivation failed: {}", e),
HandshakeError::InvalidState => write!(f, "Invalid handshake state"),
HandshakeError::MissingServerKey => write!(f, "Missing server key"),
HandshakeError::MissingServerCertificate => write!(f, "Missing server certificate"),
HandshakeError::MissingClientCertificate => write!(f, "Missing client certificate"),
HandshakeError::InvalidTranscriptHash => write!(f, "Invalid transcript hash"),
HandshakeError::MissingClientRandom => write!(f, "Missing client random from ClientHello"),
HandshakeError::MissingBaseSessionKey => write!(f, "Missing base session key"),
HandshakeError::MissingClientRandomState => write!(f, "Missing client random"),
HandshakeError::MissingServerRandom => write!(f, "Missing server random"),
HandshakeError::InsufficientSaltEntropy { actual, minimum } => {
write!(f, "CMS salt too short: {} bytes (minimum {} required)", actual, minimum)
}
HandshakeError::AbortReceived(alert) => write!(f, "Handshake aborted by peer: {:?}", alert),
HandshakeError::Timeout => write!(f, "Handshake timeout"),
HandshakeError::InvalidProfileSelection => write!(f, "Server selected profile not in client's offer"),
HandshakeError::NegotiationError(e) => write!(f, "Profile negotiation failed: {}", e),
HandshakeError::NoMutualProfiles => write!(f, "No mutually supported cryptographic profiles found"),
HandshakeError::NoSupportedProfiles => {
write!(f, "Dealer's choice failed: no supported profiles configured")
}
HandshakeError::NegotiationRequired => {
write!(f, "Profile negotiation required but no profiles configured on server")
}
HandshakeError::CertificatePolicyError(e) => write!(f, "Certificate rejected by policy: {}", e),
HandshakeError::DerError(e) => write!(f, "DER error: {}", e),
HandshakeError::InvalidAttributeArity => write!(f, "Attribute must contain exactly one value"),
HandshakeError::DuplicateAttribute => write!(f, "Duplicate attribute present"),
HandshakeError::MissingAttribute => write!(f, "Required attribute missing"),
HandshakeError::InvalidNonceEncoding => write!(f, "Nonce value not valid OCTET STRING"),
HandshakeError::NonceLengthError(e) => write!(f, "Nonce length mismatch: {}", e),
HandshakeError::OctetStringLengthError(e) => write!(f, "OCTET STRING length mismatch: {}", e),
HandshakeError::InvalidIntegerEncoding => write!(f, "Version/alert value not valid INTEGER"),
HandshakeError::IntegerOutOfRange => write!(f, "INTEGER out of range"),
HandshakeError::UnknownAlertCode(code) => write!(f, "Unknown alert code: {code}"),
HandshakeError::CertificateNotYetValid => write!(f, "Certificate not yet valid"),
HandshakeError::CertificateExpired => write!(f, "Certificate expired"),
HandshakeError::InvalidTimestamp => write!(f, "Invalid timestamp"),
HandshakeError::EciesError(e) => write!(f, "ECIES operation failed: {}", e),
HandshakeError::MissingEncryptedContent => write!(f, "Missing encrypted content in ECIES message"),
HandshakeError::InvalidDecryptedPayloadSize => write!(f, "Invalid decrypted payload size"),
HandshakeError::ClientRandomMismatchReplay => write!(f, "client_random mismatch - possible replay attack"),
HandshakeError::EcdhFailed => write!(f, "ECDH operation failed"),
HandshakeError::KdfError => write!(f, "KDF operation failed"),
HandshakeError::InvalidKeySize { expected, received } => {
write!(f, "Invalid key size: expected {}, got {}", expected, received)
}
HandshakeError::Asn1Error(e) => write!(f, "ASN.1 encoding error: {}", e),
HandshakeError::InvalidRecipientIndex => write!(f, "Invalid recipient index"),
HandshakeError::MissingUkm => write!(f, "Missing UKM in KeyAgreeRecipientInfo"),
HandshakeError::InvalidOriginatorPublicKey => write!(f, "Failed to parse originator public key"),
HandshakeError::UnsupportedOriginatorIdentifier => write!(f, "Unsupported originator identifier type"),
HandshakeError::KariBuilderConsumed => write!(f, "KARI builder already consumed"),
HandshakeError::MissingContentEncryptionAlgorithm => write!(f, "Content encryption algorithm not set"),
HandshakeError::MissingKeyWrapAlgorithm => {
write!(f, "Key wrap algorithm not configured in security profile")
}
HandshakeError::UnsupportedKeyWrapAlgorithm => {
write!(
f,
"Negotiated key wrap algorithm unsupported (expected AES-128/192/256 key wrap)"
)
}
#[cfg(all(feature = "builder", feature = "aead"))]
HandshakeError::AesKeyWrap(e) => write!(f, "AES key wrap operation failed: {}", e),
HandshakeError::RandomGenerationFailed => write!(f, "Random generation failed"),
HandshakeError::SecretUnavailable(e) => write!(f, "Secret unavailable: {}", e),
HandshakeError::InvalidOctetStringLength(m) => write!(f, "Invalid OCTET STRING length: {}", m),
HandshakeError::NonceLengthError(e) => write!(f, "Nonce length mismatch: {}", e),
HandshakeError::OctetStringLengthError(e) => write!(f, "OCTET STRING length mismatch: {}", e),
HandshakeError::UnknownAlertCode(code) => write!(f, "Unknown alert code: {code}"),
}
}
}
#[cfg(not(feature = "derive"))]
impl core::error::Error for HandshakeError {}
impl From<crate::crypto::kdf::KdfError> for HandshakeError {
fn from(_: crate::crypto::kdf::KdfError) -> Self {
HandshakeError::KeyDerivationFailed(crate::crypto::aead::Error)
}
}
impl From<crate::error::TightBeamError> for HandshakeError {
fn from(err: crate::error::TightBeamError) -> Self {
use crate::error::TightBeamError;
match err {
TightBeamError::HandshakeError(h) => h,
TightBeamError::SerializationError(e) => HandshakeError::DerError(e),
#[cfg(feature = "x509")]
TightBeamError::SpkiError(e) => HandshakeError::SpkiError(e),
#[cfg(feature = "x509")]
TightBeamError::CertificateValidationError(e) => HandshakeError::CertificateValidationError(e),
#[cfg(feature = "crypto")]
TightBeamError::CryptoPolicyError(e) => HandshakeError::CertificatePolicyError(e),
#[cfg(feature = "crypto")]
TightBeamError::KeyError(e) => HandshakeError::KeyError(e),
#[cfg(feature = "signature")]
TightBeamError::SignatureError(e) => HandshakeError::SignatureError(e),
#[cfg(feature = "ecies")]
TightBeamError::EciesError(e) => HandshakeError::EciesError(e),
#[cfg(feature = "crypto")]
TightBeamError::SecretUnavailable(e) => HandshakeError::SecretUnavailable(e),
#[cfg(feature = "random")]
TightBeamError::OsRngError(_) => HandshakeError::RandomGenerationFailed,
_ => HandshakeError::InvalidState,
}
}
}
#[cfg(all(feature = "crypto", not(feature = "derive")))]
impl From<crate::crypto::secret::SecretError> for HandshakeError {
fn from(err: crate::crypto::secret::SecretError) -> Self {
HandshakeError::SecretUnavailable(err)
}
}
#[cfg(all(feature = "builder", feature = "aead"))]
impl From<HandshakeError> for crate::cms::builder::Error {
fn from(err: HandshakeError) -> Self {
match err {
HandshakeError::CmsBuilderError(e) => e,
HandshakeError::DerError(e) => crate::cms::builder::Error::Asn1(e),
HandshakeError::Asn1Error(e) => crate::cms::builder::Error::Asn1(e),
HandshakeError::SpkiError(e) => crate::cms::builder::Error::PublicKey(e),
other => crate::cms::builder::Error::Builder(other.to_string()),
}
}
}
impl From<crypto_common::InvalidLength> for HandshakeError {
fn from(_: crypto_common::InvalidLength) -> Self {
HandshakeError::KeyDerivationFailed(crate::crypto::aead::Error)
}
}
#[cfg(not(feature = "derive"))]
impl From<crate::crypto::key::KeyError> for HandshakeError {
fn from(e: crate::crypto::key::KeyError) -> Self {
HandshakeError::KeyError(e)
}
}