# Security Policy
## Reporting Vulnerabilities
If you discover a security vulnerability, please report it privately via email to **security@entropysoftworks.com** rather than opening a public issue.
## Cryptographic Implementation Status
The hash, MAC, encoding, and protocol primitives in this crate are
**self-implemented** from their respective specifications using only `std`,
and each is tested against published known-answer test vectors:
| SHA-1 | FIPS 180-4 | NIST CAVP |
| SHA-256 | FIPS 180-4 | NIST CAVP |
| SHA-512 | FIPS 180-4 | NIST CAVP |
| HMAC-SHA1 | RFC 2104 | RFC 2202 |
| HMAC-SHA256 | RFC 2104 | RFC 4231 |
| HMAC-SHA512 | RFC 2104 | RFC 4231 |
| Base64 / Base64url | RFC 4648 | RFC 4648 Section 10 |
| Base32 | RFC 4648 | RFC 4648 Section 10 |
The memory-hard primitives and protocol machinery that would be unsafe to
hand-roll are instead **delegated to audited third-party crates**, all
always-on: Argon2id password hashing (`argon2`, RFC 9106), AES-256-GCM for
the secret-box (`aes-gcm`), and the WebAuthn/passkey ceremonies
(`webauthn-rs`). The asymmetric JWT/JWKS algorithms below add the RustCrypto
curve and RSA crates behind the `asym-jwt` feature. Diagnostic logging uses
the `tracing` facade and is never involved in cryptographic operations.
### JWT algorithm support
- **HMAC** (`HS256`, `HS512`) — always available; sign + verify.
- **EdDSA (Ed25519), ES256 (P-256)** — sign + verify, behind the `asym-jwt` feature. Curve arithmetic is delegated to the audited RustCrypto `ed25519-dalek` / `p256` crates (hand-rolling constant-time curve math would not meet this crate's bar).
- **RS256, RS512** — **verify-only**, behind `asym-jwt`, for validating ID tokens from external OIDC providers (Google, Microsoft, Okta). RSA modular arithmetic is delegated to the audited RustCrypto `rsa` crate (with `sha2`). The crate never constructs an RSA private key or performs a private-key operation, so **RUSTSEC-2023-0071** (the Marvin timing attack on RSA private-key ops) does not apply.
- `alg=none` is always rejected on verification and is unrepresentable on the signing path.
## Threat Model Assumptions
- The host operating system provides a functioning CSPRNG (`/dev/urandom` on Unix, `BCryptGenRandom` on Windows).
- The Rust standard library's memory allocator does not leak deallocated memory to other processes.
- The attacker cannot read process memory (if they can, all bets are off regardless of zeroization).
## Memory Safety Guarantees
- **`#![deny(unsafe_code)]`** is enforced in production code (`deny` rather than `forbid` because a few modules use scoped `#[allow(unsafe_code)]` overrides — `forbid` cannot be overridden by `allow`).
- `unsafe` is used only for `core::ptr::write_volatile` secret-scrubbing, with scoped `#[allow(unsafe_code)]` and `// SAFETY:` comments, in three locations:
1. `crypto/zeroize.rs` — clearing buffers/strings on drop.
2. `crypto/sha1.rs` — clearing the hasher state on drop.
3. `crypto/sha2.rs` — clearing the hasher state on drop.
- The CSPRNG uses `rand_core::OsRng` (which routes to `getrandom`/`BCryptGenRandom` internally) and contains no `unsafe` or FFI in this crate.
## Security Considerations
### Timing Side-Channels
All secret comparisons use constant-time operations (`constant_time_eq`) with `std::hint::black_box` to prevent compiler optimizations that could introduce timing leaks.
### Secret Handling
- Passwords, tokens, keys, and client secrets are stored in `Zeroizing<T>` wrappers that clear memory on drop.
- Custom `Debug` implementations render secret fields as `[REDACTED]` (and stored hashes as `[HASH]`) rather than their contents.
- Error messages never contain secret material.
### Input Validation
- Validated identifier inputs (usernames, names, client IDs, redirect URIs, scopes via `util::validation`) are length- and character-set-checked, and reject embedded null bytes.
- OAuth redirect URIs require HTTPS (except localhost for development).
- Maximum nesting depth and document size limits on JSON and XML parsers prevent DoS attacks.