Skip to main content

herolib_crypt/httpsig/
mod.rs

1//! # HeroLib HTTP Signatures
2//!
3//! RFC 9421 compliant HTTP Message Signatures with Ed25519 cryptography.
4//!
5//! This module provides secure, standards-compliant HTTP request authentication
6//! by signing message components (method, path, headers, body) with Ed25519 keys.
7//!
8//! ## Features
9//!
10//! - **RFC 9421 Compliance**: HTTP Message Signatures standard
11//! - **RFC 9530 Compliance**: Content-Digest for body integrity
12//! - **Ed25519 Signatures**: Via integrated keys module
13//! - **Replay Protection**: Timestamp-based with configurable tolerance
14//! - **Universal Integration**: Works with any HTTP library using the `http` crate
15//! - **Rhai Scripting**: Optional scripting support
16//!
17//! ## Security Policy
18//!
19//! This module enforces strict security policies:
20//!
21//! - **Always signs**: `@method`, `@path`, `@authority`, `content-digest`
22//! - **Mandatory digest**: Even for bodyless requests (GET, DELETE)
23//! - **Timestamp protection**: Configurable replay window (default: 300s)
24//! - **Canonical authority**: Normalized host:port to prevent proxy attacks
25//!
26//! ## Example: Signing a Request
27//!
28//! ```rust
29//! use herolib_crypt::httpsig::{HttpSigner, HttpSigError};
30//! use herolib_crypt::keys::Ed25519Keypair;
31//! use http::Request;
32//!
33//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
34//! // Create a signer with your keypair
35//! let keypair = Ed25519Keypair::generate()?;
36//! let signer = HttpSigner::new(keypair, "user-123");
37//!
38//! // Build your HTTP request
39//! let body = b"{\"amount\": 100}";
40//! let mut request = Request::post("https://api.service.com/api/v1/payments")
41//!     .header("content-type", "application/json")
42//!     .body(body.to_vec())?;
43//!
44//! // Sign the request (adds signature headers automatically)
45//! signer.sign_request(&mut request, body)?;
46//!
47//! // Request now has Signature-Input, Signature, and Content-Digest headers
48//! # Ok(())
49//! # }
50//! ```
51//!
52//! ## Example: Verifying a Request
53//!
54//! ```rust
55//! use herolib_crypt::httpsig::{HttpVerifier, HttpSigError};
56//! use herolib_crypt::keys::Ed25519PublicKey;
57//! use http::Request;
58//!
59//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
60//! # let public_key = herolib_crypt::keys::Ed25519Keypair::generate().unwrap().public_key();
61//! // Create a verifier with a public key
62//! let verifier = HttpVerifier::new()
63//!     .with_key(public_key)
64//!     .with_tolerance(60);
65//!
66//! // Build the request to verify (with signature headers from client)
67//! let body = b"{\"amount\": 100}";
68//! let request = Request::post("https://api.service.com/api/v1/payments")
69//!     .header("content-type", "application/json")
70//!     .header("signature-input", "sig1=(...)")
71//!     .header("signature", "sig1=:...:")
72//!     .header("content-digest", "sha-256=:...:")
73//!     .body(body.to_vec())?;
74//!
75//! // Verify the request
76//! let result = verifier.verify_request(&request, body)?;
77//!
78//! println!("Verified! Key ID: {}", result.key_id);
79//! # Ok(())
80//! # }
81//! ```
82
83mod components;
84mod digest;
85mod error;
86mod parser;
87#[cfg(feature = "rhai")]
88pub mod rhai;
89mod signature_base;
90mod signer;
91mod verifier;
92
93pub use error::HttpSigError;
94pub use signer::{HttpSigner, SignatureOutput};
95pub use verifier::{HttpVerifier, VerificationResult};
96
97pub use digest::{compute_content_digest, verify_content_digest};
98pub use components::extract_authority;
99pub use parser::{extract_key_id, parse_signature_input};