1use std::any::Any;
2use std::cmp::Eq;
3use std::convert::Into;
4use std::fmt::{Debug, Display};
5use std::ops::Deref;
6
7use anyhow::bail;
8
9use crate::jwk::Jwk;
10use crate::util;
11use crate::{JoseError, JoseHeader, Map, Value};
12
13#[derive(Debug, Eq, PartialEq, Clone)]
15pub struct JweHeader {
16 claims: Map<String, Value>,
17}
18
19impl JweHeader {
20 pub fn new() -> Self {
22 Self { claims: Map::new() }
23 }
24
25 pub fn from_bytes(value: &[u8]) -> Result<Self, JoseError> {
31 let claims = (|| -> anyhow::Result<Map<String, Value>> {
32 let claims: Map<String, Value> = serde_json::from_slice(value)?;
33 Ok(claims)
34 })()
35 .map_err(|err| JoseError::InvalidJson(err))?;
36
37 let header = Self::from_map(claims)?;
38 Ok(header)
39 }
40
41 pub fn from_map(map: impl Into<Map<String, Value>>) -> Result<Self, JoseError> {
47 let map: Map<String, Value> = map.into();
48 for (key, value) in &map {
49 Self::check_claim(key, value)?;
50 }
51
52 Ok(Self { claims: map })
53 }
54
55 pub fn set_algorithm(&mut self, value: impl Into<String>) {
61 let value: String = value.into();
62 self.claims.insert("alg".to_string(), Value::String(value));
63 }
64
65 pub fn algorithm(&self) -> Option<&str> {
67 match self.claim("alg") {
68 Some(Value::String(val)) => Some(&val),
69 _ => None,
70 }
71 }
72
73 pub fn set_content_encryption(&mut self, value: impl Into<String>) {
79 let value: String = value.into();
80 self.claims.insert("enc".to_string(), Value::String(value));
81 }
82
83 pub fn content_encryption(&self) -> Option<&str> {
85 match self.claims.get("enc") {
86 Some(Value::String(val)) => Some(val),
87 _ => None,
88 }
89 }
90
91 pub fn set_compression(&mut self, value: impl Into<String>) {
97 let value: String = value.into();
98 self.claims.insert("zip".to_string(), Value::String(value));
99 }
100
101 pub fn compression(&self) -> Option<&str> {
103 match self.claims.get("zip") {
104 Some(Value::String(val)) => Some(val),
105 _ => None,
106 }
107 }
108
109 pub fn set_jwk_set_url(&mut self, value: impl Into<String>) {
115 let value: String = value.into();
116 self.claims.insert("jku".to_string(), Value::String(value));
117 }
118
119 pub fn jwk_set_url(&self) -> Option<&str> {
121 match self.claims.get("jku") {
122 Some(Value::String(val)) => Some(val),
123 _ => None,
124 }
125 }
126
127 pub fn set_jwk(&mut self, value: Jwk) {
133 let key = "jwk";
134 let value: Map<String, Value> = value.into();
135 self.claims.insert(key.to_string(), Value::Object(value));
136 }
137
138 pub fn jwk(&self) -> Option<Jwk> {
140 match self.claims.get("jwk") {
141 Some(Value::Object(vals)) => match Jwk::from_map(vals.clone()) {
142 Ok(val) => Some(val),
143 Err(_) => None,
144 },
145 _ => None,
146 }
147 }
148
149 pub fn set_x509_url(&mut self, value: impl Into<String>) {
155 let value: String = value.into();
156 self.claims.insert("x5u".to_string(), Value::String(value));
157 }
158
159 pub fn x509_url(&self) -> Option<&str> {
161 match self.claims.get("x5u") {
162 Some(Value::String(val)) => Some(val),
163 _ => None,
164 }
165 }
166
167 pub fn set_x509_certificate_chain(&mut self, values: &Vec<impl AsRef<[u8]>>) {
173 let key = "x5c";
174 let mut vec = Vec::with_capacity(values.len());
175 for val in values {
176 vec.push(Value::String(util::encode_base64_standard(val)));
177 }
178 self.claims.insert(key.to_string(), Value::Array(vec));
179 }
180
181 pub fn x509_certificate_chain(&self) -> Option<Vec<Vec<u8>>> {
183 match self.claims.get("x5c") {
184 Some(Value::Array(vals)) => {
185 let mut vec = Vec::with_capacity(vals.len());
186 for val in vals {
187 match val {
188 Value::String(val2) => match util::decode_base64_standard(val2) {
189 Ok(val3) => vec.push(val3.clone()),
190 Err(_) => return None,
191 },
192 _ => return None,
193 }
194 }
195 Some(vec)
196 }
197 _ => None,
198 }
199 }
200
201 pub fn set_x509_certificate_sha1_thumbprint(&mut self, value: impl AsRef<[u8]>) {
207 let key = "x5t";
208 let val = util::encode_base64_urlsafe_nopad(value);
209 self.claims.insert(key.to_string(), Value::String(val));
210 }
211
212 pub fn x509_certificate_sha1_thumbprint(&self) -> Option<Vec<u8>> {
214 match self.claims.get("x5t") {
215 Some(Value::String(val)) => match util::decode_base64_urlsafe_no_pad(val) {
216 Ok(val2) => Some(val2),
217 Err(_) => None,
218 },
219 _ => None,
220 }
221 }
222
223 pub fn set_x509_certificate_sha256_thumbprint(&mut self, value: impl AsRef<[u8]>) {
229 let key = "x5t#S256";
230 let val = util::encode_base64_urlsafe_nopad(value);
231 self.claims.insert(key.to_string(), Value::String(val));
232 }
233
234 pub fn x509_certificate_sha256_thumbprint(&self) -> Option<Vec<u8>> {
236 match self.claims.get("x5t#S256") {
237 Some(Value::String(val)) => match util::decode_base64_urlsafe_no_pad(val) {
238 Ok(val2) => Some(val2),
239 Err(_) => None,
240 },
241 _ => None,
242 }
243 }
244
245 pub fn set_key_id(&mut self, value: impl Into<String>) {
251 let value: String = value.into();
252 self.claims.insert("kid".to_string(), Value::String(value));
253 }
254
255 pub fn key_id(&self) -> Option<&str> {
257 match self.claims.get("kid") {
258 Some(Value::String(val)) => Some(val),
259 _ => None,
260 }
261 }
262
263 pub fn set_token_type(&mut self, value: impl Into<String>) {
269 let value: String = value.into();
270 self.claims.insert("typ".to_string(), Value::String(value));
271 }
272
273 pub fn token_type(&self) -> Option<&str> {
275 match self.claims.get("typ") {
276 Some(Value::String(val)) => Some(val),
277 _ => None,
278 }
279 }
280
281 pub fn set_content_type(&mut self, value: impl Into<String>) {
287 let value: String = value.into();
288 self.claims.insert("cty".to_string(), Value::String(value));
289 }
290
291 pub fn content_type(&self) -> Option<&str> {
293 match self.claims.get("cty") {
294 Some(Value::String(val)) => Some(val),
295 _ => None,
296 }
297 }
298
299 pub fn set_critical(&mut self, values: &Vec<impl AsRef<str>>) {
305 let key = "crit";
306 let vec = values
307 .iter()
308 .map(|v| Value::String(v.as_ref().to_string()))
309 .collect();
310 self.claims.insert(key.to_string(), Value::Array(vec));
311 }
312
313 pub fn critical(&self) -> Option<Vec<&str>> {
315 match self.claims.get("crit") {
316 Some(Value::Array(vals)) => {
317 let mut vec = Vec::with_capacity(vals.len());
318 for val in vals {
319 match val {
320 Value::String(val2) => vec.push(val2.as_str()),
321 _ => return None,
322 }
323 }
324 Some(vec)
325 }
326 _ => None,
327 }
328 }
329
330 pub fn set_url(&mut self, value: impl Into<String>) {
336 let value: String = value.into();
337 self.claims.insert("url".to_string(), Value::String(value));
338 }
339
340 pub fn url(&self) -> Option<&str> {
342 match self.claims.get("url") {
343 Some(Value::String(val)) => Some(val),
344 _ => None,
345 }
346 }
347
348 pub fn set_nonce(&mut self, value: impl AsRef<[u8]>) {
354 let key = "nonce";
355 let val = util::encode_base64_urlsafe_nopad(value);
356 self.claims.insert(key.to_string(), Value::String(val));
357 }
358
359 pub fn nonce(&self) -> Option<Vec<u8>> {
361 match self.claims.get("nonce") {
362 Some(Value::String(val)) => match util::decode_base64_urlsafe_no_pad(val) {
363 Ok(val2) => Some(val2),
364 Err(_) => None,
365 },
366 _ => None,
367 }
368 }
369
370 pub fn set_agreement_partyuinfo(&mut self, value: impl AsRef<[u8]>) {
376 let key = "apu";
377 let val = util::encode_base64_urlsafe_nopad(value);
378 self.claims.insert(key.to_string(), Value::String(val));
379 }
380
381 pub fn agreement_partyuinfo(&self) -> Option<Vec<u8>> {
383 match self.claims.get("apu") {
384 Some(Value::String(val)) => match util::decode_base64_urlsafe_no_pad(val) {
385 Ok(val2) => Some(val2),
386 Err(_) => None,
387 },
388 _ => None,
389 }
390 }
391
392 pub fn set_agreement_partyvinfo(&mut self, value: impl AsRef<[u8]>) {
398 let key = "apv";
399 let val = util::encode_base64_urlsafe_nopad(value);
400 self.claims.insert(key.to_string(), Value::String(val));
401 }
402
403 pub fn agreement_partyvinfo(&self) -> Option<Vec<u8>> {
405 match self.claims.get("apv") {
406 Some(Value::String(val)) => match util::decode_base64_urlsafe_no_pad(val) {
407 Ok(val2) => Some(val2),
408 Err(_) => None,
409 },
410 _ => None,
411 }
412 }
413
414 pub fn set_issuer(&mut self, value: impl Into<String>) {
420 let key = "iss";
421 let value: String = value.into();
422 self.claims.insert(key.to_string(), Value::String(value));
423 }
424
425 pub fn issuer(&self) -> Option<&str> {
427 match self.claims.get("iss") {
428 Some(Value::String(val)) => Some(val),
429 _ => None,
430 }
431 }
432
433 pub fn set_subject(&mut self, value: impl Into<String>) {
439 let key = "sub";
440 let value: String = value.into();
441 self.claims.insert(key.to_string(), Value::String(value));
442 }
443
444 pub fn subject(&self) -> Option<&str> {
446 match self.claims.get("sub") {
447 Some(Value::String(val)) => Some(val),
448 _ => None,
449 }
450 }
451
452 pub fn set_audience(&mut self, values: Vec<impl Into<String>>) {
458 let key = "aud".to_string();
459 if values.len() == 1 {
460 for val in values {
461 let val: String = val.into();
462 self.claims.insert(key, Value::String(val));
463 break;
464 }
465 } else if values.len() > 1 {
466 let mut vec = Vec::with_capacity(values.len());
467 for val in values {
468 let val: String = val.into();
469 vec.push(Value::String(val.clone()));
470 }
471 self.claims.insert(key.clone(), Value::Array(vec));
472 }
473 }
474
475 pub fn audience(&self) -> Option<Vec<&str>> {
477 match self.claims.get("aud") {
478 Some(Value::Array(vals)) => {
479 let mut vec = Vec::with_capacity(vals.len());
480 for val in vals {
481 match val {
482 Value::String(val2) => {
483 vec.push(val2.as_str());
484 }
485 _ => return None,
486 }
487 }
488 Some(vec)
489 }
490 Some(Value::String(val)) => Some(vec![val]),
491 _ => None,
492 }
493 }
494
495 pub fn set_claim(&mut self, key: &str, value: Option<Value>) -> Result<(), JoseError> {
502 match value {
503 Some(val) => {
504 Self::check_claim(key, &val)?;
505 self.claims.insert(key.to_string(), val);
506 }
507 None => {
508 self.claims.remove(key);
509 }
510 }
511
512 Ok(())
513 }
514
515 pub fn claims_set(&self) -> &Map<String, Value> {
517 &self.claims
518 }
519
520 pub fn into_map(self) -> Map<String, Value> {
522 self.claims
523 }
524
525 pub(crate) fn check_claim(key: &str, value: &Value) -> Result<(), JoseError> {
526 (|| -> anyhow::Result<()> {
527 match key {
528 "alg" | "enc" | "zip" | "jku" | "x5u" | "kid" | "typ" | "cty" | "url" | "iss"
529 | "sub" => match &value {
530 Value::String(_) => {}
531 _ => bail!("The JWE {} header claim must be string.", key),
532 },
533 "aud" => match &value {
534 Value::String(_) => {}
535 Value::Array(vals) => {
536 for val in vals {
537 match val {
538 Value::String(_) => {}
539 _ => bail!(
540 "An element of the JWE {} header claim must be a string.",
541 key
542 ),
543 }
544 }
545 }
546 _ => bail!("The JWE {} payload claim must be a string or array.", key),
547 },
548 "crit" => match &value {
549 Value::Array(vals) => {
550 for val in vals {
551 match val {
552 Value::String(_) => {}
553 _ => bail!(
554 "An element of the JWE {} header claim must be a string.",
555 key
556 ),
557 }
558 }
559 }
560 _ => bail!("The JWE {} header claim must be a array.", key),
561 },
562 "x5t" | "x5t#S256" | "nonce" | "apu" | "apv" => match &value {
563 Value::String(val) => {
564 if !util::is_base64_urlsafe_nopad(val) {
565 bail!("The JWE {} header claim must be a base64 string.", key);
566 }
567 }
568 _ => bail!("The JWE {} header claim must be a string.", key),
569 },
570 "x5c" => match &value {
571 Value::Array(vals) => {
572 for val in vals {
573 match val {
574 Value::String(val) => {
575 if !util::is_base64_standard(val) {
576 bail!(
577 "The JWE {} header claim must be a base64 string.",
578 key
579 );
580 }
581 }
582 _ => bail!(
583 "An element of the JWE {} header claim must be a string.",
584 key
585 ),
586 }
587 }
588 }
589 _ => bail!("The JWE {} header claim must be a array.", key),
590 },
591 "jwk" => match &value {
592 Value::Object(vals) => Jwk::check_map(vals)?,
593 _ => bail!("The JWE {} header claim must be a string.", key),
594 },
595 _ => {}
596 }
597
598 Ok(())
599 })()
600 .map_err(|err| JoseError::InvalidJweFormat(err))
601 }
602}
603
604impl JoseHeader for JweHeader {
605 fn len(&self) -> usize {
606 self.claims.len()
607 }
608
609 fn claim(&self, key: &str) -> Option<&Value> {
610 self.claims.get(key)
611 }
612
613 fn box_clone(&self) -> Box<dyn JoseHeader> {
614 Box::new(self.clone())
615 }
616
617 fn as_any(&self) -> &dyn Any {
618 self
619 }
620
621 fn as_any_mut(&mut self) -> &mut dyn Any {
622 self
623 }
624
625 fn into_any(self: Box<Self>) -> Box<dyn Any> {
626 self
627 }
628}
629
630impl AsRef<Map<String, Value>> for JweHeader {
631 fn as_ref(&self) -> &Map<String, Value> {
632 &self.claims
633 }
634}
635
636impl Into<Map<String, Value>> for JweHeader {
637 fn into(self) -> Map<String, Value> {
638 self.into_map()
639 }
640}
641
642impl Display for JweHeader {
643 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
644 let val = serde_json::to_string(&self.claims).map_err(|_e| std::fmt::Error {})?;
645 fmt.write_str(&val)
646 }
647}
648
649impl Deref for JweHeader {
650 type Target = dyn JoseHeader;
651
652 fn deref(&self) -> &Self::Target {
653 self
654 }
655}
656
657#[cfg(test)]
658mod tests {
659 use anyhow::Result;
660 use serde_json::json;
661
662 use crate::jwe::JweHeader;
663 use crate::jwk::Jwk;
664 use crate::{Map, Value};
665
666 #[test]
667 fn test_new_jwe_header() -> Result<()> {
668 let mut header = JweHeader::new();
669 let jwk = Jwk::new("oct");
670 header.set_algorithm("alg");
671 header.set_content_encryption("enc");
672 header.set_compression("zip");
673 header.set_jwk_set_url("jku");
674 header.set_jwk(jwk.clone());
675 header.set_x509_url("x5u");
676 header.set_x509_certificate_chain(&vec![
677 b"x5c0".to_vec(),
678 b"x5c1".to_vec(),
679 "@@~".as_bytes().to_vec(),
680 ]);
681 header.set_x509_certificate_sha1_thumbprint(b"x5t@@~");
682 header.set_x509_certificate_sha256_thumbprint(b"x5t#S256 @@~");
683 header.set_key_id("kid");
684 header.set_token_type("typ");
685 header.set_content_type("cty");
686 header.set_critical(&vec!["crit0", "crit1"]);
687 header.set_url("url");
688 header.set_nonce(b"nonce");
689 header.set_agreement_partyuinfo(b"apu");
690 header.set_agreement_partyvinfo(b"apv");
691 header.set_issuer("iss");
692 header.set_subject("sub");
693 header.set_claim("header_claim", Some(json!("header_claim")))?;
694
695 assert_eq!(header.algorithm(), Some("alg"));
696 assert_eq!(header.content_encryption(), Some("enc"));
697 assert_eq!(header.compression(), Some("zip"));
698 assert_eq!(header.jwk_set_url(), Some("jku"));
699 assert_eq!(header.jwk(), Some(jwk));
700 assert_eq!(header.x509_url(), Some("x5u"));
701 assert_eq!(
702 header.x509_certificate_chain(),
703 Some(vec![
704 b"x5c0".to_vec(),
705 b"x5c1".to_vec(),
706 "@@~".as_bytes().to_vec()
707 ])
708 );
709 assert_eq!(
710 header.claim("x5c"),
711 Some(&Value::Array(vec![
712 Value::String("eDVjMA==".to_string()),
713 Value::String("eDVjMQ==".to_string()),
714 Value::String("QEB+".to_string()),
715 ]))
716 );
717 assert_eq!(
718 header.x509_certificate_sha1_thumbprint(),
719 Some(b"x5t@@~".to_vec())
720 );
721 assert_eq!(
722 header.claim("x5t"),
723 Some(&Value::String("eDV0QEB-".to_string()))
724 );
725 assert_eq!(
726 header.x509_certificate_sha256_thumbprint(),
727 Some(b"x5t#S256 @@~".to_vec())
728 );
729 assert_eq!(
730 header.claim("x5t#S256"),
731 Some(&Value::String("eDV0I1MyNTYgQEB-".to_string()))
732 );
733 assert_eq!(header.key_id(), Some("kid"));
734 assert_eq!(header.token_type(), Some("typ"));
735 assert_eq!(header.content_type(), Some("cty"));
736 assert_eq!(header.url(), Some("url"));
737 assert_eq!(header.nonce(), Some(b"nonce".to_vec()));
738 assert_eq!(header.agreement_partyuinfo(), Some(b"apu".to_vec()));
739 assert_eq!(header.agreement_partyvinfo(), Some(b"apv".to_vec()));
740 assert_eq!(header.issuer(), Some("iss"));
741 assert_eq!(header.subject(), Some("sub"));
742 assert_eq!(header.critical(), Some(vec!["crit0", "crit1"]));
743 assert_eq!(header.claim("header_claim"), Some(&json!("header_claim")));
744
745 let map: Map<String, Value> = header.clone().into();
746 assert_eq!(JweHeader::from_map(map)?, header);
747
748 Ok(())
749 }
750}