identity_jose/jwt/
header.rs

1// Copyright 2020-2023 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use identity_core::common::Url;
5
6use crate::jose::JoseHeader;
7use crate::jwk::Jwk;
8
9/// JSON Web Token JOSE Header.
10///
11/// [More Info (JWS)](https://tools.ietf.org/html/rfc7515#section-4)
12/// [More Info (JWE)](https://tools.ietf.org/html/rfc7516#section-4)
13#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
14pub struct JwtHeader {
15  /// JWK Set URL.
16  ///
17  /// Refers to a resource for a set of JSON-encoded public keys, one of which
18  /// corresponds to the key used to digitally sign the JWS.
19  ///
20  /// [More Info](https://tools.ietf.org/html/rfc7515#section-4.1.2)
21  #[serde(skip_serializing_if = "Option::is_none")]
22  jku: Option<Url>,
23  /// JSON Web Key.
24  ///
25  /// The public key that corresponds to the key used to digitally sign the JWS.
26  ///
27  /// [More Info](https://tools.ietf.org/html/rfc7515#section-4.1.3)
28  #[serde(skip_serializing_if = "Option::is_none")]
29  jwk: Option<Jwk>,
30  /// Key ID.
31  ///
32  /// A hint indicating which key was used to secure the JWS.
33  ///
34  /// [More Info](https://tools.ietf.org/html/rfc7515#section-4.1.4)
35  #[serde(skip_serializing_if = "Option::is_none")]
36  kid: Option<String>,
37  /// X.509 URL.
38  ///
39  /// A URI that refers to a resource for the X.509 public key certificate or
40  /// certificate chain corresponding to the key used to digitally sign the JWS.
41  ///
42  /// [More Info](https://tools.ietf.org/html/rfc7515#section-4.1.5)
43  #[serde(skip_serializing_if = "Option::is_none")]
44  x5u: Option<Url>,
45  /// X.509 Certificate Chain.
46  ///
47  /// Contains the X.509 public key certificate or certificate chain
48  /// corresponding to the key used to digitally sign the JWS.
49  ///
50  /// [More Info](https://tools.ietf.org/html/rfc7515#section-4.1.6)
51  #[serde(skip_serializing_if = "Option::is_none")]
52  x5c: Option<Vec<String>>,
53  /// X.509 Certificate SHA-1 Thumbprint.
54  ///
55  /// A base64url-encoded SHA-1 thumbprint of the DER encoding of the X.509
56  /// certificate corresponding to the key used to digitally sign the JWS.
57  ///
58  /// [More Info](https://tools.ietf.org/html/rfc7515#section-4.1.7)
59  #[serde(skip_serializing_if = "Option::is_none")]
60  x5t: Option<String>,
61  /// X.509 Certificate SHA-256 Thumbprint.
62  ///
63  /// A base64url-encoded SHA-256 thumbprint of the DER encoding of the X.509
64  /// certificate corresponding to the key used to digitally sign the JWS.
65  ///
66  /// [More Info](https://tools.ietf.org/html/rfc7515#section-4.1.8)
67  #[serde(rename = "x5t#S256", skip_serializing_if = "Option::is_none")]
68  x5t_s256: Option<String>,
69  /// Type.
70  ///
71  /// Used by JWS applications to declare the media type of this complete JWS.
72  ///
73  /// [More Info](https://tools.ietf.org/html/rfc7515#section-4.1.9)
74  #[serde(skip_serializing_if = "Option::is_none")]
75  typ: Option<String>,
76  /// Content Type.
77  ///
78  /// Used by JWS applications to declare the media type of the secured content.
79  ///
80  /// [More Info](https://tools.ietf.org/html/rfc7515#section-4.1.10)
81  #[serde(skip_serializing_if = "Option::is_none")]
82  cty: Option<String>,
83  /// Critical.
84  ///
85  /// Indicates that JWS extensions are being used that MUST be understood and
86  /// processed.
87  ///
88  /// [More Info](https://tools.ietf.org/html/rfc7515#section-4.1.11)
89  #[serde(skip_serializing_if = "Option::is_none")]
90  crit: Option<Vec<String>>,
91  /// URL.
92  ///
93  /// Specifies the URL to which this JWS object is directed.
94  ///
95  /// [More Info](https://tools.ietf.org/html/rfc8555#section-6.4.1)
96  #[serde(skip_serializing_if = "Option::is_none")]
97  url: Option<Url>,
98  /// Nonce.
99  ///
100  /// Provides a unique value that enables the verifier of a JWS to recognize
101  /// when replay has occurred.
102  ///
103  /// [More Info](https://tools.ietf.org/html/rfc8555#section-6.5.2)
104  #[serde(skip_serializing_if = "Option::is_none")]
105  nonce: Option<String>,
106}
107
108impl Default for JwtHeader {
109  fn default() -> Self {
110    Self::new()
111  }
112}
113
114impl JwtHeader {
115  /// Create a new `JwtHeader`.
116  pub const fn new() -> Self {
117    Self {
118      jku: None,
119      jwk: None,
120      kid: None,
121      x5u: None,
122      x5c: None,
123      x5t: None,
124      x5t_s256: None,
125      typ: None,
126      cty: None,
127      crit: None,
128      url: None,
129      nonce: None,
130    }
131  }
132
133  /// Returns the value of the JWK Set URL claim (jku).
134  pub fn jku(&self) -> Option<&Url> {
135    self.jku.as_ref()
136  }
137
138  /// Sets a value for the JWK Set URL claim (jku).
139  pub fn set_jku(&mut self, value: impl Into<Url>) {
140    self.jku = Some(value.into());
141  }
142
143  /// Returns the value of the JWK claim (jwk).
144  pub fn jwk(&self) -> Option<&Jwk> {
145    self.jwk.as_ref()
146  }
147
148  /// Sets a value for the JWK claim (jwk).
149  pub fn set_jwk(&mut self, value: impl Into<Jwk>) {
150    self.jwk = Some(value.into());
151  }
152
153  /// Returns the value of the key ID claim (kid).
154  pub fn kid(&self) -> Option<&str> {
155    self.kid.as_deref()
156  }
157
158  /// Sets a value for the key ID claim (kid).
159  pub fn set_kid(&mut self, value: impl Into<String>) {
160    self.kid = Some(value.into());
161  }
162
163  /// Returns the value of the X.509 URL claim (x5u).
164  pub fn x5u(&self) -> Option<&Url> {
165    self.x5u.as_ref()
166  }
167
168  /// Sets a value for the X.509 URL claim (x5u).
169  pub fn set_x5u(&mut self, value: impl Into<Url>) {
170    self.x5u = Some(value.into());
171  }
172
173  /// Returns the value of the X.509 certificate chain claim (x5c).
174  pub fn x5c(&self) -> Option<&[String]> {
175    self.x5c.as_deref()
176  }
177
178  /// Sets values for the X.509 certificate chain claim (x5c).
179  pub fn set_x5c(&mut self, value: impl IntoIterator<Item = impl Into<String>>) {
180    self.x5c = Some(value.into_iter().map(Into::into).collect());
181  }
182
183  /// Returns the value of the X.509 certificate SHA-1 thumbprint claim (x5t).
184  pub fn x5t(&self) -> Option<&str> {
185    self.x5t.as_deref()
186  }
187
188  /// Sets a value for the X.509 certificate SHA-1 thumbprint claim (x5t).
189  pub fn set_x5t(&mut self, value: impl Into<String>) {
190    self.x5t = Some(value.into());
191  }
192
193  /// Returns the value of the X.509 certificate SHA-256 thumbprint claim
194  /// (x5t#S256).
195  pub fn x5t_s256(&self) -> Option<&str> {
196    self.x5t_s256.as_deref()
197  }
198
199  /// Sets a value for the X.509 certificate SHA-256 thumbprint claim
200  /// (x5t#S256).
201  pub fn set_x5t_s256(&mut self, value: impl Into<String>) {
202    self.x5t_s256 = Some(value.into());
203  }
204
205  /// Returns the value of the token type claim (typ).
206  pub fn typ(&self) -> Option<&str> {
207    self.typ.as_deref()
208  }
209
210  /// Sets a value for the token type claim (typ).
211  pub fn set_typ(&mut self, value: impl Into<String>) {
212    self.typ = Some(value.into());
213  }
214
215  /// Returns the value of the content type claim (cty).
216  pub fn cty(&self) -> Option<&str> {
217    self.cty.as_deref()
218  }
219
220  /// Sets a value for the content type claim (cty).
221  pub fn set_cty(&mut self, value: impl Into<String>) {
222    self.cty = Some(value.into());
223  }
224
225  /// Returns the value of the critical claim (crit).
226  pub fn crit(&self) -> Option<&[String]> {
227    self.crit.as_deref()
228  }
229
230  /// Sets values for the critical claim (crit).
231  pub fn set_crit(&mut self, value: impl IntoIterator<Item = impl Into<String>>) {
232    self.crit = Some(value.into_iter().map(Into::into).collect());
233  }
234
235  /// Returns the value of the url claim (url).
236  pub fn url(&self) -> Option<&Url> {
237    self.url.as_ref()
238  }
239
240  /// Sets a value for the url claim (url).
241  pub fn set_url(&mut self, value: impl Into<Url>) {
242    self.url = Some(value.into());
243  }
244
245  /// Returns the value of the nonce claim (nonce).
246  pub fn nonce(&self) -> Option<&str> {
247    self.nonce.as_deref()
248  }
249
250  /// Sets a value for the nonce claim (nonce).
251  pub fn set_nonce(&mut self, value: impl Into<String>) {
252    self.nonce = Some(value.into());
253  }
254
255  /// Returns `true` if the header contains the given `claim`, `false` otherwise.
256  pub fn has(&self, claim: &str) -> bool {
257    match claim {
258      "jku" => self.jku().is_some(),
259      "jwk" => self.jwk().is_some(),
260      "kid" => self.kid().is_some(),
261      "x5u" => self.x5u().is_some(),
262      "x5c" => self.x5c().is_some(),
263      "x5t" => self.x5t().is_some(),
264      "x5t#S256" => self.x5t_s256().is_some(),
265      "typ" => self.typ().is_some(),
266      "cty" => self.cty().is_some(),
267      "crit" => self.crit().is_some(),
268      "url" => self.url().is_some(),
269      "nonce" => self.nonce().is_some(),
270      _ => false,
271    }
272  }
273
274  /// Returns `true` if none of the fields are set in both `self` and `other`.
275  pub fn is_disjoint(&self, other: &JwtHeader) -> bool {
276    let has_duplicate: bool = self.jku.is_some() && other.jku.is_some()
277      || self.jwk.is_some() && other.jwk.is_some()
278      || self.kid.is_some() && other.kid.is_some()
279      || self.x5u.is_some() && other.x5u.is_some()
280      || self.x5c.is_some() && other.x5c.is_some()
281      || self.x5t.is_some() && other.x5t.is_some()
282      || self.x5t_s256.is_some() && other.x5t_s256.is_some()
283      || self.typ.is_some() && other.typ.is_some()
284      || self.cty.is_some() && other.cty.is_some()
285      || self.crit.is_some() && other.crit.is_some()
286      || self.url.is_some() && other.url.is_some()
287      || self.nonce.is_some() && other.nonce.is_some();
288
289    !has_duplicate
290  }
291}
292
293impl JoseHeader for JwtHeader {
294  fn common(&self) -> &JwtHeader {
295    self
296  }
297
298  fn has_claim(&self, claim: &str) -> bool {
299    self.has(claim)
300  }
301}