summaryrefslogtreecommitdiffstats
path: root/server/src/apub/signatures.rs
diff options
context:
space:
mode:
authorFelix <me@nutomic.com>2020-04-19 19:35:40 +0200
committerFelix <me@nutomic.com>2020-04-19 19:35:40 +0200
commit7117b5ce324e5e24637860bbb686624ce0b80f02 (patch)
treec8b419e0241d54e5eb533425891b8bc1743aa2bb /server/src/apub/signatures.rs
parent5284dc0c5282f878f452c96ea08643e298708d26 (diff)
Verifyt http signatures
Diffstat (limited to 'server/src/apub/signatures.rs')
-rw-r--r--server/src/apub/signatures.rs48
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