1use crate::claims::Claims;
2use crate::crypto::{QVVerifyingKey, verify};
3use crate::error::{QVError, QVResult};
4use crate::issuance::decrypt_payload;
5use crate::mutation::{MutationChain, certify_entropy};
6use crate::token::QVRawToken;
7
8pub struct VerifyOutput {
10 pub claims: Claims,
11 pub issued_at: u64,
12 pub ttl: u32,
13 pub mutation_ctr: u64,
14}
15
16pub fn verify_token(
26 raw: &QVRawToken,
27 vk: &QVVerifyingKey,
28 encrypt_key: &[u8; 32],
29 chain: &MutationChain,
30) -> QVResult<VerifyOutput> {
31
32 certify_entropy(&raw.header.nonce)?;
34
35 let now_us = std::time::SystemTime::now()
37 .duration_since(std::time::UNIX_EPOCH)
38 .map_err(|e| QVError::SerializationError(e.to_string()))?
39 .as_micros() as u64;
40
41 if raw.header.issued_at > now_us + 5_000_000 {
42 return Err(QVError::NotYetValid);
43 }
44 let expiry_us = raw.header.issued_at + (raw.header.ttl as u64) * 1_000_000;
45 if now_us > expiry_us {
46 return Err(QVError::Expired { issued_at: raw.header.issued_at, ttl: raw.header.ttl });
47 }
48
49 let msg = raw.signed_bytes();
51 verify(vk, &msg, &raw.signature)?;
52
53 let plaintext = decrypt_payload(&raw.encrypted_payload, encrypt_key, &raw.header.nonce)?;
55
56 chain.check_token_counter(raw.header.mutation_ctr)?;
58
59 let claims = Claims::decode(&plaintext)?;
61
62 Ok(VerifyOutput {
63 claims,
64 issued_at: raw.header.issued_at,
65 ttl: raw.header.ttl,
66 mutation_ctr: raw.header.mutation_ctr,
67 })
68}
69
70#[cfg_attr(not(feature = "falcon"), allow(dead_code))]
75fn verify_non_sig_layers(
76 raw: &QVRawToken,
77 encrypt_key: &[u8; 32],
78 chain: &MutationChain,
79) -> QVResult<VerifyOutput> {
80 certify_entropy(&raw.header.nonce)?;
81
82 let now_us = std::time::SystemTime::now()
83 .duration_since(std::time::UNIX_EPOCH)
84 .map_err(|e| QVError::SerializationError(e.to_string()))?
85 .as_micros() as u64;
86 if raw.header.issued_at > now_us + 5_000_000 {
87 return Err(QVError::NotYetValid);
88 }
89 let expiry_us = raw.header.issued_at + (raw.header.ttl as u64) * 1_000_000;
90 if now_us > expiry_us {
91 return Err(QVError::Expired { issued_at: raw.header.issued_at, ttl: raw.header.ttl });
92 }
93
94 let plaintext = decrypt_payload(&raw.encrypted_payload, encrypt_key, &raw.header.nonce)?;
95 chain.check_token_counter(raw.header.mutation_ctr)?;
96 let claims = Claims::decode(&plaintext)?;
97
98 Ok(VerifyOutput {
99 claims,
100 issued_at: raw.header.issued_at,
101 ttl: raw.header.ttl,
102 mutation_ctr: raw.header.mutation_ctr,
103 })
104}
105
106#[cfg(feature = "falcon")]
107pub fn verify_token_falcon512(
108 raw: &QVRawToken,
109 vk: &crate::falcon::falcon512::QVFalcon512VerifyingKey,
110 encrypt_key: &[u8; 32],
111 chain: &MutationChain,
112) -> QVResult<VerifyOutput> {
113 if raw.header.suite != crate::crypto::SuiteId::Falcon512 {
114 return Err(QVError::UnknownSuite(raw.header.suite.as_byte()));
115 }
116 let msg = raw.signed_bytes();
117 crate::falcon::falcon512::verify(vk, &msg, &raw.signature)?;
118 verify_non_sig_layers(raw, encrypt_key, chain)
119}
120
121#[cfg(feature = "falcon")]
122pub fn verify_token_falcon1024(
123 raw: &QVRawToken,
124 vk: &crate::falcon::falcon1024::QVFalcon1024VerifyingKey,
125 encrypt_key: &[u8; 32],
126 chain: &MutationChain,
127) -> QVResult<VerifyOutput> {
128 if raw.header.suite != crate::crypto::SuiteId::Falcon1024 {
129 return Err(QVError::UnknownSuite(raw.header.suite.as_byte()));
130 }
131 let msg = raw.signed_bytes();
132 crate::falcon::falcon1024::verify(vk, &msg, &raw.signature)?;
133 verify_non_sig_layers(raw, encrypt_key, chain)
134}