diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 1fb2e53..35249c7 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -177,7 +177,7 @@ The logic language is described by the following EBNF grammar: ``` ::= ? "trusting " ? ("," ? ?)* ::= "authority" | "previous" | "/" - ::= "ed25519" + ::= "ed25519" | "secp256r1" ::= ( ";" ?)? ( | )* ::= ? ( | | ) ? ";" ? @@ -712,6 +712,7 @@ message PublicKey { enum Algorithm { Ed25519 = 0; + SECP256R1 = 1; } required bytes key = 2; @@ -782,13 +783,55 @@ 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 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` +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: [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 + +``` +ECDSA-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER +} +``` + #### Signed payload generation The data covered by the signature algorithm depends on the `version` field of @@ -865,7 +908,7 @@ the signed payload format for external signatures, thereafter referred as "exter #### 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) @@ -929,7 +972,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`, the signature of the payload in format "external signature payload v1" by `external_sk`. The authority block can't carry an external signature. This is necessary to make sure an external signature can't be used for any other token. diff --git a/samples/current/README.md b/samples/current/README.md index ec6e18f..78838b6 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -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]")))` ------------------------------ @@ -3187,3 +3187,88 @@ World { result: `Ok(0)` + +------------------------------ + +## ECDSA secp256r1 signatures: test036_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 1401846..fbb9462 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]" } } }, @@ -2955,6 +2955,76 @@ ] } } + }, + { + "title": "ECDSA secp256r1 signatures", + "filename": "test036_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/test036_secp256r1.bc b/samples/current/test036_secp256r1.bc new file mode 100644 index 0000000..15a8a42 Binary files /dev/null and b/samples/current/test036_secp256r1.bc differ diff --git a/schema.proto b/schema.proto index 0a45085..2f6800d 100644 --- a/schema.proto +++ b/schema.proto @@ -27,6 +27,7 @@ message PublicKey { enum Algorithm { Ed25519 = 0; + SECP256R1 = 1; } required bytes key = 2;