Skip to main content

pakery_opaque/
error.rs

1//! Error types for the OPAQUE protocol.
2
3use core::fmt;
4
5/// Errors that can occur during the OPAQUE protocol.
6///
7/// # Security
8///
9/// The distinct error variants are useful for server-side logging and
10/// debugging, but they **must not** be exposed verbatim to remote clients.
11/// Returning different error messages for [`ServerAuthenticationError`],
12/// [`EnvelopeRecoveryError`], and [`InvalidMac`] can serve as an oracle,
13/// allowing an attacker to distinguish "wrong password" from "server MAC
14/// failure" from other conditions.  Always map all authentication-related
15/// errors to a single opaque response before sending over the wire.
16///
17/// [`ServerAuthenticationError`]: OpaqueError::ServerAuthenticationError
18/// [`EnvelopeRecoveryError`]: OpaqueError::EnvelopeRecoveryError
19/// [`InvalidMac`]: OpaqueError::InvalidMac
20#[derive(Debug)]
21pub enum OpaqueError {
22    /// The server's MAC did not verify during login.
23    ServerAuthenticationError,
24    /// The client's MAC did not verify during login.
25    ClientAuthenticationError,
26    /// The envelope could not be recovered (wrong password).
27    EnvelopeRecoveryError,
28    /// A MAC verification failed.
29    InvalidMac,
30    /// A message could not be deserialized.
31    DeserializationError,
32    /// An internal error occurred.
33    InternalError(&'static str),
34    /// Invalid input was provided.
35    InvalidInput(&'static str),
36}
37
38impl fmt::Display for OpaqueError {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            Self::ServerAuthenticationError => write!(f, "server authentication failed"),
42            Self::ClientAuthenticationError => write!(f, "client authentication failed"),
43            Self::EnvelopeRecoveryError => write!(f, "envelope recovery failed"),
44            Self::InvalidMac => write!(f, "invalid MAC"),
45            Self::DeserializationError => write!(f, "deserialization error"),
46            Self::InternalError(msg) => write!(f, "internal error: {msg}"),
47            Self::InvalidInput(msg) => write!(f, "invalid input: {msg}"),
48        }
49    }
50}
51
52#[cfg(feature = "std")]
53impl std::error::Error for OpaqueError {}
54
55impl From<pakery_core::PakeError> for OpaqueError {
56    fn from(e: pakery_core::PakeError) -> Self {
57        match e {
58            pakery_core::PakeError::InvalidInput(msg) => OpaqueError::InvalidInput(msg),
59            pakery_core::PakeError::InvalidPoint => OpaqueError::InternalError("invalid point"),
60            pakery_core::PakeError::IdentityPoint => OpaqueError::InternalError("identity point"),
61            pakery_core::PakeError::ProtocolError(msg) => OpaqueError::InternalError(msg),
62        }
63    }
64}
65
66impl From<OpaqueError> for pakery_core::PakeError {
67    fn from(e: OpaqueError) -> Self {
68        match e {
69            OpaqueError::InvalidInput(msg) => pakery_core::PakeError::InvalidInput(msg),
70            _ => pakery_core::PakeError::ProtocolError("OPAQUE error"),
71        }
72    }
73}