Compare commits

...

2 commits

8 changed files with 52 additions and 5 deletions

View file

@ -7,7 +7,6 @@ pub mod inbox;
pub mod init;
pub mod outbox;
pub mod auth;
pub mod httpsign;
pub mod normalizer;
pub mod side_effects;

26
utils/httpsign/Cargo.toml Normal file
View file

@ -0,0 +1,26 @@
[package]
name = "httpsign"
version = "0.1.0"
edition = "2021"
authors = [ "alemi <me@alemi.dev>" ]
description = "fediverse-friendly implementation of http signaures in rust"
license = "MIT"
#keywords = ["html", "markdown", "parser"]
repository = "https://git.alemi.dev/upub.git"
readme = "README.md"
[lib]
path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
thiserror = "1"
tracing = "0.1"
base64 = "0.22"
openssl = "0.10" # TODO handle pubkeys with a smaller crate
axum = { version = "0.7", optional = true }
[features]
default = []
axum = ["dep:axum"]

0
utils/httpsign/README.md Normal file
View file

View file

@ -1,9 +1,25 @@
use std::collections::BTreeMap;
use axum::http::request::Parts;
use base64::Engine;
use openssl::{hash::MessageDigest, pkey::PKey, sign::Verifier};
#[derive(Debug, thiserror::Error)]
pub enum HttpSignatureError {
#[error("openssl error: {0:?}")]
OpenSSL(#[from] openssl::error::ErrorStack),
#[error("invalid UTF8 in key: {0:?}")]
UTF8(#[from] std::str::Utf8Error),
#[error("os I/O error: {0}")]
IO(#[from] std::io::Error),
#[error("invalid base64: {0}")]
Base64(#[from] base64::DecodeError),
}
type Result<T> = std::result::Result<T, HttpSignatureError>;
#[derive(Debug, Clone, Default)]
pub struct HttpSignature {
pub key_id: String,
@ -60,7 +76,8 @@ impl HttpSignature {
self
}
pub fn build_from_parts(&mut self, parts: &Parts) -> &mut Self {
#[cfg(feature = "axum")]
pub fn build_from_parts(&mut self, parts: &axum::http::request::Parts) -> &mut Self {
let mut out = Vec::new();
for header in self.headers.iter() {
match header.as_str() {
@ -82,14 +99,14 @@ impl HttpSignature {
self
}
pub fn verify(&self, key: &str) -> crate::Result<bool> {
pub fn verify(&self, key: &str) -> Result<bool> {
let pubkey = PKey::public_key_from_pem(key.as_bytes())?;
let mut verifier = Verifier::new(MessageDigest::sha256(), &pubkey)?;
let signature = base64::prelude::BASE64_STANDARD.decode(&self.signature)?;
Ok(verifier.verify_oneshot(&signature, self.control.as_bytes())?)
}
pub fn sign(&mut self, key: &str) -> crate::Result<&str> {
pub fn sign(&mut self, key: &str) -> Result<&str> {
let privkey = PKey::private_key_from_pem(key.as_bytes())?;
let mut signer = openssl::sign::Signer::new(MessageDigest::sha256(), &privkey)?;
signer.update(self.control.as_bytes())?;
@ -100,6 +117,9 @@ impl HttpSignature {
#[cfg(test)]
mod test {
// TODO more tests!!!
#[test]
fn http_signature_signs_and_verifies() {
let key = openssl::rsa::Rsa::generate(2048).unwrap();

View file

@ -10,6 +10,7 @@ repository = "https://git.alemi.dev/upub.git"
readme = "README.md"
[lib]
path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View file

@ -9,6 +9,7 @@ keywords = ["upub", "uri", "base64"]
repository = "https://moonlit.technology/alemi/upub"
[lib]
path = "lib.rs"
[dependencies]
base64 = "0.22"