diff options
author | Felix <me@nutomic.com> | 2020-04-19 19:35:40 +0200 |
---|---|---|
committer | Felix <me@nutomic.com> | 2020-04-19 19:35:40 +0200 |
commit | 7117b5ce324e5e24637860bbb686624ce0b80f02 (patch) | |
tree | c8b419e0241d54e5eb533425891b8bc1743aa2bb /server/src/apub/signatures.rs | |
parent | 5284dc0c5282f878f452c96ea08643e298708d26 (diff) |
Verifyt http signatures
Diffstat (limited to 'server/src/apub/signatures.rs')
-rw-r--r-- | server/src/apub/signatures.rs | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/server/src/apub/signatures.rs b/server/src/apub/signatures.rs index 4181e11f..40b3c738 100644 --- a/server/src/apub/signatures.rs +++ b/server/src/apub/signatures.rs @@ -1,13 +1,19 @@ use activitystreams::{actor::Actor, ext::Extension}; +use actix_web::HttpRequest; use failure::Error; use http::request::Builder; use http_signature_normalization::Config; +use log::debug; use openssl::hash::MessageDigest; -use openssl::sign::Signer; +use openssl::sign::{Signer, Verifier}; use openssl::{pkey::PKey, rsa::Rsa}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; +lazy_static! { + static ref HTTP_SIG_CONFIG: Config = Config::new(); +} + pub struct Keypair { pub private_key: String, pub public_key: String, @@ -29,7 +35,6 @@ pub fn generate_actor_keypair() -> Result<Keypair, Error> { /// TODO: would be nice to pass the sending actor in, instead of raw privatekey/id strings pub fn sign(request: &Builder, private_key: &str, sender_id: &str) -> Result<String, Error> { let signing_key_id = format!("{}#main-key", sender_id); - let config = Config::new(); let headers = request .headers_ref() @@ -40,7 +45,7 @@ pub fn sign(request: &Builder, private_key: &str, sender_id: &str) -> Result<Str }) .collect::<Result<BTreeMap<String, String>, Error>>()?; - let signature_header_value = config + let signature_header_value = HTTP_SIG_CONFIG .begin_sign( request.method_ref().unwrap().as_str(), request @@ -62,6 +67,43 @@ pub fn sign(request: &Builder, private_key: &str, sender_id: &str) -> Result<Str Ok(signature_header_value) } +pub fn verify(request: &HttpRequest, public_key: &str) -> Result<(), Error> { + let headers = request + .headers() + .iter() + .map(|h| -> Result<(String, String), Error> { + Ok((h.0.as_str().to_owned(), h.1.to_str()?.to_owned())) + }) + .collect::<Result<BTreeMap<String, String>, Error>>()?; + + let verified = HTTP_SIG_CONFIG + .begin_verify( + request.method().as_str(), + request.uri().path_and_query().unwrap().as_str(), + headers, + )? + .verify(|signature, signing_string| -> Result<bool, Error> { + debug!( + "Verifying with key {}, message {}", + &public_key, &signing_string + ); + let public_key = PKey::public_key_from_pem(public_key.as_bytes())?; + let mut verifier = Verifier::new(MessageDigest::sha256(), &public_key).unwrap(); + verifier.update(&signing_string.as_bytes()).unwrap(); + Ok(verifier.verify(&base64::decode(signature)?)?) + })?; + + if verified { + debug!("verified signature for {}", &request.uri()); + Ok(()) + } else { + Err(format_err!( + "Invalid signature on request: {}", + &request.uri() + )) + } +} + // The following is taken from here: // https://docs.rs/activitystreams/0.5.0-alpha.17/activitystreams/ext/index.html |