1use core::str;
5use std::borrow::Cow;
6
7use crate::error::Error;
8use crate::error::Result;
9use crate::jwk::Jwk;
10use crate::jws::JwsAlgorithm;
11use crate::jws::JwsHeader;
12use crate::jwu::create_message;
13use crate::jwu::decode_b64;
14use crate::jwu::decode_b64_json;
15use crate::jwu::filter_non_empty_bytes;
16use crate::jwu::parse_utf8;
17use crate::jwu::validate_jws_headers;
18
19use super::JwsVerifier;
20use super::VerificationInput;
21
22#[derive(Clone, Debug, PartialEq, Eq)]
26#[non_exhaustive]
27pub struct DecodedJws<'a> {
28 pub protected: JwsHeader,
30 pub unprotected: Option<Box<JwsHeader>>,
32 pub claims: Cow<'a, [u8]>,
34}
35
36enum DecodedHeaders {
37 Protected(JwsHeader),
38 Unprotected(JwsHeader),
39 Both {
40 protected: JwsHeader,
41 unprotected: Box<JwsHeader>,
43 },
44}
45
46impl DecodedHeaders {
47 fn new(protected: Option<JwsHeader>, unprotected: Option<JwsHeader>) -> Result<Self> {
48 match (protected, unprotected) {
49 (Some(protected), Some(unprotected)) => Ok(Self::Both {
50 protected,
51 unprotected: Box::new(unprotected),
52 }),
53 (Some(protected), None) => Ok(Self::Protected(protected)),
54 (None, Some(unprotected)) => Ok(Self::Unprotected(unprotected)),
55 (None, None) => Err(Error::MissingHeader("no headers were decoded")),
56 }
57 }
58
59 fn protected_header(&self) -> Option<&JwsHeader> {
60 match self {
61 DecodedHeaders::Protected(ref header) => Some(header),
62 DecodedHeaders::Both { ref protected, .. } => Some(protected),
63 DecodedHeaders::Unprotected(_) => None,
64 }
65 }
66
67 fn unprotected_header(&self) -> Option<&JwsHeader> {
68 match self {
69 DecodedHeaders::Unprotected(ref header) => Some(header),
70 DecodedHeaders::Both { ref unprotected, .. } => Some(unprotected.as_ref()),
71 DecodedHeaders::Protected(_) => None,
72 }
73 }
74}
75
76pub struct JwsValidationItem<'a> {
80 headers: DecodedHeaders,
81 signing_input: Box<[u8]>,
82 decoded_signature: Box<[u8]>,
83 claims: Cow<'a, [u8]>,
84}
85impl<'a> JwsValidationItem<'a> {
86 pub fn protected_header(&self) -> Option<&JwsHeader> {
88 self.headers.protected_header()
89 }
90
91 pub fn nonce(&self) -> Option<&str> {
93 self.protected_header().and_then(|header| header.nonce())
94 }
95
96 pub fn kid(&self) -> Option<&str> {
98 self.protected_header().and_then(|header| header.kid())
99 }
100
101 pub fn unprotected_header(&self) -> Option<&JwsHeader> {
103 self.headers.unprotected_header()
104 }
105
106 pub fn alg(&self) -> Option<JwsAlgorithm> {
108 self.protected_header().and_then(|protected| protected.alg())
109 }
110
111 pub fn claims(&self) -> &[u8] {
113 &self.claims
114 }
115
116 pub fn signing_input(&self) -> &[u8] {
121 &self.signing_input
122 }
123
124 pub fn decoded_signature(&self) -> &[u8] {
126 &self.decoded_signature
127 }
128
129 pub fn verify<T>(self, verifier: &T, public_key: &Jwk) -> Result<DecodedJws<'a>>
141 where
142 T: JwsVerifier,
143 {
144 let JwsValidationItem {
146 headers,
147 claims,
148 signing_input,
149 decoded_signature,
150 } = self;
151 let (protected, unprotected): (JwsHeader, Option<Box<JwsHeader>>) = match headers {
152 DecodedHeaders::Protected(protected) => (protected, None),
153 DecodedHeaders::Both { protected, unprotected } => (protected, Some(unprotected)),
154 DecodedHeaders::Unprotected(_) => return Err(Error::MissingHeader("missing protected header")),
155 };
156
157 let alg: JwsAlgorithm = protected.alg().ok_or(Error::ProtectedHeaderWithoutAlg)?;
159 public_key.check_alg(alg.name())?;
160
161 let input = VerificationInput {
163 alg,
164 signing_input,
165 decoded_signature,
166 };
167 verifier
169 .verify(input, public_key)
170 .map_err(Error::SignatureVerificationError)?;
171
172 Ok(DecodedJws {
173 protected,
174 unprotected,
175 claims,
176 })
177 }
178}
179
180#[derive(serde::Deserialize)]
184#[serde(deny_unknown_fields)]
185struct JwsSignature<'a> {
186 header: Option<JwsHeader>,
187 protected: Option<&'a str>,
188 signature: &'a str,
189}
190
191#[derive(serde::Deserialize)]
192#[serde(deny_unknown_fields)]
193struct General<'a> {
194 payload: Option<&'a str>,
195 signatures: Vec<JwsSignature<'a>>,
196}
197
198#[derive(serde::Deserialize)]
199#[serde(deny_unknown_fields)]
200struct Flatten<'a> {
201 payload: Option<&'a str>,
202 #[serde(flatten)]
203 signature: JwsSignature<'a>,
204}
205
206#[derive(Debug, Clone)]
212pub struct Decoder;
213
214impl Decoder {
215 pub fn new() -> Decoder {
217 Self
218 }
219
220 pub fn decode_compact_serialization<'b>(
228 &self,
229 jws_bytes: &'b [u8],
230 detached_payload: Option<&'b [u8]>,
231 ) -> Result<JwsValidationItem<'b>> {
232 let mut segments = jws_bytes.split(|byte| *byte == b'.');
233
234 let (Some(protected), Some(payload), Some(signature), None) =
235 (segments.next(), segments.next(), segments.next(), segments.next())
236 else {
237 return Err(Error::InvalidContent("invalid segments count"));
238 };
239
240 let signature: JwsSignature<'_> = JwsSignature {
241 header: None,
242 protected: Some(parse_utf8(protected)?),
243 signature: parse_utf8(signature)?,
244 };
245
246 let payload = Self::expand_payload(detached_payload, Some(payload))?;
247
248 self.decode_signature(payload, signature)
249 }
250
251 pub fn decode_flattened_serialization<'b>(
258 &self,
259 jws_bytes: &'b [u8],
260 detached_payload: Option<&'b [u8]>,
261 ) -> Result<JwsValidationItem<'b>> {
262 let data: Flatten<'_> = serde_json::from_slice(jws_bytes).map_err(Error::InvalidJson)?;
263 let payload = Self::expand_payload(detached_payload, data.payload)?;
264 let signature = data.signature;
265 self.decode_signature(payload, signature)
266 }
267
268 fn decode_signature<'a, 'b>(
269 &self,
270 payload: &'b [u8],
271 jws_signature: JwsSignature<'a>,
272 ) -> Result<JwsValidationItem<'b>> {
273 let JwsSignature {
274 header: unprotected_header,
275 protected,
276 signature,
277 } = jws_signature;
278
279 let protected_header: Option<JwsHeader> = protected.map(decode_b64_json).transpose()?;
280 validate_jws_headers(protected_header.as_ref(), unprotected_header.as_ref())?;
281
282 let protected_bytes: &[u8] = protected.map(str::as_bytes).unwrap_or_default();
283 let signing_input: Box<[u8]> = create_message(protected_bytes, payload).into();
284 let decoded_signature: Box<[u8]> = decode_b64(signature)?.into();
285
286 let claims: Cow<'b, [u8]> = if protected_header.as_ref().and_then(|value| value.b64()).unwrap_or(true) {
287 Cow::Owned(decode_b64(payload)?)
288 } else {
289 Cow::Borrowed(payload)
290 };
291
292 Ok(JwsValidationItem {
293 headers: DecodedHeaders::new(protected_header, unprotected_header)?,
294 signing_input,
295 decoded_signature,
296 claims,
297 })
298 }
299
300 fn expand_payload<'b>(
301 detached_payload: Option<&'b [u8]>,
302 parsed_payload: Option<&'b (impl AsRef<[u8]> + ?Sized)>,
303 ) -> Result<&'b [u8]> {
304 match (detached_payload, filter_non_empty_bytes(parsed_payload)) {
305 (Some(payload), None) => Ok(payload),
306 (None, Some(payload)) => Ok(payload),
307 (Some(_), Some(_)) => Err(Error::InvalidContent("multiple payloads")),
308 (None, None) => Err(Error::InvalidContent("missing payload")),
309 }
310 }
311}
312
313pub struct JwsValidationIter<'decoder, 'payload, 'signatures> {
320 decoder: &'decoder Decoder,
321 signatures: std::vec::IntoIter<JwsSignature<'signatures>>,
322 payload: &'payload [u8],
323}
324
325impl<'payload> Iterator for JwsValidationIter<'_, 'payload, '_> {
326 type Item = Result<JwsValidationItem<'payload>>;
327
328 fn next(&mut self) -> Option<Self::Item> {
329 self
330 .signatures
331 .next()
332 .map(|signature| self.decoder.decode_signature(self.payload, signature))
333 }
334}
335
336impl Decoder {
337 pub fn decode_general_serialization<'decoder, 'data>(
344 &'decoder self,
345 jws_bytes: &'data [u8],
346 detached_payload: Option<&'data [u8]>,
347 ) -> Result<JwsValidationIter<'decoder, 'data, 'data>> {
348 let data: General<'data> = serde_json::from_slice(jws_bytes).map_err(Error::InvalidJson)?;
349
350 let payload = Self::expand_payload(detached_payload, data.payload)?;
351 let signatures = data.signatures;
352
353 Ok(JwsValidationIter {
354 decoder: self,
355 payload,
356 signatures: signatures.into_iter(),
357 })
358 }
359}
360
361impl Default for Decoder {
362 fn default() -> Self {
363 Self::new()
364 }
365}
366
367#[cfg(test)]
368mod tests {
369 use crate::jwt::JwtClaims;
370
371 use super::*;
372
373 const RFC_7515_APPENDIX_EXAMPLE_CLAIMS: &str = r#"
374 {
375 "iss":"joe",
376 "exp":1300819380,
377 "http://example.com/is_root":true
378 }
379 "#;
380
381 const SIGNING_INPUT_ES256_RFC_7515_APPENDIX_EXAMPLE: &[u8] = &[
382 101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 70, 85, 122, 73, 49, 78, 105, 74, 57, 46, 101, 121, 74, 112, 99,
383 51, 77, 105, 79, 105, 74, 113, 98, 50, 85, 105, 76, 65, 48, 75, 73, 67, 74, 108, 101, 72, 65, 105, 79, 106, 69,
384 122, 77, 68, 65, 52, 77, 84, 107, 122, 79, 68, 65, 115, 68, 81, 111, 103, 73, 109, 104, 48, 100, 72, 65, 54, 76,
385 121, 57, 108, 101, 71, 70, 116, 99, 71, 120, 108, 76, 109, 78, 118, 98, 83, 57, 112, 99, 49, 57, 121, 98, 50, 57,
386 48, 73, 106, 112, 48, 99, 110, 86, 108, 102, 81,
387 ];
388
389 #[test]
391 fn rfc7515_appendix_a_6() {
392 let general_jws_json_serialized: &str = r#"
393 {
394 "payload": "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
395 "signatures": [
396 {
397 "protected": "eyJhbGciOiJSUzI1NiJ9",
398 "header": {
399 "kid": "2010-12-29"
400 },
401 "signature": "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"
402 },
403 {
404 "protected": "eyJhbGciOiJFUzI1NiJ9",
405 "header": {
406 "kid": "e9bc097a-ce51-4036-9562-d2ade882db0d"
407 },
408 "signature": "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
409 }
410 ]
411 }"#;
412
413 let claims: JwtClaims<serde_json::Value> = serde_json::from_str(RFC_7515_APPENDIX_EXAMPLE_CLAIMS).unwrap();
414
415 let decoder = Decoder::new();
416
417 let mut signature_iter = decoder
418 .decode_general_serialization(general_jws_json_serialized.as_bytes(), None)
419 .unwrap()
420 .filter_map(|decoded| decoded.ok());
421
422 let first_signature_decoding = signature_iter.next().unwrap();
424 let second_signature_decoding = signature_iter.next().unwrap();
425 drop(signature_iter);
426
427 assert_eq!(first_signature_decoding.alg().unwrap(), JwsAlgorithm::RS256);
429 assert_eq!(
430 first_signature_decoding
431 .unprotected_header()
432 .and_then(|value| value.kid())
433 .unwrap(),
434 "2010-12-29"
435 );
436 let decoded_claims: JwtClaims<serde_json::Value> =
437 serde_json::from_slice(first_signature_decoding.claims()).unwrap();
438 assert_eq!(claims, decoded_claims);
439
440 assert_eq!(second_signature_decoding.alg().unwrap(), JwsAlgorithm::ES256);
442 assert_eq!(
443 second_signature_decoding
444 .unprotected_header()
445 .and_then(|value| value.kid())
446 .unwrap(),
447 "e9bc097a-ce51-4036-9562-d2ade882db0d"
448 );
449
450 let decoded_claims: JwtClaims<serde_json::Value> =
451 serde_json::from_slice(second_signature_decoding.claims()).unwrap();
452 assert_eq!(decoded_claims, claims);
453 assert_eq!(
454 SIGNING_INPUT_ES256_RFC_7515_APPENDIX_EXAMPLE,
455 second_signature_decoding.signing_input()
456 );
457 }
458
459 #[test]
461 fn rfc7515_appendix_a_7() {
462 let flattened_jws_json_serialized: &str = r#"
463 {
464 "payload": "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
465 "protected":"eyJhbGciOiJFUzI1NiJ9",
466 "header": {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
467 "signature": "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
468 }
469 "#;
470
471 let claims: JwtClaims<serde_json::Value> = serde_json::from_str(RFC_7515_APPENDIX_EXAMPLE_CLAIMS).unwrap();
472 let decoder = Decoder::new();
473 let decoded = decoder
474 .decode_flattened_serialization(flattened_jws_json_serialized.as_bytes(), None)
475 .unwrap();
476 assert_eq!(decoded.alg().unwrap(), JwsAlgorithm::ES256);
477 assert_eq!(
478 decoded.unprotected_header().and_then(|value| value.kid()).unwrap(),
479 "e9bc097a-ce51-4036-9562-d2ade882db0d"
480 );
481
482 assert_eq!(decoded.signing_input(), SIGNING_INPUT_ES256_RFC_7515_APPENDIX_EXAMPLE);
483 let decoded_claims: JwtClaims<serde_json::Value> = serde_json::from_slice(decoded.claims()).unwrap();
484 assert_eq!(decoded_claims, claims);
485 }
486}