1use crate::Result;
19
20#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
22#[non_exhaustive]
23pub enum DigestAlgorithm {
24 Sha256,
26}
27
28#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
30#[non_exhaustive]
31pub enum SigningAlgorithm {
32 RS256,
34}
35
36pub trait CryptoProvider: std::fmt::Debug + Send + Sync {
38 fn digest(&self, algorithm: DigestAlgorithm) -> Result<Box<dyn DigestContext>>;
40
41 fn hmac(&self, algorithm: DigestAlgorithm, secret: &[u8]) -> Result<Box<dyn HmacContext>>;
43
44 fn sign(&self, algorithm: SigningAlgorithm, pem: &[u8]) -> Result<Box<dyn Signer>>;
46}
47
48pub trait DigestContext: Send {
50 fn update(&mut self, data: &[u8]);
54
55 fn finish(&mut self) -> Result<&[u8]>;
59}
60
61pub trait HmacContext: Send {
63 fn update(&mut self, data: &[u8]);
67
68 fn finish(&mut self) -> Result<&[u8]>;
72}
73
74pub trait Signer: Send + Sync {
76 fn sign(&self, string_to_sign: &[u8]) -> Result<Vec<u8>>;
78}
79
80pub(crate) fn crypto_provider(custom: Option<&dyn CryptoProvider>) -> Result<&dyn CryptoProvider> {
86 if let Some(x) = custom {
87 return Ok(x);
88 }
89
90 #[cfg(feature = "aws-lc-rs")]
91 {
92 Ok(&aws_lc_rs::PROVIDER)
93 }
94
95 #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
96 {
97 Ok(&ring::PROVIDER)
98 }
99
100 #[cfg(not(any(feature = "ring", feature = "aws-lc-rs")))]
101 {
102 Err(crate::Error::NotSupported {
103 source: "Must enable aws-lc-rs, ring, or specify custom CryptoProvider"
104 .to_string()
105 .into(),
106 })
107 }
108}
109
110#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
111pub(crate) mod ring {
112 use super::*;
113 use ::ring::{digest, hmac, rand, signature};
114 use thiserror::Error;
115
116 #[derive(Debug, Error)]
117 pub(crate) enum RingError {
118 #[error("No RSA key found in pem file")]
119 MissingKey,
120
121 #[error("Invalid RSA key: {}", source)]
122 InvalidKey {
123 #[from]
124 source: ::ring::error::KeyRejected,
125 },
126
127 #[error("Error reading pem file: {}", source)]
128 ReadPem {
129 source: rustls_pki_types::pem::Error,
130 },
131
132 #[error("Error signing: {}", source)]
133 Sign { source: ::ring::error::Unspecified },
134 }
135
136 impl From<RingError> for crate::Error {
137 fn from(value: RingError) -> Self {
138 Self::Generic {
139 store: "RingCryptoProvider",
140 source: Box::new(value),
141 }
142 }
143 }
144
145 pub(crate) const PROVIDER: RingCryptoProvider = RingCryptoProvider { _private: () };
146
147 #[derive(Debug, Default)]
148 pub(crate) struct RingCryptoProvider {
149 _private: (),
150 }
151
152 impl CryptoProvider for RingCryptoProvider {
153 fn digest(&self, algorithm: DigestAlgorithm) -> Result<Box<dyn DigestContext>> {
154 let algorithm = match algorithm {
155 DigestAlgorithm::Sha256 => &digest::SHA256,
156 };
157 let ctx = digest::Context::new(algorithm);
158 Ok(Box::new(RingDigestContext {
159 ctx: Some(ctx),
160 out: None,
161 }))
162 }
163
164 fn hmac(&self, algorithm: DigestAlgorithm, secret: &[u8]) -> Result<Box<dyn HmacContext>> {
165 let algorithm = match algorithm {
166 DigestAlgorithm::Sha256 => hmac::HMAC_SHA256,
167 };
168 let ctx = hmac::Context::with_key(&hmac::Key::new(algorithm, secret));
169 Ok(Box::new(RingHmacContext {
170 ctx: Some(ctx),
171 out: None,
172 }))
173 }
174
175 fn sign(&self, algorithm: SigningAlgorithm, pem: &[u8]) -> Result<Box<dyn Signer>> {
176 match algorithm {
177 SigningAlgorithm::RS256 => Ok(Box::new(RsaKeyPair::from_pem(pem)?)),
178 }
179 }
180 }
181
182 struct RingDigestContext {
183 ctx: Option<digest::Context>,
184 out: Option<digest::Digest>,
185 }
186
187 impl DigestContext for RingDigestContext {
188 fn update(&mut self, data: &[u8]) {
189 self.ctx.as_mut().unwrap().update(data);
190 }
191
192 fn finish(&mut self) -> Result<&[u8]> {
193 let digest = self.ctx.take().unwrap().finish();
194 Ok(digest::Digest::as_ref(self.out.insert(digest)))
195 }
196 }
197
198 struct RingHmacContext {
199 ctx: Option<hmac::Context>,
200 out: Option<hmac::Tag>,
201 }
202
203 impl HmacContext for RingHmacContext {
204 fn update(&mut self, data: &[u8]) {
205 self.ctx.as_mut().unwrap().update(data);
206 }
207
208 fn finish(&mut self) -> Result<&[u8]> {
209 let tag = self.ctx.take().unwrap().sign();
210 Ok(hmac::Tag::as_ref(self.out.insert(tag)))
211 }
212 }
213
214 #[derive(Debug)]
216 pub(crate) struct RsaKeyPair(signature::RsaKeyPair);
217
218 impl RsaKeyPair {
219 pub(crate) fn from_pem(encoded: &[u8]) -> Result<Self, RingError> {
221 use rustls_pki_types::PrivateKeyDer;
222 use rustls_pki_types::pem::PemObject;
223
224 match PrivateKeyDer::from_pem_slice(encoded) {
225 Ok(PrivateKeyDer::Pkcs8(key)) => Self::from_pkcs8(key.secret_pkcs8_der()),
226 Ok(PrivateKeyDer::Pkcs1(key)) => Self::from_der(key.secret_pkcs1_der()),
227 Ok(_) => Err(RingError::MissingKey),
228 Err(source) => Err(RingError::ReadPem { source }),
229 }
230 }
231
232 pub(crate) fn from_pkcs8(key: &[u8]) -> Result<Self, RingError> {
234 Ok(Self(signature::RsaKeyPair::from_pkcs8(key)?))
235 }
236
237 pub(crate) fn from_der(key: &[u8]) -> Result<Self, RingError> {
239 Ok(Self(signature::RsaKeyPair::from_der(key)?))
240 }
241 }
242
243 impl Signer for RsaKeyPair {
244 fn sign(&self, string_to_sign: &[u8]) -> Result<Vec<u8>> {
245 let mut signature = vec![0; self.0.public().modulus_len()];
246 self.0
247 .sign(
248 &signature::RSA_PKCS1_SHA256,
249 &rand::SystemRandom::new(),
250 string_to_sign,
251 &mut signature,
252 )
253 .map_err(|source| RingError::Sign { source })?;
254
255 Ok(signature)
256 }
257 }
258}
259
260#[cfg(feature = "aws-lc-rs")]
261pub(crate) mod aws_lc_rs {
262 use super::*;
263 use ::aws_lc_rs::{digest, hmac, rand, signature};
264 use thiserror::Error;
265
266 #[derive(Debug, Error)]
267 pub(crate) enum AwsLcError {
268 #[error("No RSA key found in pem file")]
269 MissingKey,
270
271 #[error("Invalid RSA key: {}", source)]
272 InvalidKey {
273 #[from]
274 source: ::aws_lc_rs::error::KeyRejected,
275 },
276
277 #[error("Error reading pem file: {}", source)]
278 ReadPem {
279 source: rustls_pki_types::pem::Error,
280 },
281
282 #[error("Error signing: {}", source)]
283 Sign {
284 source: ::aws_lc_rs::error::Unspecified,
285 },
286 }
287
288 impl From<AwsLcError> for crate::Error {
289 fn from(value: AwsLcError) -> Self {
290 Self::Generic {
291 store: "AwsLcCryptoProvider",
292 source: Box::new(value),
293 }
294 }
295 }
296
297 pub(crate) const PROVIDER: AwsLcCryptoProvider = AwsLcCryptoProvider { _private: () };
298
299 #[derive(Debug, Default)]
300 pub(crate) struct AwsLcCryptoProvider {
301 _private: (),
302 }
303
304 impl CryptoProvider for AwsLcCryptoProvider {
305 fn digest(&self, algorithm: DigestAlgorithm) -> Result<Box<dyn DigestContext>> {
306 let algorithm = match algorithm {
307 DigestAlgorithm::Sha256 => &digest::SHA256,
308 };
309 let ctx = digest::Context::new(algorithm);
310 Ok(Box::new(AwsLcDigestContext {
311 ctx: Some(ctx),
312 out: None,
313 }))
314 }
315
316 fn hmac(&self, algorithm: DigestAlgorithm, secret: &[u8]) -> Result<Box<dyn HmacContext>> {
317 let algorithm = match algorithm {
318 DigestAlgorithm::Sha256 => hmac::HMAC_SHA256,
319 };
320 let ctx = hmac::Context::with_key(&hmac::Key::new(algorithm, secret));
321 Ok(Box::new(AwsLcHmacContext {
322 ctx: Some(ctx),
323 out: None,
324 }))
325 }
326
327 fn sign(&self, algorithm: SigningAlgorithm, pem: &[u8]) -> Result<Box<dyn Signer>> {
328 match algorithm {
329 SigningAlgorithm::RS256 => Ok(Box::new(RsaKeyPair::from_pem(pem)?)),
330 }
331 }
332 }
333
334 struct AwsLcDigestContext {
335 ctx: Option<digest::Context>,
336 out: Option<digest::Digest>,
337 }
338
339 impl DigestContext for AwsLcDigestContext {
340 fn update(&mut self, data: &[u8]) {
341 self.ctx.as_mut().unwrap().update(data);
342 }
343
344 fn finish(&mut self) -> Result<&[u8]> {
345 let digest = self.ctx.take().unwrap().finish();
346 Ok(digest::Digest::as_ref(self.out.insert(digest)))
347 }
348 }
349
350 struct AwsLcHmacContext {
351 ctx: Option<hmac::Context>,
352 out: Option<hmac::Tag>,
353 }
354
355 impl HmacContext for AwsLcHmacContext {
356 fn update(&mut self, data: &[u8]) {
357 self.ctx.as_mut().unwrap().update(data);
358 }
359
360 fn finish(&mut self) -> Result<&[u8]> {
361 let tag = self.ctx.take().unwrap().sign();
362 Ok(hmac::Tag::as_ref(self.out.insert(tag)))
363 }
364 }
365
366 #[derive(Debug)]
368 pub(crate) struct RsaKeyPair(signature::RsaKeyPair);
369
370 impl RsaKeyPair {
371 pub(crate) fn from_pem(encoded: &[u8]) -> Result<Self, AwsLcError> {
373 use rustls_pki_types::PrivateKeyDer;
374 use rustls_pki_types::pem::PemObject;
375
376 match PrivateKeyDer::from_pem_slice(encoded) {
377 Ok(PrivateKeyDer::Pkcs8(key)) => Self::from_pkcs8(key.secret_pkcs8_der()),
378 Ok(PrivateKeyDer::Pkcs1(key)) => Self::from_der(key.secret_pkcs1_der()),
379 Ok(_) => Err(AwsLcError::MissingKey),
380 Err(source) => Err(AwsLcError::ReadPem { source }),
381 }
382 }
383
384 pub(crate) fn from_pkcs8(key: &[u8]) -> Result<Self, AwsLcError> {
386 Ok(Self(signature::RsaKeyPair::from_pkcs8(key)?))
387 }
388
389 pub(crate) fn from_der(key: &[u8]) -> Result<Self, AwsLcError> {
391 Ok(Self(signature::RsaKeyPair::from_der(key)?))
392 }
393 }
394
395 impl Signer for RsaKeyPair {
396 fn sign(&self, string_to_sign: &[u8]) -> Result<Vec<u8>> {
397 let mut signature = vec![0; self.0.public_modulus_len()];
398 self.0
399 .sign(
400 &signature::RSA_PKCS1_SHA256,
401 &rand::SystemRandom::new(),
402 string_to_sign,
403 &mut signature,
404 )
405 .map_err(|source| AwsLcError::Sign { source })?;
406
407 Ok(signature)
408 }
409 }
410}