actpub-httpsig 0.2.0

Dual-stack HTTP Message Signatures (Cavage draft-12 + RFC 9421) with RSA & Ed25519 via aws-lc-rs.
Documentation

Dual-stack HTTP message signatures for ActivityPub.

Provides signing and verification for both:

  • Cavage draft-12 — the de-facto Fediverse standard (Mastodon, Pleroma, Lemmy, Misskey, …)
  • RFC 9421 — the finalized IETF HTTP Message Signatures standard (Mastodon 4.5+ accepts both)

Algorithms supported out of the box:

  • rsa-sha256 (2048/4096-bit) — legacy main-key format, required for interop with current Mastodon
  • ed25519 — FEP-521a Multikey, recommended for new deployments

All cryptographic primitives are backed by aws-lc-rs, a memory-safe, constant-time, FIPS 140-3 validated library maintained by AWS. This crate is therefore not affected by RUSTSEC-2023-0071 (Marvin Attack) that impacts the pure-Rust rsa crate.

The crate is HTTP-framework agnostic: it operates on [http::Request] values and leaves transport to the caller.

Example — Cavage signing

# use actpub_httpsig::{SigningKey, CavageSigner, sha256_digest_header};
# use http::{Request, Method};
let key = SigningKey::generate_ed25519();
let body: Vec<u8> = br#"{"type":"Follow"}"#.to_vec();
let mut req = Request::builder()
    .method(Method::POST)
    .uri("https://example.com/inbox")
    .header("host", "example.com")
    .header("date", "Sun, 05 Jan 2014 21:31:40 GMT")
    .header("digest", sha256_digest_header(&body))
    .header("content-type", "application/activity+json")
    .body(body)
    .unwrap();

let signer = CavageSigner::new(&key, "https://example.com/users/alice#main-key");
signer.sign(&mut req).unwrap();
assert!(req.headers().contains_key("signature"));