opaque_ke/
errors.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2//
3// This source code is dual-licensed under either the MIT license found in the
4// LICENSE-MIT file in the root directory of this source tree or the Apache
5// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
6// of this source tree. You may select, at your option, one of the above-listed
7// licenses.
8
9//! A list of error types which are produced during an execution of the protocol
10use core::convert::Infallible;
11use core::fmt::Debug;
12#[cfg(any(feature = "std", test))]
13use std::error::Error;
14
15use displaydoc::Display;
16
17/// Represents an error in the manipulation of internal cryptographic data
18#[derive(Clone, Copy, Display, Eq, Hash, Ord, PartialEq, PartialOrd)]
19pub enum InternalError<T = Infallible> {
20    /// Custom [`SecretKey`](crate::keypair::SecretKey) error type
21    Custom(T),
22    /// Deserializing from a byte sequence failed
23    InvalidByteSequence,
24    #[allow(clippy::doc_markdown)]
25    /// Invalid length for {name}: expected {len}, but is actually {actual_len}.
26    SizeError {
27        /// name
28        name: &'static str,
29        /// length
30        len: usize,
31        /// actual
32        actual_len: usize,
33    },
34    /// Could not decompress point.
35    PointError,
36    /// Size of input is empty or longer then [`u16::MAX`].
37    HashToScalar,
38    /// Computing HKDF failed while deriving subkeys
39    HkdfError,
40    /// Computing HMAC failed while supplying a secret key
41    HmacError,
42    /// Computing the key stretching function failed
43    KsfError,
44    /** This error occurs when the envelope seal open hmac check fails
45    HMAC check in seal open failed. */
46    SealOpenHmacError,
47    /** This error occurs when attempting to open an envelope of the wrong
48    type (base mode, custom identifier) */
49    IncompatibleEnvelopeModeError,
50    /// Error from the OPRF evaluation
51    OprfError(voprf::Error),
52    /// Error from the OPRF evaluation
53    OprfInternalError(voprf::InternalError),
54}
55
56impl<T: Debug> Debug for InternalError<T> {
57    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
58        match self {
59            Self::Custom(custom) => f.debug_tuple("InvalidByteSequence").field(custom).finish(),
60            Self::InvalidByteSequence => f.debug_tuple("InvalidByteSequence").finish(),
61            Self::SizeError {
62                name,
63                len,
64                actual_len,
65            } => f
66                .debug_struct("SizeError")
67                .field("name", name)
68                .field("len", len)
69                .field("actual_len", actual_len)
70                .finish(),
71            Self::PointError => f.debug_tuple("PointError").finish(),
72            Self::HashToScalar => f.debug_tuple("HashToScalar").finish(),
73            Self::HkdfError => f.debug_tuple("HkdfError").finish(),
74            Self::HmacError => f.debug_tuple("HmacError").finish(),
75            Self::KsfError => f.debug_tuple("KsfError").finish(),
76            Self::SealOpenHmacError => f.debug_tuple("SealOpenHmacError").finish(),
77            Self::IncompatibleEnvelopeModeError => {
78                f.debug_tuple("IncompatibleEnvelopeModeError").finish()
79            }
80            Self::OprfError(error) => f.debug_tuple("OprfError").field(error).finish(),
81            Self::OprfInternalError(error) => {
82                f.debug_tuple("OprfInternalError").field(error).finish()
83            }
84        }
85    }
86}
87
88#[cfg(any(feature = "std", test))]
89impl<T: Error> Error for InternalError<T> {}
90
91impl InternalError {
92    /// Convert `InternalError<Infallible>` into `InternalError<T>`
93    pub fn into_custom<T>(self) -> InternalError<T> {
94        match self {
95            Self::Custom(_) => unreachable!(),
96            Self::InvalidByteSequence => InternalError::InvalidByteSequence,
97            Self::SizeError {
98                name,
99                len,
100                actual_len,
101            } => InternalError::SizeError {
102                name,
103                len,
104                actual_len,
105            },
106            Self::PointError => InternalError::PointError,
107            Self::HashToScalar => InternalError::HashToScalar,
108            Self::HkdfError => InternalError::HkdfError,
109            Self::HmacError => InternalError::HmacError,
110            Self::KsfError => InternalError::KsfError,
111            Self::SealOpenHmacError => InternalError::SealOpenHmacError,
112            Self::IncompatibleEnvelopeModeError => InternalError::IncompatibleEnvelopeModeError,
113            Self::OprfError(error) => InternalError::OprfError(error),
114            Self::OprfInternalError(error) => InternalError::OprfInternalError(error),
115        }
116    }
117}
118
119impl From<voprf::Error> for InternalError {
120    fn from(voprf_error: voprf::Error) -> Self {
121        Self::OprfError(voprf_error)
122    }
123}
124
125impl From<voprf::Error> for ProtocolError {
126    fn from(voprf_error: voprf::Error) -> Self {
127        Self::LibraryError(InternalError::OprfError(voprf_error))
128    }
129}
130
131impl From<voprf::InternalError> for ProtocolError {
132    fn from(voprf_error: voprf::InternalError) -> Self {
133        Self::LibraryError(InternalError::OprfInternalError(voprf_error))
134    }
135}
136
137/// Represents an error in protocol handling
138#[derive(Clone, Copy, Display, Eq, Hash, Ord, PartialEq, PartialOrd)]
139pub enum ProtocolError<T = Infallible> {
140    /// Internal error encountered
141    LibraryError(InternalError<T>),
142    /// Error in validating credentials
143    InvalidLoginError,
144    /// Error with serializing / deserializing protocol messages
145    SerializationError,
146    /** This error occurs when the client detects that the server has
147    reflected the OPRF value (beta == alpha) */
148    ReflectedValueError,
149    /** Identity group element was encountered during deserialization, which is
150    invalid */
151    IdentityGroupElementError,
152}
153
154impl<T: Debug> Debug for ProtocolError<T> {
155    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
156        match self {
157            Self::LibraryError(pake_error) => {
158                f.debug_tuple("LibraryError").field(pake_error).finish()
159            }
160            Self::InvalidLoginError => f.debug_tuple("InvalidLoginError").finish(),
161            Self::SerializationError => f.debug_tuple("SerializationError").finish(),
162            Self::ReflectedValueError => f.debug_tuple("ReflectedValueError").finish(),
163            Self::IdentityGroupElementError => f.debug_tuple("IdentityGroupElementError").finish(),
164        }
165    }
166}
167
168#[cfg(any(feature = "std", test))]
169impl<T: Error> Error for ProtocolError<T> {}
170
171// This is meant to express future(ly) non-trivial ways of converting the
172// internal error into a ProtocolError
173impl<T> From<InternalError<T>> for ProtocolError<T> {
174    fn from(e: InternalError<T>) -> ProtocolError<T> {
175        Self::LibraryError(e)
176    }
177}
178
179// See https://github.com/rust-lang/rust/issues/64715 and remove this when merged,
180// and https://github.com/dtolnay/thiserror/issues/62 for why this comes up in our
181// doc tests.
182impl<T> From<::core::convert::Infallible> for ProtocolError<T> {
183    fn from(_: ::core::convert::Infallible) -> Self {
184        unreachable!()
185    }
186}
187
188impl ProtocolError {
189    /// Convert `ProtocolError<Infallible>` into `ProtocolError<T>`
190    pub fn into_custom<T>(self) -> ProtocolError<T> {
191        match self {
192            Self::LibraryError(internal_error) => {
193                ProtocolError::LibraryError(internal_error.into_custom())
194            }
195            Self::InvalidLoginError => ProtocolError::InvalidLoginError,
196            Self::SerializationError => ProtocolError::SerializationError,
197            Self::ReflectedValueError => ProtocolError::ReflectedValueError,
198            Self::IdentityGroupElementError => ProtocolError::IdentityGroupElementError,
199        }
200    }
201}
202
203pub(crate) mod utils {
204    use super::*;
205
206    pub fn check_slice_size<'a, T>(
207        slice: &'a [u8],
208        expected_len: usize,
209        arg_name: &'static str,
210    ) -> Result<&'a [u8], InternalError<T>> {
211        if slice.len() != expected_len {
212            return Err(InternalError::SizeError {
213                name: arg_name,
214                len: expected_len,
215                actual_len: slice.len(),
216            });
217        }
218        Ok(slice)
219    }
220
221    pub fn check_slice_size_atleast<'a>(
222        slice: &'a [u8],
223        expected_len: usize,
224        arg_name: &'static str,
225    ) -> Result<&'a [u8], InternalError> {
226        if slice.len() < expected_len {
227            return Err(InternalError::SizeError {
228                name: arg_name,
229                len: expected_len,
230                actual_len: slice.len(),
231            });
232        }
233        Ok(slice)
234    }
235}