Skip to main content

jwt_simple/
jwe_header.rs

1use serde::{Deserialize, Deserializer, Serialize};
2use serde_json::Value;
3
4use crate::algorithms::jwk::UniqueMembers;
5
6/// JWE (JSON Web Encryption) header structure.
7///
8/// This header identifies the cryptographic algorithms used to encrypt
9/// the content encryption key (CEK) and the plaintext.
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct JWEHeader {
12    /// Key management algorithm (e.g., "RSA-OAEP", "A256KW", "ECDH-ES+A256KW")
13    #[serde(rename = "alg")]
14    pub algorithm: String,
15
16    /// Content encryption algorithm (e.g., "A256GCM", "A128GCM")
17    #[serde(rename = "enc")]
18    pub encryption: String,
19
20    /// Key ID - identifies which key was used for encryption
21    #[serde(rename = "kid", default, skip_serializing_if = "Option::is_none")]
22    pub key_id: Option<String>,
23
24    /// Token type (typically "JWE" or omitted)
25    #[serde(rename = "typ", default, skip_serializing_if = "Option::is_none")]
26    pub token_type: Option<String>,
27
28    /// Content type - describes the media type of the encrypted content
29    #[serde(rename = "cty", default, skip_serializing_if = "Option::is_none")]
30    pub content_type: Option<String>,
31
32    /// Ephemeral public key (for ECDH key agreement)
33    ///
34    /// Duplicate members are rejected, including in nested objects.
35    #[serde(
36        rename = "epk",
37        default,
38        skip_serializing_if = "Option::is_none",
39        deserialize_with = "deserialize_without_duplicates"
40    )]
41    pub ephemeral_public_key: Option<serde_json::Value>,
42
43    /// Agreement PartyUInfo (for ECDH)
44    #[serde(rename = "apu", default, skip_serializing_if = "Option::is_none")]
45    pub apu: Option<String>,
46
47    /// Agreement PartyVInfo (for ECDH)
48    #[serde(rename = "apv", default, skip_serializing_if = "Option::is_none")]
49    pub apv: Option<String>,
50
51    /// Initialization vector (for AES-GCM key wrap)
52    #[serde(rename = "iv", default, skip_serializing_if = "Option::is_none")]
53    pub iv: Option<String>,
54
55    /// Authentication tag (for AES-GCM key wrap)
56    #[serde(rename = "tag", default, skip_serializing_if = "Option::is_none")]
57    pub tag: Option<String>,
58
59    /// PBES2 salt (not used - PBES2 not supported)
60    #[serde(rename = "p2s", default, skip_serializing_if = "Option::is_none")]
61    pub p2s: Option<String>,
62
63    /// PBES2 iteration count (not used - PBES2 not supported)
64    #[serde(rename = "p2c", default, skip_serializing_if = "Option::is_none")]
65    pub p2c: Option<u32>,
66
67    /// Critical headers that must be understood
68    #[serde(rename = "crit", default, skip_serializing_if = "Option::is_none")]
69    pub critical: Option<Vec<String>>,
70
71    /// X.509 certificate chain
72    #[serde(rename = "x5c", default, skip_serializing_if = "Option::is_none")]
73    pub certificate_chain: Option<Vec<String>>,
74
75    /// X.509 certificate URL
76    #[serde(rename = "x5u", default, skip_serializing_if = "Option::is_none")]
77    pub certificate_url: Option<String>,
78
79    /// X.509 certificate SHA-1 thumbprint
80    #[serde(rename = "x5t", default, skip_serializing_if = "Option::is_none")]
81    pub certificate_sha1_thumbprint: Option<String>,
82
83    /// X.509 certificate SHA-256 thumbprint
84    #[serde(rename = "x5t#S256", default, skip_serializing_if = "Option::is_none")]
85    pub certificate_sha256_thumbprint: Option<String>,
86
87    /// JWK Set URL
88    #[serde(rename = "jku", default, skip_serializing_if = "Option::is_none")]
89    pub key_set_url: Option<String>,
90
91    /// Embedded JWK public key
92    #[serde(rename = "jwk", default, skip_serializing_if = "Option::is_none")]
93    pub public_key: Option<serde_json::Value>,
94}
95
96impl JWEHeader {
97    /// Create a new JWE header with the specified algorithms.
98    pub fn new(algorithm: impl Into<String>, encryption: impl Into<String>) -> Self {
99        JWEHeader {
100            algorithm: algorithm.into(),
101            encryption: encryption.into(),
102            key_id: None,
103            token_type: None,
104            content_type: None,
105            ephemeral_public_key: None,
106            apu: None,
107            apv: None,
108            iv: None,
109            tag: None,
110            p2s: None,
111            p2c: None,
112            critical: None,
113            certificate_chain: None,
114            certificate_url: None,
115            certificate_sha1_thumbprint: None,
116            certificate_sha256_thumbprint: None,
117            key_set_url: None,
118            public_key: None,
119        }
120    }
121
122    /// Set the key ID.
123    pub fn with_key_id(mut self, key_id: impl Into<String>) -> Self {
124        self.key_id = Some(key_id.into());
125        self
126    }
127
128    /// Set the content type.
129    pub fn with_content_type(mut self, content_type: impl Into<String>) -> Self {
130        self.content_type = Some(content_type.into());
131        self
132    }
133
134    /// Set the ephemeral public key (for ECDH).
135    pub fn with_ephemeral_public_key(mut self, epk: serde_json::Value) -> Self {
136        self.ephemeral_public_key = Some(epk);
137        self
138    }
139}
140
141impl Default for JWEHeader {
142    fn default() -> Self {
143        JWEHeader::new("RSA-OAEP", "A256GCM")
144    }
145}
146
147fn deserialize_without_duplicates<'de, D: Deserializer<'de>>(
148    deserializer: D,
149) -> Result<Option<Value>, D::Error> {
150    let value = UniqueMembers::deserialize(deserializer)?.0;
151    Ok(if value.is_null() { None } else { Some(value) })
152}