1use std::fmt::{self, Display};
19
20use crate::jwk::{Algorithm, KeyOperation, KeyType};
21
22#[derive(Debug)]
24#[non_exhaustive]
25pub enum Error {
26 Json(serde_json::Error),
28
29 Parse(ParseError),
31
32 InvalidUrl(url::ParseError),
34
35 InvalidUrlScheme(&'static str),
37
38 InvalidKey(InvalidKeyError),
41
42 IncompatibleKey(IncompatibleKeyError),
44
45 Base64(base64ct::Error),
47
48 InvalidInput(&'static str),
50
51 #[cfg(feature = "http")]
53 Http(reqwest::Error),
54
55 Fetch(String),
57
58 Cache(String),
60
61 Other(String),
63
64 #[cfg(feature = "web-crypto")]
66 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
67 UnsupportedForWebCrypto {
68 reason: &'static str,
70 },
71
72 #[cfg(feature = "web-crypto")]
74 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
75 WebCrypto(String),
76}
77
78impl Display for Error {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 match self {
81 Error::Json(e) => write!(f, "JSON error: {}", e),
82 Error::Parse(e) => write!(f, "parse error: {}", e),
83 Error::InvalidUrl(err) => write!(f, "invalid URL: {}", err),
84 Error::InvalidUrlScheme(msg) => write!(f, "invalid URL scheme: {}", msg),
85 Error::InvalidKey(e) => write!(f, "invalid key: {}", e),
86 Error::IncompatibleKey(e) => write!(f, "incompatible key: {}", e),
87 Error::Base64(e) => write!(f, "base64 decoding error: {:?}", e),
88 Error::InvalidInput(msg) => write!(f, "invalid input: {}", msg),
89 #[cfg(feature = "http")]
90 Error::Http(e) => write!(f, "HTTP error: {}", e),
91 Error::Fetch(msg) => write!(f, "fetch error: {}", msg),
92 Error::Cache(msg) => write!(f, "cache error: {}", msg),
93 Error::Other(msg) => write!(f, "{}", msg),
94 #[cfg(feature = "web-crypto")]
95 Error::UnsupportedForWebCrypto { reason } => {
96 write!(f, "unsupported for WebCrypto: {}", reason)
97 }
98 #[cfg(feature = "web-crypto")]
99 Error::WebCrypto(msg) => write!(f, "WebCrypto error: {}", msg),
100 }
101 }
102}
103
104impl std::error::Error for Error {
105 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
106 match self {
107 Error::Json(e) => Some(e),
108 Error::Parse(e) => Some(e),
109 Error::InvalidUrl(e) => Some(e),
110 Error::InvalidKey(e) => Some(e),
111 Error::IncompatibleKey(e) => Some(e),
112 Error::Base64(e) => Some(e),
113 #[cfg(feature = "http")]
114 Error::Http(e) => Some(e),
115 _ => None,
116 }
117 }
118}
119
120impl From<InvalidKeyError> for Error {
121 fn from(e: InvalidKeyError) -> Self {
122 Error::InvalidKey(e)
123 }
124}
125
126impl From<IncompatibleKeyError> for Error {
127 fn from(e: IncompatibleKeyError) -> Self {
128 Error::IncompatibleKey(e)
129 }
130}
131
132impl From<base64ct::Error> for Error {
133 fn from(e: base64ct::Error) -> Self {
134 Error::Base64(e)
135 }
136}
137
138impl From<serde_json::Error> for Error {
139 fn from(e: serde_json::Error) -> Self {
140 Error::Json(e)
141 }
142}
143
144impl From<url::ParseError> for Error {
145 fn from(e: url::ParseError) -> Self {
146 Error::InvalidUrl(e)
147 }
148}
149
150#[cfg(feature = "http")]
151impl From<reqwest::Error> for Error {
152 fn from(e: reqwest::Error) -> Self {
153 Error::Http(e)
154 }
155}
156
157#[derive(Debug, Clone, PartialEq, Eq)]
159#[non_exhaustive]
160pub enum ParseError {
161 UnknownKeyType(String),
163 UnknownCurve(String),
165}
166
167impl Display for ParseError {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 match self {
170 ParseError::UnknownKeyType(kty) => write!(f, "unknown key type: {}", kty),
171 ParseError::UnknownCurve(crv) => write!(f, "unknown curve: {}", crv),
172 }
173 }
174}
175
176impl std::error::Error for ParseError {}
177
178#[derive(Debug, Clone, PartialEq, Eq)]
184#[non_exhaustive]
185pub enum InvalidKeyError {
186 InvalidKeySize {
188 expected: usize,
190 actual: usize,
192 context: &'static str,
194 },
195 MissingParameter(&'static str),
197 InconsistentParameters(String),
199 InvalidParameter {
201 name: &'static str,
203 reason: String,
205 },
206 InvalidOtherPrime {
208 index: usize,
210 source: Box<InvalidKeyError>,
212 },
213}
214
215impl Display for InvalidKeyError {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 match self {
218 InvalidKeyError::InvalidKeySize {
219 expected,
220 actual,
221 context,
222 } => {
223 write!(
224 f,
225 "invalid key size for {}: expected {} bytes, got {}",
226 context, expected, actual
227 )
228 }
229 InvalidKeyError::MissingParameter(param) => {
230 write!(f, "missing required parameter: {}", param)
231 }
232 InvalidKeyError::InconsistentParameters(msg) => {
233 write!(f, "inconsistent key parameters: {}", msg)
234 }
235 InvalidKeyError::InvalidParameter { name, reason } => {
236 write!(f, "invalid parameter '{}': {}", name, reason)
237 }
238 InvalidKeyError::InvalidOtherPrime { index, source } => {
239 write!(f, "invalid oth[{}]: {}", index, source)
240 }
241 }
242 }
243}
244
245impl std::error::Error for InvalidKeyError {
246 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
247 match self {
248 InvalidKeyError::InvalidOtherPrime { source, .. } => Some(source.as_ref()),
249 _ => None,
250 }
251 }
252}
253
254#[derive(Debug, Clone, PartialEq, Eq)]
260#[non_exhaustive]
261pub enum IncompatibleKeyError {
262 AlgorithmMismatch {
264 requested: Algorithm,
266 declared: Algorithm,
268 },
269 IncompatibleAlgorithm {
271 algorithm: Algorithm,
273 key_type: KeyType,
275 },
276 InsufficientKeyStrength {
278 minimum_bits: usize,
280 actual_bits: usize,
282 context: &'static str,
284 },
285 KeySizeMismatch {
287 required_bits: usize,
289 actual_bits: usize,
291 context: &'static str,
293 },
294 OperationNotPermitted {
297 operations: Vec<KeyOperation>,
299 reason: String,
301 },
302}
303
304impl Display for IncompatibleKeyError {
305 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306 match self {
307 IncompatibleKeyError::AlgorithmMismatch {
308 requested,
309 declared,
310 } => {
311 let requested_display = match requested {
312 Algorithm::Unknown(value) => {
313 format!("unknown({})", sanitize_for_display(value))
314 }
315 _ => requested.to_string(),
316 };
317 let declared_display = match declared {
318 Algorithm::Unknown(value) => {
319 format!("unknown({})", sanitize_for_display(value))
320 }
321 _ => declared.to_string(),
322 };
323 write!(
324 f,
325 "requested algorithm '{}' does not match key's declared alg '{}'",
326 requested_display, declared_display
327 )
328 }
329 IncompatibleKeyError::IncompatibleAlgorithm {
330 algorithm,
331 key_type,
332 } => {
333 let algorithm_display = match algorithm {
334 Algorithm::Unknown(value) => {
335 format!("unknown({})", sanitize_for_display(value))
336 }
337 _ => algorithm.to_string(),
338 };
339 write!(
340 f,
341 "algorithm '{}' is not compatible with key type '{}'",
342 algorithm_display, key_type
343 )
344 }
345 IncompatibleKeyError::InsufficientKeyStrength {
346 minimum_bits,
347 actual_bits,
348 context,
349 } => {
350 write!(
351 f,
352 "insufficient key strength for {}: need {} bits, got {}",
353 context, minimum_bits, actual_bits
354 )
355 }
356 IncompatibleKeyError::KeySizeMismatch {
357 required_bits,
358 actual_bits,
359 context,
360 } => {
361 write!(
362 f,
363 "key size mismatch for {}: expected {} bits, got {}",
364 context, required_bits, actual_bits
365 )
366 }
367 IncompatibleKeyError::OperationNotPermitted { operations, reason } => {
368 let ops: Vec<String> = operations
369 .iter()
370 .map(|op| match op {
371 KeyOperation::Unknown(value) => {
372 format!("unknown({})", sanitize_for_display(value))
373 }
374 _ => op.to_string(),
375 })
376 .collect();
377 write!(
378 f,
379 "operation(s) not permitted ({}): {}",
380 ops.join(", "),
381 reason
382 )
383 }
384 }
385 }
386}
387
388impl std::error::Error for IncompatibleKeyError {}
389
390#[cfg(feature = "jwt-simple")]
392#[cfg_attr(docsrs, doc(cfg(feature = "jwt-simple")))]
393#[derive(Debug)]
394#[non_exhaustive]
395pub enum JwtSimpleKeyConversionError {
396 InvalidKey(InvalidKeyError),
398 IncompatibleKey(IncompatibleKeyError),
400 KeyTypeMismatch {
402 expected: &'static str,
404 actual: String,
406 },
407 CurveMismatch {
409 expected: &'static str,
411 actual: String,
413 },
414 MissingComponent {
416 field: &'static str,
418 },
419 MissingPrivateKey,
421 Core(Error),
423 Encoding(String),
425 Import(String),
427}
428
429#[cfg(feature = "jwt-simple")]
430impl Display for JwtSimpleKeyConversionError {
431 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
432 match self {
433 JwtSimpleKeyConversionError::InvalidKey(e) => write!(f, "invalid key: {}", e),
434 JwtSimpleKeyConversionError::IncompatibleKey(e) => {
435 write!(f, "incompatible key: {}", e)
436 }
437 JwtSimpleKeyConversionError::KeyTypeMismatch { expected, actual } => {
438 write!(
439 f,
440 "key type mismatch: expected {}, got {}",
441 expected, actual
442 )
443 }
444 JwtSimpleKeyConversionError::CurveMismatch { expected, actual } => {
445 write!(f, "curve mismatch: expected {}, got {}", expected, actual)
446 }
447 JwtSimpleKeyConversionError::MissingComponent { field } => {
448 write!(f, "missing required field: {}", field)
449 }
450 JwtSimpleKeyConversionError::MissingPrivateKey => {
451 write!(f, "private key parameters required but not present")
452 }
453 JwtSimpleKeyConversionError::Core(err) => {
454 write!(f, "core error: {}", err)
455 }
456 JwtSimpleKeyConversionError::Encoding(msg) => write!(f, "encoding error: {}", msg),
457 JwtSimpleKeyConversionError::Import(msg) => write!(f, "import error: {}", msg),
458 }
459 }
460}
461
462#[cfg(feature = "jwt-simple")]
463impl std::error::Error for JwtSimpleKeyConversionError {
464 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
465 match self {
466 JwtSimpleKeyConversionError::InvalidKey(e) => Some(e),
467 JwtSimpleKeyConversionError::IncompatibleKey(e) => Some(e),
468 JwtSimpleKeyConversionError::Core(err) => Some(err),
469 _ => None,
470 }
471 }
472}
473
474#[cfg(feature = "jwt-simple")]
475impl From<InvalidKeyError> for JwtSimpleKeyConversionError {
476 fn from(e: InvalidKeyError) -> Self {
477 JwtSimpleKeyConversionError::InvalidKey(e)
478 }
479}
480
481#[cfg(feature = "jwt-simple")]
482impl From<IncompatibleKeyError> for JwtSimpleKeyConversionError {
483 fn from(e: IncompatibleKeyError) -> Self {
484 JwtSimpleKeyConversionError::IncompatibleKey(e)
485 }
486}
487
488const MAX_DISPLAY_IDENTIFIER_CHARS: usize = 256;
491
492pub(crate) fn sanitize_for_display(value: &str) -> String {
497 value
498 .chars()
499 .take(MAX_DISPLAY_IDENTIFIER_CHARS)
500 .map(|ch| if ch.is_control() { ' ' } else { ch })
501 .collect()
502}
503
504pub type Result<T> = std::result::Result<T, Error>;