From 4c2b1ad57b7c9491627eae5872cff5144df09f81 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sun, 10 Nov 2024 15:03:22 +0100 Subject: [PATCH] add the payload version and separators to the signed payload --- biscuit-auth/samples/README.md | 117 +++++++----------- biscuit-auth/samples/samples.json | 8 +- biscuit-auth/samples/test024_third_party.bc | Bin 460 -> 460 bytes .../samples/test026_public_keys_interning.bc | Bin 1553 -> 1553 bytes biscuit-auth/src/crypto/mod.rs | 48 ++++--- biscuit-auth/src/token/mod.rs | 3 +- biscuit-auth/src/token/third_party.rs | 20 +-- 7 files changed, 96 insertions(+), 100 deletions(-) diff --git a/biscuit-auth/samples/README.md b/biscuit-auth/samples/README.md index 8cac52a0..53cc6ad1 100644 --- a/biscuit-auth/samples/README.md +++ b/biscuit-auth/samples/README.md @@ -1835,7 +1835,7 @@ allow if true; revocation ids: - `470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03` -- `f599b64287ccd9adbe007d5cdbd0cfa572f5f73495c95594b1bbbe938c011dc6683c52ba0354cdc4970405c6c318aef8271e6e802a7fb34eb07dd2c2d50d5707` +- `8556bc91ed8bd1e4c0b6b37bead75d91d332c4144d72e7db715e6300732dc691dbd1f444f1a7a07be8bac60358bf14330b5b8963685490cfb648df879efc9e0a` authorizer world: ``` @@ -2097,9 +2097,9 @@ allow if true; revocation ids: - `3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04` -- `fbd926ee447865f2fafdc431273cce2b32005802cb8d268c2ed54cb897fb5ad25f9765aaf79188b6703cdecccc654e6906724d978da4360a36ddf3bb638c8700` -- `6e36db11093148c577c737067b5918b02e8db3fc8990755e2d2ab44d6a48f6694a31ce8fdcb6d811cc81ba3b6db2dce53abae52900d1d3984ad7875438a7f401` -- `4522a4b94bce9265c6962f9784fb971d36b400adbae30f444b7ab91d91c91eff4830e4e6d8da97dddea4399217342b0b600ecccb928678729c8d388e0285c904` +- `87ce330211e0bca95aebcbbe349c954473f49e6593b6fee34f2be93122d4f930f0fc2dedfc1721b9d2e5346befb97aef75c28a13cc2647bb99e499ceb565470d` +- `f3dc02647a3c011e87dda6050fbd67c2e037454f186eb4ba0c029c0da7b0eb309c7d24ad5f073571b11876ef9bb7955ecb462c00457a258c4e1ba4eafbae420c` +- `88c9eea7c2e17409ce542a0e8fe78c53627fc2346ffde3d8d280eb86250c6c84efa5d84ea1f644a7bcfdfc68e2efc07350132c7fc80061014fa9d678c201b20a` - `3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900` authorizer world: @@ -2657,88 +2657,45 @@ result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedB ### token authority: -symbols: ["fact", "value", "fact2"] +symbols: ["abcD12", "abcD12x"] public keys: [] ``` -check if fact(1, $value), 1 == $value; -check if fact2(1, $value), 1 != $value; +check if true == true; +check if false != false; +check if 1 != true; +check if 1 == 1; +check if 1 != 3; +check if 1 != true; +check if "abcD12" == "abcD12"; +check if "abcD12x" != "abcD12"; +check if "abcD12x" != true; +check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z; +check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z; +check if 2022-12-04T09:46:41Z != true; +check if hex:12abcd == hex:12abcd; +check if hex:12abcd != hex:12ab; +check if hex:12abcd != true; +check if {1, 2} == {1, 2}; +check if {1, 4} != {1, 2}; +check if {1, 4} != true; ``` -### validation for "authorized same type" - -authorizer code: -``` -fact(1, 1); -fact2(1, 2); - -allow if true; -``` - -revocation ids: -- `d65b3aeceb6268124190f5eb87788a5eb81c89a3fc8370c9a3ea362731c55660b2b390ca6270e68afab90862bd2bbb808aa6b5576c975ae773a992a2434c930d` - -authorizer world: -``` -World { - facts: [ - Facts { - origin: { - None, - }, - facts: [ - "fact(1, 1)", - "fact2(1, 2)", - ], - }, -] - rules: [] - checks: [ - Checks { - origin: Some( - 0, - ), - checks: [ - "check if fact(1, $value), 1 == $value", - "check if fact2(1, $value), 1 != $value", - ], - }, -] - policies: [ - "allow if true", -] -} -``` - -result: `Ok(0)` -### validation for "unauthorized failed logic different type" +### validation authorizer code: ``` -fact(1, true); -fact2(1, false); - allow if true; ``` revocation ids: -- `d65b3aeceb6268124190f5eb87788a5eb81c89a3fc8370c9a3ea362731c55660b2b390ca6270e68afab90862bd2bbb808aa6b5576c975ae773a992a2434c930d` +- `4af245a2504ec00809bd0cd8d20ceaaac35f8ec5aaa8c7d3fd6652b126d2bf246d64fec8f0e65c409b196d4a60c9723dd4fbb3328988790e97fc4e08e9528208` authorizer world: ``` World { - facts: [ - Facts { - origin: { - None, - }, - facts: [ - "fact(1, true)", - "fact2(1, false)", - ], - }, -] + facts: [] rules: [] checks: [ Checks { @@ -2746,8 +2703,24 @@ World { 0, ), checks: [ - "check if fact(1, $value), 1 == $value", - "check if fact2(1, $value), 1 != $value", + "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12x\" != \"abcD12\"", + "check if \"abcD12x\" != true", + "check if 1 != 3", + "check if 1 != true", + "check if 1 != true", + "check if 1 == 1", + "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", + "check if 2022-12-04T09:46:41Z != true", + "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", + "check if false != false", + "check if hex:12abcd != hex:12ab", + "check if hex:12abcd != true", + "check if hex:12abcd == hex:12abcd", + "check if true == true", + "check if {1, 2} == {1, 2}", + "check if {1, 4} != true", + "check if {1, 4} != {1, 2}", ], }, ] @@ -2757,7 +2730,7 @@ World { } ``` -result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(1, $value), 1 == $value" })] }))` +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "check if false != false" })] }))` ------------------------------ diff --git a/biscuit-auth/samples/samples.json b/biscuit-auth/samples/samples.json index 7d2a19a0..d14fd521 100644 --- a/biscuit-auth/samples/samples.json +++ b/biscuit-auth/samples/samples.json @@ -1795,7 +1795,7 @@ "authorizer_code": "allow if true;\n", "revocation_ids": [ "470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03", - "f599b64287ccd9adbe007d5cdbd0cfa572f5f73495c95594b1bbbe938c011dc6683c52ba0354cdc4970405c6c318aef8271e6e802a7fb34eb07dd2c2d50d5707" + "8556bc91ed8bd1e4c0b6b37bead75d91d332c4144d72e7db715e6300732dc691dbd1f444f1a7a07be8bac60358bf14330b5b8963685490cfb648df879efc9e0a" ] } } @@ -2087,9 +2087,9 @@ "authorizer_code": "check if query(1, 2) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189, ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\n\ndeny if query(3);\ndeny if query(1, 2);\ndeny if query(0) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\nallow if true;\n", "revocation_ids": [ "3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04", - "fbd926ee447865f2fafdc431273cce2b32005802cb8d268c2ed54cb897fb5ad25f9765aaf79188b6703cdecccc654e6906724d978da4360a36ddf3bb638c8700", - "6e36db11093148c577c737067b5918b02e8db3fc8990755e2d2ab44d6a48f6694a31ce8fdcb6d811cc81ba3b6db2dce53abae52900d1d3984ad7875438a7f401", - "4522a4b94bce9265c6962f9784fb971d36b400adbae30f444b7ab91d91c91eff4830e4e6d8da97dddea4399217342b0b600ecccb928678729c8d388e0285c904", + "87ce330211e0bca95aebcbbe349c954473f49e6593b6fee34f2be93122d4f930f0fc2dedfc1721b9d2e5346befb97aef75c28a13cc2647bb99e499ceb565470d", + "f3dc02647a3c011e87dda6050fbd67c2e037454f186eb4ba0c029c0da7b0eb309c7d24ad5f073571b11876ef9bb7955ecb462c00457a258c4e1ba4eafbae420c", + "88c9eea7c2e17409ce542a0e8fe78c53627fc2346ffde3d8d280eb86250c6c84efa5d84ea1f644a7bcfdfc68e2efc07350132c7fc80061014fa9d678c201b20a", "3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900" ] } diff --git a/biscuit-auth/samples/test024_third_party.bc b/biscuit-auth/samples/test024_third_party.bc index dea7274cd0dd47eb868bbccaf7c92e92ea6574ac..b095f13d5e47fb3bf63a4890ec5be80c8095f7f7 100644 GIT binary patch delta 144 zcmV;B0B`@y1Iz=E{C|a3ypipT(d59kvwP~-U6Io=#1u_(=i6~!V*qn4#*y36^hEKe zpnK@L#sgTt6f+B3iDPI~kk7VA--n+3o(dvp3P6_dsqNzApJe!U>@(gMXFbh|q*nA8 ykGRfV*qwJ-sru{x&VzzdsgQn){4gq?W$SOVfB{VMhEI9` delta 144 zcmV;B0B`@y1Iz=E{D1YCwnB%@*{!|+eO%kn&!uwp_cWEsRg|&2zLSgr9mZ%pQn~|F z&BT`k1;)b|uJ|V&Zh$I(vre#m(!$jZR|g_!3P9(h?KrLoAoXUJ=8<)dBCB*9x|-EO y7x$i!X*4Qs>2zH1=~yzLg~`M2z!lIFm3{VWx-fz^tOcH+@s&w10oRvg#^qystw*KQ!E9o&J)cG**{4MSL z7a_UQie!j3?gU>Ko^h(gsld1Xm;zU@A(q!LL-VLlrrkwo|86bozd<-B1Dzd zHnU0QojQwuJ#$BDULkZ~f!g(tzuRB@AqY@1@vIq4q?ly#4%W;_tw7P!lYF$N*shPpQ^;!U3`h zB4`Rg9M?7OchwLuT)(=ryK^lqm)Ks*Jj!zY=K3_5I8Lc=XINv4HA>!10}Ql1QY>4EYOz# delta 436 zcmV;l0Zaao43P}5j{$%C*(UBpcxCeX{lqaRJkBdJ09XRcjV6pP)l9gT`&!apmu0H= zk%+c%Jl@RAWlm`Za!r?wq&5mR-SfL+jE4XsXbM311OLe#XR^Ke6J7ZNLSG=UClspl zaLcxiqCjaUjo(^EbSeF}%&Au5Z0*mFv%l>hDFXt5M0J8r<~0VT=dq*)5|Jt;lQ{yo ze{MG05eYF!#dpUy276f;ur7_W{E3itUM(uLO=?K?X-YB9kKDG{5zK+QJ8iPubECBGjmc*eBzbKbQBO2&F*{ e`tK?bX4rc>J=GEhk~7dF4HA>!10}Ql1QY=x#>R&L diff --git a/biscuit-auth/src/crypto/mod.rs b/biscuit-auth/src/crypto/mod.rs index 5a2519ea..bc3ac728 100644 --- a/biscuit-auth/src/crypto/mod.rs +++ b/biscuit-auth/src/crypto/mod.rs @@ -280,6 +280,7 @@ pub fn verify_block_signature( public_key, previous_signature, external_signature, + block.version, verification_mode, )?; } @@ -292,6 +293,7 @@ pub fn verify_external_signature( public_key: &PublicKey, previous_signature: Option<&Signature>, external_signature: &ExternalSignature, + version: u32, verification_mode: ThirdPartyVerificationMode, ) -> Result<(), error::Format> { let to_verify = match verification_mode { @@ -299,7 +301,23 @@ pub fn verify_external_signature( generate_external_signature_payload_v0(payload, public_key) } ThirdPartyVerificationMode::PreviousSignatureHashing => { - generate_external_signature_payload_v1(payload, public_key, previous_signature)? + let previous_signature = match previous_signature { + Some(s) => s, + None => { + return Err(error::Format::Signature( + error::Signature::InvalidSignature( + "the authority block must not contain an external signature" + .to_string(), + ), + )) + } + }; + generate_external_signature_payload_v1( + payload, + public_key, + previous_signature.to_bytes().as_slice(), + version, + )? } }; @@ -337,26 +355,26 @@ fn generate_external_signature_payload_v0(payload: &[u8], public_key: &PublicKey to_verify } -fn generate_external_signature_payload_v1( +pub(crate) fn generate_external_signature_payload_v1( payload: &[u8], public_key: &PublicKey, - previous_signature: Option<&Signature>, + previous_signature: &[u8], + version: u32, ) -> Result, error::Format> { - let mut to_verify = payload.to_vec(); + let mut to_verify = b"\0VERSION\0".to_vec(); + to_verify.extend(version.to_le_bytes()); + + to_verify.extend(b"\0PAYLOAD\0".to_vec()); + to_verify.extend(payload.to_vec()); + + to_verify.extend(b"\0ALGORITHM\0".to_vec()); to_verify.extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes()); + + to_verify.extend(b"\0PUBKEY\0".to_vec()); to_verify.extend(&public_key.to_bytes()); - let previous_signature = match previous_signature { - Some(s) => s, - None => { - return Err(error::Format::Signature( - error::Signature::InvalidSignature( - "the authority block must not contain an external signature".to_string(), - ), - )) - } - }; - to_verify.extend(&previous_signature.to_bytes()); + to_verify.extend(b"\0PREVSIG\0".to_vec()); + to_verify.extend(previous_signature); Ok(to_verify) } diff --git a/biscuit-auth/src/token/mod.rs b/biscuit-auth/src/token/mod.rs index 763fd5ab..a1025de1 100644 --- a/biscuit-auth/src/token/mod.rs +++ b/biscuit-auth/src/token/mod.rs @@ -15,7 +15,7 @@ use rand_core::{CryptoRng, RngCore}; use crate::crypto::{self}; use crate::format::convert::proto_block_to_token_block; use crate::format::schema::{self, ThirdPartyBlockContents}; -use crate::format::ThirdPartyVerificationMode; +use crate::format::{ThirdPartyVerificationMode, THIRD_PARTY_SIGNATURE_VERSION}; use authorizer::Authorizer; pub mod authorizer; @@ -444,6 +444,7 @@ impl Biscuit { .signature, ), &external_signature, + THIRD_PARTY_SIGNATURE_VERSION, ThirdPartyVerificationMode::PreviousSignatureHashing, )?; diff --git a/biscuit-auth/src/token/third_party.rs b/biscuit-auth/src/token/third_party.rs index fbe0951a..38b32f9c 100644 --- a/biscuit-auth/src/token/third_party.rs +++ b/biscuit-auth/src/token/third_party.rs @@ -5,13 +5,15 @@ use prost::Message; use crate::{ builder::BlockBuilder, - crypto::PublicKey, + crypto::{generate_external_signature_payload_v1, PublicKey}, datalog::SymbolTable, error, format::{convert::token_block_to_proto_block, schema, SerializedBiscuit}, KeyPair, PrivateKey, }; +use super::THIRD_PARTY_SIGNATURE_VERSION; + /// Third party block request #[derive(Debug)] pub struct ThirdPartyRequest { @@ -108,22 +110,24 @@ impl ThirdPartyRequest { let mut block = block_builder.build(symbols); block.version = max(super::DATALOG_3_2, block.version); - let mut v = Vec::new(); + let mut payload = Vec::new(); token_block_to_proto_block(&block) - .encode(&mut v) + .encode(&mut payload) .map_err(|e| { error::Format::SerializationError(format!("serialization error: {:?}", e)) })?; - let payload = v.clone(); - v.extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes()); - v.extend(self.previous_key.to_bytes()); - v.extend(&self.previous_signature); + let signed_payload = generate_external_signature_payload_v1( + &payload, + &self.previous_key, + &self.previous_signature, + THIRD_PARTY_SIGNATURE_VERSION, + )?; let keypair = KeyPair::from(private_key); let signature = keypair .kp - .try_sign(&v) + .try_sign(&signed_payload) .map_err(|s| s.to_string()) .map_err(error::Signature::InvalidSignatureGeneration) .map_err(error::Format::Signature)?;