1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//! # obsigil
//!
//! A mandate-token format and shared-secret **JWT alternative**: a
//! token split into a public **manifest** and an encrypted
//! **mandate**. Each half is an
//! authenticated, deterministically-encrypted ciphertext — AES-SIV
//! (RFC 5297, code `0`) or AES-GCM-SIV (RFC 8452, code `1`) — joined by a
//! separator that names the text encoding (`.` b64, `~` hex), with a
//! per-half algorithm code in the clear:
//!
//! ```text
//! token = [ manifest ALG ] SEP [ ALG mandate ]
//! ```
//!
//! This crate is the **backend** side: an [`Issuer`] mints mandates under
//! a secret [`MandateKey`], and [`Verifier::clauses`] checks them against the
//! reserved fields (the Reserved fields section, §8). The manifest is keyless and advisory; read
//! its [`claims`] with no secret. Verification is symmetric — the same
//! [`MandateKey`] both mints and verifies — so obsigil fits shared-secret
//! (HS256-style) JWT and JWE use cases, not public-key verification.
//!
//! Built directly on RustCrypto (`aes-siv`, `aes-gcm-siv`, `hkdf`). Only
//! authenticated AEADs are ever compiled in, so an unauthenticated mandate
//! is structurally unrepresentable (the mandate-must-be-authenticated rule of the Security Considerations, §16.2).
//!
//! The normative format is the obsigil specification; section references in
//! this source (e.g. the manifest construction, §5.2) point there.
//!
//! # Example
//!
//! ```rust
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use obsigil::{claims, generate_key, Claims, Clauses, Issuer, MandateKey, Verifier};
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Serialize, Deserialize)]
//! struct ClauseData { role: String }
//! #[derive(Serialize, Deserialize)]
//! struct ClaimData { theme: String }
//!
//! // One secret key as hex, provisioned to both sides. `generate_key()`
//! // returns 128 lowercase hex digits (§6.2) to store as a secret (e.g. an
//! // environment variable); load it with `MandateKey::from_hex`.
//! let key_hex = generate_key();
//! let issuer_key = MandateKey::from_hex(&key_hex)?;
//!
//! // Issuer: mint a token. The mandate carries the authoritative clauses;
//! // the optional manifest carries advisory claims.
//! let token = Issuer::new(issuer_key)
//! .clauses(&ClauseData { role: "admin".into() })
//! .exp(4_000_000_000)
//! .audience(["api"])
//! .manifest("auth.example", &ClaimData { theme: "dark".into() })
//! .mint()?;
//!
//! // Front end: read the manifest's claims with no secret (advisory only).
//! let advisory: Claims<ClaimData> = claims(&token).expect("present");
//! assert_eq!(advisory.issuer(), "auth.example");
//!
//! // Backend: verify the mandate's clauses (authoritative). `now` is pinned
//! // here for a deterministic example; omit it to read the system clock.
//! let verify_key = MandateKey::from_hex(&key_hex)?;
//! let clauses: Clauses<ClauseData> = Verifier::new()
//! .key(&verify_key)
//! .audience("api")
//! .now(1_000_000_000)
//! .clauses(&token)?;
//! assert_eq!(clauses.app().role, "admin");
//! # Ok(()) }
//! ```
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
// Re-exported for callers handling `tid` (the `tid` field, §8.2).
pub use Uuid;