1use super::crypto::{self, KeyPair, PrivateKey, PublicKey, TokenNext};
12
13use prost::Message;
14
15use super::error;
16use super::token::Block;
17use crate::crypto::ExternalSignature;
18use crate::crypto::Signature;
19use crate::datalog::SymbolTable;
20use crate::token::RootKeyProvider;
21use crate::token::DATALOG_3_3;
22
23pub mod schema; pub mod convert;
29
30use self::convert::*;
31
32pub(crate) const THIRD_PARTY_SIGNATURE_VERSION: u32 = 1;
33pub(crate) const DATALOG_3_3_SIGNATURE_VERSION: u32 = 1;
34pub(crate) const NON_ED25519_SIGNATURE_VERSION: u32 = 1;
35#[derive(Clone, Debug)]
40pub struct SerializedBiscuit {
41 pub root_key_id: Option<u32>,
42 pub authority: crypto::Block,
43 pub blocks: Vec<crypto::Block>,
44 pub proof: crypto::TokenNext,
45}
46
47impl SerializedBiscuit {
48 pub fn from_slice<KP>(slice: &[u8], key_provider: KP) -> Result<Self, error::Format>
49 where
50 KP: RootKeyProvider,
51 {
52 let deser = SerializedBiscuit::deserialize(
53 slice,
54 ThirdPartyVerificationMode::PreviousSignatureHashing,
55 )?;
56
57 let root = key_provider.choose(deser.root_key_id)?;
58 deser.verify(&root)?;
59
60 Ok(deser)
61 }
62
63 pub(crate) fn unsafe_from_slice<KP>(
64 slice: &[u8],
65 key_provider: KP,
66 ) -> Result<Self, error::Format>
67 where
68 KP: RootKeyProvider,
69 {
70 let deser =
71 SerializedBiscuit::deserialize(slice, ThirdPartyVerificationMode::UnsafeLegacy)?;
72
73 let root = key_provider.choose(deser.root_key_id)?;
74 deser.verify_inner(&root, ThirdPartyVerificationMode::UnsafeLegacy)?;
75
76 Ok(deser)
77 }
78
79 pub(crate) fn deserialize(
80 slice: &[u8],
81 verification_mode: ThirdPartyVerificationMode,
82 ) -> Result<Self, error::Format> {
83 let data = schema::Biscuit::decode(slice).map_err(|e| {
84 error::Format::DeserializationError(format!("deserialization error: {:?}", e))
85 })?;
86
87 let next_key = PublicKey::from_proto(&data.authority.next_key)?;
88 let mut next_key_algorithm = next_key.algorithm();
89
90 let signature = Signature::from_vec(data.authority.signature);
91
92 if data.authority.external_signature.is_some() {
93 return Err(error::Format::DeserializationError(
94 "the authority block must not contain an external signature".to_string(),
95 ));
96 }
97
98 let authority = crypto::Block {
99 data: data.authority.block,
100 next_key,
101 signature,
102 external_signature: None,
103 version: data.authority.version.unwrap_or_default(),
104 };
105
106 let mut blocks = Vec::new();
107 for block in data.blocks {
108 let next_key = PublicKey::from_proto(&block.next_key)?;
109 next_key_algorithm = next_key.algorithm();
110
111 let signature = Signature::from_vec(block.signature);
112
113 let external_signature = if let Some(ex) = block.external_signature {
114 if verification_mode == ThirdPartyVerificationMode::PreviousSignatureHashing
115 && block.version != Some(THIRD_PARTY_SIGNATURE_VERSION)
116 {
117 return Err(error::Format::DeserializationError(
118 "Unsupported third party block version".to_string(),
119 ));
120 }
121
122 let public_key = PublicKey::from_proto(&ex.public_key)?;
123 let signature = Signature::from_vec(ex.signature);
124
125 Some(ExternalSignature {
126 public_key,
127 signature,
128 })
129 } else {
130 None
131 };
132
133 blocks.push(crypto::Block {
134 data: block.block.clone(),
135 next_key,
136 signature,
137 external_signature,
138 version: block.version.unwrap_or_default(),
139 });
140 }
141
142 let proof = match data.proof.content {
143 None => {
144 return Err(error::Format::DeserializationError(
145 "could not find proof".to_string(),
146 ))
147 }
148 Some(schema::proof::Content::NextSecret(v)) => {
149 let next_key_algorithm = match next_key_algorithm {
150 schema::public_key::Algorithm::Ed25519 => crate::builder::Algorithm::Ed25519,
151 schema::public_key::Algorithm::Secp256r1 => {
152 crate::builder::Algorithm::Secp256r1
153 }
154 };
155 TokenNext::Secret(PrivateKey::from_bytes(&v, next_key_algorithm)?)
156 }
157 Some(schema::proof::Content::FinalSignature(v)) => {
158 let signature = Signature::from_vec(v);
159
160 TokenNext::Seal(signature)
161 }
162 };
163
164 let deser = SerializedBiscuit {
165 root_key_id: data.root_key_id,
166 authority,
167 blocks,
168 proof,
169 };
170
171 Ok(deser)
172 }
173
174 pub(crate) fn extract_blocks(
175 &self,
176 symbols: &mut SymbolTable,
177 ) -> Result<(schema::Block, Vec<schema::Block>), error::Token> {
178 let mut block_external_keys = Vec::new();
179
180 let authority = schema::Block::decode(&self.authority.data[..]).map_err(|e| {
181 error::Token::Format(error::Format::BlockDeserializationError(format!(
182 "error deserializing authority block: {:?}",
183 e
184 )))
185 })?;
186
187 symbols.extend(&SymbolTable::from(authority.symbols.clone())?)?;
188
189 for pk in &authority.public_keys {
190 symbols
191 .public_keys
192 .insert_fallible(&PublicKey::from_proto(pk)?)?;
193 }
194 block_external_keys.push(None);
196 let mut blocks = vec![];
199
200 for block in self.blocks.iter() {
201 let deser = schema::Block::decode(&block.data[..]).map_err(|e| {
202 error::Token::Format(error::Format::BlockDeserializationError(format!(
203 "error deserializing block: {:?}",
204 e
205 )))
206 })?;
207
208 if let Some(external_signature) = &block.external_signature {
209 block_external_keys.push(Some(external_signature.public_key));
210 } else {
211 block_external_keys.push(None);
212 symbols.extend(&SymbolTable::from(deser.symbols.clone())?)?;
213 for pk in &deser.public_keys {
214 symbols
215 .public_keys
216 .insert_fallible(&PublicKey::from_proto(pk)?)?;
217 }
218 }
219
220 blocks.push(deser);
221 }
222
223 Ok((authority, blocks))
224 }
225
226 pub fn to_proto(&self) -> schema::Biscuit {
228 let authority = schema::SignedBlock {
229 block: self.authority.data.clone(),
230 next_key: self.authority.next_key.to_proto(),
231 signature: self.authority.signature.to_bytes().to_vec(),
232 external_signature: None,
233 version: if self.authority.version > 0 {
234 Some(self.authority.version)
235 } else {
236 None
237 },
238 };
239
240 let mut blocks = Vec::new();
241 for block in &self.blocks {
242 let b = schema::SignedBlock {
243 block: block.data.clone(),
244 next_key: block.next_key.to_proto(),
245 signature: block.signature.to_bytes().to_vec(),
246 external_signature: block.external_signature.as_ref().map(|external_signature| {
247 schema::ExternalSignature {
248 signature: external_signature.signature.to_bytes().to_vec(),
249 public_key: external_signature.public_key.to_proto(),
250 }
251 }),
252 version: if block.version > 0 {
253 Some(block.version)
254 } else {
255 None
256 },
257 };
258
259 blocks.push(b);
260 }
261
262 schema::Biscuit {
263 root_key_id: self.root_key_id,
264 authority,
265 blocks,
266 proof: schema::Proof {
267 content: match &self.proof {
268 TokenNext::Seal(signature) => Some(schema::proof::Content::FinalSignature(
269 signature.to_bytes().to_vec(),
270 )),
271 TokenNext::Secret(private) => Some(schema::proof::Content::NextSecret(
272 private.to_bytes().to_vec(),
273 )),
274 },
275 },
276 }
277 }
278
279 pub fn serialized_size(&self) -> usize {
280 self.to_proto().encoded_len()
281 }
282
283 pub fn to_vec(&self) -> Result<Vec<u8>, error::Format> {
285 let b = self.to_proto();
286
287 let mut v = Vec::new();
288
289 b.encode(&mut v)
290 .map(|_| v)
291 .map_err(|e| error::Format::SerializationError(format!("serialization error: {:?}", e)))
292 }
293
294 pub fn new(
296 root_key_id: Option<u32>,
297 root_keypair: &KeyPair,
298 next_keypair: &KeyPair,
299 authority: &Block,
300 ) -> Result<Self, error::Token> {
301 let authority_signature_version = block_signature_version(
302 root_keypair,
303 next_keypair,
304 &None,
305 &Some(authority.version),
306 std::iter::empty(),
307 );
308 Self::new_inner(
309 root_key_id,
310 root_keypair,
311 next_keypair,
312 authority,
313 authority_signature_version,
314 )
315 }
316
317 pub(crate) fn new_inner(
319 root_key_id: Option<u32>,
320 root_keypair: &KeyPair,
321 next_keypair: &KeyPair,
322 authority: &Block,
323 authority_signature_version: u32,
324 ) -> Result<Self, error::Token> {
325 let mut v = Vec::new();
326 token_block_to_proto_block(authority)
327 .encode(&mut v)
328 .map_err(|e| {
329 error::Format::SerializationError(format!("serialization error: {:?}", e))
330 })?;
331
332 let signature = crypto::sign_authority_block(
333 root_keypair,
334 next_keypair,
335 &v,
336 authority_signature_version,
337 )?;
338
339 Ok(SerializedBiscuit {
340 root_key_id,
341 authority: crypto::Block {
342 data: v,
343 next_key: next_keypair.public(),
344 signature,
345 external_signature: None,
346 version: authority_signature_version,
347 },
348 blocks: vec![],
349 proof: TokenNext::Secret(next_keypair.private()),
350 })
351 }
352
353 pub fn append(
355 &self,
356 next_keypair: &KeyPair,
357 block: &Block,
358 external_signature: Option<ExternalSignature>,
359 ) -> Result<Self, error::Token> {
360 let keypair = self.proof.keypair()?;
361
362 let mut v = Vec::new();
363 token_block_to_proto_block(block)
364 .encode(&mut v)
365 .map_err(|e| {
366 error::Format::SerializationError(format!("serialization error: {:?}", e))
367 })?;
368
369 let signature_version = block_signature_version(
370 &keypair,
371 next_keypair,
372 &external_signature,
373 &Some(block.version),
374 self.blocks
377 .iter()
378 .chain([&self.authority])
379 .map(|block| block.version),
380 );
381
382 let signature = crypto::sign_block(
383 &keypair,
384 next_keypair,
385 &v,
386 external_signature.as_ref(),
387 &self.last_block().signature,
388 signature_version,
389 )?;
390
391 let mut blocks = self.blocks.clone();
393 blocks.push(crypto::Block {
394 data: v,
395 next_key: next_keypair.public(),
396 signature,
397 external_signature,
398 version: signature_version,
399 });
400
401 Ok(SerializedBiscuit {
402 root_key_id: self.root_key_id,
403 authority: self.authority.clone(),
404 blocks,
405 proof: TokenNext::Secret(next_keypair.private()),
406 })
407 }
408
409 pub fn append_serialized(
411 &self,
412 next_keypair: &KeyPair,
413 block: Vec<u8>,
414 external_signature: Option<ExternalSignature>,
415 ) -> Result<Self, error::Token> {
416 let keypair = self.proof.keypair()?;
417
418 let signature_version = block_signature_version(
419 &keypair,
420 next_keypair,
421 &external_signature,
422 &None,
425 std::iter::once(self.authority.version)
426 .chain(self.blocks.iter().map(|block| block.version)),
427 );
428
429 let signature = crypto::sign_block(
430 &keypair,
431 next_keypair,
432 &block,
433 external_signature.as_ref(),
434 &self.last_block().signature,
435 signature_version,
436 )?;
437
438 let mut blocks = self.blocks.clone();
440 blocks.push(crypto::Block {
441 data: block,
442 next_key: next_keypair.public(),
443 signature,
444 external_signature,
445 version: signature_version,
446 });
447
448 Ok(SerializedBiscuit {
449 root_key_id: self.root_key_id,
450 authority: self.authority.clone(),
451 blocks,
452 proof: TokenNext::Secret(next_keypair.private()),
453 })
454 }
455
456 pub fn verify(&self, root: &PublicKey) -> Result<(), error::Format> {
458 self.verify_inner(root, ThirdPartyVerificationMode::PreviousSignatureHashing)
459 }
460
461 pub(crate) fn verify_inner(
462 &self,
463 root: &PublicKey,
464 verification_mode: ThirdPartyVerificationMode,
465 ) -> Result<(), error::Format> {
466 let mut current_pub = root;
468 let mut previous_signature;
469
470 crypto::verify_authority_block_signature(&self.authority, current_pub)?;
471 current_pub = &self.authority.next_key;
472 previous_signature = &self.authority.signature;
473
474 for block in &self.blocks {
475 let verification_mode = match (block.version, verification_mode) {
476 (0, ThirdPartyVerificationMode::UnsafeLegacy) => {
477 ThirdPartyVerificationMode::UnsafeLegacy
478 }
479 _ => ThirdPartyVerificationMode::PreviousSignatureHashing,
480 };
481
482 crypto::verify_block_signature(
483 block,
484 current_pub,
485 previous_signature,
486 verification_mode,
487 )?;
488 current_pub = &block.next_key;
489 previous_signature = &block.signature;
490 }
491
492 match &self.proof {
493 TokenNext::Secret(private) => {
494 if current_pub != &private.public() {
495 return Err(error::Format::Signature(
496 error::Signature::InvalidSignature(
497 "the last public key does not match the private key".to_string(),
498 ),
499 ));
500 }
501 }
502 TokenNext::Seal(signature) => {
503 let block = if self.blocks.is_empty() {
505 &self.authority
506 } else {
507 &self.blocks[self.blocks.len() - 1]
508 };
509
510 let to_verify = crypto::generate_seal_signature_payload_v0(block);
511
512 current_pub.verify_signature(&to_verify, &signature)?;
513 }
514 }
515
516 Ok(())
517 }
518
519 pub fn seal(&self) -> Result<Self, error::Token> {
520 let keypair = self.proof.keypair()?;
521
522 let block = if self.blocks.is_empty() {
524 &self.authority
525 } else {
526 &self.blocks[self.blocks.len() - 1]
527 };
528
529 let to_sign = crypto::generate_seal_signature_payload_v0(block);
530
531 let signature = keypair.sign(&to_sign)?;
532
533 Ok(SerializedBiscuit {
534 root_key_id: self.root_key_id,
535 authority: self.authority.clone(),
536 blocks: self.blocks.clone(),
537 proof: TokenNext::Seal(signature),
538 })
539 }
540
541 pub(crate) fn last_block(&self) -> &crypto::Block {
542 self.blocks.last().unwrap_or(&self.authority)
543 }
544}
545
546#[derive(Clone, Copy, Debug, PartialEq)]
547pub(crate) enum ThirdPartyVerificationMode {
548 UnsafeLegacy,
549 PreviousSignatureHashing,
550}
551
552fn block_signature_version<I>(
553 block_keypair: &KeyPair,
554 next_keypair: &KeyPair,
555 external_signature: &Option<ExternalSignature>,
556 block_version: &Option<u32>,
557 previous_blocks_sig_versions: I,
558) -> u32
559where
560 I: Iterator<Item = u32>,
561{
562 if external_signature.is_some() {
563 return THIRD_PARTY_SIGNATURE_VERSION;
564 }
565
566 match block_version {
567 Some(block_version) if *block_version >= DATALOG_3_3 => {
568 return DATALOG_3_3_SIGNATURE_VERSION;
569 }
570 _ => {}
571 }
572
573 match (block_keypair, next_keypair) {
574 (KeyPair::Ed25519(_), KeyPair::Ed25519(_)) => {}
575 _ => {
576 return NON_ED25519_SIGNATURE_VERSION;
577 }
578 }
579
580 previous_blocks_sig_versions.max().unwrap_or(0)
581}
582
583#[cfg(test)]
584mod tests {
585 use std::io::Read;
586
587 use crate::{
588 builder::Algorithm,
589 crypto::{ExternalSignature, Signature},
590 format::block_signature_version,
591 token::{DATALOG_3_1, DATALOG_3_3},
592 KeyPair,
593 };
594
595 #[test]
596 fn proto() {
597 let out_dir = match std::env::var("OUT_DIR") {
599 Ok(dir) => dir,
600 Err(_) => return,
601 };
602 prost_build::compile_protos(&["src/format/schema.proto"], &["src/"]).unwrap();
603 let mut file = std::fs::File::open(&format!("{out_dir}/biscuit.format.schema.rs")).unwrap();
604 let mut contents = String::new();
605 file.read_to_string(&mut contents).unwrap();
606
607 let commited_schema = include_str!("schema.rs");
608
609 if &contents != commited_schema {
610 println!(
611 "{}",
612 colored_diff::PrettyDifference {
613 expected: &contents,
614 actual: commited_schema
615 }
616 );
617 panic!();
618 }
619 }
620
621 #[test]
622 fn test_block_signature_version() {
623 assert_eq!(
624 block_signature_version(
625 &KeyPair::new(),
626 &KeyPair::new(),
627 &None,
628 &Some(DATALOG_3_1),
629 std::iter::empty()
630 ),
631 0,
632 "ed25519 everywhere, authority block, no new datalog features"
633 );
634 assert_eq!(
635 block_signature_version(
636 &KeyPair::new_with_algorithm(Algorithm::Secp256r1),
637 &KeyPair::new_with_algorithm(Algorithm::Ed25519),
638 &None,
639 &Some(DATALOG_3_1),
640 std::iter::empty()
641 ),
642 1,
643 "s256r1 root key, authority block, no new datalog features"
644 );
645 assert_eq!(
646 block_signature_version(
647 &KeyPair::new_with_algorithm(Algorithm::Ed25519),
648 &KeyPair::new_with_algorithm(Algorithm::Secp256r1),
649 &None,
650 &Some(DATALOG_3_1),
651 std::iter::empty()
652 ),
653 1,
654 "s256r1 next key, authority block, no new datalog features"
655 );
656 assert_eq!(
657 block_signature_version(
658 &KeyPair::new_with_algorithm(Algorithm::Secp256r1),
659 &KeyPair::new_with_algorithm(Algorithm::Secp256r1),
660 &None,
661 &Some(DATALOG_3_1),
662 std::iter::empty()
663 ),
664 1,
665 "s256r1 root & next key, authority block, no new datalog features"
666 );
667 assert_eq!(
668 block_signature_version(
669 &KeyPair::new(),
670 &KeyPair::new(),
671 &Some(ExternalSignature {
672 public_key: KeyPair::new().public(),
673 signature: Signature::from_vec(Vec::new())
674 }),
675 &Some(DATALOG_3_1),
676 std::iter::once(0)
677 ),
678 1,
679 "ed25519 root & next key, third-party block, no new datalog features"
680 );
681 assert_eq!(
682 block_signature_version(
683 &KeyPair::new(),
684 &KeyPair::new(),
685 &None,
686 &Some(DATALOG_3_3),
687 std::iter::empty()
688 ),
689 1,
690 "ed25519 root & next key, first-party block, new datalog features"
691 );
692 assert_eq!(
693 block_signature_version(
694 &KeyPair::new(),
695 &KeyPair::new(),
696 &None,
697 &Some(DATALOG_3_1),
698 std::iter::once(1)
699 ),
700 1,
701 "ed25519 root & next key, first-party block, no new datalog features, previous v1 block"
702 );
703 }
704}