1 | // Copyright 2016 Brian Smith. |
2 | // |
3 | // Permission to use, copy, modify, and/or distribute this software for any |
4 | // purpose with or without fee is hereby granted, provided that the above |
5 | // copyright notice and this permission notice appear in all copies. |
6 | // |
7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | |
15 | //! Error reporting. |
16 | |
17 | #[cfg (feature = "std" )] |
18 | extern crate std; |
19 | |
20 | /// An error with absolutely no details. |
21 | /// |
22 | /// *ring* uses this unit type as the error type in most of its results |
23 | /// because (a) usually the specific reasons for a failure are obvious or are |
24 | /// not useful to know, and/or (b) providing more details about a failure might |
25 | /// provide a dangerous side channel, and/or (c) it greatly simplifies the |
26 | /// error handling logic. |
27 | /// |
28 | /// `Result<T, ring::error::Unspecified>` is mostly equivalent to |
29 | /// `Result<T, ()>`. However, `ring::error::Unspecified` implements |
30 | /// [`std::error::Error`] and users of *ring* can implement |
31 | /// `From<ring::error::Unspecified>` to map this to their own error types, as |
32 | /// described in [“Error Handling” in the Rust Book]: |
33 | /// |
34 | /// ``` |
35 | /// use ring::rand::{self, SecureRandom}; |
36 | /// |
37 | /// enum Error { |
38 | /// CryptoError, |
39 | /// |
40 | /// # #[cfg (feature = "alloc" )] |
41 | /// IOError(std::io::Error), |
42 | /// // [...] |
43 | /// } |
44 | /// |
45 | /// impl From<ring::error::Unspecified> for Error { |
46 | /// fn from(_: ring::error::Unspecified) -> Self { Error::CryptoError } |
47 | /// } |
48 | /// |
49 | /// fn eight_random_bytes() -> Result<[u8; 8], Error> { |
50 | /// let rng = rand::SystemRandom::new(); |
51 | /// let mut bytes = [0; 8]; |
52 | /// |
53 | /// // The `From<ring::error::Unspecified>` implementation above makes this |
54 | /// // equivalent to |
55 | /// // `rng.fill(&mut bytes).map_err(|_| Error::CryptoError)?`. |
56 | /// rng.fill(&mut bytes)?; |
57 | /// |
58 | /// Ok(bytes) |
59 | /// } |
60 | /// |
61 | /// assert!(eight_random_bytes().is_ok()); |
62 | /// ``` |
63 | /// |
64 | /// Experience with using and implementing other crypto libraries like has |
65 | /// shown that sophisticated error reporting facilities often cause significant |
66 | /// bugs themselves, both within the crypto library and within users of the |
67 | /// crypto library. This approach attempts to minimize complexity in the hopes |
68 | /// of avoiding such problems. In some cases, this approach may be too extreme, |
69 | /// and it may be important for an operation to provide some details about the |
70 | /// cause of a failure. Users of *ring* are encouraged to report such cases so |
71 | /// that they can be addressed individually. |
72 | /// |
73 | /// [`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html |
74 | /// [“Error Handling” in the Rust Book]: |
75 | /// https://doc.rust-lang.org/book/first-edition/error-handling.html#the-from-trait |
76 | #[derive (Clone, Copy, Debug, PartialEq)] |
77 | pub struct Unspecified; |
78 | |
79 | // This is required for the implementation of `std::error::Error`. |
80 | impl core::fmt::Display for Unspecified { |
81 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
82 | f.write_str(data:"ring::error::Unspecified" ) |
83 | } |
84 | } |
85 | |
86 | #[cfg (feature = "std" )] |
87 | impl std::error::Error for Unspecified {} |
88 | |
89 | impl From<untrusted::EndOfInput> for Unspecified { |
90 | fn from(_: untrusted::EndOfInput) -> Self { |
91 | Self |
92 | } |
93 | } |
94 | |
95 | impl From<core::array::TryFromSliceError> for Unspecified { |
96 | fn from(_: core::array::TryFromSliceError) -> Self { |
97 | Self |
98 | } |
99 | } |
100 | |
101 | /// An error parsing or validating a key. |
102 | /// |
103 | /// The `Display` implementation will return a string that will help you better |
104 | /// understand why a key was rejected change which errors are reported in which |
105 | /// situations while minimizing the likelihood that any applications will be |
106 | /// broken. |
107 | /// |
108 | /// Here is an incomplete list of reasons a key may be unsupported: |
109 | /// |
110 | /// * Invalid or Inconsistent Components: A component of the key has an invalid |
111 | /// value, or the mathematical relationship between two (or more) components |
112 | /// required for a valid key does not hold. |
113 | /// |
114 | /// * The encoding of the key is invalid. Perhaps the key isn't in the correct |
115 | /// format; e.g. it may be Base64 ("PEM") encoded, in which case the Base64 |
116 | /// encoding needs to be undone first. |
117 | /// |
118 | /// * The encoding includes a versioning mechanism and that mechanism indicates |
119 | /// that the key is encoded in a version of the encoding that isn't supported. |
120 | /// This might happen for multi-prime RSA keys (keys with more than two |
121 | /// private prime factors), which aren't supported, for example. |
122 | /// |
123 | /// * Too small or too Large: One of the primary components of the key is too |
124 | /// small or two large. Too-small keys are rejected for security reasons. Some |
125 | /// unnecessarily large keys are rejected for performance reasons. |
126 | /// |
127 | /// * Wrong algorithm: The key is not valid for the algorithm in which it was |
128 | /// being used. |
129 | /// |
130 | /// * Unexpected errors: Report this as a bug. |
131 | #[derive (Copy, Clone, Debug)] |
132 | pub struct KeyRejected(&'static str); |
133 | |
134 | impl KeyRejected { |
135 | pub(crate) fn inconsistent_components() -> Self { |
136 | Self("InconsistentComponents" ) |
137 | } |
138 | |
139 | pub(crate) fn invalid_component() -> Self { |
140 | Self("InvalidComponent" ) |
141 | } |
142 | |
143 | #[inline ] |
144 | pub(crate) fn invalid_encoding() -> Self { |
145 | Self("InvalidEncoding" ) |
146 | } |
147 | |
148 | // XXX: See the comment at the call site. |
149 | pub(crate) fn rng_failed() -> Self { |
150 | Self("RNG failed" ) |
151 | } |
152 | |
153 | pub(crate) fn public_key_is_missing() -> Self { |
154 | Self("PublicKeyIsMissing" ) |
155 | } |
156 | |
157 | #[cfg (feature = "alloc" )] |
158 | pub(crate) fn too_small() -> Self { |
159 | Self("TooSmall" ) |
160 | } |
161 | |
162 | #[cfg (feature = "alloc" )] |
163 | pub(crate) fn too_large() -> Self { |
164 | Self("TooLarge" ) |
165 | } |
166 | |
167 | pub(crate) fn version_not_supported() -> Self { |
168 | Self("VersionNotSupported" ) |
169 | } |
170 | |
171 | pub(crate) fn wrong_algorithm() -> Self { |
172 | Self("WrongAlgorithm" ) |
173 | } |
174 | |
175 | #[cfg (feature = "alloc" )] |
176 | pub(crate) fn private_modulus_len_not_multiple_of_512_bits() -> Self { |
177 | Self("PrivateModulusLenNotMultipleOf512Bits" ) |
178 | } |
179 | |
180 | pub(crate) fn unexpected_error() -> Self { |
181 | Self("UnexpectedError" ) |
182 | } |
183 | } |
184 | |
185 | #[cfg (feature = "std" )] |
186 | impl std::error::Error for KeyRejected {} |
187 | |
188 | impl core::fmt::Display for KeyRejected { |
189 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
190 | f.write_str(self.0) |
191 | } |
192 | } |
193 | |
194 | impl From<KeyRejected> for Unspecified { |
195 | fn from(_: KeyRejected) -> Self { |
196 | Self |
197 | } |
198 | } |
199 | |