Switch to ring for crypto

This commit is contained in:
asonix 2023-08-04 18:34:42 -05:00
parent 731a831070
commit 2cbe4864c3
6 changed files with 54 additions and 37 deletions

8
Cargo.lock generated
View file

@ -423,6 +423,7 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"quanta", "quanta",
"rand", "rand",
"ring",
"rsa", "rsa",
"rsa-magic-public-key", "rsa-magic-public-key",
"ructe", "ructe",
@ -1460,9 +1461,9 @@ dependencies = [
[[package]] [[package]]
name = "http-signature-normalization-actix" name = "http-signature-normalization-actix"
version = "0.10.0" version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7978cadb8c73ab0d7115a4260e8a64188212ce44d11f0b0109c4beebc6bbb5c9" checksum = "f16b1af0de27fe75ea5c1da8da1ce826274cc623bda49eb5e9395aa4ea0b34d4"
dependencies = [ dependencies = [
"actix-http", "actix-http",
"actix-rt", "actix-rt",
@ -1471,7 +1472,7 @@ dependencies = [
"base64 0.13.1", "base64 0.13.1",
"futures-util", "futures-util",
"http-signature-normalization", "http-signature-normalization",
"sha2", "ring",
"thiserror", "thiserror",
"tokio", "tokio",
"tracing", "tracing",
@ -2743,7 +2744,6 @@ dependencies = [
"pkcs1", "pkcs1",
"pkcs8", "pkcs8",
"rand_core", "rand_core",
"sha2",
"signature", "signature",
"spki", "spki",
"subtle", "subtle",

View file

@ -55,7 +55,8 @@ opentelemetry-otlp = "0.12"
pin-project-lite = "0.2.9" pin-project-lite = "0.2.9"
quanta = "0.11.0" quanta = "0.11.0"
rand = "0.8" rand = "0.8"
rsa = { version = "0.9", features = ["sha2"] } ring = "0.16.20"
rsa = { version = "0.9" }
rsa-magic-public-key = "0.8.0" rsa-magic-public-key = "0.8.0"
rustls = "0.20.7" rustls = "0.20.7"
rustls-pemfile = "1.0.1" rustls-pemfile = "1.0.1"
@ -89,9 +90,9 @@ default-features = false
features = ["background-jobs-actix", "error-logging"] features = ["background-jobs-actix", "error-logging"]
[dependencies.http-signature-normalization-actix] [dependencies.http-signature-normalization-actix]
version = "0.10.0" version = "0.10.1"
default-features = false default-features = false
features = ["client", "server", "sha-2"] features = ["client", "server", "ring"]
[dependencies.tracing-actix-web] [dependencies.tracing-actix-web]
version = "0.7.5" version = "0.7.5"

View file

@ -11,8 +11,7 @@ use activitystreams::{
}, },
}; };
use config::Environment; use config::Environment;
use http_signature_normalization_actix::prelude::VerifyDigest; use http_signature_normalization_actix::{digest::ring::Sha256, prelude::VerifyDigest};
use rsa::sha2::{Digest, Sha256};
use rustls::{Certificate, PrivateKey}; use rustls::{Certificate, PrivateKey};
use std::{ use std::{
io::BufReader, io::BufReader,

View file

@ -81,6 +81,9 @@ pub(crate) enum ErrorKind {
#[error("Couldn't encode public key, {0}")] #[error("Couldn't encode public key, {0}")]
Spki(#[from] rsa::pkcs8::spki::Error), Spki(#[from] rsa::pkcs8::spki::Error),
#[error("Couldn't sign request")]
SignRequest,
#[error("Couldn't parse IRI, {0}")] #[error("Couldn't parse IRI, {0}")]
ParseIri(#[from] activitystreams::iri_string::validate::Error), ParseIri(#[from] activitystreams::iri_string::validate::Error),
@ -105,11 +108,11 @@ pub(crate) enum ErrorKind {
#[error("Couldn't sign digest")] #[error("Couldn't sign digest")]
Signature(#[from] rsa::signature::Error), Signature(#[from] rsa::signature::Error),
#[error("Couldn't read signature")]
ReadSignature(rsa::signature::Error),
#[error("Couldn't verify signature")] #[error("Couldn't verify signature")]
VerifySignature(rsa::signature::Error), VerifySignature,
#[error("Failed to encode key der")]
DerEncode,
#[error("Couldn't parse the signature header")] #[error("Couldn't parse the signature header")]
HeaderValidation(#[from] actix_web::http::header::InvalidHeaderValue), HeaderValidation(#[from] actix_web::http::header::InvalidHeaderValue),

View file

@ -8,10 +8,7 @@ use crate::{
use activitystreams::{base::BaseExt, iri, iri_string::types::IriString}; use activitystreams::{base::BaseExt, iri, iri_string::types::IriString};
use base64::{engine::general_purpose::STANDARD, Engine}; use base64::{engine::general_purpose::STANDARD, Engine};
use http_signature_normalization_actix::{prelude::*, verify::DeprecatedAlgorithm, Spawn}; use http_signature_normalization_actix::{prelude::*, verify::DeprecatedAlgorithm, Spawn};
use rsa::{ use rsa::{pkcs1::EncodeRsaPublicKey, pkcs8::DecodePublicKey, RsaPublicKey};
pkcs1v15::Signature, pkcs1v15::VerifyingKey, pkcs8::DecodePublicKey, sha2::Sha256,
signature::Verifier, RsaPublicKey,
};
use std::{future::Future, pin::Pin}; use std::{future::Future, pin::Pin};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -128,19 +125,23 @@ async fn do_verify(
signing_string: String, signing_string: String,
) -> Result<(), Error> { ) -> Result<(), Error> {
let public_key = RsaPublicKey::from_public_key_pem(public_key.trim())?; let public_key = RsaPublicKey::from_public_key_pem(public_key.trim())?;
let public_key_der = public_key
.to_pkcs1_der()
.map_err(|_| ErrorKind::DerEncode)?;
let public_key = ring::signature::UnparsedPublicKey::new(
&ring::signature::RSA_PKCS1_2048_8192_SHA256,
public_key_der,
);
let span = tracing::Span::current(); let span = tracing::Span::current();
spawner spawner
.spawn_blocking(move || { .spawn_blocking(move || {
span.in_scope(|| { span.in_scope(|| {
let decoded = STANDARD.decode(signature)?; let decoded = STANDARD.decode(signature)?;
let signature =
Signature::try_from(decoded.as_slice()).map_err(ErrorKind::ReadSignature)?;
let verifying_key = VerifyingKey::<Sha256>::new(public_key); public_key
verifying_key .verify(signing_string.as_bytes(), decoded.as_slice())
.verify(signing_string.as_bytes(), &signature) .map_err(|_| ErrorKind::VerifySignature)?;
.map_err(ErrorKind::VerifySignature)?;
Ok(()) as Result<(), Error> Ok(()) as Result<(), Error>
}) })

View file

@ -8,14 +8,12 @@ use actix_web::http::header::Date;
use awc::{error::SendRequestError, Client, ClientResponse, Connector}; use awc::{error::SendRequestError, Client, ClientResponse, Connector};
use base64::{engine::general_purpose::STANDARD, Engine}; use base64::{engine::general_purpose::STANDARD, Engine};
use dashmap::DashMap; use dashmap::DashMap;
use http_signature_normalization_actix::prelude::*; use http_signature_normalization_actix::{digest::ring::Sha256, prelude::*};
use rand::thread_rng; use ring::{
use rsa::{ rand::SystemRandom,
pkcs1v15::SigningKey, signature::{RsaKeyPair, RSA_PKCS1_SHA256},
sha2::{Digest, Sha256},
signature::{RandomizedSigner, SignatureEncoding},
RsaPrivateKey,
}; };
use rsa::{pkcs1::EncodeRsaPrivateKey, RsaPrivateKey};
use std::{ use std::{
sync::Arc, sync::Arc,
time::{Duration, SystemTime}, time::{Duration, SystemTime},
@ -145,7 +143,8 @@ pub(crate) struct Requests {
client: Client, client: Client,
key_id: String, key_id: String,
user_agent: String, user_agent: String,
private_key: RsaPrivateKey, private_key: Arc<RsaKeyPair>,
rng: SystemRandom,
config: Config<Spawner>, config: Config<Spawner>,
breakers: Breakers, breakers: Breakers,
last_online: Arc<LastOnline>, last_online: Arc<LastOnline>,
@ -196,12 +195,16 @@ impl Requests {
timeout_seconds: u64, timeout_seconds: u64,
spawner: Spawner, spawner: Spawner,
) -> Self { ) -> Self {
let private_key_der = private_key.to_pkcs1_der().expect("Can encode der");
let private_key = ring::signature::RsaKeyPair::from_der(private_key_der.as_bytes())
.expect("Key is valid");
Requests { Requests {
pool_size, pool_size,
client: build_client(&user_agent, pool_size, timeout_seconds), client: build_client(&user_agent, pool_size, timeout_seconds),
key_id, key_id,
user_agent, user_agent,
private_key, private_key: Arc::new(private_key),
rng: SystemRandom::new(),
config: Config::new().mastodon_compat().spawner(spawner), config: Config::new().mastodon_compat().spawner(spawner),
breakers, breakers,
last_online, last_online,
@ -407,19 +410,29 @@ impl Requests {
fn signer(&self) -> Signer { fn signer(&self) -> Signer {
Signer { Signer {
private_key: self.private_key.clone(), private_key: self.private_key.clone(),
rng: self.rng.clone(),
} }
} }
} }
struct Signer { struct Signer {
private_key: RsaPrivateKey, private_key: Arc<RsaKeyPair>,
rng: SystemRandom,
} }
impl Signer { impl Signer {
fn sign(&self, signing_string: &str) -> Result<String, Error> { fn sign(&self, signing_string: &str) -> Result<String, Error> {
let signing_key = SigningKey::<Sha256>::new(self.private_key.clone()); let mut signature = vec![0; self.private_key.public_modulus_len()];
let signature =
signing_key.try_sign_with_rng(&mut thread_rng(), signing_string.as_bytes())?; self.private_key
Ok(STANDARD.encode(signature.to_bytes().as_ref())) .sign(
&RSA_PKCS1_SHA256,
&self.rng,
signing_string.as_bytes(),
&mut signature,
)
.map_err(|_| ErrorKind::SignRequest)?;
Ok(STANDARD.encode(&signature))
} }
} }