From 870de8e7594dbe6824dd0c344dad0e43a6b7dee9 Mon Sep 17 00:00:00 2001 From: Adam Preuss Date: Fri, 25 Apr 2025 10:08:18 -0600 Subject: [PATCH 1/3] Remove cached revocation identifiers from `UnverifiedBiscuit`. This simplifies the code and doesn't do unnecessary recomputation of the revoked ids collection every time a new block is added. Likely, a relying party would only access the collection of revoked ids once to check revocation anyway. This is in line with the rust implemention that also assembles the collection of revoked identifiers on the fly. --- .../org/eclipse/biscuit/token/Biscuit.java | 15 +++++--------- .../biscuit/token/UnverifiedBiscuit.java | 20 +++++-------------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/eclipse/biscuit/token/Biscuit.java b/src/main/java/org/eclipse/biscuit/token/Biscuit.java index ea4281ab..854ab5ea 100644 --- a/src/main/java/org/eclipse/biscuit/token/Biscuit.java +++ b/src/main/java/org/eclipse/biscuit/token/Biscuit.java @@ -128,10 +128,9 @@ private static Biscuit make( throw container.getLeft(); } else { SerializedBiscuit s = container.get(); - List revocationIds = s.revocationIdentifiers(); Option c = Option.some(s); - return new Biscuit(authority, blocks, authority.getSymbolTable(), s, revocationIds); + return new Biscuit(authority, blocks, authority.getSymbolTable(), s); } } @@ -139,9 +138,8 @@ private static Biscuit make( Block authority, List blocks, SymbolTable symbolTable, - SerializedBiscuit serializedBiscuit, - List revocationIds) { - super(authority, blocks, symbolTable, serializedBiscuit, revocationIds); + SerializedBiscuit serializedBiscuit) { + super(authority, blocks, symbolTable, serializedBiscuit); } /** @@ -268,9 +266,7 @@ static Biscuit fromSerializedBiscuit(SerializedBiscuit ser, SymbolTable symbolTa Block authority = t._1; ArrayList blocks = t._2; - List revocationIds = ser.revocationIdentifiers(); - - return new Biscuit(authority, blocks, symbolTable, ser, revocationIds); + return new Biscuit(authority, blocks, symbolTable, ser); } /** @@ -365,9 +361,8 @@ public Biscuit attenuate(final SecureRandom rng, final KeyPair keypair, Block bl blocks.add(block); SerializedBiscuit container = containerRes.get(); - List revocationIds = container.revocationIdentifiers(); - return new Biscuit(copiedBiscuit.authority, blocks, symbolTable, container, revocationIds); + return new Biscuit(copiedBiscuit.authority, blocks, symbolTable, container); } /** Generates a third party block request from a token */ diff --git a/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java b/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java index 63ab602d..f78b2fc4 100644 --- a/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java +++ b/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java @@ -36,19 +36,16 @@ public class UnverifiedBiscuit { protected final List blocks; protected final SymbolTable symbolTable; protected final SerializedBiscuit serializedBiscuit; - protected final List revocationIds; UnverifiedBiscuit( Block authority, List blocks, SymbolTable symbolTable, - SerializedBiscuit serializedBiscuit, - List revocationIds) { + SerializedBiscuit serializedBiscuit) { this.authority = authority; this.blocks = blocks; this.symbolTable = symbolTable; this.serializedBiscuit = serializedBiscuit; - this.revocationIds = revocationIds; } /** @@ -98,9 +95,7 @@ private static UnverifiedBiscuit fromSerializedBiscuit( Block authority = t._1; ArrayList blocks = t._2; - List revocationIds = ser.revocationIdentifiers(); - - return new UnverifiedBiscuit(authority, blocks, symbolTable, ser, revocationIds); + return new UnverifiedBiscuit(authority, blocks, symbolTable, ser); } /** @@ -189,16 +184,13 @@ private UnverifiedBiscuit attenuate(final SecureRandom rng, final KeyPair keypai blocks.add(block); SerializedBiscuit container = containerRes.get(); - List revocationIds = container.revocationIdentifiers(); - - return new UnverifiedBiscuit( - copiedBiscuit.authority, blocks, symbols, container, revocationIds); + return new UnverifiedBiscuit(copiedBiscuit.authority, blocks, symbols, container); } // FIXME: attenuate 3rd Party public List revocationIdentifiers() { - return this.revocationIds.stream() + return this.serializedBiscuit.revocationIdentifiers().stream() .map(RevocationIdentifier::fromBytes) .collect(Collectors.toList()); } @@ -304,9 +296,7 @@ public UnverifiedBiscuit appendThirdPartyBlock( } blocks.add(block); - List revocationIds = container.revocationIdentifiers(); - return new UnverifiedBiscuit( - copiedBiscuit.authority, blocks, symbols, container, revocationIds); + return new UnverifiedBiscuit(copiedBiscuit.authority, blocks, symbols, container); } /** Prints a token's content */ From 0b8699cf0d56261a2b531fb3ee6bdbd40c3e4ef6 Mon Sep 17 00:00:00 2001 From: Adam Preuss Date: Fri, 25 Apr 2025 10:34:51 -0600 Subject: [PATCH 2/3] Augment `UnverifiedBiscuit` with external key accessors. These methods are akin to those of the rust implementation. --- .../biscuit/token/UnverifiedBiscuit.java | 35 ++++++++++++++++--- .../eclipse/biscuit/token/BiscuitTest.java | 3 ++ .../eclipse/biscuit/token/ThirdPartyTest.java | 6 ++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java b/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java index f78b2fc4..e1ada075 100644 --- a/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java +++ b/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java @@ -17,6 +17,7 @@ import java.util.Base64; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.biscuit.crypto.BlockSignatureBuffer; import org.eclipse.biscuit.crypto.KeyDelegate; import org.eclipse.biscuit.crypto.KeyPair; @@ -134,7 +135,7 @@ public org.eclipse.biscuit.token.builder.Block createBlock() { * @return */ public UnverifiedBiscuit attenuate( - org.eclipse.biscuit.token.builder.Block block, Algorithm algorithm) throws Error { + org.eclipse.biscuit.token.builder.Block block, Algorithm algorithm) throws Error { SecureRandom rng = new SecureRandom(); KeyPair keypair = KeyPair.generate(algorithm, rng); SymbolTable builderSymbols = new SymbolTable(this.symbolTable); @@ -142,9 +143,7 @@ public UnverifiedBiscuit attenuate( } public UnverifiedBiscuit attenuate( - final SecureRandom rng, - final KeyPair keypair, - org.eclipse.biscuit.token.builder.Block block) + final SecureRandom rng, final KeyPair keypair, org.eclipse.biscuit.token.builder.Block block) throws Error { SymbolTable builderSymbols = new SymbolTable(this.symbolTable); return attenuate(rng, keypair, block.build(builderSymbols)); @@ -195,6 +194,14 @@ public List revocationIdentifiers() { .collect(Collectors.toList()); } + public List> externalPublicKeys() { + return Stream.>concat( + Stream.of(Option.none()), + this.serializedBiscuit.getBlocks().stream() + .map(b -> b.getExternalSignature().map(ExternalSignature::getKey))) + .collect(Collectors.toList()); + } + public List> getChecks() { ArrayList> l = new ArrayList<>(); l.add(new ArrayList<>(this.authority.getChecks())); @@ -229,6 +236,26 @@ public Option getRootKeyId() { return this.serializedBiscuit.getRootKeyId(); } + public int blockCount() { + return 1 + blocks.size(); + } + + public Option blockExternalKey(int index) { + if (index == 0) { + return authority.getExternalKey(); + } else { + return blocks.get(index - 1).getExternalKey(); + } + } + + public List blockPublicKeys(int index) { + if (index == 0) { + return authority.getPublicKeys(); + } else { + return blocks.get(index - 1).getPublicKeys(); + } + } + /** Generates a third party block request from a token */ public ThirdPartyBlockRequest thirdPartyRequest() { PublicKey previousKey; diff --git a/src/test/java/org/eclipse/biscuit/token/BiscuitTest.java b/src/test/java/org/eclipse/biscuit/token/BiscuitTest.java index a59c28d4..95138e6b 100644 --- a/src/test/java/org/eclipse/biscuit/token/BiscuitTest.java +++ b/src/test/java/org/eclipse/biscuit/token/BiscuitTest.java @@ -72,6 +72,7 @@ public void testBasic() System.out.println("deserializing the first token"); Biscuit deser = Biscuit.fromBytes(data, root.getPublicKey()); + assertEquals(1, deser.blockCount()); System.out.println(deser.print()); @@ -105,6 +106,7 @@ public void testBasic() System.out.println("deserializing the second token"); Biscuit deser2 = Biscuit.fromBytes(data2, root.getPublicKey()); + assertEquals(2, deser2.blockCount()); System.out.println(deser2.print()); @@ -135,6 +137,7 @@ public void testBasic() System.out.println("deserializing the third token"); Biscuit finalToken = Biscuit.fromBytes(data3, root.getPublicKey()); + assertEquals(3, finalToken.blockCount()); System.out.println(finalToken.print()); diff --git a/src/test/java/org/eclipse/biscuit/token/ThirdPartyTest.java b/src/test/java/org/eclipse/biscuit/token/ThirdPartyTest.java index b68610b7..a09b04bb 100644 --- a/src/test/java/org/eclipse/biscuit/token/ThirdPartyTest.java +++ b/src/test/java/org/eclipse/biscuit/token/ThirdPartyTest.java @@ -8,6 +8,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import biscuit.format.schema.Schema; +import io.vavr.control.Option; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -15,6 +16,7 @@ import java.security.SignatureException; import java.time.Duration; import java.util.Arrays; +import java.util.List; import org.eclipse.biscuit.crypto.KeyPair; import org.eclipse.biscuit.datalog.RunLimits; import org.eclipse.biscuit.error.Error; @@ -66,6 +68,10 @@ public void testRoundTrip() byte[] data = b2.serialize(); Biscuit deser = Biscuit.fromBytes(data, root.getPublicKey()); assertEquals(b2.print(), deser.print()); + assertEquals( + b2.externalPublicKeys(), List.of(Option.none(), Option.of(external.getPublicKey()))); + assertEquals(Option.none(), b2.blockExternalKey(0)); + assertEquals(Option.of(external.getPublicKey()), b2.blockExternalKey(1)); System.out.println("will check the token for resource=file1"); Authorizer authorizer = deser.authorizer(); From edbb12ea6a57d16842cb410c10c30a4c1c90286e Mon Sep 17 00:00:00 2001 From: Adam Preuss Date: Mon, 5 May 2025 12:58:37 -0600 Subject: [PATCH 3/3] Fix algorithm type of proof. --- .../token/format/SerializedBiscuit.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/eclipse/biscuit/token/format/SerializedBiscuit.java b/src/main/java/org/eclipse/biscuit/token/format/SerializedBiscuit.java index 9f39c4c7..500fa790 100644 --- a/src/main/java/org/eclipse/biscuit/token/format/SerializedBiscuit.java +++ b/src/main/java/org/eclipse/biscuit/token/format/SerializedBiscuit.java @@ -172,13 +172,18 @@ private static SerializedBiscuit deserialize(Schema.Biscuit data) throw new Error.FormatError.DeserializationError("invalid proof"); } - final Proof proof = - data.getProof().hasFinalSignature() - ? new Proof.FinalSignature(data.getProof().getFinalSignature().toByteArray()) - : new Proof.NextSecret( - KeyPair.generate( - authority.getKey().getAlgorithm(), - data.getProof().getNextSecret().toByteArray())); + final Proof proof; + if (data.getProof().hasFinalSignature()) { + proof = new Proof.FinalSignature(data.getProof().getFinalSignature().toByteArray()); + } else { + final Schema.PublicKey.Algorithm proofAlgorithm = + blocks.isEmpty() + ? authority.getKey().getAlgorithm() + : blocks.get(blocks.size() - 1).getKey().getAlgorithm(); + proof = + new Proof.NextSecret( + KeyPair.generate(proofAlgorithm, data.getProof().getNextSecret().toByteArray())); + } Option rootKeyId = data.hasRootKeyId() ? Option.some(data.getRootKeyId()) : Option.none();