biscuit_auth/token/
unverified.rs

1use std::convert::TryInto;
2
3use super::{default_symbol_table, Biscuit, Block};
4use crate::{
5    builder::BlockBuilder,
6    crypto,
7    crypto::PublicKey,
8    datalog::SymbolTable,
9    error,
10    format::{convert::proto_block_to_token_block, schema, SerializedBiscuit},
11    token::{ThirdPartyBlockContents, ThirdPartyRequest},
12    KeyPair, RootKeyProvider,
13};
14use prost::Message;
15
16/// A token that was parsed without cryptographic signature verification
17///
18/// Use this if you want to attenuate or print the content of a token
19/// without verifying it.
20///
21/// It can be converted to a [Biscuit] using [UnverifiedBiscuit::verify],
22/// and then used for authorization
23#[derive(Clone, Debug)]
24pub struct UnverifiedBiscuit {
25    pub(crate) authority: schema::Block,
26    pub(crate) blocks: Vec<schema::Block>,
27    pub(crate) symbols: SymbolTable,
28    container: SerializedBiscuit,
29}
30
31impl UnverifiedBiscuit {
32    /// deserializes a token from raw bytes
33    pub fn from<T>(slice: T) -> Result<Self, error::Token>
34    where
35        T: AsRef<[u8]>,
36    {
37        Self::from_with_symbols(slice.as_ref(), default_symbol_table())
38    }
39
40    /// deserializes a token from base64
41    pub fn from_base64<T>(slice: T) -> Result<Self, error::Token>
42    where
43        T: AsRef<[u8]>,
44    {
45        Self::from_base64_with_symbols(slice, default_symbol_table())
46    }
47
48    #[deprecated(since = "4.1.0", note = "please use `verify` instead")]
49    /// checks the signature of the token and convert it to a [Biscuit] for authorization
50    pub fn check_signature<F>(self, f: F) -> Result<Biscuit, error::Format>
51    where
52        F: Fn(Option<u32>) -> PublicKey,
53    {
54        self.verify(|kid| Ok(f(kid)))
55    }
56
57    /// checks the signature of the token and convert it to a [Biscuit] for authorization
58    pub fn verify<KP>(self, key_provider: KP) -> Result<Biscuit, error::Format>
59    where
60        KP: RootKeyProvider,
61    {
62        let key = key_provider.choose(self.root_key_id())?;
63        self.container.verify(&key)?;
64
65        Ok(Biscuit {
66            root_key_id: self.container.root_key_id,
67            authority: self.authority,
68            blocks: self.blocks,
69            symbols: self.symbols,
70            container: self.container,
71        })
72    }
73
74    /// adds a new block to the token
75    ///
76    /// since the public key is integrated into the token, the keypair can be
77    /// discarded right after calling this function
78    pub fn append(&self, block_builder: BlockBuilder) -> Result<Self, error::Token> {
79        let keypair = KeyPair::new_with_rng(&mut rand::rngs::OsRng);
80        self.append_with_keypair(&keypair, block_builder)
81    }
82
83    /// serializes the token
84    pub fn to_vec(&self) -> Result<Vec<u8>, error::Token> {
85        self.container.to_vec().map_err(error::Token::Format)
86    }
87
88    /// serializes the token and encode it to a (URL safe) base64 string
89    pub fn to_base64(&self) -> Result<String, error::Token> {
90        self.container
91            .to_vec()
92            .map_err(error::Token::Format)
93            .map(|v| base64::encode_config(v, base64::URL_SAFE))
94    }
95
96    /// deserializes from raw bytes with a custom symbol table
97    pub fn from_with_symbols(slice: &[u8], mut symbols: SymbolTable) -> Result<Self, error::Token> {
98        let container = SerializedBiscuit::deserialize(slice)?;
99
100        let (authority, blocks) = container.extract_blocks(&mut symbols)?;
101
102        Ok(UnverifiedBiscuit {
103            authority,
104            blocks,
105            symbols,
106            container,
107        })
108    }
109
110    /// deserializes a token from base64 with a custom symbol table
111    pub fn from_base64_with_symbols<T>(slice: T, symbols: SymbolTable) -> Result<Self, error::Token>
112    where
113        T: AsRef<[u8]>,
114    {
115        let decoded = base64::decode_config(slice, base64::URL_SAFE)?;
116        Self::from_with_symbols(&decoded, symbols)
117    }
118
119    /// adds a new block to the token
120    ///
121    /// since the public key is integrated into the token, the keypair can be
122    /// discarded right after calling this function
123    pub fn append_with_keypair(
124        &self,
125        keypair: &KeyPair,
126        block_builder: BlockBuilder,
127    ) -> Result<Self, error::Token> {
128        let block = block_builder.build(self.symbols.clone());
129
130        if !self.symbols.is_disjoint(&block.symbols) {
131            return Err(error::Token::Format(error::Format::SymbolTableOverlap));
132        }
133
134        let authority = self.authority.clone();
135        let mut blocks = self.blocks.clone();
136        let mut symbols = self.symbols.clone();
137
138        let container = self.container.append(keypair, &block, None)?;
139
140        symbols.extend(&block.symbols)?;
141        symbols.public_keys.extend(&block.public_keys)?;
142
143        let deser = schema::Block::decode(
144            &container
145                .blocks
146                .last()
147                .expect("a new block was just added so the list is not empty")
148                .data[..],
149        )
150        .map_err(|e| {
151            error::Token::Format(error::Format::BlockDeserializationError(format!(
152                "error deserializing block: {:?}",
153                e
154            )))
155        })?;
156        blocks.push(deser);
157
158        Ok(UnverifiedBiscuit {
159            authority,
160            blocks,
161            symbols,
162            container,
163        })
164    }
165
166    /// returns an (optional) root key identifier. It provides a hint for public key selection during verification
167    pub fn root_key_id(&self) -> Option<u32> {
168        self.container.root_key_id
169    }
170
171    /// returns a list of revocation identifiers for each block, in order
172    ///
173    /// revocation identifiers are unique: tokens generated separately with
174    /// the same contents will have different revocation ids
175    pub fn revocation_identifiers(&self) -> Vec<Vec<u8>> {
176        let mut res = vec![self.container.authority.signature.to_bytes().to_vec()];
177
178        for block in self.container.blocks.iter() {
179            res.push(block.signature.to_bytes().to_vec());
180        }
181
182        res
183    }
184
185    /// returns a list of external key for each block, in order
186    ///
187    /// Blocks carrying an external public key are _third-party blocks_
188    /// and their contents can be trusted as coming from the holder of
189    /// the corresponding private key
190    pub fn external_public_keys(&self) -> Vec<Option<Vec<u8>>> {
191        let mut res = vec![None];
192
193        for block in self.container.blocks.iter() {
194            res.push(
195                block
196                    .external_signature
197                    .as_ref()
198                    .map(|sig| sig.public_key.to_bytes().to_vec()),
199            );
200        }
201
202        res
203    }
204
205    /// returns the number of blocks (at least 1)
206    pub fn block_count(&self) -> usize {
207        1 + self.container.blocks.len()
208    }
209
210    /// prints the content of a block as Datalog source code
211    pub fn print_block_source(&self, index: usize) -> Result<String, error::Token> {
212        self.block(index).map(|block| {
213            let symbols = if block.external_key.is_some() {
214                &block.symbols
215            } else {
216                &self.symbols
217            };
218            block.print_source(symbols)
219        })
220    }
221
222    pub(crate) fn block(&self, index: usize) -> Result<Block, error::Token> {
223        let mut block = if index == 0 {
224            proto_block_to_token_block(
225                &self.authority,
226                self.container
227                    .authority
228                    .external_signature
229                    .as_ref()
230                    .map(|ex| ex.public_key),
231            )
232            .map_err(error::Token::Format)?
233        } else {
234            if index > self.blocks.len() + 1 {
235                return Err(error::Token::Format(
236                    error::Format::BlockDeserializationError("invalid block index".to_string()),
237                ));
238            }
239
240            proto_block_to_token_block(
241                &self.blocks[index - 1],
242                self.container.blocks[index - 1]
243                    .external_signature
244                    .as_ref()
245                    .map(|ex| ex.public_key),
246            )
247            .map_err(error::Token::Format)?
248        };
249
250        // we have to add the entire list of public keys here because
251        // they are used to validate 3rd party tokens
252        block.symbols.public_keys = self.symbols.public_keys.clone();
253        Ok(block)
254    }
255
256    /// creates a sealed version of the token
257    ///
258    /// sealed tokens cannot be attenuated
259    pub fn seal(&self) -> Result<UnverifiedBiscuit, error::Token> {
260        let container = self.container.seal()?;
261        let mut token = self.clone();
262        token.container = container;
263        Ok(token)
264    }
265
266    pub fn third_party_request(&self) -> Result<ThirdPartyRequest, error::Token> {
267        ThirdPartyRequest::from_container(&self.container)
268    }
269
270    pub fn append_third_party(&self, slice: &[u8]) -> Result<Self, error::Token> {
271        let next_keypair = KeyPair::new_with_rng(&mut rand::rngs::OsRng);
272
273        let ThirdPartyBlockContents {
274            payload,
275            external_signature,
276        } = schema::ThirdPartyBlockContents::decode(slice).map_err(|e| {
277            error::Format::DeserializationError(format!("deserialization error: {:?}", e))
278        })?;
279
280        if external_signature.public_key.algorithm != schema::public_key::Algorithm::Ed25519 as i32
281        {
282            return Err(error::Token::Format(error::Format::DeserializationError(
283                format!(
284                    "deserialization error: unexpected key algorithm {}",
285                    external_signature.public_key.algorithm
286                ),
287            )));
288        }
289        let external_key =
290            PublicKey::from_bytes(&external_signature.public_key.key).map_err(|e| {
291                error::Format::BlockSignatureDeserializationError(format!(
292                    "block external public key deserialization error: {:?}",
293                    e
294                ))
295            })?;
296
297        let bytes: [u8; 64] = (&external_signature.signature[..])
298            .try_into()
299            .map_err(|_| error::Format::InvalidSignatureSize(external_signature.signature.len()))?;
300
301        let signature = ed25519_dalek::Signature::from_bytes(&bytes);
302        let previous_key = self
303            .container
304            .blocks
305            .last()
306            .unwrap_or(&self.container.authority)
307            .next_key;
308        let mut to_verify = payload.clone();
309        to_verify
310            .extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes());
311        to_verify.extend(&previous_key.to_bytes());
312
313        let block = schema::Block::decode(&payload[..]).map_err(|e| {
314            error::Token::Format(error::Format::DeserializationError(format!(
315                "deserialization error: {:?}",
316                e
317            )))
318        })?;
319
320        let external_signature = crypto::ExternalSignature {
321            public_key: external_key,
322            signature,
323        };
324
325        let mut symbols = self.symbols.clone();
326        let mut blocks = self.blocks.clone();
327
328        let container =
329            self.container
330                .append_serialized(&next_keypair, payload, Some(external_signature))?;
331
332        let token_block = proto_block_to_token_block(&block, Some(external_key)).unwrap();
333        for key in &token_block.public_keys.keys {
334            symbols.public_keys.insert_fallible(key)?;
335        }
336
337        blocks.push(block);
338
339        Ok(UnverifiedBiscuit {
340            authority: self.authority.clone(),
341            blocks,
342            symbols,
343            container,
344        })
345    }
346
347    pub fn append_third_party_base64<T>(&self, slice: T) -> Result<Self, error::Token>
348    where
349        T: AsRef<[u8]>,
350    {
351        let decoded = base64::decode_config(slice, base64::URL_SAFE)?;
352        self.append_third_party(&decoded)
353    }
354}