Skip to main content

cloud_sdk/authentication/signing/
build.rs

1use core::fmt;
2
3use cloud_sdk_sanitization::sanitize_bytes;
4
5use super::{MAX_SIGNING_BODY_DIGEST_BYTES, SigningInputError, SigningValueError};
6
7#[derive(Clone, Copy, Eq, PartialEq)]
8pub(super) struct SigningBodyDigest<'a>(&'a [u8]);
9
10impl<'a> SigningBodyDigest<'a> {
11    pub(super) fn new(value: &'a [u8]) -> Result<Self, SigningValueError> {
12        if value.is_empty() {
13            return Err(SigningValueError::Empty);
14        }
15        if value.len() > MAX_SIGNING_BODY_DIGEST_BYTES {
16            return Err(SigningValueError::TooLong);
17        }
18        Ok(Self(value))
19    }
20
21    pub(super) const fn as_bytes(self) -> &'a [u8] {
22        self.0
23    }
24}
25
26impl fmt::Debug for SigningBodyDigest<'_> {
27    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
28        formatter.write_str("SigningBodyDigest([redacted])")
29    }
30}
31
32/// Body hashing and canonical signing-input construction failure.
33pub enum SigningBuildError<E> {
34    /// The hasher and signed context declare different digest algorithms.
35    DigestAlgorithmMismatch,
36    /// The caller-provided body hasher rejected the exact request body.
37    Hasher(E),
38    /// The hasher returned an empty or out-of-bounds digest.
39    Digest(SigningValueError),
40    /// Canonical input validation or encoding failed.
41    Input(SigningInputError),
42}
43
44impl<E> fmt::Debug for SigningBuildError<E> {
45    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
46        formatter.write_str(match self {
47            Self::DigestAlgorithmMismatch => "SigningBuildError::DigestAlgorithmMismatch",
48            Self::Hasher(_) => "SigningBuildError::Hasher([redacted])",
49            Self::Digest(_) => "SigningBuildError::Digest",
50            Self::Input(_) => "SigningBuildError::Input",
51        })
52    }
53}
54
55impl<E> fmt::Display for SigningBuildError<E> {
56    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
57        formatter.write_str(match self {
58            Self::DigestAlgorithmMismatch => {
59                "request body hasher does not match the signed digest algorithm"
60            }
61            Self::Hasher(_) => "request body hashing failed",
62            Self::Digest(_) => "request body hasher returned an invalid digest length",
63            Self::Input(_) => "canonical signing input construction failed",
64        })
65    }
66}
67
68impl<E> core::error::Error for SigningBuildError<E>
69where
70    E: core::error::Error + 'static,
71{
72    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
73        match self {
74            Self::Hasher(error) => Some(error),
75            Self::Digest(error) => Some(error),
76            Self::Input(error) => Some(error),
77            Self::DigestAlgorithmMismatch => None,
78        }
79    }
80}
81
82pub(super) struct DigestScratch<'a>(&'a mut [u8]);
83
84impl<'a> DigestScratch<'a> {
85    pub(super) fn new(storage: &'a mut [u8]) -> Self {
86        sanitize_bytes(storage);
87        Self(storage)
88    }
89
90    pub(super) fn as_mut(&mut self) -> &mut [u8] {
91        self.0
92    }
93
94    pub(super) fn as_slice(&self) -> &[u8] {
95        self.0
96    }
97}
98
99impl Drop for DigestScratch<'_> {
100    fn drop(&mut self) {
101        sanitize_bytes(self.0);
102    }
103}