1use crate::keys::IssuerKeyStore;
2use crate::payload::Rsp6Ticket;
3use anyhow::anyhow;
4use num_bigint::BigUint;
5
6pub mod keys;
7pub mod payload;
8#[cfg(feature = "wasm")]
9pub mod wasm;
10
11fn base26_decode(input: &str) -> BigUint {
12 let mut out = BigUint::new(Vec::new());
13 for val in input.as_bytes().iter().rev() {
14 out *= 26u32;
15 out += *val - b'A';
16 }
17 BigUint::from_bytes_le(&out.to_bytes_be())
18}
19
20fn strip_padding(tkt: &[u8]) -> Option<&[u8]> {
21 if tkt.is_empty() {
22 return None;
23 }
24 match tkt[0] {
25 1 => {
26 let tkt = &tkt[1..];
28 let mut iter = tkt.iter();
29 loop {
30 match iter.next()? {
31 0 => {
32 return Some(iter.as_slice());
33 }
34 255 => {}
35 _ => return None,
36 }
37 }
38 }
39 2 => {
40 let tkt = &tkt[1..];
42 let mut iter = tkt.iter();
43 loop {
44 match iter.next()? {
45 0 => {
46 return Some(iter.as_slice());
47 }
48 _ => {}
49 }
50 }
51 }
52 _ => None,
53 }
54}
55
56pub fn decode_ticket(iks: &IssuerKeyStore, ticket_str: &str) -> anyhow::Result<Rsp6Ticket> {
57 if ticket_str.len() < 16 {
58 return Err(anyhow!("ticket too short"));
59 }
60 if &ticket_str[0..2] != "06" {
61 return Err(anyhow!(
62 "ticket isn't a RSP6 ticket: magic was {}",
63 &ticket_str[0..2]
64 ));
65 }
66 let issuer_id = &ticket_str[13..15];
67 let ticket = base26_decode(&ticket_str[15..]);
68 let keys = iks
69 .keys
70 .get(issuer_id)
71 .ok_or_else(|| anyhow!("unknown issuer ID {}", issuer_id))?;
72 for key in keys {
73 let message = ticket.modpow(&key.public_exponent, &key.modulus);
74 let message = message.to_bytes_be();
75 if let Some(unpadded) = strip_padding(&message) {
76 let ticket = Rsp6Ticket::decode(unpadded, issuer_id.into(), ticket_str[11..13].into())?;
77 return Ok(ticket);
78 }
79 }
80 Err(anyhow!(
81 "all signature unwrap attempts failed (tried {} keys for issuer {})",
82 keys.len(),
83 issuer_id
84 ))
85}
86
87#[cfg(test)]
88mod test {
89 #[test]
90 fn test_base26() {
91 assert_eq!(
92 super::base26_decode("RANEBZCYPNQVMMYJBOJBONYSIYXTREYFSHTZFZEXWTVBNXJBFVOFBMXVQPZTFWVYSWYKINRXRVDCCUWUERKQZKYBPVIIAPJOOFJJXUBFGNVXGXTCFPBHXYVPEKWIURBEOYTYNZUXWVIXHAODACOQLZEQKRUNGWSJHIIWOYSNXJKVYWIGLWCIZKAHFKKAKRDUQSQBGEJMOFCSHSKXSFDDKYCFQI").to_bytes_be(),
93 [53, 242, 184, 141, 14, 99, 169, 215, 200, 223, 85, 250, 45, 253, 184, 100, 225, 124, 82, 70, 138, 222, 246, 185, 192, 129, 247, 218, 24, 26, 249, 112, 74, 225, 71, 139, 27, 50, 218, 11, 93, 238, 232, 163, 151, 68, 159, 146, 80, 133, 11, 45, 57, 245, 163, 117, 218, 11, 187, 246, 18, 147, 88, 171, 133, 216, 166, 47, 232, 246, 198, 170, 99, 36, 120, 114, 73, 207, 19, 218, 202, 146, 158, 223, 107, 234, 171, 172, 20, 189, 133, 246, 192, 248, 57, 111, 65, 65, 135, 64, 241, 99, 87, 107, 75, 40, 224, 223, 100, 53, 180, 212, 53, 200, 172, 117, 127, 248, 193, 0, 147, 167, 222, 81, 135, 158, 135, 137]
94 )
95 }
96}