forked from mirrors/relay
Switch to ring for crypto
This commit is contained in:
parent
731a831070
commit
2cbe4864c3
6 changed files with 54 additions and 37 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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,
|
||||||
|
|
11
src/error.rs
11
src/error.rs
|
@ -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),
|
||||||
|
|
|
@ -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>
|
||||||
})
|
})
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue