1use crypto::hashes::sha::SHA256;
5use crypto::hashes::sha::SHA256_LEN;
6use identity_core::common::Url;
7use zeroize::Zeroize;
8
9use crate::error::Error;
10use crate::error::Result;
11use crate::jwk::EcCurve;
12use crate::jwk::EcxCurve;
13use crate::jwk::EdCurve;
14use crate::jwk::JwkOperation;
15use crate::jwk::JwkParams;
16use crate::jwk::JwkParamsAkp;
17use crate::jwk::JwkParamsEc;
18use crate::jwk::JwkParamsOct;
19use crate::jwk::JwkParamsOkp;
20use crate::jwk::JwkParamsRsa;
21use crate::jwk::JwkType;
22use crate::jwk::JwkUse;
23use crate::jwu::encode_b64;
24
25pub type JwkThumbprintSha256 = [u8; SHA256_LEN];
27
28#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
32pub struct Jwk {
33 pub(super) kty: JwkType,
39 #[serde(rename = "use", skip_serializing_if = "Option::is_none")]
45 pub(super) use_: Option<JwkUse>,
46 #[serde(skip_serializing_if = "Option::is_none")]
52 pub(super) key_ops: Option<Vec<JwkOperation>>,
53 #[serde(skip_serializing_if = "Option::is_none")]
59 pub(super) alg: Option<String>,
60 #[serde(skip_serializing_if = "Option::is_none")]
66 pub(super) kid: Option<String>,
67 #[serde(skip_serializing_if = "Option::is_none")]
74 pub(super) x5u: Option<Url>,
75 #[serde(skip_serializing_if = "Option::is_none")]
81 pub(super) x5c: Option<Vec<String>>,
82 #[serde(skip_serializing_if = "Option::is_none")]
89 pub(super) x5t: Option<String>,
90 #[serde(rename = "x5t#S256", skip_serializing_if = "Option::is_none")]
97 pub(super) x5t_s256: Option<String>,
98 #[serde(flatten)]
102 pub(super) params: JwkParams,
103}
104
105impl Jwk {
106 pub const fn new(kty: JwkType) -> Self {
108 Self {
109 kty,
110 use_: None,
111 key_ops: None,
112 alg: None,
113 kid: None,
114 x5u: None,
115 x5c: None,
116 x5t: None,
117 x5t_s256: None,
118 params: JwkParams::new(kty),
119 }
120 }
121
122 pub fn from_params(params: impl Into<JwkParams>) -> Self {
124 let params: JwkParams = params.into();
125
126 Self {
127 kty: params.kty(),
128 use_: None,
129 key_ops: None,
130 alg: None,
131 kid: None,
132 x5u: None,
133 x5c: None,
134 x5t: None,
135 x5t_s256: None,
136 params,
137 }
138 }
139
140 pub fn kty(&self) -> JwkType {
142 self.kty
143 }
144
145 pub fn set_kty(&mut self, value: impl Into<JwkType>) {
149 self.kty = value.into();
150 self.params = JwkParams::new(self.kty);
151 }
152
153 pub fn use_(&self) -> Option<JwkUse> {
155 self.use_
156 }
157
158 pub fn set_use(&mut self, value: impl Into<JwkUse>) {
160 self.use_ = Some(value.into());
161 }
162
163 pub fn key_ops(&self) -> Option<&[JwkOperation]> {
165 self.key_ops.as_deref()
166 }
167
168 pub fn set_key_ops(&mut self, value: impl IntoIterator<Item = impl Into<JwkOperation>>) {
170 self.key_ops = Some(value.into_iter().map(Into::into).collect());
171 }
172
173 pub fn alg(&self) -> Option<&str> {
175 self.alg.as_deref()
176 }
177
178 pub fn set_alg(&mut self, value: impl Into<String>) {
180 self.alg = Some(value.into());
181 }
182
183 pub fn kid(&self) -> Option<&str> {
185 self.kid.as_deref()
186 }
187
188 pub fn set_kid(&mut self, value: impl Into<String>) {
190 self.kid = Some(value.into());
191 }
192
193 pub fn x5u(&self) -> Option<&Url> {
195 self.x5u.as_ref()
196 }
197
198 pub fn set_x5u(&mut self, value: impl Into<Url>) {
200 self.x5u = Some(value.into());
201 }
202
203 pub fn x5c(&self) -> Option<&[String]> {
205 self.x5c.as_deref()
206 }
207
208 pub fn set_x5c(&mut self, value: impl IntoIterator<Item = impl Into<String>>) {
210 self.x5c = Some(value.into_iter().map(Into::into).collect());
211 }
212
213 pub fn x5t(&self) -> Option<&str> {
216 self.x5t.as_deref()
217 }
218
219 pub fn set_x5t(&mut self, value: impl Into<String>) {
221 self.x5t = Some(value.into());
222 }
223
224 pub fn x5t_s256(&self) -> Option<&str> {
227 self.x5t_s256.as_deref()
228 }
229
230 pub fn set_x5t_s256(&mut self, value: impl Into<String>) {
233 self.x5t_s256 = Some(value.into());
234 }
235
236 pub fn params(&self) -> &JwkParams {
238 &self.params
239 }
240
241 pub fn params_mut(&mut self) -> &mut JwkParams {
243 &mut self.params
244 }
245
246 pub fn set_params(&mut self, params: impl Into<JwkParams>) -> Result<()> {
252 match (self.kty, params.into()) {
253 (JwkType::Ec, value @ JwkParams::Ec(_)) => {
254 self.set_params_unchecked(value);
255 }
256 (JwkType::Rsa, value @ JwkParams::Rsa(_)) => {
257 self.set_params_unchecked(value);
258 }
259 (JwkType::Oct, value @ JwkParams::Oct(_)) => {
260 self.set_params_unchecked(value);
261 }
262 (JwkType::Okp, value @ JwkParams::Okp(_)) => {
263 self.set_params_unchecked(value);
264 }
265 (JwkType::Akp, value @ JwkParams::Akp(_)) => {
266 self.set_params_unchecked(value);
267 }
268 (_, _) => {
269 return Err(Error::InvalidParam("`params` type does not match `kty`"));
270 }
271 }
272 Ok(())
273 }
274
275 pub fn set_params_unchecked(&mut self, value: impl Into<JwkParams>) {
279 self.params = value.into();
280 }
281
282 pub fn try_ec_params(&self) -> Result<&JwkParamsEc> {
284 match self.params() {
285 JwkParams::Ec(params) => Ok(params),
286 _ => Err(Error::KeyError("Ec")),
287 }
288 }
289
290 pub fn try_ec_params_mut(&mut self) -> Result<&mut JwkParamsEc> {
292 match self.params_mut() {
293 JwkParams::Ec(params) => Ok(params),
294 _ => Err(Error::KeyError("Ec")),
295 }
296 }
297
298 pub fn try_rsa_params(&self) -> Result<&JwkParamsRsa> {
300 match self.params() {
301 JwkParams::Rsa(params) => Ok(params),
302 _ => Err(Error::KeyError("Rsa")),
303 }
304 }
305
306 pub fn try_rsa_params_mut(&mut self) -> Result<&mut JwkParamsRsa> {
308 match self.params_mut() {
309 JwkParams::Rsa(params) => Ok(params),
310 _ => Err(Error::KeyError("Rsa")),
311 }
312 }
313
314 pub fn try_oct_params(&self) -> Result<&JwkParamsOct> {
316 match self.params() {
317 JwkParams::Oct(params) => Ok(params),
318 _ => Err(Error::KeyError("Oct")),
319 }
320 }
321
322 pub fn try_oct_params_mut(&mut self) -> Result<&mut JwkParamsOct> {
324 match self.params_mut() {
325 JwkParams::Oct(params) => Ok(params),
326 _ => Err(Error::KeyError("Oct")),
327 }
328 }
329
330 pub fn try_okp_params(&self) -> Result<&JwkParamsOkp> {
332 match self.params() {
333 JwkParams::Okp(params) => Ok(params),
334 _ => Err(Error::KeyError("Okp")),
335 }
336 }
337
338 pub fn try_okp_params_mut(&mut self) -> Result<&mut JwkParamsOkp> {
340 match self.params_mut() {
341 JwkParams::Okp(params) => Ok(params),
342 _ => Err(Error::KeyError("Okp")),
343 }
344 }
345
346 pub fn try_akp_params(&self) -> Result<&JwkParamsAkp> {
348 match self.params() {
349 JwkParams::Akp(params) => Ok(params),
350 _ => Err(Error::KeyError("Akp")),
351 }
352 }
353
354 pub fn try_akp_params_mut(&mut self) -> Result<&mut JwkParamsAkp> {
356 match self.params_mut() {
357 JwkParams::Akp(params) => Ok(params),
358 _ => Err(Error::KeyError("Akp")),
359 }
360 }
361
362 pub fn thumbprint_sha256_b64(&self) -> String {
372 encode_b64(self.thumbprint_sha256())
373 }
374
375 pub fn thumbprint_sha256(&self) -> JwkThumbprintSha256 {
381 let json: String = self.thumbprint_hash_input();
382
383 let mut out: JwkThumbprintSha256 = Default::default();
384
385 SHA256(json.as_bytes(), &mut out);
386
387 out
388 }
389
390 pub fn thumbprint_hash_input(&self) -> String {
394 let kty: &str = self.kty.name();
395
396 match self.params() {
397 JwkParams::Ec(JwkParamsEc { crv, x, y, .. }) => {
398 format!(r#"{{"crv":"{crv}","kty":"{kty}","x":"{x}","y":"{y}"}}"#)
399 }
400 JwkParams::Rsa(JwkParamsRsa { e, n, .. }) => {
401 format!(r#"{{"e":"{e}","kty":"{kty}","n":"{n}"}}"#)
402 }
403 JwkParams::Oct(JwkParamsOct { k }) => {
404 format!(r#"{{"k":"{k}","kty":"{kty}"}}"#)
405 }
406 JwkParams::Okp(JwkParamsOkp { crv, x, .. }) => {
408 format!(r#"{{"crv":"{crv}","kty":"{kty}","x":"{x}"}}"#)
409 }
410 JwkParams::Akp(JwkParamsAkp { public, .. }) => {
411 format!(r#"{{"kty":"{kty}","pub":"{public}"}}"#)
412 }
413 }
414 }
415
416 pub fn check_alg(&self, expected: impl AsRef<str>) -> Result<()> {
422 match self.alg() {
423 Some(value) if value == expected.as_ref() => Ok(()),
424 Some(_) => Err(Error::InvalidClaim("alg")),
425 None => Ok(()),
426 }
427 }
428
429 pub fn try_ec_curve(&self) -> Result<EcCurve> {
431 match self.params() {
432 JwkParams::Ec(inner) => inner.try_ec_curve(),
433 _ => Err(Error::KeyError("Ec Curve")),
434 }
435 }
436
437 pub fn try_ed_curve(&self) -> Result<EdCurve> {
439 match self.params() {
440 JwkParams::Okp(inner) => inner.try_ed_curve(),
441 _ => Err(Error::KeyError("Ed Curve")),
442 }
443 }
444
445 pub fn try_ecx_curve(&self) -> Result<EcxCurve> {
447 match self.params() {
448 JwkParams::Okp(inner) => inner.try_ecx_curve(),
449 _ => Err(Error::KeyError("Ecx Curve")),
450 }
451 }
452
453 pub fn is_public(&self) -> bool {
455 self.params.is_public()
456 }
457
458 pub fn is_private(&self) -> bool {
460 match self.params() {
461 JwkParams::Ec(params) => params.is_private(),
462 JwkParams::Rsa(params) => params.is_private(),
463 JwkParams::Oct(_) => true,
464 JwkParams::Okp(params) => params.is_private(),
465 JwkParams::Akp(params) => params.is_private(),
466 }
467 }
468
469 pub fn to_public(&self) -> Option<Jwk> {
473 let mut public: Jwk = Jwk::from_params(self.params().to_public()?);
474
475 if let Some(value) = self.use_() {
476 public.set_use(value);
477 }
478
479 if let Some(value) = self.key_ops() {
480 public.set_key_ops(value.iter().map(|op| op.invert()));
481 }
482
483 if let Some(value) = self.alg() {
484 public.set_alg(value);
485 }
486
487 if let Some(value) = self.kid() {
488 public.set_kid(value);
489 }
490
491 Some(public)
492 }
493
494 #[inline(always)]
497 pub fn strip_private(&mut self) {
498 self.params_mut().strip_private();
499 }
500
501 pub fn into_public(mut self) -> Option<Self> {
504 if matches!(&self.params, JwkParams::Oct(_)) {
505 None
506 } else {
507 self.params.strip_private();
508 Some(self)
509 }
510 }
511}
512
513impl Zeroize for Jwk {
514 fn zeroize(&mut self) {
515 self.params.zeroize();
516 }
517}
518
519impl Drop for Jwk {
520 fn drop(&mut self) {
521 self.zeroize();
522 }
523}
524
525#[cfg(test)]
526mod tests {
527 use identity_core::convert::FromJson;
528
529 use super::Jwk;
530
531 #[test]
532 fn into_public_and_to_public_return_the_same() {
533 let priv_jwk = Jwk::from_json_slice(
534 r#"
535 {
536 "kty": "OKP",
537 "crv": "Ed25519",
538 "d": "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A",
539 "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
540 }
541 "#,
542 )
543 .unwrap();
544
545 assert_eq!(priv_jwk.to_public(), priv_jwk.into_public());
546 }
547}