Create inline module for crypto primitives

This commit is contained in:
Dirkjan Ochtman 2024-07-16 10:03:18 +02:00
parent 3679fc3eb2
commit e0ac09439e
2 changed files with 54 additions and 39 deletions

View File

@ -8,11 +8,6 @@ use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
#[cfg(feature = "aws-lc-rs")]
pub(crate) use aws_lc_rs as ring_like;
#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
pub(crate) use ring as ring_like;
use base64::prelude::{Engine, BASE64_URL_SAFE_NO_PAD}; use base64::prelude::{Engine, BASE64_URL_SAFE_NO_PAD};
use http_body_util::{BodyExt, Full}; use http_body_util::{BodyExt, Full};
use hyper::body::{Bytes, Incoming}; use hyper::body::{Bytes, Incoming};
@ -22,10 +17,6 @@ use hyper_util::client::legacy::connect::Connect;
use hyper_util::client::legacy::Client as HyperClient; use hyper_util::client::legacy::Client as HyperClient;
#[cfg(feature = "hyper-rustls")] #[cfg(feature = "hyper-rustls")]
use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor}; use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor};
use ring_like::digest::{digest, SHA256};
use ring_like::rand::SystemRandom;
use ring_like::signature::{EcdsaKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING};
use ring_like::{hmac, pkcs8};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::Serialize; use serde::Serialize;
@ -550,20 +541,28 @@ impl fmt::Debug for Client {
} }
struct Key { struct Key {
rng: SystemRandom, rng: crypto::SystemRandom,
signing_algorithm: SigningAlgorithm, signing_algorithm: SigningAlgorithm,
inner: EcdsaKeyPair, inner: crypto::EcdsaKeyPair,
thumb: String, thumb: String,
} }
impl Key { impl Key {
fn generate() -> Result<(Self, pkcs8::Document), Error> { fn generate() -> Result<(Self, crypto::pkcs8::Document), Error> {
let rng = SystemRandom::new(); let rng = crypto::SystemRandom::new();
let pkcs8 = EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, &rng)?; let pkcs8 =
crypto::EcdsaKeyPair::generate_pkcs8(&crypto::ECDSA_P256_SHA256_FIXED_SIGNING, &rng)?;
#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))] #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
let key = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, pkcs8.as_ref(), &rng)?; let key = crypto::EcdsaKeyPair::from_pkcs8(
&crypto::ECDSA_P256_SHA256_FIXED_SIGNING,
pkcs8.as_ref(),
&rng,
)?;
#[cfg(feature = "aws-lc-rs")] #[cfg(feature = "aws-lc-rs")]
let key = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, pkcs8.as_ref())?; let key = crypto::EcdsaKeyPair::from_pkcs8(
&crypto::ECDSA_P256_SHA256_FIXED_SIGNING,
pkcs8.as_ref(),
)?;
let thumb = BASE64_URL_SAFE_NO_PAD.encode(Jwk::thumb_sha256(&key)?); let thumb = BASE64_URL_SAFE_NO_PAD.encode(Jwk::thumb_sha256(&key)?);
Ok(( Ok((
@ -578,11 +577,16 @@ impl Key {
} }
fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self, Error> { fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self, Error> {
let rng = SystemRandom::new(); let rng = crypto::SystemRandom::new();
#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))] #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
let key = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, pkcs8_der, &rng)?; let key = crypto::EcdsaKeyPair::from_pkcs8(
&crypto::ECDSA_P256_SHA256_FIXED_SIGNING,
pkcs8_der,
&rng,
)?;
#[cfg(feature = "aws-lc-rs")] #[cfg(feature = "aws-lc-rs")]
let key = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, pkcs8_der)?; let key =
crypto::EcdsaKeyPair::from_pkcs8(&crypto::ECDSA_P256_SHA256_FIXED_SIGNING, pkcs8_der)?;
let thumb = BASE64_URL_SAFE_NO_PAD.encode(Jwk::thumb_sha256(&key)?); let thumb = BASE64_URL_SAFE_NO_PAD.encode(Jwk::thumb_sha256(&key)?);
@ -596,7 +600,7 @@ impl Key {
} }
impl Signer for Key { impl Signer for Key {
type Signature = ring_like::signature::Signature; type Signature = crypto::Signature;
fn header<'n, 'u: 'n, 's: 'u>(&'s self, nonce: Option<&'n str>, url: &'u str) -> Header<'n> { fn header<'n, 'u: 'n, 's: 'u>(&'s self, nonce: Option<&'n str>, url: &'u str) -> Header<'n> {
debug_assert!(nonce.is_some()); debug_assert!(nonce.is_some());
@ -638,7 +642,7 @@ impl KeyAuthorization {
/// ///
/// <https://datatracker.ietf.org/doc/html/rfc8737#section-3> /// <https://datatracker.ietf.org/doc/html/rfc8737#section-3>
pub fn digest(&self) -> impl AsRef<[u8]> { pub fn digest(&self) -> impl AsRef<[u8]> {
digest(&SHA256, self.0.as_bytes()) crypto::digest(&crypto::SHA256, self.0.as_bytes())
} }
/// Get the base64-encoded SHA256 digest of the key authorization /// Get the base64-encoded SHA256 digest of the key authorization
@ -660,7 +664,7 @@ impl fmt::Debug for KeyAuthorization {
/// See RFC 8555 section 7.3.4 for more information. /// See RFC 8555 section 7.3.4 for more information.
pub struct ExternalAccountKey { pub struct ExternalAccountKey {
id: String, id: String,
key: hmac::Key, key: crypto::hmac::Key,
} }
impl ExternalAccountKey { impl ExternalAccountKey {
@ -668,13 +672,13 @@ impl ExternalAccountKey {
pub fn new(id: String, key_value: &[u8]) -> Self { pub fn new(id: String, key_value: &[u8]) -> Self {
Self { Self {
id, id,
key: hmac::Key::new(hmac::HMAC_SHA256, key_value), key: crypto::hmac::Key::new(crypto::hmac::HMAC_SHA256, key_value),
} }
} }
} }
impl Signer for ExternalAccountKey { impl Signer for ExternalAccountKey {
type Signature = hmac::Tag; type Signature = crypto::hmac::Tag;
fn header<'n, 'u: 'n, 's: 'u>(&'s self, nonce: Option<&'n str>, url: &'u str) -> Header<'n> { fn header<'n, 'u: 'n, 's: 'u>(&'s self, nonce: Option<&'n str>, url: &'u str) -> Header<'n> {
debug_assert_eq!(nonce, None); debug_assert_eq!(nonce, None);
@ -687,7 +691,7 @@ impl Signer for ExternalAccountKey {
} }
fn sign(&self, payload: &[u8]) -> Result<Self::Signature, Error> { fn sign(&self, payload: &[u8]) -> Result<Self::Signature, Error> {
Ok(hmac::sign(&self.key, payload)) Ok(crypto::hmac::sign(&self.key, payload))
} }
} }
@ -750,6 +754,20 @@ where
} }
} }
mod crypto {
#[cfg(feature = "aws-lc-rs")]
pub(crate) use aws_lc_rs as ring_like;
#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
pub(crate) use ring as ring_like;
pub(crate) use ring_like::digest::{digest, Digest, SHA256};
pub(crate) use ring_like::error::{KeyRejected, Unspecified};
pub(crate) use ring_like::rand::SystemRandom;
pub(crate) use ring_like::signature::{EcdsaKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING};
pub(crate) use ring_like::signature::{KeyPair, Signature};
pub(crate) use ring_like::{hmac, pkcs8};
}
const JOSE_JSON: &str = "application/jose+json"; const JOSE_JSON: &str = "application/jose+json";
const REPLAY_NONCE: &str = "Replay-Nonce"; const REPLAY_NONCE: &str = "Replay-Nonce";

View File

@ -1,22 +1,17 @@
use std::fmt; use std::fmt;
#[cfg(feature = "aws-lc-rs")]
pub(crate) use aws_lc_rs as ring_like;
#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
pub(crate) use ring as ring_like;
use base64::prelude::{Engine, BASE64_URL_SAFE_NO_PAD}; use base64::prelude::{Engine, BASE64_URL_SAFE_NO_PAD};
use http_body_util::BodyExt; use http_body_util::BodyExt;
use hyper::body::Incoming; use hyper::body::Incoming;
use hyper::Response; use hyper::Response;
use ring_like::digest::{digest, Digest, SHA256};
use ring_like::signature::{EcdsaKeyPair, KeyPair};
use rustls_pki_types::CertificateDer; use rustls_pki_types::CertificateDer;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::ser::SerializeMap; use serde::ser::SerializeMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
use crate::crypto::{self, KeyPair};
/// Error type for instant-acme /// Error type for instant-acme
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum Error { pub enum Error {
@ -30,10 +25,10 @@ pub enum Error {
Base64(#[from] base64::DecodeError), Base64(#[from] base64::DecodeError),
/// Failed from cryptographic operations /// Failed from cryptographic operations
#[error("cryptographic operation failed: {0}")] #[error("cryptographic operation failed: {0}")]
Crypto(#[from] ring_like::error::Unspecified), Crypto(#[from] crypto::Unspecified),
/// Failed to instantiate a private key /// Failed to instantiate a private key
#[error("invalid key bytes: {0}")] #[error("invalid key bytes: {0}")]
CryptoKey(#[from] ring_like::error::KeyRejected), CryptoKey(#[from] crypto::KeyRejected),
/// HTTP failure /// HTTP failure
#[error("HTTP request failure: {0}")] #[error("HTTP request failure: {0}")]
Http(#[from] hyper::http::Error), Http(#[from] hyper::http::Error),
@ -205,7 +200,7 @@ pub(crate) enum KeyOrKeyId<'a> {
} }
impl<'a> KeyOrKeyId<'a> { impl<'a> KeyOrKeyId<'a> {
pub(crate) fn from_key(key: &EcdsaKeyPair) -> KeyOrKeyId<'static> { pub(crate) fn from_key(key: &crypto::EcdsaKeyPair) -> KeyOrKeyId<'static> {
KeyOrKeyId::Key(Jwk::new(key)) KeyOrKeyId::Key(Jwk::new(key))
} }
} }
@ -221,7 +216,7 @@ pub(crate) struct Jwk {
} }
impl Jwk { impl Jwk {
pub(crate) fn new(key: &EcdsaKeyPair) -> Self { pub(crate) fn new(key: &crypto::EcdsaKeyPair) -> Self {
let (x, y) = key.public_key().as_ref()[1..].split_at(32); let (x, y) = key.public_key().as_ref()[1..].split_at(32);
Self { Self {
alg: SigningAlgorithm::Es256, alg: SigningAlgorithm::Es256,
@ -233,10 +228,12 @@ impl Jwk {
} }
} }
pub(crate) fn thumb_sha256(key: &EcdsaKeyPair) -> Result<Digest, serde_json::Error> { pub(crate) fn thumb_sha256(
key: &crypto::EcdsaKeyPair,
) -> Result<crypto::Digest, serde_json::Error> {
let jwk = Self::new(key); let jwk = Self::new(key);
Ok(digest( Ok(crypto::digest(
&SHA256, &crypto::SHA256,
&serde_json::to_vec(&JwkThumb { &serde_json::to_vec(&JwkThumb {
crv: jwk.crv, crv: jwk.crv,
kty: jwk.kty, kty: jwk.kty,