From 336a73cb6e77400a3c84dc1cb933e726d4003f26 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Mon, 20 May 2024 21:14:11 +0200 Subject: [PATCH 1/6] introduce ECDSA signatures with secp256r1 --- SPECIFICATIONS.md | 51 +++++++++++++++++++++++++++++++++++++++++++---- schema.proto | 1 + 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index bfe4ad1..5650a66 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -165,7 +165,7 @@ The logic language is described by the following EBNF grammar: ``` ::= ? "trusting " ? ("," ? ?)* ::= "authority" | "previous" | "/" - ::= "ed25519" + ::= "ed25519" | "secp256r1" ::= ( ";" ?)? ( | )* ::= ? ( | | ) ? ";" ? @@ -614,6 +614,7 @@ message PublicKey { enum Algorithm { Ed25519 = 0; + SECP256R1 = 1; } required bytes key = 2; @@ -683,16 +684,58 @@ is a Biscuit token, that base 64 string should be prefixed with `biscuit:`. ### Cryptography -Biscuit tokens are based on public key cryptography, with a chain of Ed25519 +Biscuit tokens are based on public key cryptography, with a chain of signatures. Each block contains the serialized Datalog, the next public key, and the signature by the previous key. The token also contains the private key corresponding to the last public key, to sign a new block and attenuate the token, or a signature of the last block by the last private key, to seal the token. +#### Algorithms + +Biscuit supports multiple signature algorithms for it blocks, that can change +between blocks in one token. The algorithm kind is defined in the `Algorithm` +enum of the protobuf serialization of the public key. The `nextSecret` field +in the proof section of the token uses the same algorithm as the `nextKey` +of the last block. + +The following algorithms are supported: + +##### Ed25519 + +The default signature algorithm is Ed25519 as introduced in [Bernstein, Daniel J.; +Duif, Niels; Lange, Tanja; Schwabe, Peter; Bo-Yin Yang (2012). "High-speed +high-security signatures" (PDF). Journal of Cryptographic Engineering](https://ed25519.cr.yp.to/ed25519-20110926.pdf) +and specified in [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032). + +The protobuf encoding is defined as follows: +- `key` field of the `Publickey` message: [compressed Edwards Y format](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.2) +- `nextSecret` in the `Proof` message: [32 bytes of cryptographically secure random data in little-endian](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5) +- `signature` field in `Signature` and `ExternalSignature` messages: [concatenation of R and S values](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6) + +##### ECDSA + +Biscuit supports the ECDSA algorithm over the secp256r1 curve as defined in +[SEC2v1](https://www.secg.org/sec1-v2.pdf), using the SHA-256 hashing +algorithm. It is recommended to use a deterministic signature algorithm +version like the one defined in [RFC 6979](https://datatracker.ietf.org/doc/html/rfc6979). + + +The protobuf encoding is defined as follows: +- `key` field of the `Publickey` message: [SEC1 format, defined in section 2.3.3](https://www.secg.org/sec1-v2.pdf). Allowed prefixes: `02`, `03`, `04` +- `nextSecret` in the `Proof` message: big endian representation of the secret scalar +- `signature` field in `Signature` and `ExternalSignature` messages: [SEC1 ASN.1 format, defined in section C5](https://www.secg.org/sec1-v2.pdf), only using the `r` and `s` parameters + +``` +ECDSA-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER +} +``` + #### Signature (one block) -- `(pk_0, sk_0)` the root public and private Ed25519 keys +- `(pk_0, sk_0)` the root public and private keys - `data_0` the serialized Datalog - `(pk_1, sk_1)` the next key pair, generated at random - `alg_1` the little endian representation of the signature algorithm fr `pk1, sk1` (see protobuf schema) @@ -753,7 +796,7 @@ Token { ##### Optional external signature Blocks generated by a trusted third party can carry an *extra* signature to provide a proof of their -origin. Same as regular signatures, they rely on Ed25519. +origin. Same as regular signatures, they rely on public key cryptography. The external signature for block `n+1`, with `(external_pk, external_sk)` is `external_sig_n+1 = sign(external_sk, data_n+1 + alg_n+1 + pk_n+1)`. It's quite similar to the regular signature, with a crucial difference: the public key appended to the block payload is the one _carried_ by block `n` (and which is used to verify block `n+1`). diff --git a/schema.proto b/schema.proto index bc6cb29..641b4cf 100644 --- a/schema.proto +++ b/schema.proto @@ -26,6 +26,7 @@ message PublicKey { enum Algorithm { Ed25519 = 0; + SECP256R1 = 1; } required bytes key = 2; From bd9901d70a72b3f6c1163114f1eea996ccc289b0 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 22 May 2024 11:17:57 +0200 Subject: [PATCH 2/6] Update SPECIFICATIONS.md --- SPECIFICATIONS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 5650a66..497fd60 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -722,7 +722,7 @@ version like the one defined in [RFC 6979](https://datatracker.ietf.org/doc/html The protobuf encoding is defined as follows: -- `key` field of the `Publickey` message: [SEC1 format, defined in section 2.3.3](https://www.secg.org/sec1-v2.pdf). Allowed prefixes: `02`, `03`, `04` +- `key` field of the `Publickey` message: [compressed SEC1 format, defined in section 2.3.3](https://www.secg.org/sec1-v2.pdf). Allowed prefixes: `02`, `03` - `nextSecret` in the `Proof` message: big endian representation of the secret scalar - `signature` field in `Signature` and `ExternalSignature` messages: [SEC1 ASN.1 format, defined in section C5](https://www.secg.org/sec1-v2.pdf), only using the `r` and `s` parameters From bd31567677e91dedc3775bea6883d14a4c98bcd1 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Thu, 23 May 2024 11:13:42 +0200 Subject: [PATCH 3/6] add samples --- samples/current/README.md | 317 ++++++++++++++++++--------- samples/current/samples.json | 106 ++++++++- samples/current/test031_secp256r1.bc | Bin 0 -> 366 bytes 3 files changed, 305 insertions(+), 118 deletions(-) create mode 100644 samples/current/test031_secp256r1.bc diff --git a/samples/current/README.md b/samples/current/README.md index bec8ced..1151c22 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -45,7 +45,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -53,7 +53,7 @@ World { "resource(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -68,7 +68,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -141,7 +141,7 @@ check if resource($0), operation("read"), right($0, "read"); ### validation -result: `Err(Format(InvalidSignatureSize(16)))` +result: `Err(Format(BlockSignatureDeserializationError("block signature deserialization error: [117, 149, 161, 18, 161, 235, 91, 129, 166, 227, 152, 133, 46, 97, 24, 183]")))` ------------------------------ @@ -296,7 +296,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -305,7 +305,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -316,7 +316,7 @@ World { "user_id(\"alice\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -328,7 +328,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -338,7 +338,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -407,7 +407,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -416,7 +416,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -426,7 +426,7 @@ World { "right(\"file1\", \"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -439,7 +439,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -499,7 +499,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -512,7 +512,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -574,7 +574,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -583,7 +583,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -593,7 +593,7 @@ World { "right(\"file1\", \"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -606,7 +606,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -657,7 +657,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -666,7 +666,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -679,7 +679,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -728,7 +728,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -740,7 +740,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -773,7 +773,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -785,7 +785,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -847,7 +847,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -856,7 +856,7 @@ World { "time(2020-12-21T09:23:12Z)", ], }, - AuthorizerFactSet { + Facts { origin: { None, Some( @@ -867,7 +867,7 @@ World { "valid_date(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -880,7 +880,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -891,7 +891,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -925,7 +925,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -934,7 +934,7 @@ World { "time(2020-12-21T09:23:12Z)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -947,7 +947,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -958,7 +958,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1006,7 +1006,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1017,7 +1017,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1049,7 +1049,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1060,7 +1060,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1108,7 +1108,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1121,7 +1121,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1177,7 +1177,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1190,7 +1190,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1278,7 +1278,7 @@ World { facts: [] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1404,7 +1404,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1412,7 +1412,7 @@ World { "operation(\"write\")", ], }, - AuthorizerFactSet { + Facts { origin: { None, Some( @@ -1425,7 +1425,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -1435,7 +1435,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1496,7 +1496,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1505,7 +1505,7 @@ World { "resource(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1520,7 +1520,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1568,7 +1568,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1581,7 +1581,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1656,7 +1656,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1696,7 +1696,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1763,7 +1763,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1773,7 +1773,7 @@ World { "authority_fact(1)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1786,7 +1786,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 2, ), @@ -1847,7 +1847,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1857,7 +1857,7 @@ World { "right(\"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1870,7 +1870,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1878,7 +1878,7 @@ World { "check if group(\"admin\") trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1928,7 +1928,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1937,7 +1937,7 @@ World { "operation(\"B\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1950,7 +1950,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1983,7 +1983,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1992,7 +1992,7 @@ World { "operation(\"invalid\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -2005,7 +2005,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2112,7 +2112,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -2122,7 +2122,7 @@ World { "query(0)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -2132,7 +2132,7 @@ World { "query(1)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -2145,7 +2145,7 @@ World { "query(1, 2)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -2155,7 +2155,7 @@ World { "query(2)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 3, @@ -2165,7 +2165,7 @@ World { "query(3)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 4, @@ -2177,7 +2177,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -2187,7 +2187,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2195,7 +2195,7 @@ World { "check if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -2204,7 +2204,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 2, ), @@ -2213,7 +2213,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 3, ), @@ -2222,7 +2222,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 4, ), @@ -2231,7 +2231,7 @@ World { "check if query(4) trusting ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -2284,7 +2284,7 @@ World { facts: [] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2339,7 +2339,7 @@ World { facts: [] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2391,21 +2391,30 @@ revocation ids: authorizer world: ``` World { - facts: { - ( - "test(false)", - { + facts: [ + Facts { + origin: { None, }, - ), -} - rules: {} - checks: { - "reject if test($test), $test", -} - policies: { + facts: [ + "test(false)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "reject if test($test), $test", + ], + }, +] + policies: [ "allow if true", -} +] } ``` @@ -2425,23 +2434,117 @@ revocation ids: authorizer world: ``` World { - facts: { - ( - "test(true)", - { + facts: [ + Facts { + origin: { None, }, - ), -} - rules: {} - checks: { - "reject if test($test), $test", -} - policies: { + facts: [ + "test(true)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "reject if test($test), $test", + ], + }, +] + policies: [ "allow if true", -} +] } ``` result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "reject if test($test), $test" })] }))` + +------------------------------ + +## ECDSA secp256r1 signatures: test031_secp256r1.bc +### token + +authority: +symbols: ["file1", "file2"] + +public keys: [] + +``` +right("file1", "read"); +right("file2", "read"); +right("file1", "write"); +``` + +1: +symbols: ["0"] + +public keys: [] + +``` +check if resource($0), operation("read"), right($0, "read"); +``` + +### validation + +authorizer code: +``` +resource("file1"); +operation("read"); + +allow if true; +``` + +revocation ids: +- `760785de30d7348e9c847aab8b3bdad6a0d463f4f50ed9667aade563e9112ee6d2f589630dd7553c2eced2a57edf3636d5c874b35df15120c62fddcbdbd2de09` +- `30440220039667c7a4d964e4b449289dc8fd206d7aa0e77eb701a9253b3307d32c177fa8022023f7523c143c5fb55ee4cafe49804702ef05a70883ebf42185b54bd36a7e7cd4` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "operation(\"read\")", + "resource(\"file1\")", + ], + }, + Facts { + origin: { + Some( + 0, + ), + }, + facts: [ + "right(\"file1\", \"read\")", + "right(\"file1\", \"write\")", + "right(\"file2\", \"read\")", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 1, + ), + checks: [ + "check if resource($0), operation(\"read\"), right($0, \"read\")", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` + diff --git a/samples/current/samples.json b/samples/current/samples.json index 28730f3..c5a218c 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -154,7 +154,7 @@ "result": { "Err": { "Format": { - "InvalidSignatureSize": 16 + "BlockSignatureDeserializationError": "block signature deserialization error: [117, 149, 161, 18, 161, 235, 91, 129, 166, 227, 152, 133, 46, 97, 24, 183]" } } }, @@ -2195,16 +2195,23 @@ "": { "world": { "facts": [ - [ - "test(false)", - [ + { + "origin": [ null + ], + "facts": [ + "test(false)" ] - ] + } ], "rules": [], "checks": [ - "reject if test($test), $test" + { + "origin": 0, + "checks": [ + "reject if test($test), $test" + ] + } ], "policies": [ "allow if true" @@ -2221,16 +2228,23 @@ "rejection": { "world": { "facts": [ - [ - "test(true)", - [ + { + "origin": [ null + ], + "facts": [ + "test(true)" ] - ] + } ], "rules": [], "checks": [ - "reject if test($test), $test" + { + "origin": 0, + "checks": [ + "reject if test($test), $test" + ] + } ], "policies": [ "allow if true" @@ -2262,6 +2276,76 @@ ] } } + }, + { + "title": "ECDSA secp256r1 signatures", + "filename": "test031_secp256r1.bc", + "token": [ + { + "symbols": [ + "file1", + "file2" + ], + "public_keys": [], + "external_key": null, + "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n" + }, + { + "symbols": [ + "0" + ], + "public_keys": [], + "external_key": null, + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "operation(\"read\")", + "resource(\"file1\")" + ] + }, + { + "origin": [ + 0 + ], + "facts": [ + "right(\"file1\", \"read\")", + "right(\"file1\", \"write\")", + "right(\"file2\", \"read\")" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 1, + "checks": [ + "check if resource($0), operation(\"read\"), right($0, \"read\")" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "resource(\"file1\");\noperation(\"read\");\n\nallow if true;\n", + "revocation_ids": [ + "760785de30d7348e9c847aab8b3bdad6a0d463f4f50ed9667aade563e9112ee6d2f589630dd7553c2eced2a57edf3636d5c874b35df15120c62fddcbdbd2de09", + "30440220039667c7a4d964e4b449289dc8fd206d7aa0e77eb701a9253b3307d32c177fa8022023f7523c143c5fb55ee4cafe49804702ef05a70883ebf42185b54bd36a7e7cd4" + ] + } + } } ] } diff --git a/samples/current/test031_secp256r1.bc b/samples/current/test031_secp256r1.bc new file mode 100644 index 0000000000000000000000000000000000000000..15a8a429e52823e318d362c4264507f2a92fc49d GIT binary patch literal 366 zcmWey!N_IH#hR9xlWGW|j3k(qc)7SaScI4*8aRZQBpBe_MpQ0XmQhHRgHcG4DQ;r_ z6*mi`b&Hy8|4tWMob5YXxO{K$-KM)=4(us?o4sGkp^Uxtp22mKzBw&btGlglU0ZM^ z`O8RpC-Q))O&X6YiBa=^-vqVbC;IZ-8VD4dZJ`=?8iWbWBPYb-@bH@Q)&() zmo^upfdsRW3YQWW6Nj`AI|q{xGe;AL5E}Joi6Mq$Qs}?-3+s?RB z)!LZ-vW|HD3MK{R??E;qHt}2Io}BvU+2GFfo^?4#^Xo5)ty{e>XVukQQBvYkIOTY2 jL+gaMOPmb1{rR$6kf&8!<%7ZgnOU75bj}>D+xigzPX&iC literal 0 HcmV?d00001 From c55e73568f0c727a138269c36de5f35bf5ca07b9 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Thu, 23 May 2024 14:34:16 +0200 Subject: [PATCH 4/6] update samples --- samples/current/README.md | 193 +++++++++++++++++++++++++++ samples/current/samples.json | 225 ++++++++++++++++++++++++++++++++ samples/current/test030_null.bc | Bin 0 -> 248 bytes 3 files changed, 418 insertions(+) create mode 100644 samples/current/test030_null.bc diff --git a/samples/current/README.md b/samples/current/README.md index 1151c22..66077eb 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -2464,6 +2464,199 @@ World { result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "reject if test($test), $test" })] }))` +------------------------------ + +## test null: test030_null.bc +### token + +authority: +symbols: ["fact", "value"] + +public keys: [] + +``` +check if fact(null, $value), $value == null; +reject if fact(null, $value), $value != null; +``` + +### validation + +authorizer code: +``` +fact(null, null); + +allow if true; +``` + +revocation ids: +- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, null)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` +### validation for "rejection1" + +authorizer code: +``` +fact(null, 1); + +allow if true; +``` + +revocation ids: +- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, 1)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(null, $value), $value == null" }), Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "reject if fact(null, $value), $value != null" })] }))` +### validation for "rejection2" + +authorizer code: +``` +fact(null, true); + +allow if true; +``` + +revocation ids: +- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, true)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(null, $value), $value == null" }), Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "reject if fact(null, $value), $value != null" })] }))` +### validation for "rejection3" + +authorizer code: +``` +fact(null, "abcd"); + +allow if true; +``` + +revocation ids: +- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, \"abcd\")", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(null, $value), $value == null" }), Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "reject if fact(null, $value), $value != null" })] }))` + + ------------------------------ ## ECDSA secp256r1 signatures: test031_secp256r1.bc diff --git a/samples/current/samples.json b/samples/current/samples.json index c5a218c..e14abd8 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -2277,6 +2277,231 @@ } } }, + { + "title": "test null", + "filename": "test030_null.bc", + "token": [ + { + "symbols": [ + "fact", + "value" + ], + "public_keys": [], + "external_key": null, + "code": "check if fact(null, $value), $value == null;\nreject if fact(null, $value), $value != null;\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, null)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "fact(null, null);\n\nallow if true;\n", + "revocation_ids": [ + "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + ] + }, + "rejection1": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, 1)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "check if fact(null, $value), $value == null" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 1, + "rule": "reject if fact(null, $value), $value != null" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(null, 1);\n\nallow if true;\n", + "revocation_ids": [ + "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + ] + }, + "rejection2": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, true)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "check if fact(null, $value), $value == null" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 1, + "rule": "reject if fact(null, $value), $value != null" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(null, true);\n\nallow if true;\n", + "revocation_ids": [ + "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + ] + }, + "rejection3": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, \"abcd\")" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "check if fact(null, $value), $value == null" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 1, + "rule": "reject if fact(null, $value), $value != null" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(null, \"abcd\");\n\nallow if true;\n", + "revocation_ids": [ + "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + ] + } + } + }, { "title": "ECDSA secp256r1 signatures", "filename": "test031_secp256r1.bc", diff --git a/samples/current/test030_null.bc b/samples/current/test030_null.bc new file mode 100644 index 0000000000000000000000000000000000000000..2337a1114ef4e0530bb0283a7e36ff07aa920989 GIT binary patch literal 248 zcmWf-$jFt>#gdkoT*Ad#mY7qTD#2=`$)(Q4#33!j!_mMY#N@;v#LUsiAtlVk$^~L@ zv2X#!xLBl^I9QCdiB&2hz$B!?!62j{5PCddPP$2UNR<`+DIN%IdD0A-g5zynHfbpoUMiR^0))% znoDzSVrjhE<0dI#*E#)giF@0N2h2)JTnaN^RP#-Y2$p-dmHEG@TAsG@p+y1J!aZ}P M<+Zj%+}BM60M+S53jhEB literal 0 HcmV?d00001 From 4f4d68c7a723cca768dece1ddac00b08aba10361 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Thu, 23 May 2024 14:41:33 +0200 Subject: [PATCH 5/6] Update SPECIFICATIONS.md --- SPECIFICATIONS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index ac4400a..b565bb4 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -698,7 +698,7 @@ token. #### Algorithms -Biscuit supports multiple signature algorithms for it blocks, that can change +Biscuit supports multiple signature algorithms for its blocks, that can change between blocks in one token. The algorithm kind is defined in the `Algorithm` enum of the protobuf serialization of the public key. The `nextSecret` field in the proof section of the token uses the same algorithm as the `nextKey` From 3f5055fc3dc771500ce8bd573c6d2c52e293d551 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Thu, 23 May 2024 14:41:58 +0200 Subject: [PATCH 6/6] remove unused sample --- samples/current/test30_null.bc | Bin 248 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 samples/current/test30_null.bc diff --git a/samples/current/test30_null.bc b/samples/current/test30_null.bc deleted file mode 100644 index 2337a1114ef4e0530bb0283a7e36ff07aa920989..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 248 zcmWf-$jFt>#gdkoT*Ad#mY7qTD#2=`$)(Q4#33!j!_mMY#N@;v#LUsiAtlVk$^~L@ zv2X#!xLBl^I9QCdiB&2hz$B!?!62j{5PCddPP$2UNR<`+DIN%IdD0A-g5zynHfbpoUMiR^0))% znoDzSVrjhE<0dI#*E#)giF@0N2h2)JTnaN^RP#-Y2$p-dmHEG@TAsG@p+y1J!aZ}P M<+Zj%+}BM60M+S53jhEB